wangliang 4 жил өмнө
parent
commit
5daf61e535

+ 4 - 12
distributed-print-business/pom.xml

@@ -80,26 +80,18 @@
             <groupId>com.itextpdf</groupId>
             <artifactId>itextpdf</artifactId>
         </dependency>
-		<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
 		<dependency>
 			<groupId>com.alibaba</groupId>
 			<artifactId>easyexcel</artifactId>
 			<version>2.2.8</version>
 		</dependency>
         <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi</artifactId>
-            <version>3.17</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi-ooxml</artifactId>
-            <version>3.17</version>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi-ooxml-schemas</artifactId>
-            <version>3.17</version>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
         </dependency>
     </dependencies>
 

+ 5 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/enums/UploadFileEnum.java

@@ -21,7 +21,11 @@ public enum UploadFileEnum {
     /**
      * 导入导出
      */
-    FILE("file");
+    FILE("file"),
+
+    PDF("pdf"),
+
+    HTML("html");
 
     private String title;
 

+ 22 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/BasicAttachmentService.java

@@ -5,6 +5,9 @@ import com.qmth.distributed.print.business.entity.BasicAttachment;
 import com.qmth.distributed.print.business.enums.UploadFileEnum;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
+import java.util.List;
+
 /**
  * <p>
  * 所有附件记录表 服务类
@@ -38,10 +41,29 @@ public interface BasicAttachmentService extends IService<BasicAttachment> {
      */
     public BasicAttachment saveAttachment(MultipartFile file, String md5, UploadFileEnum type, Long objId);
 
+    /**
+     * 保存html附件
+     *
+     * @param fileName
+     * @param htmlContent
+     * @param schoolId
+     * @param userId
+     * @return
+     * @throws IOException
+     */
+    public BasicAttachment saveAttachmentHtml(String fileName, String htmlContent, Long schoolId, Long userId) throws IOException;
+
     /**
      * 删除附件
      *
      * @param tbAttachment
      */
     public void deleteAttachment(BasicAttachment tbAttachment);
+
+    /**
+     * 批量删除附件
+     *
+     * @param basicAttachmentList
+     */
+    public void batchDeleteAttachment(List<BasicAttachment> basicAttachmentList);
 }

+ 92 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/service/impl/BasicAttachmentServiceImpl.java

@@ -11,6 +11,7 @@ import com.qmth.distributed.print.business.entity.SysUser;
 import com.qmth.distributed.print.business.enums.UploadFileEnum;
 import com.qmth.distributed.print.business.mapper.BasicAttachmentMapper;
 import com.qmth.distributed.print.business.service.BasicAttachmentService;
+import com.qmth.distributed.print.business.util.FileMd5Util;
 import com.qmth.distributed.print.business.util.OssUtil;
 import com.qmth.distributed.print.business.util.ServletUtil;
 import com.qmth.distributed.print.common.contant.SystemConstant;
@@ -25,6 +26,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.FileCopyUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
@@ -159,15 +161,101 @@ public class BasicAttachmentServiceImpl extends ServiceImpl<BasicAttachmentMappe
         return saveAttachmentCommon(file, md5, type, objId);
     }
 
