master
小萌新 3 months ago
parent 896ba81d60
commit f2a53a6e33
  1. 1
      src/main/java/com/teaching/backend/model/dto/chapter/ChapterDTO.java
  2. 100
      src/main/java/com/teaching/backend/model/dto/chapter/ChapterExcelDTO.java
  3. 2
      src/main/java/com/teaching/backend/model/entity/chapter/TemporaryChapter.java
  4. 4
      src/main/java/com/teaching/backend/service/chapter/IChapterService.java
  5. 13
      src/main/java/com/teaching/backend/service/impl/chapter/ChapterServiceImpl.java
  6. 24
      src/main/java/com/teaching/backend/utils/Chapter/ExcelParser.java
  7. 131
      src/main/java/com/teaching/backend/utils/Chapter/SheetHandler.java
  8. 34
      src/main/java/com/teaching/backend/utils/Chapter/SheetPreScanner.java

@ -67,7 +67,6 @@ public class ChapterDTO implements Serializable {
@ApiModelProperty(value = "要求") @ApiModelProperty(value = "要求")
private String requirement; private String requirement;
@ApiModelProperty(value = "线上学时") @ApiModelProperty(value = "线上学时")
private String onlineClassHours; private String onlineClassHours;

@ -0,0 +1,100 @@
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;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* ClassName: ChapterExcelDto
* Package: com.teaching.backend.model.dto.chapter
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/10 13:44
* @Version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChapterExcelDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "创建人")
private String createBy;
@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 = "所属部门")
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 = "课程id")
private String courseId;
@ApiModelProperty(value = "课程目标")
private String courseObjectivesId;
@ApiModelProperty(value = "总学时")
private double totalClassHours;
@ApiModelProperty(value = "要求")
private String requirement;
@TableField(exist = false)
@ApiModelProperty(value = "是否是节")
private boolean isSection;
@TableField(exist = false)
@ApiModelProperty(value = "章内序号")
private Integer internalOrder;
@ApiModelProperty(value = "线上学时")
private String onlineClassHours;
@ApiModelProperty(value = "周次")
private String zc;
@ApiModelProperty(value = "内部序号显示")
private String numshow;
@ApiModelProperty(value = "excel上级序号")
@TableField(exist = false)
private Long ParentExcelId;
@ApiModelProperty(value = "excel序号")
@TableField(exist = false)
private Long ExcelId;
public void setIsSection(boolean b) {
this.isSection=b;
}
}

