diff --git a/src/main/java/com/teaching/backend/controller/chapter/ChapterController2.java b/src/main/java/com/teaching/backend/controller/chapter/ChapterController2.java index 68f58f1..d77e609 100644 --- a/src/main/java/com/teaching/backend/controller/chapter/ChapterController2.java +++ b/src/main/java/com/teaching/backend/controller/chapter/ChapterController2.java @@ -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> AllList(){ - List list= chapterService.list(); - return ResultUtils.success(list); + public BaseResponse> 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> getCourseChapters2(@RequestParam String courseId){ return ResultUtils.success(chapterService.getChapterTree(courseId)); - } + @ApiOperation("根据课程id查出对应的详细章节信息") + @GetMapping("/select/chapter/{chapterId}") + public BaseResponseselectChapter(@PathVariable Long chapterId){ + return ResultUtils.success(chapterService.selectChapter(chapterId)); + + } @ApiOperation("添加章节") @PostMapping("/add") @@ -65,7 +79,36 @@ public BaseResponse> 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 addChapter3(MultipartFile file, String courseId) { + try { + List 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 udChapter(@RequestBody Chapter chapter){ diff --git a/src/main/java/com/teaching/backend/mapper/chapter/ChapterMapper.java b/src/main/java/com/teaching/backend/mapper/chapter/ChapterMapper.java index 6825636..01859f9 100644 --- a/src/main/java/com/teaching/backend/mapper/chapter/ChapterMapper.java +++ b/src/main/java/com/teaching/backend/mapper/chapter/ChapterMapper.java @@ -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 { @Select("SELECT * FROM course_chapter WHERE course_id = #{courseId} AND (pid = #{parentId} )") List 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 selectByIdAndPid(@Param("chapterId") Long chapterId, @Param("courseId")String courseId); } diff --git a/src/main/java/com/teaching/backend/mapper/chapter/TemporaryChapterMapper.java b/src/main/java/com/teaching/backend/mapper/chapter/TemporaryChapterMapper.java new file mode 100644 index 0000000..54c2347 --- /dev/null +++ b/src/main/java/com/teaching/backend/mapper/chapter/TemporaryChapterMapper.java @@ -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; + +/** + *

+ * Mapper 接口 + *

+ * + * @author author + * @since 2024-05-31 + */ +public interface TemporaryChapterMapper extends BaseMapper { + + TemporaryChapter selectOneByPidAndOrderNumDesc(long l); + + List selectAll(); + + void deleteAll(); +} diff --git a/src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java b/src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java index 7ceb140..de5a912 100644 --- a/src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java +++ b/src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java @@ -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; } diff --git a/src/main/java/com/teaching/backend/model/entity/chapter/TemporaryChapter.java b/src/main/java/com/teaching/backend/model/entity/chapter/TemporaryChapter.java new file mode 100644 index 0000000..d7f371b --- /dev/null +++ b/src/main/java/com/teaching/backend/model/entity/chapter/TemporaryChapter.java @@ -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.knowtmp.Knowtmp; +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; + +/** + *

+ * + *

+ * + * @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 children; // 用于存储子章节 + + @ApiModelProperty(value = "知识点") + @TableField(exist = false) + private List knowledgePoints; // 用于存储章节下的知识点 + + +} diff --git a/src/main/java/com/teaching/backend/service/chapter/IChapterService.java b/src/main/java/com/teaching/backend/service/chapter/IChapterService.java index 9f50a31..6eafd1f 100644 --- a/src/main/java/com/teaching/backend/service/chapter/IChapterService.java +++ b/src/main/java/com/teaching/backend/service/chapter/IChapterService.java @@ -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 { 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 { 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); } diff --git a/src/main/java/com/teaching/backend/service/impl/chapter/ChapterExcelServiceImpl.java b/src/main/java/com/teaching/backend/service/impl/chapter/ChapterExcelServiceImpl.java new file mode 100644 index 0000000..a1a7af4 --- /dev/null +++ b/src/main/java/com/teaching/backend/service/impl/chapter/ChapterExcelServiceImpl.java @@ -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 uploadExcel(MultipartFile file, String courseId) { + List validationErrors = new ArrayList<>(); + try (InputStream inputStream = file.getInputStream()) { + validationErrors = excelParser.parse(inputStream, courseId); + } catch (Exception e) { + validationErrors.add("系统错误: " + e.getMessage()); + } + return validationErrors; + } +} \ No newline at end of file diff --git a/src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java b/src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java index 3e869b7..b763758 100644 --- a/src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java +++ b/src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java @@ -4,24 +4,32 @@ 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.KnowtmpMapper; 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.chapter.Chapter; +import com.teaching.backend.model.entity.chapter.TemporaryChapter; import com.teaching.backend.model.entity.knowtmp.Knowtmp; import com.teaching.backend.model.vo.chapter.ChapterVo; import com.teaching.backend.service.Know.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; @@ -33,14 +41,16 @@ import java.util.stream.Collectors; */ @Service public class ChapterServiceImpl extends ServiceImpl implements IChapterService { + @Autowired private ChapterMapper chapterMapper; @Autowired - private KnowtmpMapper knowtmpMapper; -// private int count=0; - List list=new ArrayList<>(); - + private TemporaryChapterMapper temporaryChapterMapper; + @Autowired + private KnowtmpMapper knowtmpMapper; + // private int count=0; + List list = new ArrayList<>(); @Override @@ -50,26 +60,26 @@ public class ChapterServiceImpl extends ServiceImpl impl String courseid = chapter.getCourseId(); Long pid = chapter.getPid(); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - Long countChapter ; + Long countChapter; // pid为0时,说明为章 - if("0".equals(pid)|| "".equals(pid)){ - wrapper.eq(Chapter::getCourseId,courseid); + if ("0".equals(pid) || "".equals(pid)) { + wrapper.eq(Chapter::getCourseId, courseid); countChapter = chapterMapper.selectCount(wrapper); - finalNumShow=String.valueOf(countChapter+1); + finalNumShow = String.valueOf(countChapter + 1); // chapter.setNumshow(String.valueOf(countChapter+1)); // System.out.println(chapter.getNumshow()); - }else{ + } else { // 为小节 Chapter chapter1 = chapterMapper.selectById(pid); - String parentNumShow =chapter1.getNumshow(); + String parentNumShow = chapter1.getNumshow(); System.out.println("909090"); System.out.println(parentNumShow); - wrapper.eq(Chapter::getCourseId,courseid) - .eq(Chapter::getPid,pid); + wrapper.eq(Chapter::getCourseId, courseid) + .eq(Chapter::getPid, pid); countChapter = chapterMapper.selectCount(wrapper); - System.out.println("-=-=-=-=-="+countChapter); - finalNumShow=parentNumShow + "-" + String.valueOf(countChapter + 1); + System.out.println("-=-=-=-=-=" + countChapter); + finalNumShow = parentNumShow + "-" + String.valueOf(countChapter + 1); } System.out.println("-=-=-=-=11"); System.out.println(finalNumShow); @@ -80,10 +90,10 @@ public class ChapterServiceImpl extends ServiceImpl impl public LinkedList getAll() { List list = chapterMapper.selectList(null); LinkedList linkedList = new LinkedList<>(list); - int i=0; - for (Chapter chapter:linkedList){ + int i = 0; + for (Chapter chapter : linkedList) { System.out.println(linkedList.get(i)); - System.out.println(i+"----"+chapter); + System.out.println(i + "----" + chapter); i++; } System.out.println(linkedList); @@ -93,7 +103,7 @@ public class ChapterServiceImpl extends ServiceImpl impl @Override public LinkedList getCourseChapter(String courseid) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(Chapter::getCourseId,courseid) + wrapper.eq(Chapter::getCourseId, courseid) .orderByAsc(Chapter::getNumshow); List list = chapterMapper.selectList(wrapper); LinkedList linkedList = new LinkedList<>(list); @@ -101,38 +111,38 @@ public class ChapterServiceImpl extends ServiceImpl impl } @Override - public LinkedList getChapterSection(String courseid){ + public LinkedList getChapterSection(String courseid) { // LinkedList list = new LinkedList<>(); // 获得所有的节,并按顺序进行排列 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(Chapter::getCourseId,courseid) - .like(Chapter::getNumshow,"-") + wrapper.eq(Chapter::getCourseId, courseid) + .like(Chapter::getNumshow, "-") .orderByAsc(Chapter::getNumshow); List prelist = chapterMapper.selectList(wrapper); System.out.println("所有的节"); System.out.println(prelist); // 获得所有的章节信息 LambdaQueryWrapper wrapper1 = new LambdaQueryWrapper<>(); - wrapper1.eq(Chapter::getCourseId,courseid) - .notLike(Chapter::getNumshow,"-") + wrapper1.eq(Chapter::getCourseId, courseid) + .notLike(Chapter::getNumshow, "-") .orderByAsc(Chapter::getNumshow); List chapterList = chapterMapper.selectList(wrapper1); System.out.println("0-0-0-0所有的章------------"); System.out.println(chapterList); // 类型转换chapter => chapterVo List chapterVoList = BeanUtil.copyToList(chapterList, ChapterVo.class); - chapterVoList = chapterVoList.stream().map((item) ->{ - for (int i=0;i { + for (int i = 0; i < prelist.size(); i++) { System.out.println("====================="); // System.out.println(prelist.get(i).getNumshow().split("-")[0].equals(item.getNumshow())); - if (prelist.get(i).getNumshow().split("-")[0].equals(item.getNumshow())){ + if (prelist.get(i).getNumshow().split("-")[0].equals(item.getNumshow())) { // System.out.println(item.getNumshow()+"[][][]"+i); - System.out.println("88888888888888888888888888"+prelist.get(i).getNumshow().split("-")[0]); + System.out.println("88888888888888888888888888" + prelist.get(i).getNumshow().split("-")[0]); // Chapter chapter = prelist.get(i); list.add(prelist.get(i)); item.setChapterSection(list); - System.out.println(prelist.get(i).getNumshow()+"-------------+121--"); - }else { + System.out.println(prelist.get(i).getNumshow() + "-------------+121--"); + } else { // list1=list; // System.out.println(item.getNumshow() + "[8888][][]"); // System.out.println(prelist.get(i).getNumshow().split("-")[0]); @@ -166,27 +176,27 @@ public class ChapterServiceImpl extends ServiceImpl impl @Override public List getChapterTree(String courseId) { - List chapters=baseMapper.selectSectionsByCourseId(courseId); + List chapters = baseMapper.selectSectionsByCourseId(courseId); - Map chapterMap=new HashMap<>(); + Map chapterMap = new HashMap<>(); - List roots=new ArrayList<>(); + List roots = new ArrayList<>(); - for (Chapter chapter:chapters){ + for (Chapter chapter : chapters) { chapter.setChildren(new ArrayList<>()); chapter.setKnowledgePoints(new ArrayList<>()); - chapterMap.put(chapter.getId(),chapter); + chapterMap.put(chapter.getId(), chapter); } - for (Chapter chapter:chapters){ - Long parentId=chapter.getPid(); - if (parentId!=0){ - Chapter parentChapter=chapterMap.get(parentId); + for (Chapter chapter : chapters) { + Long parentId = chapter.getPid(); + if (parentId != 0) { + Chapter parentChapter = chapterMap.get(parentId); if (parentChapter != null) { parentChapter.getChildren().add(chapter); } - }else { + } else { roots.add(chapter); } } @@ -208,15 +218,16 @@ public class ChapterServiceImpl extends ServiceImpl impl .collect(Collectors.toList()); chapter.setChildren(sortedChildren); - QueryWrapperqueryWrapper = new QueryWrapper<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); for (Chapter child : sortedChildren) { - queryWrapper.eq("chapterId",child.getId()); + queryWrapper.eq("chapterId", child.getId()); List knows = knowtmpMapper.selectList(queryWrapper); child.setKnowledgePoints(new ArrayList<>(knows)); loadKnowledgePointsRecursively(child); } } + @Override public void saveChapter(ChapterDTO chapterDTO) { @@ -227,7 +238,7 @@ public class ChapterServiceImpl extends ServiceImpl impl throw new RuntimeException("复制数据出错", e); } Long pid = chapter.getPid(); - if (pid == null ) { + if (pid == null) { chapter.setPid(0L); LambdaQueryWrapper maxSortWrapper = new LambdaQueryWrapper<>(); maxSortWrapper.eq(Chapter::getPid, 0).orderByDesc(Chapter::getOrderNum).last("limit 1"); @@ -247,7 +258,7 @@ public class ChapterServiceImpl extends ServiceImpl impl if (parentChapter != null) { LambdaQueryWrapper maxSortWrapper = new LambdaQueryWrapper<>(); - maxSortWrapper.eq(Chapter::getPid,pid).orderByDesc(Chapter::getOrderNum).last("limit 1"); + maxSortWrapper.eq(Chapter::getPid, pid).orderByDesc(Chapter::getOrderNum).last("limit 1"); parentChapter.setUpdateTime(LocalDateTime.now()); Chapter maxSortChapter = this.getOne(maxSortWrapper); @@ -264,11 +275,65 @@ public class ChapterServiceImpl extends ServiceImpl impl chapter.setUpdateTime(LocalDateTime.now()); this.save(chapter); } else { - throw new BusinessException(ErrorCode.PARAMS_ERROR,"未找到父章节,ID 为: " + pid); + throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,ID 为: " + pid); } } } + @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 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 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) { @@ -279,13 +344,14 @@ public class ChapterServiceImpl extends ServiceImpl impl throw new RuntimeException("复制数据出错", e); } - if (chapterId1 == null && chapterId2 == null||chapterId1!=null && chapterId2==null) { + if (chapterId1 == null && chapterId2 == null || chapterId1 != null && chapterId2 == null) { handleRootChapterInsertion(chapter); } else { handleChapterInsertion(chapterId1, chapterId2, chapter); } } + private void handleRootChapterInsertion(Chapter chapter) { Long pid = chapter.getPid(); if (pid == null) { @@ -343,11 +409,149 @@ public class ChapterServiceImpl extends ServiceImpl impl public void upChapter(Long chapterId) { moveChapter(chapterId, true); } + @Override public void downChapter(Long chapterId) { moveChapter(chapterId, false); } + @Override + public void downExcel(HttpServletResponse response) throws IOException { + ExcelUtils.createTemplateExcel(response); + } + + @Override + public Page getAllChapters(int page, int pageSize) { + + Page pageInfo = new Page<>(page, pageSize); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + this.page(pageInfo, queryWrapper); + + return pageInfo; + } + + @Override + public Chapter selectChapter(Long chapterId) { + LambdaQueryWrapper 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 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 lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(Chapter::getCourseId, courseId); + + List chapterList = this.list(lambdaQueryWrapper); + ExcelUtils.createDataExcel(response, chapterList); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public void moveDataFromTemporaryToFinal() { + List temporaryChapters = temporaryChapterMapper.selectAll(); + Map 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) { @@ -402,79 +606,80 @@ public class ChapterServiceImpl extends ServiceImpl impl updateChapter.setOrderNum(newOrderNum); this.updateById(updateChapter); } + @Override public void deleteChapter(Long id) { - if (id==null){ - throw new BusinessException(ErrorCode.PARAMS_ERROR,"请求参数不能为空"); + if (id == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空"); } - LambdaQueryWrapperqueryWrapper=new LambdaQueryWrapper<>(); - queryWrapper.eq(Chapter::getId,id); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Chapter::getId, id); - LambdaQueryWrapperlambdaQueryWrapper=new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Chapter::getPid,id); - Long count= this.count(lambdaQueryWrapper); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(Chapter::getPid, id); + Long count = this.count(lambdaQueryWrapper); - if (count>0){ - throw new BusinessException(ErrorCode.OPERATION_ERROR,"存在子章节,无法删除"); - } - QueryWrapperqueryWrapper1 = new QueryWrapper<>(); - queryWrapper1.eq("chapterId",id); + if (count > 0) { + throw new BusinessException(ErrorCode.OPERATION_ERROR, "存在子章节,无法删除"); + } + QueryWrapper queryWrapper1 = new QueryWrapper<>(); + queryWrapper1.eq("chapterId", id); List knows = knowtmpMapper.selectList(queryWrapper1); if (!knows.isEmpty()) { throw new BusinessException(ErrorCode.OPERATION_ERROR, "子章节下存在知识点,无法删除"); } - this.remove(queryWrapper); + this.remove(queryWrapper); } - public void updateNumShow(String numshow, String courseid){ + public void updateNumShow(String numshow, String courseid) { // 查询课程章节 getCourseChapter LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(Chapter::getCourseId,courseid) + wrapper.eq(Chapter::getCourseId, courseid) .orderByAsc(Chapter::getNumshow); List chapterList = chapterMapper.selectList(wrapper); System.out.println("0-0-0-0-00-------"); System.out.println(chapterList); List newlist = new ArrayList<>(); - int count=0,j=0; + int count = 0, j = 0; int i = numshow.indexOf("-"); // 删除的为章 - if(i==-1){ + if (i == -1) { System.out.println("9999999"); - for(int k=0;k impl // list.get(i).setNumshow( String.valueOf(num) ); // } } - } - else{ + } else { String[] split = numshow.split("-"); - for (int k=0;k< chapterList.size();k++){ - System.out.println("009988"+String.valueOf(Integer.parseInt(split[0])+1)); + for (int k = 0; k < chapterList.size(); k++) { + System.out.println("009988" + String.valueOf(Integer.parseInt(split[0]) + 1)); // 找到下一章的起始点 - if (chapterList.get(k).getNumshow().equals(String.valueOf(Integer.parseInt(split[0])+1))){ - count=k; + if (chapterList.get(k).getNumshow().equals(String.valueOf(Integer.parseInt(split[0]) + 1))) { + count = k; } - if (chapterList.get(k).getNumshow().equals(numshow)){ - j=k; + if (chapterList.get(k).getNumshow().equals(numshow)) { + j = k; chapterMapper.deleteById(chapterList.get(k).getId()); - }else{ + } else { newlist.add(chapterList.get(k)); } } - System.out.println(count+"''''''"+j); - for (int k=j;k parse(InputStream inputStream, String courseId) throws Exception { + OPCPackage pkg = OPCPackage.open(inputStream); + List 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/teaching/backend/utils/Chapter/ExcelUtils.java b/src/main/java/com/teaching/backend/utils/Chapter/ExcelUtils.java new file mode 100644 index 0000000..1f08f3b --- /dev/null +++ b/src/main/java/com/teaching/backend/utils/Chapter/ExcelUtils.java @@ -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 chapterList) throws IOException { + String[] titles = new String[]{"编号", "章节", "上级编号"}; + Sheet sheet = createWorkbookAndSheet("用户数据", titles); + + Map 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 createIdMapping(List chapterList) { + Map 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(); + } + } +} diff --git a/src/main/java/com/teaching/backend/utils/Chapter/SheetHandler.java b/src/main/java/com/teaching/backend/utils/Chapter/SheetHandler.java new file mode 100644 index 0000000..c78d062 --- /dev/null +++ b/src/main/java/com/teaching/backend/utils/Chapter/SheetHandler.java @@ -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 excelIdToDatabaseIdMap = new HashMap<>(); + private List validationErrors = new ArrayList<>(); + private boolean hasErrors = false; + private List 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 errors = validateChapter(chapterDTO); + if (!errors.isEmpty()) { + validationErrors.addAll(errors); + hasErrors = true; + return; + } + + collectedChapters.add(chapterDTO); + } + } + + public List 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 validateChapter(ChapterDTO chapterDTO) { + List 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; + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/mapper/TemporaryChapterMapper.xml b/src/main/resources/mapper/TemporaryChapterMapper.xml new file mode 100644 index 0000000..54932b1 --- /dev/null +++ b/src/main/resources/mapper/TemporaryChapterMapper.xml @@ -0,0 +1,21 @@ + + + + + DELETE FROM temporary_chapter + + + + + + \ No newline at end of file