+    /**
+     * 保存html附件
+     *
+     * @param fileName
+     * @param htmlContent
+     * @param schoolId
+     * @param userId
+     * @return
+     * @throws IOException
+     */
+    @Override
+    @Transactional
+    public BasicAttachment saveAttachmentHtml(String fileName, String htmlContent, Long schoolId, Long userId) throws IOException {
+        BasicAttachment basicAttachment = null;
+        try {
+            byte[] bytes = htmlContent.getBytes();
+            int size = bytes.length;
+            boolean oss = dictionaryConfig.sysDomain().isOss();
+            LocalDateTime nowTime = LocalDateTime.now();
+            StringJoiner stringJoiner = new StringJoiner("");
+            if (!oss) {
+                stringJoiner.add(SystemConstant.TEMP_FILES_DIR).add(File.separator);
+            }
+            stringJoiner.add(UploadFileEnum.HTML.getTitle()).add(File.separator)
+                    .add(String.valueOf(schoolId)).add(File.separator)
+                    .add(String.valueOf(nowTime.getYear())).add(File.separator)
+                    .add(String.format("%02d", nowTime.getMonthValue())).add(File.separator)
+                    .add(String.format("%02d", nowTime.getDayOfMonth()));
+
+            JSONObject jsonObject = new JSONObject();
+            stringJoiner.add(File.separator).add(SystemConstant.getUuid()).add(File.separator).add(fileName).add(SystemConstant.HTML_PREFIX);
+            //计算html文件md5
+            String fileMd5 = FileMd5Util.pathMd5(stringJoiner.toString());
+            if (oss) {//上传至oss\
+                String dirName = stringJoiner.toString().replaceAll("\\\\", "/");
+                ossUtil.ossUpload(dirName, htmlContent);
+                jsonObject.put(SystemConstant.TYPE, SystemConstant.OSS);
+                jsonObject.put(SystemConstant.PATH, dirName);
+            } else {//上传至服务器
+                File finalFile = new File(stringJoiner.toString());
+                if (!finalFile.exists()) {
+                    finalFile.getParentFile().mkdirs();
+                    finalFile.createNewFile();
+                }
+                FileCopyUtils.copy(bytes, new File(stringJoiner.toString()));
+                jsonObject.put(SystemConstant.TYPE, SystemConstant.LOCAL);
+                jsonObject.put(SystemConstant.PATH, stringJoiner.toString());
+            }
+            jsonObject.put(SystemConstant.UPLOAD_TYPE, UploadFileEnum.HTML);
+            basicAttachment = new BasicAttachment(jsonObject.toJSONString(), fileName, SystemConstant.HTML_PREFIX, new BigDecimal(size), fileMd5, userId);
+            save(basicAttachment);
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            deleteAttachment(basicAttachment);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
+        }
+        return basicAttachment;
+    }
+
     /**
      * 删除附件
      *
-     * @param tbAttachment
+     * @param basicAttachment
+     */
+    @Override
+    public void deleteAttachment(BasicAttachment basicAttachment) {
+        deleteAttachmentCommon(basicAttachment);
+    }
+
+    /**
+     * 批量删除附件
+     *
+     * @param basicAttachmentList
      */
     @Override
