haogh 10 bulan lalu
induk
melakukan
8c86097a24
20 mengubah file dengan 653 tambahan dan 35 penghapusan
  1. 2 2
      paper-library-business/pom.xml
  2. 9 0
      paper-library-business/src/main/java/com/qmth/paper/library/business/bean/result/DocManageDetailResult.java
  3. 3 0
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/PaperLibraryService.java
  4. 13 4
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperLibraryCommonServiceImpl.java
  5. 21 9
      paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperLibraryServiceImpl.java
  6. 67 0
      paper-library-business/src/main/java/com/qmth/paper/library/business/templete/execute/AsyncGeneratePdfService.java
  7. 7 0
      paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/TaskLogicService.java
  8. 279 1
      paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/impl/TaskLogicServiceImpl.java
  9. 2 1
      paper-library-business/src/main/resources/mapper/DocManageMapper.xml
  10. 10 0
      paper-library-common/pom.xml
  11. 0 10
      paper-library-common/src/main/java/com/qmth/paper/library/common/bean/params/DownLoadPaperParams.java
  12. 1 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/contant/SystemConstant.java
  13. 2 1
      paper-library-common/src/main/java/com/qmth/paper/library/common/enums/TaskTypeEnum.java
  14. 5 1
      paper-library-common/src/main/java/com/qmth/paper/library/common/enums/UploadFileEnum.java
  15. 2 1
      paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockType.java
  16. 69 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/util/pdf/ItextDocumentInfo.java
  17. 153 0
      paper-library-common/src/main/java/com/qmth/paper/library/common/util/pdf/ItextPdfUtil.java
  18. TEMPAT SAMPAH
      paper-library-common/src/main/resources/font/STSONG.TTF
  19. 7 4
      paper-library/src/main/java/com/qmth/paper/library/api/DocManageController.java
  20. 1 1
      paper-library/src/main/java/com/qmth/paper/library/api/PictureManageController.java

+ 2 - 2
paper-library-business/pom.xml

@@ -43,10 +43,10 @@
             <groupId>org.jetbrains</groupId>
             <artifactId>annotations</artifactId>
         </dependency>
-        <dependency>
+        <!--<dependency>
             <groupId>com.itextpdf</groupId>
             <artifactId>itextpdf</artifactId>
-        </dependency>
+        </dependency>-->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>

+ 9 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/bean/result/DocManageDetailResult.java

