小萌新 4 months ago
parent f2086ebf35
commit bdf0301721
  1. 51
      src/main/java/com/teaching/backend/controller/chapter/ChapterController2.java
  2. 10
      src/main/java/com/teaching/backend/mapper/chapter/ChapterMapper.java
  3. 28
      src/main/java/com/teaching/backend/mapper/chapter/TemporaryChapterMapper.java
  4. 11
      src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java
  5. 95
      src/main/java/com/teaching/backend/model/entity/chapter/TemporaryChapter.java
  6. 20
      src/main/java/com/teaching/backend/service/chapter/IChapterService.java
  7. 36
      src/main/java/com/teaching/backend/service/impl/chapter/ChapterExcelServiceImpl.java
  8. 208
      src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java
  9. 75
      src/main/java/com/teaching/backend/utils/Chapter/ExcelParser.java
  10. 113
      src/main/java/com/teaching/backend/utils/Chapter/ExcelUtils.java
  11. 134
      src/main/java/com/teaching/backend/utils/Chapter/SheetHandler.java
  12. 21
      src/main/resources/mapper/TemporaryChapterMapper.xml

@ -1,15 +1,21 @@
package com.teaching.backend.controller.chapter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.teaching.backend.common.BaseResponse;
import com.teaching.backend.common.ErrorCode;
import com.teaching.backend.common.ResultUtils;
import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.service.chapter.IChapterService;
import com.teaching.backend.service.impl.chapter.ChapterExcelServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
@ -29,21 +35,29 @@ public class ChapterController2 {
@Autowired
IChapterService chapterService;
@Autowired
ChapterExcelServiceImpl chapterExcelService;
@ApiOperation("查询全部的章节")
@GetMapping("/list")
public BaseResponse<List<Chapter>> AllList(){
List<Chapter> list= chapterService.list();
return ResultUtils.success(list);
public BaseResponse<Page<Chapter>> AllList(@RequestParam(value = "page",defaultValue = "1") int page,
@RequestParam(value = "pageSize",defaultValue = "5") int pageSize){
return ResultUtils.success(chapterService.getAllChapters(page,pageSize));
}
@ApiOperation("根据课程id查出对应的父子章节")
@GetMapping("/chapter")
public BaseResponse<List<Chapter>> getCourseChapters2(@RequestParam String courseId){
return ResultUtils.success(chapterService.getChapterTree(courseId));
}
@ApiOperation("根据课程id查出对应的详细章节信息")
@GetMapping("/select/chapter/{chapterId}")
public BaseResponse<Chapter>selectChapter(@PathVariable Long chapterId){
return ResultUtils.success(chapterService.selectChapter(chapterId));
}
@ApiOperation("添加章节")
@PostMapping("/add")
@ -65,7 +79,36 @@ public BaseResponse<List<Chapter>> getCourseChapters2(@RequestParam String cours
return ResultUtils.success("删除成功");
}
@ApiOperation("下载Excel模版")
@GetMapping("/downExcel")
public void downExcel2(HttpServletResponse response) throws IOException {
chapterService.downExcel(response);
}
@ApiOperation("导入excel")
@PostMapping("/uploadExcel")
public BaseResponse<String> addChapter3(MultipartFile file, String courseId) {
try {
List<String> validationErrors = chapterExcelService.uploadExcel(file, courseId);
if (!validationErrors.isEmpty()) {
StringBuilder errorMessage = new StringBuilder();
for (String error : validationErrors) {
errorMessage.append(error).append("\n");
}
return ResultUtils.error(ErrorCode.OPERATION_ERROR, errorMessage.toString());
} else {
return ResultUtils.success("添加成功!!!!!!!!");
}
} catch (Exception e) {
return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误: " + e.getMessage());
}
}
@ApiOperation("导出数据")
@GetMapping(value = "/downLoadExcel")
public void downLoadXlsx(HttpServletResponse response,String courseId) throws Exception{
chapterService.downLoadXlsx(response,courseId);
}
@ApiOperation("修改章节")
@PutMapping("/update")
public BaseResponse<String> udChapter(@RequestBody Chapter chapter){

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.teaching.backend.model.entity.chapter.Chapter;
import io.lettuce.core.dynamic.annotation.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
@ -22,5 +23,14 @@ public interface ChapterMapper extends BaseMapper<Chapter> {
@Select("SELECT * FROM course_chapter WHERE course_id = #{courseId} AND (pid = #{parentId} )")
List<Chapter> selectSectionsWithChildren(@Param("courseId") String courseId, @Param("parentId") String parentId);
@Select("SELECT * FROM chapter WHERE id = #{excelId}")
Chapter findByExcelId(Long excelId);
@Update("UPDATE chapter SET pid = #{newPid} WHERE id = #{id}")
void updatePidById(@Param("id") Long id, @Param("newPid") Long newPid);
@Select("SELECT id, name, course_id FROM chapter WHERE name = #{name} AND course_id = #{courseId}")
Chapter selectByNameAndCourseId(@Param("name") String name, @Param("courseId") String courseId);
@Select("select pid ,course_id,total_class_hours from chapter where pid = #{chapterId} and course_id = #{courseId} ")
List<Chapter> selectByIdAndPid(@Param("chapterId") Long chapterId, @Param("courseId")String courseId);
}

@ -0,0 +1,28 @@
package com.teaching.backend.mapper.chapter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.model.entity.chapter.TemporaryChapter;
import io.lettuce.core.dynamic.annotation.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* <p>
* Mapper 接口
* </p>
*
* @author author
* @since 2024-05-31
*/
public interface TemporaryChapterMapper extends BaseMapper<TemporaryChapter> {
TemporaryChapter selectOneByPidAndOrderNumDesc(long l);
List<TemporaryChapter> selectAll();
void deleteAll();
}

@ -1,5 +1,7 @@
package com.teaching.backend.model.dto.chapter;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -28,12 +30,14 @@ public class ChapterDTO implements Serializable {
@ApiModelProperty(value = "创建日期")
@JsonFormat(pattern = "yyyy/M/d HH:mm:ss")
private LocalDateTime createTime;
@ApiModelProperty(value = "更新人")
private String updateBy;
@ApiModelProperty(value = "更新日期")
@JsonFormat(pattern = "yyyy/M/d HH-mm-ss")
private LocalDateTime updateTime;
@ApiModelProperty(value = "所属部门")
@ -74,7 +78,12 @@ public class ChapterDTO implements Serializable {
@ApiModelProperty(value = "内部序号显示")
private String numshow;
@ApiModelProperty(value = "excel上级序号")
@TableField(exist = false)
private Long ParentExcelId;
@ApiModelProperty(value = "excel序号")
@TableField(exist = false)
private Long ExcelId;
}

@ -0,0 +1,95 @@
package com.teaching.backend.model.entity.chapter;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.teaching.backend.model.entity.Knowtemp.Knowtemp;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
*
* </p>
*
* @author author
* @since 2024-05-31
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("temporary_chapter")
public class TemporaryChapter implements Serializable {
@ApiModelProperty(value = "主键")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "创建人")
private String createBy;
@ApiModelProperty(value = "创建日期")
private LocalDateTime createTime;
@ApiModelProperty(value = "更新人")
private String updateBy;
@ApiModelProperty(value = "更新日期")
private LocalDateTime updateTime;
@ApiModelProperty(value = "所属部门")
private String sysOrgCode;
@ApiModelProperty(value = "序号")
private Double orderNum;
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "简介")
private String content;
@ApiModelProperty(value = "父级节点")
private Long pid;
@ApiModelProperty(value = "课程")
private String courseId;
@ApiModelProperty(value = "课程目标")
private String courseObjectivesId;
@ApiModelProperty(value = "总学时")
private String totalClassHours;
@ApiModelProperty(value = "要求")
private String requirement;
@ApiModelProperty(value = "线上学时")
private String onlineClassHours;
@ApiModelProperty(value = "周次")
private String zc;
@ApiModelProperty(value = "内部序号显示")
private String numshow;
@ApiModelProperty(value = "子章节")
@TableField(exist = false)
private List<TemporaryChapter> children; // 用于存储子章节
@ApiModelProperty(value = "知识点")
@TableField(exist = false)
private List<Knowtemp> knowledgePoints; // 用于存储章节下的知识点
}

@ -1,11 +1,15 @@
package com.teaching.backend.service.chapter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.model.vo.chapter.ChapterVo;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
@ -32,6 +36,9 @@ public interface IChapterService extends IService<Chapter> {
void saveChapter(ChapterDTO chapterDTO);
Long saveExcelChapter2(ChapterDTO chapterDTO, boolean b);
void insertChapter(Long chapterId1, Long chapterId2, ChapterDTO newChapterDTO);
void deleteChapter(Long id);
@ -41,4 +48,17 @@ public interface IChapterService extends IService<Chapter> {
void downChapter(Long chapterId);
void downLoadXlsx(HttpServletResponse response, String courseId) throws IOException;
void moveDataFromTemporaryToFinal();
Long saveToTemporaryTable(ChapterDTO chapterDTO);
void downExcel(HttpServletResponse response) throws IOException;
Page getAllChapters(int page, int pageSize);
Chapter selectChapter(Long chapterId);
}

@ -0,0 +1,36 @@
package com.teaching.backend.service.impl.chapter;
import com.teaching.backend.utils.Chapter.ExcelParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* ClassName: ChapterExcelServiceImpl
* Package: com.teaching.backend.service.impl.chapter
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/4 10:50
* @Version 1.0
*/
@Service
public class ChapterExcelServiceImpl {
@Autowired
ExcelParser excelParser;
public List<String> uploadExcel(MultipartFile file, String courseId) {
List<String> validationErrors = new ArrayList<>();
try (InputStream inputStream = file.getInputStream()) {
validationErrors = excelParser.parse(inputStream, courseId);
} catch (Exception e) {
validationErrors.add("系统错误: " + e.getMessage());
}
return validationErrors;
}
}

@ -4,21 +4,29 @@ package com.teaching.backend.service.impl.chapter;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.teaching.backend.common.ErrorCode;
import com.teaching.backend.exception.BusinessException;
import com.teaching.backend.mapper.Knowtemp.KnowtempMapper;
import com.teaching.backend.mapper.chapter.ChapterMapper;
import com.teaching.backend.mapper.chapter.TemporaryChapterMapper;
import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.model.entity.Knowtemp.Knowtemp;
import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.model.entity.chapter.TemporaryChapter;
import com.teaching.backend.model.vo.chapter.ChapterVo;
import com.teaching.backend.service.KnowGraph.KnowService;
import com.teaching.backend.service.chapter.IChapterService;
import com.teaching.backend.utils.Chapter.ExcelUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -30,9 +38,12 @@ import java.util.stream.Collectors;
*/
@Service
public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> implements IChapterService {
@Autowired
private ChapterMapper chapterMapper;
@Autowired
private TemporaryChapterMapper temporaryChapterMapper;
@Autowired
private KnowtempMapper knowtempMapper;
// private int count=0;
@ -217,7 +228,7 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
}
@Override
public void saveChapter(ChapterDTO chapterDTO) {
System.out.println("我导入Excel成功进入到了这一步");
Chapter chapter = new Chapter();
try {
BeanUtils.copyProperties(chapterDTO, chapter);
@ -225,7 +236,7 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
throw new RuntimeException("复制数据出错", e);
}
Long pid = chapter.getPid();
if (pid == null ) {
if (pid == null ) {
chapter.setPid(0L);
LambdaQueryWrapper<Chapter> maxSortWrapper = new LambdaQueryWrapper<>();
maxSortWrapper.eq(Chapter::getPid, 0).orderByDesc(Chapter::getOrderNum).last("limit 1");
@ -266,6 +277,59 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
}
}
}
@Override
public Long saveExcelChapter2(ChapterDTO chapterDTO, boolean isParent) {
Chapter chapter = new Chapter();
try {
BeanUtils.copyProperties(chapterDTO, chapter);
} catch (Exception e) {
throw new RuntimeException("复制数据出错", e); // 使用自定义异常
}
LocalDateTime now = LocalDateTime.now();
chapter.setCreateTime(now);
chapter.setUpdateTime(now);
Long pid = chapter.getPid();
if (isParent) {
if (pid == null || pid == 0) {
chapter.setPid(0L);
LambdaQueryWrapper<Chapter> maxSortWrapper = new LambdaQueryWrapper<>();
maxSortWrapper.eq(Chapter::getPid, 0).orderByDesc(Chapter::getOrderNum).last("limit 1");
Chapter maxSortChapter = this.getOne(maxSortWrapper);
double newSort = (maxSortChapter != null) ? maxSortChapter.getOrderNum() + 1 : 1;
chapter.setOrderNum(newSort);
this.save(chapter);
return chapter.getId();
}
}else {
Chapter parentChapter = this.getById(pid);
if (parentChapter != null) {
LambdaQueryWrapper<Chapter> maxSortWrapper = new LambdaQueryWrapper<>();
maxSortWrapper.eq(Chapter::getPid, pid).orderByDesc(Chapter::getOrderNum).last("limit 1");
Chapter maxSortChapter = this.getOne(maxSortWrapper);
double newSort = (maxSortChapter != null) ? maxSortChapter.getOrderNum() + 1 : 1;
chapter.setOrderNum(newSort);
parentChapter.setUpdateTime(now);
this.updateById(parentChapter);
this.save(chapter);
return chapter.getId();
} else {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,ID 为: " + pid);
}
} return null;
}
@Override
public void insertChapter(Long chapterId1, Long chapterId2, ChapterDTO newChapterDTO) {
@ -346,6 +410,146 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
moveChapter(chapterId, false);
}
@Override
public void downExcel(HttpServletResponse response) throws IOException {
ExcelUtils.createTemplateExcel(response);
}
@Override
public Page<Chapter>getAllChapters(int page, int pageSize) {
Page<Chapter> pageInfo=new Page<>(page,pageSize);
LambdaQueryWrapper<Chapter> queryWrapper=new LambdaQueryWrapper<>();
this.page(pageInfo,queryWrapper);
return pageInfo;
}
@Override
public Chapter selectChapter(Long chapterId) {
LambdaQueryWrapper<Chapter> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Chapter::getId, chapterId);
Chapter chapter = this.getOne(lambdaQueryWrapper);
if (chapter == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "请求数据不存在");
}
if (chapter.getPid() == 0) {
String courseId = chapter.getCourseId();
List<Chapter> subChapters = chapterMapper.selectByIdAndPid(chapterId,courseId);
BigDecimal totalClassHours = BigDecimal.ZERO;
for (Chapter subChapter : subChapters) {
try {
BigDecimal classHours = new BigDecimal(subChapter.getTotalClassHours());
totalClassHours = totalClassHours.add(classHours);
} catch (NumberFormatException e) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "无效的总学时数据");
}
}
chapter.setTotalClassHours(String.valueOf(totalClassHours));
}else {
chapter.setTotalClassHours(chapter.getTotalClassHours());
}
return chapter;
}
@Override
public void downLoadXlsx(HttpServletResponse response, String courseId) throws IOException {
LambdaQueryWrapper<Chapter> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Chapter::getCourseId, courseId);
List<Chapter> chapterList = this.list(lambdaQueryWrapper);
ExcelUtils.createDataExcel(response, chapterList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void moveDataFromTemporaryToFinal() {
List<TemporaryChapter> temporaryChapters = temporaryChapterMapper.selectAll();
Map<Long, Long> tempIdToFinalIdMap = new HashMap<>();
for (TemporaryChapter tempChapter : temporaryChapters) {
Chapter existingChapter = chapterMapper.selectByNameAndCourseId(tempChapter.getName(), tempChapter.getCourseId());
if (existingChapter != null) {
tempIdToFinalIdMap.put(tempChapter.getId(), existingChapter.getId());
continue;
}
Chapter finalChapter = new Chapter();
try {
BeanUtils.copyProperties(tempChapter, finalChapter);
} catch (Exception e) {
throw new RuntimeException("复制数据出错", e);
}
finalChapter.setId(null);
this.save(finalChapter);
tempIdToFinalIdMap.put(tempChapter.getId(), finalChapter.getId());
}
for (TemporaryChapter tempChapter : temporaryChapters) {
if (tempChapter.getPid() != 0) {
Long newPid = tempIdToFinalIdMap.get(tempChapter.getPid());
if (newPid != null) {
chapterMapper.updatePidById(tempIdToFinalIdMap.get(tempChapter.getId()), newPid);
} else {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,临时表 ID 为: " + tempChapter.getPid());
}
}
}
temporaryChapterMapper.deleteAll();
}
@Transactional(rollbackFor = Exception.class)
@Override
public Long saveToTemporaryTable(ChapterDTO chapterDTO) {
TemporaryChapter temporaryChapter = new TemporaryChapter();
try {
BeanUtils.copyProperties(chapterDTO, temporaryChapter);
} catch (Exception e) {
throw new RuntimeException("复制数据出错", e);
}
Long pid = temporaryChapter.getPid();
if (pid == null || pid == 0) {
temporaryChapter.setPid(0L);
setChapterOrder(temporaryChapter, 0L);
} else {
TemporaryChapter parentChapter = temporaryChapterMapper.selectById(pid);
if (parentChapter != null) {
temporaryChapter.setPid(parentChapter.getId());
setChapterOrder(temporaryChapter, pid);
} else {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,ID 为: " + pid);
}
}
temporaryChapterMapper.insert(temporaryChapter);
return temporaryChapter.getId();
}
private void setChapterOrder(TemporaryChapter chapter, Long pid) {
TemporaryChapter maxSortChapter = temporaryChapterMapper.selectOneByPidAndOrderNumDesc(pid);
double newSort = (maxSortChapter != null) ? maxSortChapter.getOrderNum() + 1 : 1;
chapter.setOrderNum(newSort);
chapter.setCreateTime(LocalDateTime.now());
chapter.setUpdateTime(LocalDateTime.now());
}
public void moveChapter(Long chapterId, boolean moveUp) {

@ -0,0 +1,75 @@
package com.teaching.backend.utils.Chapter;
/**
* ClassName: ExcelParser
* Package: com.teaching
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/3 14:58
* @Version 1.0
*/
import com.teaching.backend.service.chapter.IChapterService;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义Excel解析器
*/
@Component
public class ExcelParser {
@Autowired
IChapterService chapterService;
public List<String> parse(InputStream inputStream, String courseId) throws Exception {
OPCPackage pkg = OPCPackage.open(inputStream);
List<String> validationErrors = new ArrayList<>();
try {
XSSFReader reader = new XSSFReader(pkg);
SharedStringsTable sst = reader.getSharedStringsTable();
StylesTable styles = reader.getStylesTable();
XMLReader parser = XMLReaderFactory.createXMLReader();
SheetHandler sheetHandler = new SheetHandler(chapterService, courseId);
parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, sheetHandler, false));
XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
while (sheets.hasNext()) {
InputStream sheetstream = sheets.next();
InputSource sheetSource = new InputSource(sheetstream);
try {
parser.parse(sheetSource);
} finally {
sheetstream.close();
}
}
validationErrors = sheetHandler.finalizeProcess();
if (!validationErrors.isEmpty()) {
for (String error : validationErrors) {
System.out.println("导入错误: " + error);
}
} else {
System.out.println("数据导入成功!");
}
} finally {
pkg.close();
}
return validationErrors;
}
}