-    public void deleteAttachment(BasicAttachment tbAttachment) {
-        if (Objects.nonNull(tbAttachment) && Objects.nonNull(tbAttachment.getPath())) {
-            JSONObject jsonObject = JSONObject.parseObject(tbAttachment.getPath());
+    public void batchDeleteAttachment(List<BasicAttachment> basicAttachmentList) {
+        if (Objects.nonNull(basicAttachmentList) && basicAttachmentList.size() > 0) {
+            for (BasicAttachment basicAttachment : basicAttachmentList) {
+                deleteAttachmentCommon(basicAttachment);
+            }
+        }
+    }
+
+    /**
+     * 删除附件公用
+     *
+     * @param basicAttachment
+     */
+    public void deleteAttachmentCommon(BasicAttachment basicAttachment) {
+        if (Objects.nonNull(basicAttachment) && Objects.nonNull(basicAttachment.getPath())) {
+            JSONObject jsonObject = JSONObject.parseObject(basicAttachment.getPath());
             String type = String.valueOf(jsonObject.get(SystemConstant.TYPE));
             if (Objects.nonNull(type) && Objects.equals(type, SystemConstant.OSS)) {//删除阿里云附件
                 ossUtil.ossDelete(jsonObject.get(SystemConstant.PATH).toString());

+ 5 - 4
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/importData/AsyncImportTaskTemplete.java

@@ -42,6 +42,7 @@ public abstract class AsyncImportTaskTemplete {
     public static final String FINISH_TITLE = "->数据处理结束,共处理了";
     public static final String FINISH_SIZE = "条数据";
     public static final String TXT_PREFIX = ".txt";
+    public static final String EXCEPTION_CREATE_TXT_TITLE = "->创建导出文件时发生异常!";
     public static final String FORMAT_TIME = DateUtil.format(new Date(), SystemConstant.DEFAULT_DATE_PATTERN);
 
     /**
@@ -119,15 +120,15 @@ public abstract class AsyncImportTaskTemplete {
             tbTask.setReportFilePath(json.toJSONString());
         } catch (Exception e) {
             log.error("请求出错", e);
+            StringJoiner stringJoinerSummary = new StringJoiner("").add(tbTask.getSummary()).add("\n");
+            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", FORMAT_TIME, EXCEPTION_CREATE_TXT_TITLE, EXCEPTION_DATA, e.getMessage()));
+            tbTask.setSummary(stringJoinerSummary.toString());
+            tbTask.setResult(TaskResultEnum.ERROR);
             if (e instanceof ApiException) {
                 ResultUtil.error((ApiException) e, e.getMessage());
             } else {
                 ResultUtil.error(e.getMessage());
             }
-            StringJoiner stringJoinerSummary = new StringJoiner("").add(tbTask.getSummary());
-            stringJoinerSummary.add(MessageFormat.format("{0}{1}{2}{3}", FORMAT_TIME, EXCEPTION_TITLE, EXCEPTION_DATA, e.getMessage()));
-            tbTask.setSummary(stringJoinerSummary.toString());
-            tbTask.setResult(TaskResultEnum.ERROR);
         } finally {
             try {
                 if (Objects.nonNull(inputStream)) {

+ 2 - 1
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/TaskLogicService.java

@@ -2,6 +2,7 @@ package com.qmth.distributed.print.business.templete.service;
 
 import org.springframework.util.LinkedMultiValueMap;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
@@ -29,5 +30,5 @@ public interface TaskLogicService {
      * @param map
      * @return
      */
-    public Map<String, Object> executeCreatePdfLogic(Map<String, Object> map);
+    public Map<String, Object> executeCreatePdfLogic(Map<String, Object> map) throws IOException;
 }

+ 173 - 65
distributed-print-business/src/main/java/com/qmth/distributed/print/business/templete/service/impl/TaskLogicServiceImpl.java

@@ -1,28 +1,31 @@
 package com.qmth.distributed.print.business.templete.service.impl;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.google.gson.Gson;
+import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.bean.dto.excel.UserImportDto;
 import com.qmth.distributed.print.business.entity.*;
-import com.qmth.distributed.print.business.enums.ExamCardStatusEnum;
 import com.qmth.distributed.print.business.enums.ExamStatusEnum;
 import com.qmth.distributed.print.business.service.*;
 import com.qmth.distributed.print.business.templete.service.TaskLogicService;
+import com.qmth.distributed.print.business.util.GoogleBarCodeUtil;
 import com.qmth.distributed.print.business.util.ServletUtil;
 import com.qmth.distributed.print.business.util.excel.ExcelError;
 import com.qmth.distributed.print.common.contant.SystemConstant;
 import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
 import com.qmth.distributed.print.common.util.Base64Util;
+import com.qmth.distributed.print.common.util.ResultUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.LinkedMultiValueMap;
 
 import javax.annotation.Resource;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.io.IOException;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -34,6 +37,7 @@ import java.util.stream.Collectors;
  */
 @Service
 public class TaskLogicServiceImpl implements TaskLogicService {
+    private final static Logger log = LoggerFactory.getLogger(TaskLogicServiceImpl.class);
 
     @Resource
     SysUserService sysUserService;
@@ -68,6 +72,9 @@ public class TaskLogicServiceImpl implements TaskLogicService {
     @Resource
     ExamStudentService examStudentService;
 
+    @Resource
+    BasicAttachmentService basicAttachmentService;
+
     /**
      * 执行导入用户逻辑
      *
@@ -127,71 +134,172 @@ public class TaskLogicServiceImpl implements TaskLogicService {
      */
     @Override
     @Transactional
-    public Map<String, Object> executeCreatePdfLogic(Map<String, Object> map) {
-        TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
-        SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
-        //查询printPlan
-        ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTask.getPrintPlanId());
-        if (Objects.isNull(examPrintPlan)) {
-            throw ExceptionResultEnum.ERROR.exception("印刷计划为空");
-        }
-
-        //查询examDetail
-        QueryWrapper<ExamDetail> examDetailQueryWrapper = new QueryWrapper<>();
-        examDetailQueryWrapper.lambda().eq(ExamDetail::getSchoolId, sysUser.getSchoolId())
-                .eq(ExamDetail::getPrintPlanId, tbTask.getPrintPlanId());
-        ExamDetail examDetail = detailService.getOne(examDetailQueryWrapper);
-        if (Objects.isNull(examDetail)) {
-            throw ExceptionResultEnum.ERROR.exception("考务计划为空");
-        }
+    public Map<String, Object> executeCreatePdfLogic(Map<String, Object> map) throws IOException {
+        List<BasicAttachment> basicAttachmentList = null;
+        try {
+            TBTask tbTask = (TBTask) map.get(SystemConstant.TASK);
+            SysUser sysUser = (SysUser) map.get(SystemConstant.USER);
+            //这里为保存附件html的逻辑
+            //查询题卡详情是否有附件id,有的话则把以前的附件删除
+            Set<Long> attachmentIds = null;
 
-        //查询examDetailCourse
-        QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
-        examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, examDetail.getId());
-        List<ExamDetailCourse> examDetailCourseList = detailCourseService.list(examDetailCourseQueryWrapper);
-
-        for (ExamDetailCourse examDetailCourse : examDetailCourseList) {
-            //查询试卷
-            QueryWrapper<ExamTask> examTaskQueryWrapper = new QueryWrapper<>();
-            examTaskQueryWrapper.lambda().eq(ExamTask::getSchoolId, sysUser.getSchoolId())
-                    .eq(ExamTask::getCourseCode, examDetailCourse.getCourseCode())
-                    .eq(ExamTask::getCourseName, examDetailCourse.getCourseName())
-                    .eq(ExamTask::getPaperNumber, examDetailCourse.getPaperNumber())
-                    .eq(ExamTask::getEnable, true)
-                    .eq(ExamTask::getStatus, ExamStatusEnum.FINISH);
-            List<ExamTask> examTaskList = examTaskService.list(examTaskQueryWrapper);
-            if (Objects.isNull(examTaskList) || examTaskList.size() == 0) {
-                throw ExceptionResultEnum.ERROR.exception("命题任务为空");
+            //查询printPlan
+            ExamPrintPlan examPrintPlan = examPrintPlanService.getById(tbTask.getPrintPlanId());
+            if (Objects.isNull(examPrintPlan)) {
+                throw ExceptionResultEnum.ERROR.exception("印刷计划为空");
             }
-            Set<Long> examTaskIds = examTaskList.stream().map(s -> s.getId()).collect(Collectors.toSet());
-
-            QueryWrapper<ExamTaskDetail> examTaskDetailQueryWrapper = new QueryWrapper<>();
-            examTaskDetailQueryWrapper.lambda().in(ExamTaskDetail::getExamTaskId, examTaskIds)
-                    .eq(ExamTaskDetail::getEnable, true);
-            List<ExamTaskDetail> examTaskDetailList = examTaskDetailService.list(examTaskDetailQueryWrapper);
-            Set<Long> examTaskDetailIds = examTaskDetailList.stream().map(s -> s.getId()).collect(Collectors.toSet());
-
-            //查询题卡
-            QueryWrapper<ExamCard> examCardQueryWrapper = new QueryWrapper<>();
-            examCardQueryWrapper.lambda().eq(ExamCard::getSchoolId, sysUser.getSchoolId())
-                    .eq(ExamCard::getCourseCode, examDetailCourse.getCourseCode())
-                    .eq(ExamCard::getCourseName, examDetailCourse.getCourseName())
-                    .eq(ExamCard::getStatus, ExamCardStatusEnum.SUBMIT);
-            List<ExamCard> examCardList = examCardService.list(examCardQueryWrapper);
-            if (Objects.isNull(examCardList) || examCardList.size() == 0) {
-                throw ExceptionResultEnum.ERROR.exception("题卡为空");
+
+            //查询examDetail
+            QueryWrapper<ExamDetail> examDetailQueryWrapper = new QueryWrapper<>();
+            examDetailQueryWrapper.lambda().eq(ExamDetail::getSchoolId, sysUser.getSchoolId())
+                    .eq(ExamDetail::getPrintPlanId, tbTask.getPrintPlanId());
+            ExamDetail examDetail = detailService.getOne(examDetailQueryWrapper);
+            if (Objects.isNull(examDetail)) {
+                throw ExceptionResultEnum.ERROR.exception("考务计划为空");
             }
-            Set<Long> examCardIds = examCardList.stream().map(s -> s.getId()).collect(Collectors.toSet());
+            attachmentIds = Objects.isNull(attachmentIds) ? attachmentIds = new HashSet<>() : attachmentIds;
+            attachmentIds.add(examDetail.getAttachmentId());
+
+            //查询examDetailCourse
+            QueryWrapper<ExamDetailCourse> examDetailCourseQueryWrapper = new QueryWrapper<>();
+            examDetailCourseQueryWrapper.lambda().eq(ExamDetailCourse::getExamDetailId, examDetail.getId());
+            List<ExamDetailCourse> examDetailCourseList = detailCourseService.list(examDetailCourseQueryWrapper);
+
+            for (ExamDetailCourse examDetailCourse : examDetailCourseList) {
+                //查询试卷
+                QueryWrapper<ExamTask> examTaskQueryWrapper = new QueryWrapper<>();
+                examTaskQueryWrapper.lambda().eq(ExamTask::getSchoolId, sysUser.getSchoolId())
+                        .eq(ExamTask::getCourseCode, examDetailCourse.getCourseCode())
+                        .eq(ExamTask::getCourseName, examDetailCourse.getCourseName())
+                        .eq(ExamTask::getPaperNumber, examDetailCourse.getPaperNumber())
+                        .eq(ExamTask::getEnable, true)
+                        .eq(ExamTask::getStatus, ExamStatusEnum.FINISH);
+                List<ExamTask> examTaskList = examTaskService.list(examTaskQueryWrapper);
+                if (Objects.isNull(examTaskList) || examTaskList.size() == 0) {
+                    throw ExceptionResultEnum.ERROR.exception("命题任务为空");
+                }
+                Set<Long> examTaskIds = examTaskList.stream().map(s -> s.getId()).collect(Collectors.toSet());
+
+                QueryWrapper<ExamTaskDetail> examTaskDetailQueryWrapper = new QueryWrapper<>();
+                examTaskDetailQueryWrapper.lambda().in(ExamTaskDetail::getExamTaskId, examTaskIds)
+                        .eq(ExamTaskDetail::getEnable, true);
+                List<ExamTaskDetail> examTaskDetailList = examTaskDetailService.list(examTaskDetailQueryWrapper);
+                JSONObject jsonObject = new JSONObject();
+                JSONArray jsonArray = new JSONArray();
+                for (ExamTaskDetail examTaskDetail : examTaskDetailList) {
+                    //查询题卡
+                    ExamCard examCard = examCardService.getById(examTaskDetail.getCardId());
+                    if (Objects.isNull(examCard)) {
+                        throw ExceptionResultEnum.ERROR.exception("题卡为空");
+                    }
+                    QueryWrapper<ExamCardDetail> examCardDetailQueryWrapper = new QueryWrapper<>();
+                    examCardDetailQueryWrapper.lambda().eq(ExamCardDetail::getCardId, examCard.getId());
+                    List<ExamCardDetail> examCardDetailList = examCardDetailService.list(examCardDetailQueryWrapper);
+
+                    String[] paperTypes = examTaskDetail.getPaperType().split("/");
+                    basicAttachmentList = Objects.isNull(basicAttachmentList) ? basicAttachmentList = new ArrayList<>() : basicAttachmentList;
+                    for (ExamCardDetail examCardDetail : examCardDetailList) {
+                        if (Objects.nonNull(examCardDetail.getAttachmentId())) {
+                            JSONObject jsonObjectCard = JSONObject.parseObject(examCardDetail.getAttachmentId());
+                            JSONArray jsonArrayCard = (JSONArray) jsonObjectCard.get("card");
+                            for (int i = 0; i < jsonArrayCard.size(); i++) {
+                                JSONObject object = (JSONObject) jsonArrayCard.get(i);
+                                if (Objects.nonNull(object.get("attachmentId"))) {
+                                    attachmentIds.add((Long) object.get("attachmentId"));
+                                }
+                            }
+                        }
+
+                        //把模板页面上的 ${} 替换成实际内容
+                        String content = examCardDetail.getHtmlContent();
+                        log.info("contentTemp:{}", content);
+                        String cardContent = content;
+                        String studentContent = content;
+                        cardContent = cardContent.replaceAll("<img src=\"data:image/png;base64,\\$\\{examNumber\\}\">", "");
+                        cardContent = cardContent.replaceAll("\\$\\{examNumberStr\\}", "");
+
+                        for (String paperType : paperTypes) {
+                            for (Integer integer = 1; integer <= examPrintPlan.getBackupCount(); integer++) {
+                                //通用题卡
+                                String cardTemp = cardContent;
+                                cardTemp = cardTemp.replaceAll("\\$\\{paperTypeName\\}", paperType);
+                                //随机生成试卷条码并将图片转成base64
+                                cardTemp = cardTemp.replaceAll("\\$\\{paperType\\}", GoogleBarCodeUtil.createBarCode(SystemConstant.convertPaperType(paperType), false));
+                                //通用题卡生成卷袋贴条码
+                                String paperCode = examDetailCourse.getPaperNumber();
+                                String paperCodeImg = GoogleBarCodeUtil.createBarCode(paperCode, false);
+                                String paperCodeDiv = "<div class=\"page-box page-box-0\"><div class=\"package-number\" style=\"position: absolute;width: 200px;height: 40px;top: 80px;right: 35px;transform: rotate(-90deg);transform-origin: center right;text-align: center;z-index: 99;\"><img src=\"data:image/png;base64," + paperCodeImg + "\" style=\"display: block; height: 28px; width: 100%\" /><p style=\"line-height: 1; font-size: 12px; margin: 0;\">" + paperCode + "</p></div>";
+                                cardTemp = cardTemp.replaceAll("<div class=\"page-box page-box-0\">", paperCodeDiv);
+                                BasicAttachment cardAttachment = basicAttachmentService.saveAttachmentHtml(examCard.getSchoolId() + "|" + examCard.getCourseCode(), cardTemp, examCard.getSchoolId(), sysUser.getId());
+                                JSONObject object = new JSONObject();
+                                object.put("name", paperType);
+                                object.put("examTaskDetailId", examTaskDetail.getId());
+                                object.put("attachmentId", cardAttachment.getId());
+                                jsonArray.add(object);
+                                basicAttachmentList.add(cardAttachment);
+                            }
+
+                            //查询考生
+                            QueryWrapper<ExamStudent> examStudentQueryWrapper = new QueryWrapper<>();
+                            examStudentQueryWrapper.lambda().eq(ExamStudent::getSchoolId, sysUser.getSchoolId())
+                                    .eq(ExamStudent::getExamDetailCourseId, examTaskDetail.getId());
+                            List<ExamStudent> examStudentList = examStudentService.list(examStudentQueryWrapper);
 
-            QueryWrapper<ExamCardDetail> examCardDetailQueryWrapper = new QueryWrapper<>();
-            examCardDetailQueryWrapper.lambda().in(ExamCardDetail::getCardId, examCardIds);
-            List<ExamCardDetail> examCardDetailList = examCardDetailService.list(examCardDetailQueryWrapper);
+                            for (ExamStudent t : examStudentList) {
+//                            if (Objects.nonNull(t.getAttachmentIds())) {
+//                                attachmentIds.add(t.getAttachmentId());
+//                            }
+                                String studentHtml = studentContent;
+                                if (Objects.nonNull(t.getExtendFields())) {
+                                    JSONArray jsonObjectExtend = (JSONArray) JSONArray.parse(t.getExtendFields());//扩展字段
+                                    if (Objects.nonNull(jsonObjectExtend)) {
+                                        for (int i = 0; i < jsonObjectExtend.size(); i++) {
+                                            JSONObject object = (JSONObject) jsonObjectExtend.get(i);
+                                            studentHtml = studentHtml.replaceAll("\\$\\{" + object.get("code") + "\\}", String.valueOf(object.get("value")));
+                                        }
+                                    }
+                                }
+                                //生成学生考号条码并将图片转成base64
+                                studentHtml = studentHtml.replaceAll("\\$\\{examNumber\\}", GoogleBarCodeUtil.createBarCode(t.getTicketNumber(), false));
+                                studentHtml = studentHtml.replaceAll("\\$\\{examNumberStr\\}", t.getTicketNumber());
+                                //随机生成学生试卷条码并将图片转成base64
+                                studentHtml = studentHtml.replaceAll("\\$\\{paperType\\}", GoogleBarCodeUtil.createBarCode(SystemConstant.convertPaperType(paperType), false));
+                                studentHtml = studentHtml.replaceAll("\\$\\{paperTypeName\\}", paperType);
+                                studentHtml = studentHtml.replaceAll("\\$\\{studentCode\\}", t.getStudentCode());
+                                studentHtml = studentHtml.replaceAll("\\$\\{name\\}", t.getStudentName());
+                                studentHtml = studentHtml.replaceAll("\\$\\{courseName\\}", examCard.getCourseName());
 
-            //查询考生
-            QueryWrapper<ExamStudent> examStudentQueryWrapper = new QueryWrapper<>();
-            examStudentQueryWrapper.lambda().eq(ExamStudent::getSchoolId, sysUser.getSchoolId())
-                    .in(ExamStudent::getExamDetailCourseId, examTaskDetailIds);
-            List<ExamStudent> examStudentList = examStudentService.list(examStudentQueryWrapper);
+                                //学生题卡
+                                BasicAttachment examStudentAttachment = basicAttachmentService.saveAttachmentHtml(examCard.getSchoolId() + "|" + examCard.getCourseCode(), studentHtml, examCard.getSchoolId(), sysUser.getId());
+                                JSONObject jsonObjectExamStudent = new JSONObject();
+                                jsonObjectExamStudent.put("htmlAttachmentId", examStudentAttachment.getId());
+                                jsonObjectExamStudent.put("pdfAttachmentId", 123L);
+                                t.setAttachmentIds(jsonObjectExamStudent.toJSONString());
+                                basicAttachmentList.add(examStudentAttachment);
+                            }
+                            examStudentService.saveOrUpdateBatch(examStudentList);
+                        }
+                        jsonObject.put("card", jsonArray);
+                        examCardDetail.setAttachmentId(jsonObject.toJSONString());
+                    }
+                    examCardDetailService.saveOrUpdateBatch(examCardDetailList);
+                }
+            }
+            //最后一步删除附件
+            if (Objects.nonNull(attachmentIds) && attachmentIds.size() > 0) {
+                QueryWrapper<BasicAttachment> basicAttachmentQueryWrapper = new QueryWrapper<>();
+                basicAttachmentQueryWrapper.lambda().in(BasicAttachment::getId, attachmentIds);
+                basicAttachmentService.batchDeleteAttachment(basicAttachmentService.list(basicAttachmentQueryWrapper));
+                basicAttachmentService.removeByIds(attachmentIds);
+            }
+        } catch (Exception e) {
+            log.error("请求出错", e);
+            basicAttachmentService.batchDeleteAttachment(basicAttachmentList);
+            if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
         }
         return map;
     }

+ 46 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/FileMd5Util.java

@@ -0,0 +1,46 @@
+package com.qmth.distributed.print.business.util;
+
+import com.qmth.distributed.print.common.contant.SystemConstant;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+
+public class FileMd5Util {
+
+    public static String pathMd5(String path) {
+        if (StringUtils.isEmpty(path)) {
+            return "";
+        }
+        File file = new File(path);
+        if (!file.exists()) {
+            return "";
+        }
+
+        FileInputStream fileInputStream = null;
+        try {
+            MessageDigest MD5 = MessageDigest.getInstance(SystemConstant.MD5);
+            fileInputStream = new FileInputStream(file);
+            byte[] buffer = new byte[8192];
+            int length;
+            while ((length = fileInputStream.read(buffer)) != -1) {
+                MD5.update(buffer, 0, length);
+            }
+            return new String(Hex.encodeHex(MD5.digest()));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        } finally {
+            try {
+                if (fileInputStream != null) {
+                    fileInputStream.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 181 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/GoogleBarCodeUtil.java

@@ -0,0 +1,181 @@
+package com.qmth.distributed.print.business.util;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.oned.Code128Writer;
+import sun.misc.BASE64Encoder;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @Description: 条形码生成
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2020/4/27
+ */
+public class GoogleBarCodeUtil {
+    /**
+     * 条形码宽度
+     */
+    private static final int WIDTH = 300;
+
+    /**
+     * 条形码高度
+     */
+    private static final int HEIGHT = 50;
+
+    /**
+     * 加文字 条形码
+     */
+    private static final int WORDHEIGHT = 85;
+    /**
+     * 设置 条形码参数
+     */
+    private static Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>() {
+        private static final long serialVersionUID = 1L;
+
+        {
+            // 设置编码方式
+            put(EncodeHintType.CHARACTER_SET, "utf-8");
+//            put(EncodeHintType.MARGIN, 0);
+        }
+    };
+
+    /**
+     * 生成 图片缓冲
+     *
+     * @param vaNumber VA 码
+     * @return 返回BufferedImage
+     * @author fxbin
+     */
+    public static BufferedImage getBarCode(String vaNumber) {
+        try {
+            Code128Writer writer = new Code128Writer();
+            BitMatrix bitMatrix = writer.encode(vaNumber, BarcodeFormat.CODE_128, WIDTH, HEIGHT, hints);
+            return MatrixToImageWriter.toBufferedImage(bitMatrix);
+        } catch (WriterException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 把带logo的二维码下面加上文字
+     *
+     * @param image 条形码图片
+     * @param words 文字
+     * @param word
+     * @return 返回BufferedImage
+     * @author fxbin
+     */
+    public static BufferedImage insertWords(BufferedImage image, String words, boolean word) {
+        // 新的图片,把带logo的二维码下面加上文字
+        BufferedImage outImage = new BufferedImage(WIDTH, WORDHEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = outImage.createGraphics();
+        // 抗锯齿
+        setGraphics2D(g2d);
+        // 设置白色
+        setColorWhite(g2d);
+        // 画条形码到新的面板
+//        g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);//画字用
+        g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
+        if (Objects.nonNull(words) && word) {
+            // 画文字到新的面板
+            Color color = new Color(0, 0, 0);
+            g2d.setColor(color);
+            // 字体、字型、字号
+            g2d.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+            //文字长度
+            int strWidth = g2d.getFontMetrics().stringWidth(words);
+            //总长度减去文字长度的一半  (居中显示)
+            int wordStartX = (WIDTH - strWidth) / 2;
+            //height + (outImage.getHeight() - height) / 2 + 12
+            int wordStartY = HEIGHT + 30;
+            // 画文字
+            g2d.drawString(words, wordStartX, wordStartY);
+            g2d.dispose();
+//            outImage.flush();
+//            return outImage;
+        }
+        outImage.flush();
+        return outImage;
+    }
+
+    /**
+     * 设置 Graphics2D 属性  (抗锯齿)
+     *
+     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
+     */
+    private static void setGraphics2D(Graphics2D g2d) {
+        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
+        Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
+        g2d.setStroke(s);
+    }
+
+    /**
+     * 设置背景为白色
+     *
+     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
+     */
+    private static void setColorWhite(Graphics2D g2d) {
+        g2d.setColor(Color.WHITE);
+        //填充整个屏幕
+        g2d.fillRect(0, 0, 600, 600);
+        //设置笔刷
+        g2d.setColor(Color.BLACK);
+    }
+
+//    public static void main(String[] args) throws IOException {
+//        BufferedImage image = getBarCode("202004270001");
+//        ImageIO.write(image, "jpg", new File("/Users/king/Downloads/3.png"));
+//
+//        StringJoiner result = new StringJoiner("");
+//        try {
+//            BufferedReader br = new BufferedReader(new FileReader("/Users/king/Downloads/线下测试学校_1_阶梯教室_签到表和卷袋贴.html"));//构造一个BufferedReader类来读取文件
+//            String s = null;
+//            while ((s = br.readLine()) != null) {//使用readLine方法,一次读一行
+//                result.add(System.lineSeparator() + s);
+//            }
+//            br.close();
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//        String s = result.toString();
+//        s = s.replaceAll("\\$\\{examNumber\\}", createBarCode("202007080001", true));
+//        //随机生成学生试卷条码并将图片转成base64
+//        s = s.replaceAll("\\$\\{paperType\\}", createBarCode(SystemConstant.convertPaperType("A"), false));
+//        System.out.println(s);
+//    }
+
+    /**
+     * 创建条码
+     *
+     * @param contennt
+     * @param word
+     * @return
+     * @throws IOException
+     */
+    public static String createBarCode(String contennt, boolean word) throws IOException {
+        BufferedImage image = GoogleBarCodeUtil.getBarCode(contennt);
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        ImageIO.write(image, "png", os);
+        byte[] imageBytes = os.toByteArray();
+        BASE64Encoder encoder = new BASE64Encoder();
+        String imageBase64 = encoder.encode(imageBytes);
+        os.flush();
+        os.close();
+        return imageBase64;
+    }
+}

+ 13 - 0
distributed-print-common/src/main/java/com/qmth/distributed/print/common/contant/SystemConstant.java

@@ -48,6 +48,7 @@ public class SystemConstant {
     public static final String ID = "id";
     public static final String FILE = "file";
     public static final String SIZE = "size";
+    public static final String HTML_PREFIX = ".html";
     public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
     public static final int PAGE_NUMBER = 0;
     public static final int PAGE_SIZE = 10000000;
@@ -153,4 +154,16 @@ public class SystemConstant {
     public static Boolean convertEnable(Boolean enable) {
         return Objects.nonNull(enable) ? enable : true;
     }
+
+    /**
+     * 试卷类型转换
+     *
+     * @param paperType
+     * @return
+     */
+    public static String convertPaperType(String paperType) {
+        paperType = paperType.toLowerCase();
+        int ascii = (int) paperType.charAt(0);
+        return String.valueOf(ascii + 704);
+    }
 }

+ 11 - 0
pom.xml

@@ -41,6 +41,7 @@
         <version-plugin.version>2.8.1</version-plugin.version>
         <netty-all.version>4.1.49.Final</netty-all.version>
         <itextpdf.version>5.5.13</itextpdf.version>
+        <googleBar.version>3.4.0</googleBar.version>
     </properties>
 
     <dependencyManagement>
@@ -213,6 +214,16 @@
                 <artifactId>itextpdf</artifactId>
                 <version>${itextpdf.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.google.zxing</groupId>
+                <artifactId>core</artifactId>
+                <version>${googleBar.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.zxing</groupId>
+                <artifactId>javase</artifactId>
+                <version>${googleBar.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>