@@ -23,6 +23,7 @@ public class DocManageDetailResult {
     private Double score;
     private String remark;
     private Integer bindCount;
+    private String filePath;
 
     public Long getExamId() {
         return examId;
@@ -151,4 +152,12 @@ public class DocManageDetailResult {
     public void setBindCount(Integer bindCount) {
         this.bindCount = bindCount;
     }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
 }

+ 3 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/service/PaperLibraryService.java

@@ -7,6 +7,7 @@ import com.qmth.paper.library.business.bean.result.TaskStudentResult;
 import com.qmth.paper.library.business.bean.vo.RecognitionResultVo;
 import com.qmth.paper.library.business.entity.PaperLibrary;
 import com.qmth.paper.library.business.entity.PaperScanTask;
+import com.qmth.paper.library.common.bean.params.DownLoadPaperParams;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
@@ -46,4 +47,6 @@ public interface PaperLibraryService extends IService<PaperLibrary> {
     boolean deletePicture(Long paperLibraryId);
 
     boolean rotatePictureUpload(Long paperLibraryId, boolean isFront, Integer rotate);
+
+    Map<String, Object> pdfGenerate(DownLoadPaperParams params);
 }

+ 13 - 4
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperLibraryCommonServiceImpl.java

@@ -4,7 +4,8 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
-import com.itextpdf.text.pdf.PdfReader;
+import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfReader;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.paper.library.business.bean.vo.FilePathVo;
 import com.qmth.paper.library.business.bean.vo.PathSequenceVo;
@@ -140,10 +141,18 @@ public class PaperLibraryCommonServiceImpl implements PaperLibraryCommonService
             basicAttachmentService.save(basicAttachment);
 
             // pdf需要读取总页数
-            Integer pages = 0;
+            int pages = 0;
             if (".pdf".equals(format)) {
-                PdfReader pdfReader = new PdfReader(file.getBytes());
-                pages = pdfReader.getNumberOfPages();
+                /*  itextpdf5的写法
+                    PdfReader pdfReader = new PdfReader(file.getBytes());
+                    pages = pdfReader.getNumberOfPages();
+                */
+                //itextpdf7的写法
+                PdfReader pdfReader = new PdfReader(file.getInputStream());
+                PdfDocument pdfDoc = new PdfDocument(pdfReader);
+                pages = pdfDoc.getNumberOfPages();
+                pdfDoc.close();
+                pdfReader.close();
             }
             basicAttachment.setPages(pages);
         } catch (Exception e) {

+ 21 - 9
paper-library-business/src/main/java/com/qmth/paper/library/business/service/impl/PaperLibraryServiceImpl.java

@@ -18,24 +18,20 @@ import com.qmth.paper.library.business.entity.PaperLibrary;
 import com.qmth.paper.library.business.entity.PaperScanTask;
 import com.qmth.paper.library.business.mapper.PaperLibraryMapper;
 import com.qmth.paper.library.business.service.*;
+import com.qmth.paper.library.business.templete.execute.AsyncGeneratePdfService;
 import com.qmth.paper.library.common.bean.dto.syssetting.SimpleObject;
+import com.qmth.paper.library.common.bean.params.DownLoadPaperParams;
 import com.qmth.paper.library.common.contant.SysSettingConstant;
 import com.qmth.paper.library.common.contant.SystemConstant;
-import com.qmth.paper.library.common.entity.BasicExam;
-import com.qmth.paper.library.common.entity.BasicSchool;
-import com.qmth.paper.library.common.entity.BasicSemester;
-import com.qmth.paper.library.common.entity.ExamStudent;
-import com.qmth.paper.library.common.enums.ExceptionResultEnum;
-import com.qmth.paper.library.common.enums.RecognitionTypeEnum;
-import com.qmth.paper.library.common.enums.StoreTypeEnum;
-import com.qmth.paper.library.common.enums.UploadFileEnum;
+import com.qmth.paper.library.common.entity.*;
+import com.qmth.paper.library.common.enums.*;
 import com.qmth.paper.library.common.lock.LockService;
 import com.qmth.paper.library.common.lock.LockType;
 import com.qmth.paper.library.common.service.BasicSchoolService;
 import com.qmth.paper.library.common.service.BasicSemesterService;
 import com.qmth.paper.library.common.service.CommonCacheService;
+import com.qmth.paper.library.common.service.TBTaskService;
 import com.qmth.paper.library.common.util.*;
-import net.coobird.thumbnailator.Thumbnails;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -82,6 +78,10 @@ public class PaperLibraryServiceImpl extends ServiceImpl<PaperLibraryMapper, Pap
     private CommonCacheService commonCacheService;
     @Resource
     private LockService lockService;
+    @Resource
+    private TBTaskService tbTaskService;
+    @Resource
+    private AsyncGeneratePdfService asyncGeneratePdfService;
 
     @Override
     public int countScanStudentCount(Long paperScanTaskId) {
@@ -429,5 +429,17 @@ public class PaperLibraryServiceImpl extends ServiceImpl<PaperLibraryMapper, Pap
         }
     }
 
+    @Override
+    public Map<String, Object> pdfGenerate(DownLoadPaperParams params) {
+        SysUser user = (SysUser) ServletUtil.getRequestUser();
+        boolean lockFlag = lockService.trylock(LockType.STUDENT_PDF_GENERATE, user.getId());
+        if(!lockFlag) {
+            throw ExceptionResultEnum.ERROR.exception("已经在生成,在生成完成之前,不要重复生成");
+        }
+        String remark = JSON.toJSONString(params);
+        Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.STUDENT_PDF_GENERATE, remark, (SysUser) ServletUtil.getRequestUser());
+        asyncGeneratePdfService.exportTask(map);
+        return map;
+    }
 
 }

+ 67 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/templete/execute/AsyncGeneratePdfService.java

@@ -0,0 +1,67 @@
+package com.qmth.paper.library.business.templete.execute;
+
+import cn.hutool.core.date.DateUtil;
+import com.qmth.boot.api.exception.ApiException;
+import com.qmth.paper.library.business.templete.export.AsyncExportTaskTemplate;
+import com.qmth.paper.library.business.templete.service.TaskLogicService;
+import com.qmth.paper.library.common.contant.SpringContextHolder;
+import com.qmth.paper.library.common.contant.SystemConstant;
+import com.qmth.paper.library.common.entity.TBTask;
+import com.qmth.paper.library.common.enums.TaskResultEnum;
+import com.qmth.paper.library.common.enums.TaskStatusEnum;
+import com.qmth.paper.library.common.service.TBTaskService;
+import com.qmth.paper.library.common.util.Result;
+import com.qmth.paper.library.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * @Description 异步将考生的试卷生成pdf
+ */
+@Service
+public class AsyncGeneratePdfService extends AsyncExportTaskTemplate {
+
+    private static final Logger log = LoggerFactory.getLogger(AsyncGeneratePdfService.class);
+
+    private static final String OBJ_TITLE = "生成pdf";
+
+    @Override
+    public Result exportTask(Map<String, Object> map) {
+        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+        StringJoiner stringJoinerSummary = new StringJoiner("\n").add(
+                MessageFormat.format("{0}{1}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), OBJ_TITLE));
+        tbTask.setStatus(TaskStatusEnum.RUNNING);
+        TBTaskService taskService = SpringContextHolder.getBean(TBTaskService.class);
+        taskService.updateById(tbTask);
+        try {
+            TaskLogicService taskLogicService = SpringContextHolder.getBean(TaskLogicService.class);
+            taskLogicService.executeStudentPdfGenerateLogic(map);
+            stringJoinerSummary.add(
+                    MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), FINISH_TITLE, map.get("size"),
+                            FINISH_SIZE));
+            tbTask.setResult(TaskResultEnum.SUCCESS);
+        } catch (Exception e) {
+            log.error(SystemConstant.LOG_ERROR, e);
+            stringJoinerSummary.add(
+                    MessageFormat.format("{0}{1}{2}{3}", DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN), EXCEPTION_TITLE, EXCEPTION_DATA,
+                            e.getMessage()));
+            tbTask.setResult(TaskResultEnum.ERROR);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        } finally {
+            tbTask.setSummary(stringJoinerSummary.toString());
+            tbTask.setStatus(TaskStatusEnum.FINISH);
+            taskService.updateById(tbTask);
+        }
+        return ResultUtil.ok(map);
+    }
+}