@ -0,0 +1,113 @@
package com.teaching.backend.utils.Chapter;
import com.teaching.backend.common.ErrorCode;
import com.teaching.backend.exception.BusinessException;
import com.teaching.backend.model.entity.chapter.Chapter;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ClassName: ExcelUtils
* Package: com.teaching.backend.utils.Chapter
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/7 18:57
* @Version 1.0
*/
public class ExcelUtils {
public static void createTemplateExcel(HttpServletResponse response) throws IOException {
String[] titles = new String[]{"编号", "章节", "上级编号"};
Sheet sheet = createWorkbookAndSheet("模版", titles);
// 添加模板数据
Row templateRow = sheet.createRow(1);
templateRow.createCell(0).setCellValue(1);
templateRow.createCell(1).setCellValue("示例父章节名");
templateRow.createCell(2).setCellValue(0);
Row templateRow2 = sheet.createRow(2);
templateRow2.createCell(0).setCellValue(2);
templateRow2.createCell(1).setCellValue("示例子章节名");
templateRow2.createCell(2).setCellValue(1);
writeWorkbookToResponse(sheet.getWorkbook(), response, "章节模版.xlsx");
}
public static void createDataExcel(HttpServletResponse response, List<Chapter> chapterList) throws IOException {
String[] titles = new String[]{"编号", "章节", "上级编号"};
Sheet sheet = createWorkbookAndSheet("用户数据", titles);
Map<Long, Integer> idMapping = createIdMapping(chapterList);
int rowIndex = 1;
for (Chapter chapter : chapterList) {
Row row = sheet.createRow(rowIndex);
Integer excelId = idMapping.get(chapter.getId());
if (excelId == null) {
throw new BusinessException(ErrorCode.OPERATION_ERROR);
}
row.createCell(0).setCellValue(excelId);
row.createCell(1).setCellValue(chapter.getName());
long parentId = chapter.getPid() != 0 ? idMapping.get(chapter.getPid()) : 0;
row.createCell(2).setCellValue(parentId != 0 ? parentId : 0);
rowIndex++;
}
writeWorkbookToResponse(sheet.getWorkbook(), response, "章节数据.xlsx");
}
private static Map<Long, Integer> createIdMapping(List<Chapter> chapterList) {
Map<Long, Integer> idMapping = new HashMap<>();
int newId = 1;
for (Chapter chapter : chapterList) {
idMapping.put(chapter.getId(), newId);
newId++;
}
return idMapping;
}
private static Sheet createWorkbookAndSheet(String sheetName, String[] titles) throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet(sheetName);
// 设置列宽
sheet.setColumnWidth(0, 30 * 256);
sheet.setColumnWidth(1, 60 * 256);
sheet.setColumnWidth(2, 30 * 256);
// 创建标题行
Row titleRow = sheet.createRow(0);
for (int i = 0; i < titles.length; i++) {
Cell cell = titleRow.createCell(i);
cell.setCellValue(titles[i]);
}
return sheet;
}
private static void writeWorkbookToResponse(Workbook workbook, HttpServletResponse response, String filename) throws IOException {
response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes(), "ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
try (ServletOutputStream outputStream = response.getOutputStream()) {
workbook.write(outputStream);
outputStream.flush();
} finally {
workbook.close();
}
}
}