@ -69,7 +69,7 @@ public class TemporaryChapter implements Serializable {
private String courseObjectivesId; private String courseObjectivesId;
@ApiModelProperty(value = "总学时") @ApiModelProperty(value = "总学时")
private String totalClassHours; private double totalClassHours;
@ApiModelProperty(value = "要求") @ApiModelProperty(value = "要求")
private String requirement; private String requirement;

@ -4,12 +4,12 @@ package com.teaching.backend.service.chapter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.teaching.backend.model.dto.chapter.ChapterDTO; import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.model.dto.chapter.ChapterExcelDTO;
import com.teaching.backend.model.entity.chapter.Chapter; import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.model.vo.chapter.ChapterVo; import com.teaching.backend.model.vo.chapter.ChapterVo;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -54,7 +54,7 @@ public interface IChapterService extends IService<Chapter> {
void moveDataFromTemporaryToFinal(); void moveDataFromTemporaryToFinal();
Long saveToTemporaryTable(ChapterDTO chapterDTO); Long saveToTemporaryTable(ChapterExcelDTO chapterDTO);
void downExcel(HttpServletResponse response) throws IOException; void downExcel(HttpServletResponse response) throws IOException;

@ -14,12 +14,12 @@ import com.teaching.backend.mapper.chapter.ChapterMapper;
import com.teaching.backend.mapper.chapter.TemporaryChapterMapper; import com.teaching.backend.mapper.chapter.TemporaryChapterMapper;
import com.teaching.backend.model.dto.chapter.ChapterDTO; import com.teaching.backend.model.dto.chapter.ChapterDTO;
import com.teaching.backend.model.dto.chapter.ChapterExcelDTO;
import com.teaching.backend.model.entity.chapter.Chapter; import com.teaching.backend.model.entity.chapter.Chapter;
import com.teaching.backend.model.entity.chapter.TemporaryChapter; import com.teaching.backend.model.entity.chapter.TemporaryChapter;
import com.teaching.backend.model.entity.knowtmp.Knowtmp; import com.teaching.backend.model.entity.knowtmp.Knowtmp;
import com.teaching.backend.model.vo.chapter.ChapterVo; 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.service.chapter.IChapterService;
import com.teaching.backend.utils.Chapter.ExcelUtils; import com.teaching.backend.utils.Chapter.ExcelUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@ -29,7 +29,6 @@ import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -517,7 +516,7 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public Long saveToTemporaryTable(ChapterDTO chapterDTO) { public Long saveToTemporaryTable(ChapterExcelDTO chapterDTO) {
TemporaryChapter temporaryChapter = new TemporaryChapter(); TemporaryChapter temporaryChapter = new TemporaryChapter();
try { try {
BeanUtils.copyProperties(chapterDTO, temporaryChapter); BeanUtils.copyProperties(chapterDTO, temporaryChapter);
@ -526,10 +525,13 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
} }
Long pid = temporaryChapter.getPid(); Long pid = temporaryChapter.getPid();
//pid=0的时候
if (pid == null || pid == 0) { if (pid == null || pid == 0) {
temporaryChapter.setPid(0L); temporaryChapter.setPid(0L);
setChapterOrder(temporaryChapter, 0L); setChapterOrder(temporaryChapter, 0L);
} else { }
//pid!=0的时候
else {
TemporaryChapter parentChapter = temporaryChapterMapper.selectById(pid); TemporaryChapter parentChapter = temporaryChapterMapper.selectById(pid);
if (parentChapter != null) { if (parentChapter != null) {
temporaryChapter.setPid(parentChapter.getId()); temporaryChapter.setPid(parentChapter.getId());
@ -538,8 +540,9 @@ public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter> impl
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,ID 为: " + pid); throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,ID 为: " + pid);
} }
} }
// 执行
temporaryChapterMapper.insert(temporaryChapter); temporaryChapterMapper.insert(temporaryChapter);
return temporaryChapter.getId(); return temporaryChapter.getId();
} }

@ -13,10 +13,13 @@ package com.teaching.backend.utils.Chapter;
import com.teaching.backend.mapper.chapter.TemporaryChapterMapper; import com.teaching.backend.mapper.chapter.TemporaryChapterMapper;
import com.teaching.backend.service.chapter.IChapterService; import com.teaching.backend.service.chapter.IChapterService;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
@ -40,20 +43,35 @@ public class ExcelParser {
public List<String> parse(InputStream inputStream, String courseId) throws Exception { public List<String> parse(InputStream inputStream, String courseId) throws Exception {
OPCPackage pkg = OPCPackage.open(inputStream); OPCPackage pkg = OPCPackage.open(inputStream);
List<String> validationErrors = new ArrayList<>(); List<String> validationErrors = new ArrayList<>();
int totalRows = 0;
try { try {
XSSFReader reader = new XSSFReader(pkg); XSSFReader reader = new XSSFReader(pkg);
SharedStringsTable sst = reader.getSharedStringsTable(); SharedStringsTable sst = reader.getSharedStringsTable();
StylesTable styles = reader.getStylesTable(); StylesTable styles = reader.getStylesTable();
XMLReader parser = XMLReaderFactory.createXMLReader(); XMLReader parser = XMLReaderFactory.createXMLReader();
SheetHandler sheetHandler = new SheetHandler(temporaryChapterMapper, chapterService, courseId);
parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, sheetHandler, false));
XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData(); XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
SheetPreScanner preScanner = new SheetPreScanner();
while (sheets.hasNext()) { while (sheets.hasNext()) {
InputStream sheetstream = sheets.next(); InputStream sheetstream = sheets.next();
InputSource sheetSource = new InputSource(sheetstream); InputSource sheetSource = new InputSource(sheetstream);
try { try {
parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, preScanner, false));
parser.parse(sheetSource);
} finally {
sheetstream.close();
}
}
totalRows = preScanner.getRowCount();
sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
SheetHandler sheetHandler = null;
while (sheets.hasNext()) {
InputStream sheetstream = sheets.next();
InputSource sheetSource = new InputSource(sheetstream);
try {
sheetHandler = new SheetHandler(temporaryChapterMapper, chapterService, courseId, totalRows);
parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, sheetHandler, false));
parser.parse(sheetSource); parser.parse(sheetSource);
} finally { } finally {
sheetstream.close(); sheetstream.close();

@ -3,10 +3,17 @@ package com.teaching.backend.utils.Chapter;
import com.teaching.backend.common.ErrorCode; import com.teaching.backend.common.ErrorCode;
import com.teaching.backend.exception.BusinessException; import com.teaching.backend.exception.BusinessException;
import com.teaching.backend.mapper.chapter.TemporaryChapterMapper; import com.teaching.backend.mapper.chapter.TemporaryChapterMapper;
import com.teaching.backend.model.dto.chapter.ChapterDTO; import com.teaching.backend.model.dto.chapter.ChapterExcelDTO;
import com.teaching.backend.service.chapter.IChapterService; import com.teaching.backend.service.chapter.IChapterService;
import jdk.nashorn.internal.ir.IfNode;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
@ -23,127 +30,139 @@ import java.util.*;
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler { public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {
private Long currentChapterPid;
private final TemporaryChapterMapper temporaryChapterMapper; private final TemporaryChapterMapper temporaryChapterMapper;
private Double chapterHour;
private final IChapterService chapterService; private final IChapterService chapterService;
private final String courseId; private final String courseId;
private ChapterDTO chapterDTO; private ChapterExcelDTO chapterDTO;
private Map<Long, Long> excelIdToDatabaseIdMap = new HashMap<>(); private Map<Long, Long> excelIdToDatabaseIdMap = new HashMap<>();
private List<String> validationErrors = new ArrayList<>(); private List<String> validationErrors = new ArrayList<>();
private boolean hasErrors = false; private boolean hasErrors = false;
private List<ChapterDTO> collectedChapters = new ArrayList<>(); private int totalRows;
public SheetHandler(TemporaryChapterMapper temporaryChapterMapper, IChapterService chapterService, String courseId) {
public SheetHandler(TemporaryChapterMapper temporaryChapterMapper, IChapterService chapterService, String courseId,int totalRows) {
this.temporaryChapterMapper = temporaryChapterMapper; this.temporaryChapterMapper = temporaryChapterMapper;
this.chapterService = chapterService; this.chapterService = chapterService;
this.courseId = courseId; this.courseId = courseId;
this.totalRows=totalRows;
} }
@Override @Override
public void startRow(int rowIndex) { public void startRow(int rowIndex) {
if (rowIndex == 0) { if (rowIndex < totalRows - 1) {
if (rowIndex == 0 || rowIndex == 1) {
chapterDTO = null; chapterDTO = null;
} else { } else {
chapterDTO = new ChapterDTO(); chapterDTO = new ChapterExcelDTO();
chapterDTO.setCourseId(courseId); chapterDTO.setCourseId(courseId);
} }
} else {
chapterDTO = null;
} }
@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);
}
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public List<String> finalizeProcess() { public List<String> finalizeProcess() {
if (hasErrors) { if (hasErrors) {
return validationErrors; 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(); chapterService.moveDataFromTemporaryToFinal();
return Collections.emptyList(); return Collections.emptyList();
} }
private void saveToTemporaryTable(ChapterExcelDTO chapterDTO) {
private void saveToTemporaryTable(ChapterDTO chapterDTO) {
Long pid = chapterDTO.getParentExcelId(); Long pid = chapterDTO.getParentExcelId();
if (pid != null && pid != 0) { if (pid != null && pid != 0) {
Long parentId = excelIdToDatabaseIdMap.get(pid); Long parentId = excelIdToDatabaseIdMap.get(pid);
if (parentId != null) { if (parentId != null) {
chapterDTO.setPid(parentId); chapterDTO.setPid(parentId);
} else { } else {
temporaryChapterMapper.deleteAll();
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,Excel ID 为: " + pid); throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,Excel ID 为: " + pid);
} }
} }
Long savedChapterId = chapterService.saveToTemporaryTable(chapterDTO); Long savedChapterId = chapterService.saveToTemporaryTable(chapterDTO);
excelIdToDatabaseIdMap.put(chapterDTO.getExcelId(), savedChapterId); excelIdToDatabaseIdMap.put(chapterDTO.getExcelId(), savedChapterId);
}
}
private List<String> validateChapter(ChapterDTO chapterDTO) { private List<String> validateChapter(ChapterExcelDTO chapterDTO) {
List<String> errors = new ArrayList<>(); List<String> errors = new ArrayList<>();
if (chapterDTO.getName() == null || chapterDTO.getName().isEmpty()) { return errors;
errors.add("编号:"+chapterDTO.getExcelId()+"的章节名字不能为空");
} }
if (chapterDTO.getExcelId() == null || chapterDTO.getExcelId() <= 0) { @Override
errors.add("编号不能小于0"); public void endRow(int rowIndex) {
if (rowIndex != 0 && chapterDTO != null) {
List<String> errors = validateChapter(chapterDTO);
if (!errors.isEmpty()) {
validationErrors.addAll(errors);
hasErrors = true;
return;
}
if (chapterDTO.isSection()) {
if (currentChapterPid != null) {
chapterDTO.setTotalClassHours(chapterHour);
chapterDTO.setPid(currentChapterPid);
saveToTemporaryTable(chapterDTO);
} else {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到父章节,Excel ID 为: " + chapterDTO.getExcelId());
} }
if (chapterDTO.getParentExcelId() == null || chapterDTO.getParentExcelId() < 0) {
errors.add("编号:"+chapterDTO.getExcelId()+"的上级编号不能小于0");
} }
if (chapterDTO.getParentExcelId().equals(chapterDTO.getExcelId())) {
errors.add("编号:"+chapterDTO.getExcelId()+"的 上级编号不能等于其自身");
} }
return errors;
} }
@Override @Override
public void cell(String cellReference, String formattedValue, XSSFComment comment) { public void cell(String cellReference, String formattedValue, XSSFComment comment) {
if (chapterDTO != null && formattedValue != null) { if (chapterDTO != null) {
String letter = cellReference.substring(0, 1); String letter = cellReference.substring(0, 1);
switch (letter) { switch (letter) {
case "A": case "A":
chapterDTO.setExcelId(Long.valueOf(formattedValue)); chapterDTO.setExcelId(Long.valueOf(formattedValue));
break; break;
case "B": case "B":
chapterDTO.setName(formattedValue); chapterDTO.setName(formattedValue);
break; break;
case "C": case "C":
chapterDTO.setParentExcelId(Long.valueOf(formattedValue)); if (!chapterDTO.isSection()) {
chapterDTO.setTotalClassHours(Double.parseDouble(formattedValue));
saveToTemporaryTable(chapterDTO);
currentChapterPid = excelIdToDatabaseIdMap.get(chapterDTO.getExcelId());
}
break;
case "D":
chapterDTO.setOrderNum(Double.valueOf(formattedValue));
break; break;
case "E":
if (!formattedValue.isEmpty()) {
chapterDTO.setName(formattedValue);
chapterDTO.setIsSection(true);
} }
break;
case "F":
if (chapterDTO.isSection()) {
chapterDTO.setTotalClassHours(Double.parseDouble(formattedValue));
chapterHour = chapterDTO.getTotalClassHours();
} }
break;
}
} }
}
} }

@ -0,0 +1,34 @@
package com.teaching.backend.utils.Chapter;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;
/**
* ClassName: Sheet
* Package: com.teaching.backend.utils.Chapter
* Description:
*
* @Author 姜钧瀚
* @Create 2024/8/11 18:04
* @Version 1.0
*/
public class SheetPreScanner implements XSSFSheetXMLHandler.SheetContentsHandler {
private int rowCount = 0;
@Override
public void startRow(int rowNum) {
rowCount++;
}
@Override
public void endRow(int rowNum) {
}
@Override
public void cell(String cellReference, String formattedValue, XSSFComment comment) {
}
public int getRowCount() {
return rowCount;
}
}
Loading…
Cancel
Save