+ 7 - 0
paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/TaskLogicService.java

@@ -45,4 +45,11 @@ public interface TaskLogicService {
      */
     Map<String, Object> executeDownloadPictureLogic(Map<String, Object> map);
     Map<String, Object> executeImportExamStudentLogic(Map<String, Object> map, StringJoiner stringJoinerSummary);
+
+    /**
+     * 考生试卷生成pdf
+     *
+     * @param map 数据源
+     */
+    Map<String, Object> executeStudentPdfGenerateLogic(Map<String, Object> map);
 }

+ 279 - 1
paper-library-business/src/main/java/com/qmth/paper/library/business/templete/service/impl/TaskLogicServiceImpl.java

@@ -5,6 +5,9 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.google.common.collect.Lists;
+import com.itextpdf.io.image.ImageDataFactory;
+import com.itextpdf.layout.Document;
+import com.itextpdf.layout.element.Image;
 import com.qmth.boot.api.exception.ApiException;
 import com.qmth.boot.tools.excel.ExcelReader;
 import com.qmth.boot.tools.excel.enums.ExcelType;
@@ -16,6 +19,7 @@ import com.qmth.paper.library.business.bean.result.DocManageDetailResult;
 import com.qmth.paper.library.business.bean.result.PictureManageDetailResult;
 import com.qmth.paper.library.business.entity.PaperLibrary;
 import com.qmth.paper.library.business.entity.PaperScanTask;
+import com.qmth.paper.library.business.mapper.DocManageMapper;
 import com.qmth.paper.library.business.service.*;
 import com.qmth.paper.library.business.templete.service.TaskLogicService;
 import com.qmth.paper.library.common.bean.dto.excel.DescribeImportDto;
@@ -29,9 +33,13 @@ import com.qmth.paper.library.common.entity.*;
 import com.qmth.paper.library.common.enums.ExceptionResultEnum;
 import com.qmth.paper.library.common.enums.StoreTypeEnum;
 import com.qmth.paper.library.common.enums.UploadFileEnum;
+import com.qmth.paper.library.common.lock.LockService;
+import com.qmth.paper.library.common.lock.LockType;
 import com.qmth.paper.library.common.service.*;
 import com.qmth.paper.library.common.util.*;
 import com.qmth.paper.library.common.util.excel.ExcelError;
+import com.qmth.paper.library.common.util.pdf.ItextDocumentInfo;
+import com.qmth.paper.library.common.util.pdf.ItextPdfUtil;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.ss.usermodel.*;
@@ -47,7 +55,6 @@ import javax.annotation.Resource;
 import java.io.*;
 import java.lang.reflect.Field;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -91,6 +98,11 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     private PictureManageService pictureManageService;
     @Resource
     private BasicFieldService basicFieldService;
+    @Resource
+    private LockService lockService;
+    @Resource
+    private DocManageMapper docManageMapper;
+
 
     @Transactional
     @Override
@@ -703,6 +715,272 @@ public class TaskLogicServiceImpl implements TaskLogicService {
         return map;
     }
 