@ -0,0 +1,134 @@
package com.teaching.backend.utils.Chapter;
import com.teaching.backend.common.ErrorCode;
import com.teaching.backend.common.ResultUtils;
import com.teaching.backend.exception.BusinessException;
import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.service.chapter.IChapterService;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;
import java.util.*;
/**
* ClassName: SheetHandler
* Package: com.teaching.backend.utils
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/3 14:13
* @Version 1.0
*/
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {
private final IChapterService chapterService;
private final String courseId;
private ChapterDTO chapterDTO;
private Map<Long, Long> excelIdToDatabaseIdMap = new HashMap<>();
private List<String> validationErrors = new ArrayList<>();
private boolean hasErrors = false;
private List<ChapterDTO> collectedChapters = new ArrayList<>();
public SheetHandler(IChapterService chapterService, String courseId) {
this.chapterService = chapterService;
this.courseId = courseId;
}
@Override
public void startRow(int rowIndex) {
if (rowIndex == 0) {
chapterDTO = null;
} else {
chapterDTO = new ChapterDTO();
chapterDTO.setCourseId(courseId);
}
}
@Override
public void endRow(int rowIndex) {
if (rowIndex != 0 && chapterDTO != null) {
List<String> errors = validateChapter(chapterDTO);
if (!errors.isEmpty()) {
validationErrors.addAll(errors);
hasErrors = true;
return;
}
collectedChapters.add(chapterDTO);
}
}
public List<String> finalizeProcess() {
if (hasErrors) {
return validationErrors;
}
for (ChapterDTO chapter : collectedChapters) {
if (chapter.getParentExcelId() == null || chapter.getParentExcelId() == 0) {
saveToTemporaryTable(chapter);
}
}
for (ChapterDTO chapter : collectedChapters) {
if (chapter.getParentExcelId() != null && chapter.getParentExcelId() != 0) {
saveToTemporaryTable(chapter);
}
}
chapterService.moveDataFromTemporaryToFinal();
return Collections.emptyList();
}
private void saveToTemporaryTable(ChapterDTO chapterDTO) {
Long pid = chapterDTO.getParentExcelId();
if (pid != null && pid != 0) {
Long parentId = excelIdToDatabaseIdMap.get(pid);
if (parentId != null) {
chapterDTO.setPid(parentId);
} else {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,Excel ID 为: " + pid);
}
}
Long savedChapterId = chapterService.saveToTemporaryTable(chapterDTO);
excelIdToDatabaseIdMap.put(chapterDTO.getExcelId(), savedChapterId);
}
private List<String> validateChapter(ChapterDTO chapterDTO) {
List<String> errors = new ArrayList<>();
if (chapterDTO.getName() == null || chapterDTO.getName().isEmpty()) {
errors.add("编号:"+chapterDTO.getExcelId()+"的章节名字不能为空");
}
if (chapterDTO.getExcelId() == null || chapterDTO.getExcelId() <= 0) {
errors.add("编号不能小于0");
}
if (chapterDTO.getParentExcelId() == null || chapterDTO.getParentExcelId() < 0) {
errors.add("编号:"+chapterDTO.getExcelId()+"的上级编号不能小于0");
}
return errors;
}
@Override
public void cell(String cellReference, String formattedValue, XSSFComment comment) {
if (chapterDTO != null && formattedValue != null) {
String letter = cellReference.substring(0, 1);
switch (letter) {
case "A":
chapterDTO.setExcelId(Long.valueOf(formattedValue));
break;
case "B":
chapterDTO.setName(formattedValue);
break;
case "C":
chapterDTO.setParentExcelId(Long.valueOf(formattedValue));
break;
}
}
}
}

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.teaching.backend.mapper.chapter.TemporaryChapterMapper">
<delete id="deleteAll">
DELETE FROM temporary_chapter
</delete>
<select id="selectOneByPidAndOrderNumDesc" resultType="com.teaching.backend.model.entity.chapter.TemporaryChapter">
SELECT * FROM temporary_chapter
WHERE pid = #{pid}
ORDER BY order_num DESC
LIMIT 1
</select>
<select id="selectAll" resultType="com.teaching.backend.model.entity.chapter.TemporaryChapter">
SELECT * FROM temporary_chapter
</select>
</mapper>
Loading…
Cancel
Save