+    @Override
+    public Map<String, Object> executeStudentPdfGenerateLogic(Map<String, Object> map) {
+        SysUser user = (SysUser) map.get(SystemConstant.USER);
+        Map<Long,Integer> successMap = new HashMap<>();
+        Map<Long,Integer> errorMap = new HashMap<>();
+        List<DocManageDetailResult> toBeGeneratedList;
+        List<String> studentIdList = new ArrayList<>();
+        String rootPath = fileStoreUtil.buildPath(UploadFileEnum.DOWNLOAD, true, String.valueOf(System.currentTimeMillis()));
+        String pictureLocalPath;
+        try {
+            //以用户为粒度加锁
+            lockService.trylock(LockType.STUDENT_PDF_GENERATE, user.getId());
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+            DownLoadPaperParams params = JSON.parseObject(tbTask.getRemark(), DownLoadPaperParams.class);
+            String ids = params.getIds();
+            if (StringUtils.isNotEmpty(ids)) {
+                studentIdList = Arrays.asList(ids.split(","));
+            }
+            Long paperScanTaskId = params.getPaperScanTaskId();
+            if (paperScanTaskId == null) {
+                throw ExceptionResultEnum.ERROR.exception("扫描任务ID必传");
+            }
+            PaperScanTask scanTask = paperScanTaskService.getById(paperScanTaskId);
+            if(Objects.isNull(scanTask)) {
+                throw ExceptionResultEnum.ERROR.exception("扫描任务不存在");
+            }
+            BasicSchool school = basicSchoolService.getById(scanTask.getSchoolId());
+            pictureLocalPath = rootPath + File.separator + school.getName();
+            //查询考生数据
+            if (!studentIdList.isEmpty()) {
+                toBeGeneratedList = docManageMapper.listDetail(paperScanTaskId, studentIdList);
+            } else { //根据查询条件
+                String collegeName = params.getCollegeName();
+                String majorName = params.getMajorName();
+                String className = params.getClassName();
+                String courseName = params.getCourseName();
+                String teacher = params.getTeacher();
+                String teachClass = params.getTeachClass();
+                Boolean isBind = params.getIsBind() == null ? null : params.getIsBind() == 1;
+                String param = params.getParam();
+                Double minScore = params.getMinScore();
+                Double maxScore = params.getMaxScore();
+                Integer minBindCount = params.getMinBindCount();
+                Integer maxBindCount = params.getMaxBindCount();
+                String pictureSymbol = params.getPictureSymbol();
+                Integer pictureCount = params.getPictureCount();
+                toBeGeneratedList = docManageMapper.pageDetail(paperScanTaskId, collegeName, majorName, className, courseName, teacher, teachClass, isBind,
+                        param, minScore, maxScore, minBindCount, maxBindCount, pictureSymbol, pictureCount);
+            }
+            toBeGeneratedList = toBeGeneratedList.stream().filter(item -> StringUtils.isEmpty(item.getFilePath())).collect(Collectors.toList());
+
+            //循环考生
+            for(DocManageDetailResult result : toBeGeneratedList) {
+                successMap.putIfAbsent(result.getStudentId(), 0);
+                errorMap.putIfAbsent(result.getStudentId(), 0);
+                List<File> fileList = new ArrayList<>();
+                //创建本地目录
+                String courseNameCode = String.format("%s(%s)", result.getCourseName(), result.getCourseCode());
+                String downloadLocalPath = pictureLocalPath +File.separator + courseNameCode;
+                File dir = new File(downloadLocalPath);
+                if (!dir.exists()) {
+                    dir.mkdirs();
+                }
+
+                //查询考生的试卷
+                LambdaQueryWrapper<PaperLibrary> queryWrapper = new LambdaQueryWrapper<>();
+                queryWrapper.eq(PaperLibrary::getStudentId, result.getStudentId());
+                queryWrapper.eq(PaperLibrary::getPaperScanTaskId, paperScanTaskId);
+                List<PaperLibrary> paperLibraryList = paperLibraryService.list(queryWrapper);
+
+                //下载试卷
+                for(PaperLibrary paperLibrary : paperLibraryList) {
+                    List<JSONObject> objectList = JSON.parseArray(paperLibrary.getPath(), JSONObject.class);
+                    for (JSONObject jsonObject : objectList) {
+                        try {
+                            File file = paperLibraryCommonService.downloadFile(downloadLocalPath, jsonObject.getString(SystemConstant.PATH),
+                                    jsonObject.getString(SystemConstant.UPLOAD_TYPE), jsonObject.getString(SystemConstant.TYPE));
+                            fileList.add(file);
+                            successMap.put(result.getStudentId(), successMap.get(result.getStudentId()) + 1);
+                        } catch (Exception e) {
+                            //下载失败
+                            errorMap.put(result.getStudentId(), errorMap.get(result.getStudentId()) + 1);
+                        }
+                    }
+                }
+
+                //试卷写入到pdf
+                if(!fileList.isEmpty()) {
+                    String pdfPath = generateStudentPaperPdf(result.getStudentCode(), fileList, school.getName(), courseNameCode);
+                    //更新考生
+                    ExamStudent student = examStudentService.getById(result.getStudentId());
+                    student.setFilePath(pdfPath);
+                    examStudentService.updateById(student);
+                }
+            }
+
+            map.put("size", successMap.size());
+
+            //执行情况写入到excel
+            String path = fileStoreUtil.buildPath(UploadFileEnum.PDF, true);
+            path += File.separator + school.getName();
+            createPdfExcel(path, toBeGeneratedList, successMap, errorMap);
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        } finally {
+            if (Objects.nonNull(rootPath)) {
+                ConvertUtil.delFolder(rootPath);
+            }
+            lockService.unlock(LockType.STUDENT_PDF_GENERATE,user.getId());
+        }
+        return map;
+    }
+
+    private String generateStudentPaperPdf(String pdfName, List<File> fileList, String... paths) {
+        StringBuilder pdfRootPath = new StringBuilder(fileStoreUtil.buildPath(UploadFileEnum.PDF, true));
+        for (String path : paths) {
+            pdfRootPath.append(File.separator).append(path);
+        }
+        File dir = new File(pdfRootPath.toString());
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+        String pdfPath = pdfRootPath + File.separator + pdfName + SystemConstant.PDF_SUFFIX;
+
+        Document document = null;
+        try {
+            ItextDocumentInfo pageModel = new ItextDocumentInfo();
+            pageModel.rotate();
+            File file = new File(pdfPath);
+            document = pageModel.prepareDocument(file);
+            for (File imageFile : fileList) {
+                Image image = new Image(ImageDataFactory.create(FileUtil.fileConvertToByteArray(imageFile)));
+                document.add(image);
+            }
+        } catch (Exception e) {
+            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
+        } finally {
+            ItextPdfUtil.closePdf(document);
+        }
+        return pdfPath;
+    }
+
+    private void createPdfExcel(String path, List<DocManageDetailResult> list, Map<Long, Integer> successMap,
+            Map<Long, Integer> errorMap) throws IOException {
+        String fileName = "执行清单-" + System.currentTimeMillis() +".xlsx";
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet("数据");
+
+        // 表头
+        CellStyle headerStyle = wb.createCellStyle();
+        headerStyle.setAlignment(HorizontalAlignment.CENTER);
+        headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        headerStyle.setBorderRight(BorderStyle.THIN);
+        headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
+        headerStyle.setBorderLeft(BorderStyle.THIN);
+        headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+        headerStyle.setBorderTop(BorderStyle.THIN);
+        headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
+        headerStyle.setBorderBottom(BorderStyle.THIN);
+        headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+        // 背景颜色
+        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        headerStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.getIndex());
+        Font font = wb.createFont();
+        font.setFontHeightInPoints((short) 12);
+        font.setFontName("宋体");
+        font.setColor(IndexedColors.WHITE.getIndex());
+        headerStyle.setFont(font);
+
+        // 数据
+        XSSFCellStyle dataStyle = wb.createCellStyle();
+        dataStyle.setAlignment(HorizontalAlignment.CENTER);
+        dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        dataStyle.setBorderRight(BorderStyle.THIN);
+        dataStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
+        dataStyle.setBorderLeft(BorderStyle.THIN);
+        dataStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+        dataStyle.setBorderTop(BorderStyle.THIN);
+        dataStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
+        dataStyle.setBorderBottom(BorderStyle.THIN);
+        dataStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+        dataStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        // 背景颜色
+        dataStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+        font = wb.createFont();
+        font.setFontHeightInPoints((short) 10);
+        font.setFontName("宋体");
+        dataStyle.setFont(font);
+
+        // 锁定样式
+        XSSFCellStyle lockStyle = wb.createCellStyle();
+        lockStyle.setLocked(true);//设置锁定
+
+        // 未锁定样式
+        XSSFCellStyle unlockStyle = wb.createCellStyle();
+        unlockStyle.setLocked(false);//设置未锁定
+
+        XSSFRow headRow = sheet.createRow(0);
+        // 表头
+        String[] fieldsNameList = {"学号", "姓名", "课程名称(代码)",  "是否成功", "成功图片(页)", "失败图片(页)"};
+        for (int i = 0; i < fieldsNameList.length; i++) {
+            XSSFCell cell = headRow.createCell(i);
+            cell.setCellValue(fieldsNameList[i]);
+            cell.setCellStyle(headerStyle);
+        }
+
+        for (int i = 1; i <= list.size(); i++) {
+            DocManageDetailResult result = list.get(i - 1);
+            XSSFRow row = sheet.createRow(i);
+
+            XSSFCell cell0 = row.createCell(0);
+            cell0.setCellStyle(lockStyle);
+            cell0.setCellStyle(dataStyle);
+            cell0.setCellValue(result.getStudentCode());
+
+            XSSFCell cell1 = row.createCell(1);
+            cell1.setCellStyle(lockStyle);
+            cell1.setCellStyle(dataStyle);
+            cell1.setCellValue(result.getStudentName());
+
+            XSSFCell cell2 = row.createCell(2);
+            cell2.setCellStyle(lockStyle);
+            cell2.setCellStyle(dataStyle);
+            cell2.setCellValue(result.getCourseName() + "(" + result.getCourseCode() + ")");
+
+
+            XSSFCell cell3 = row.createCell(3);
+            cell3.setCellStyle(lockStyle);
+            cell3.setCellStyle(dataStyle);
+            String remark = "";
+            if (successMap.get(result.getStudentId()) > 0 && errorMap.get(result.getStudentId()) == 0) {
+                remark = "成功";
+            }
+            if (successMap.get(result.getStudentId()) == 0 && errorMap.get(result.getStudentId()) > 0) {
+                remark = "失败";
+            }
+            if (successMap.get(result.getStudentId()) > 0 && errorMap.get(result.getStudentId()) > 0) {
+                remark = "部分成功";
+            }
+            cell3.setCellValue(remark);
+
+            XSSFCell cell4 = row.createCell(4);
+            cell4.setCellStyle(lockStyle);
+            cell4.setCellStyle(dataStyle);
+            cell4.setCellValue(successMap.get(result.getStudentId()));
+
+            XSSFCell cell5 = row.createCell(5);
+            cell5.setCellStyle(lockStyle);
+            cell5.setCellStyle(dataStyle);
+            cell5.setCellValue(errorMap.get(result.getStudentId()));
+        }
+
+        for (int i = 0; i < fieldsNameList.length; i++) {
+            sheet.autoSizeColumn(i);
+            sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 6);
+        }
+
+        // sheet添加保护,这个一定要否则光锁定还是可以编辑的
+        sheet.protectSheet(SystemConstant.EXCEL_PROTECT_KEY);
+
+        File file = new File(path, fileName);
+        FileOutputStream outputStream = new FileOutputStream(file);
+        wb.write(outputStream);
+        outputStream.close();
+    }
+
     /**
      * 生成清单
      *

+ 2 - 1
paper-library-business/src/main/resources/mapper/DocManageMapper.xml

@@ -142,7 +142,8 @@
             es.class_name className,
             es.score,
             es.remark,
-            es.bind_count bindCount
+            es.bind_count bindCount,
+            es.file_path filePath
         FROM
             exam_student es
                 LEFT JOIN

+ 10 - 0
paper-library-common/pom.xml

@@ -192,5 +192,15 @@
             <groupId>com.qmth.boot</groupId>
             <artifactId>core-concurrent</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>layout</artifactId>
+            <version>7.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>kernel</artifactId>
+            <version>7.0.1</version>
+        </dependency>
     </dependencies>
 </project>

+ 0 - 10
paper-library-common/src/main/java/com/qmth/paper/library/common/bean/params/DownLoadPaperParams.java

@@ -46,8 +46,6 @@ public class DownLoadPaperParams implements Serializable {
     private String pictureSymbol;
     @ApiModelProperty("图片张数")
     private Integer pictureCount;
-    @ApiModelProperty("考生IDS")
-    private List<Long> studentIds;
 
 
     public Long getPaperScanTaskId() {
@@ -177,12 +175,4 @@ public class DownLoadPaperParams implements Serializable {
     public void setPictureCount(Integer pictureCount) {
         this.pictureCount = pictureCount;
     }
-
-    public List<Long> getStudentIds() {
-        return studentIds;
-    }
-
-    public void setStudentIds(List<Long> studentIds) {
-        this.studentIds = studentIds;
-    }
 }

+ 1 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/contant/SystemConstant.java

@@ -68,6 +68,7 @@ public class SystemConstant {
     public static final String SIZE = "size";
     public static final String EXCEL_PREFIX = ".xlsx";
     public static final String ZIP_SUFFIX = ".zip";
+    public static final String PDF_SUFFIX = ".pdf";
     public static final String SCAN_TASK_CODE_PREFIX = "T";
     public static final String TMP_DIR = "java.io.tmpdir";
 

+ 2 - 1
paper-library-common/src/main/java/com/qmth/paper/library/common/enums/TaskTypeEnum.java

@@ -15,7 +15,8 @@ public enum TaskTypeEnum {
     USER_IMPORT("用户导入"),
     EXAM_STUDENT_IMPORT("考生导入"),
     PAPER_DOWNLOAD("批量下载"),
-    PICTURE_DOWNLOAD("图片下载");
+    PICTURE_DOWNLOAD("图片下载"),
+    STUDENT_PDF_GENERATE("考生试卷生成pdf");
 
     private String title;
 

+ 5 - 1
paper-library-common/src/main/java/com/qmth/paper/library/common/enums/UploadFileEnum.java

@@ -15,7 +15,11 @@ public enum UploadFileEnum {
     DOWNLOAD("download", "local"),
     CUT("cut", "local"),
 
-    IMAGE("image", "local");
+    IMAGE("image", "local"),
+
+    PDF("pdf", "local");
+
+
 
     private String prefix;
     private String fssType;

+ 2 - 1
paper-library-common/src/main/java/com/qmth/paper/library/common/lock/LockType.java

@@ -7,7 +7,8 @@ public enum LockType {
     GET_OTHER_SEQUENCE("获取其它文件批次顺序号"),
     UPLOAD_OTHER_FILE("上传其它文件"),
     ROTATE_PICTURE("旋转图片"),
-    SCAN_TASK_SEQUENCE("获取任务编号顺序号");
+    SCAN_TASK_SEQUENCE("获取任务编号顺序号"),
+    STUDENT_PDF_GENERATE("考生试卷pdf生成");
 
     private String name;
 

+ 69 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/util/pdf/ItextDocumentInfo.java

@@ -0,0 +1,69 @@
+package com.qmth.paper.library.common.util.pdf;
+
+import com.itextpdf.kernel.font.PdfFont;
+import com.itextpdf.layout.Document;
+import io.swagger.annotations.ApiModelProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.Serializable;
+
+public class ItextDocumentInfo implements Serializable {
+
+    private final static Logger log = LoggerFactory.getLogger(ItextDocumentInfo.class);
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("页面宽度,单位mm")
+    private int page_width = 210;
+
+    @ApiModelProperty("页面高度,单位mm")
+    private int page_height = 297;
+
+    protected int margin_top = 10;
+    protected int margin_right = 10;
+    protected int margin_bottom = 10;
+    protected int margin_left = 10;
+
+    protected PdfFont font = null;
+
+    protected PdfFont getFont() {
+        return font;
+    }
+
+    public Document prepareDocument(File tempFile) {
+        return prepareDocument(tempFile, ItextPdfUtil.getPdfFontSTSong());
+    }
+
+    public Document prepareDocument(File tempFile, PdfFont font) {
+        try {
+            String page_margin = "20 30 20 30";
+            String[] array = page_margin.split("\\s+");
+            margin_top = Integer.parseInt(array[0]);
+            margin_right = Integer.parseInt(array[1]);
+            margin_bottom = Integer.parseInt(array[2]);
+            margin_left = Integer.parseInt(array[3]);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+
+        Document doc = ItextPdfUtil.createPdf(tempFile,
+                ItextPdfUtil.getPageSizeByMillimeter(this.page_width, this.page_height));
+
+        doc.setMargins(margin_top, margin_right, margin_bottom, margin_left);
+        if (font == null)
+            font = ItextPdfUtil.getPdfFontSTSong();
+        this.font = font;
+        doc.setFont(font);
+
+        return doc;
+    }
+
+    public void rotate() {
+        int w = this.page_width;
+        this.page_width = this.page_height;
+        this.page_height = w;
+    }
+
+}

+ 153 - 0
paper-library-common/src/main/java/com/qmth/paper/library/common/util/pdf/ItextPdfUtil.java

@@ -0,0 +1,153 @@
+package com.qmth.paper.library.common.util.pdf;
+
+import cn.hutool.core.io.resource.ResourceUtil;
+import com.itextpdf.io.font.PdfEncodings;
+import com.itextpdf.kernel.font.PdfFont;
+import com.itextpdf.kernel.font.PdfFontFactory;
+import com.itextpdf.kernel.geom.PageSize;
+import com.itextpdf.kernel.pdf.EncryptionConstants;
+import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfWriter;
+import com.itextpdf.kernel.pdf.WriterProperties;
+import com.itextpdf.layout.Document;
+import com.qmth.boot.core.exception.StatusException;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ItextPdfUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(ItextPdfUtil.class);
+
+    /*********************
+     * 默认页面72像素/英寸
+     */
+    public static int ItextPagePix = 72;
+    // 一英寸等于25.4毫米
+    public final static double InchMillimeter = 25.4;
+
+    /********************
+     * 获取pdf默认字体
+     */
+    public static PdfFont getPdfFont() {
+        try {
+            return PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", false);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**********************
+     * 获取宋体字体,如无法获取,获取默认字体
+     */
+    public static PdfFont getPdfFontSTSong() {
+        try {
+            InputStream in = ResourceUtil.getStream("font" + File.separator + "STSONG.TTF");
+            return PdfFontFactory.createFont(getByte(in), PdfEncodings.IDENTITY_H, false);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            return getPdfFont();
+        }
+    }
+
+    public static byte[] getByte(InputStream in) {
+        InputStream stream = ResourceUtil.getStream("font" + File.separator + "STSONG.TTF");
+        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
+        byte[] buff = new byte[100];
+        int rc = 0;
+        try {
+            while ((rc = stream.read(buff, 0, 100)) > 0) {
+                swapStream.write(buff, 0, rc);
+            }
+        } catch (IOException e) {
+            throw new StatusException("读取文件异常");
+        }
+        return swapStream.toByteArray();
+    }
+
+    public static Document createPdf(File file, PageSize pageSize, String passwd) {
+        PdfDocument pdfDoc = null;
+        Document doc = null;
+        try {
+
+            if (StringUtils.isNotEmpty(passwd))
+                pdfDoc = new PdfDocument(new PdfWriter(file.getPath(),
+                        new WriterProperties().setStandardEncryption(null, passwd.getBytes(),
+                                EncryptionConstants.ALLOW_PRINTING,
+                                EncryptionConstants.ENCRYPTION_AES_128 | EncryptionConstants.DO_NOT_ENCRYPT_METADATA)));
+            else
+                pdfDoc = new PdfDocument(new PdfWriter(file.getPath()));
+            doc = new Document(pdfDoc, pageSize);
+            return doc;
+        } catch (Exception e) {
+            throw new StatusException("无法创建临时文件!");
+        }
+    }
+
+    /**********************
+     * 创建A4,自带加密
+     */
+    public static Document createPdf(File file, String passwd) {
+        return createPdf(file, PageSize.A4, passwd);
+    }
+
+    /**********************
+     * 创建A4,自带加密
+     */
+    public static Document createPdf(File file, PageSize pageSize) {
+        return createPdf(file, pageSize, null);
+    }
+
+    public static Document createPdf(File file) {
+        return createPdf(file, PageSize.A4, null);
+    }
+
+    public static void closePdf(Document doc) {
+        if (doc != null) {
+            try {
+
+                doc.flush();
+                doc.close();
+            } catch (Exception ex) {
+                log.error(ex.getMessage());
+            }
+            try {
+                doc.getPdfDocument().close();
+            } catch (Exception ex) {
+                log.error(ex.getMessage());
+            }
+            doc = null;
+
+        }
+    }
+
+    /*********************
+     * 获取纸张大小
+     * 
+     * @param width  宽度 单位毫米
+     * @param height 高度 单位毫米 72像素/英寸=28.346像素/厘米 A4:595, 842 A3:842, 1190
+     */
+    public static PageSize getPageSizeByMillimeter(int width, int height) {
+        return new PageSize(getPixByMillimeter(width), getPixByMillimeter(height));
+
+    }
+
+    /****************
+     * 根据毫米返回itext的像素
+     */
+    public static int getPixByMillimeter(int millimeter) {
+        return (int) Math.round(millimeter / InchMillimeter * ItextPagePix);
+    }
+
+    /****************
+     * 根据itext像素返回的毫米
+     */
+    public static int getMillimeterByPix(int pix) {
+        return (int) Math.round((double) pix / ItextPagePix * InchMillimeter);
+    }
+}

TEMPAT SAMPAH
paper-library-common/src/main/resources/font/STSONG.TTF


+ 7 - 4
paper-library/src/main/java/com/qmth/paper/library/api/DocManageController.java

@@ -1,6 +1,5 @@
 package com.qmth.paper.library.api;
 
-
 import com.alibaba.fastjson.JSON;
 import com.qmth.boot.api.constant.ApiConstant;
 import com.qmth.paper.library.business.bean.result.EditResult;
@@ -19,7 +18,10 @@ import com.qmth.paper.library.common.util.ResultUtil;
 import com.qmth.paper.library.common.util.ServletUtil;
 import io.swagger.annotations.*;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.constraints.Max;
@@ -140,8 +142,9 @@ public class DocManageController {
     @PostMapping("/pdf/generate")
     @ApiResponses({@ApiResponse(code = 200, message = "下载成功", response = EditResult.class)})
     public Result pdfGenerate(DownLoadPaperParams params) {
-        //TODO pdf生成
-        return ResultUtil.ok();
+        Map<String, Object> map = paperLibraryService.pdfGenerate(params);
+        TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
+        return Objects.nonNull(tbTask) ? ResultUtil.ok(new EditResult(tbTask.getId())) : ResultUtil.error("创建任务失败");
     }
 
     @ApiOperation(value = "删除图片")

+ 1 - 1
paper-library/src/main/java/com/qmth/paper/library/api/PictureManageController.java

@@ -100,7 +100,7 @@ public class PictureManageController {
         Map<String, Object> map = tbTaskService.saveTask(TaskTypeEnum.PICTURE_DOWNLOAD, pictureParams, (SysUser) ServletUtil.getRequestUser());
         Long schoolId = Long.valueOf(ServletUtil.getRequestHeaderSchoolId().toString());
         map.put("schoolId", schoolId);
-        //异步任务 TODO 待优化
+        //异步任务
         asyncDownloadPictureService.exportTask(map);
         TBTask tbTask = Objects.nonNull(map.get(SystemConstant.TASK)) ? (TBTask) map.get(SystemConstant.TASK) : null;
         return Objects.nonNull(tbTask) ? ResultUtil.ok(new EditResult(tbTask.getId())) : ResultUtil.error("创建任务失败");