Browse Source

Merge remote-tracking branch 'origin/dev_v3.3.1' into dev_v3.3.1

caozixuan 1 year ago
parent
commit
4cd8838e4e

+ 12 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TCScoreNormal.java

@@ -71,6 +71,18 @@ public class TCScoreNormal implements Serializable {
 
     }
 
+    public TCScoreNormal(Long examId, String courseCode, String courseName, String paperNumber, String paperType, Long userId) {
+        this.id = SystemConstant.getDbUuid();
+        this.examId = examId;
+        this.courseCode = courseCode;
+        this.courseName = courseName;
+        this.paperNumber = paperNumber;
+        this.paperType = paperType;
+        this.enable = true;
+        this.createId = userId;
+        this.createTime = System.currentTimeMillis();
+    }
+
     public TCScoreNormal(Long examId, String courseCode, String courseName, String paperNumber, String paperType, String name, String examNumber, String scoreNormal, Long userId) {
         this.id = SystemConstant.getDbUuid();
         this.examId = examId;

+ 11 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/entity/TRExamStudent.java

@@ -37,9 +37,20 @@ public class TRExamStudent implements Serializable {
     @ApiModelProperty(value = "行政班级")
     private String clazz;
 
+    @ApiModelProperty(value = "学生成绩")
+    private Double score;
+
     @ApiModelProperty(value = "考生课程考核成绩评价明细结果")
     private String resultDetail;
 
+    public Double getScore() {
+        return score;
+    }
+
+    public void setScore(Double score) {
+        this.score = score;
+    }
+
     public Long getId() {
         return id;
     }

+ 227 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/excel/BasicExcelListener.java

@@ -0,0 +1,227 @@
+package com.qmth.distributed.print.business.util.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.metadata.CellExtra;
+import com.alibaba.fastjson.JSONObject;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.LinkedMultiValueMap;
+
+import javax.validation.constraints.*;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * @Description: easyexcel监听
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2022/5/14
+ */
+public abstract class BasicExcelListener<T> extends AnalysisEventListener<T> {
+    private final static Logger log = LoggerFactory.getLogger(BasicExcelListener.class);
+
+    /**
+     * 批处理阈值2000
+     */
+    private static int BATCH_COUNT = 2000;
+    public static final String SUCCESS = "success";
+    public static final String ERROR = "error";
+    private LinkedMultiValueMap<String, T> list;
+    private StringJoiner errorDataSj = new StringJoiner("\n");
+    private Exception exception = null;
+
+    public BasicExcelListener() {
+        this.list = new LinkedMultiValueMap<>(BATCH_COUNT);
+    }
+
+    public BasicExcelListener(int batchCount) {
+        BATCH_COUNT = batchCount;
+        this.list = new LinkedMultiValueMap<>(BATCH_COUNT);
+    }
+
+    public abstract void handle(LinkedMultiValueMap<String, T> dataList, StringJoiner errorData, Exception exception);
+
+//    public abstract void errorData(List<String> errorDataList);
+
+    @Override
+    public void invoke(T o, AnalysisContext analysisContext) {
+//        if (validData(o, analysisContext) || (analysisContext.readRowHolder().getRowIndex() == 2001 || analysisContext.readRowHolder().getRowIndex() == 7001)) {
+        if (validData(o, analysisContext)) {
+            list.add(ERROR, o);
+            BasicExcelRow basicExcelRow = (BasicExcelRow) o;
+            errorDataSj.add("第" + basicExcelRow.getSheet() + "个sheet第" + (basicExcelRow.getRow() - 1) + "行" + basicExcelRow.getErrorMessage().toString());
+        } else {
+            list.add(SUCCESS, o);
+        }
+        if (list.size() >= BATCH_COUNT) {
+            handle(list, errorDataSj, this.exception);
+            list.clear();
+        }
+    }
+
+//    @Override
+//    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
+//        log.info("表头:{}", JSONObject.toJSONString(headMap));
+//    }
+
+    @Override
+    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
+        log.info("表头:{}", JSONObject.toJSONString(headMap));
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+        log.info("所有数据解析完成!");
+        handle(list, errorDataSj, this.exception);
+    }
+
+    @Override
+    public void onException(Exception exception, AnalysisContext context) {
+        log.info("onException is come in!");
+//        XlsxReadSheetHolder xlsxReadSheetHolder = (XlsxReadSheetHolder) context.currentReadHolder();
+//        errorDataSj.add("第" + (xlsxReadSheetHolder.getSheetNo() + 1) + "个sheet第" + (xlsxReadSheetHolder.getRowIndex() - 1) + "行" + exception.getMessage().toString());
+        this.exception = exception;
+    }
+
+    @Override
+    public void extra(CellExtra extra, AnalysisContext context) {
+        log.info("extra is come in!");
+    }
+
+    private void extendBasicExcelField(T o, AnalysisContext analysisContext, List<String> errorMessage) {
+        try {
+            Field rowField = o.getClass().getField("row");
+            rowField.setAccessible(true);
+            rowField.set(o, analysisContext.readRowHolder().getRowIndex());
+
+            Field sheetField = o.getClass().getField("sheet");
+            sheetField.setAccessible(true);
+            sheetField.set(o, analysisContext.readSheetHolder().getSheetNo() + 1);
+
+            Field errorMessageMapField = o.getClass().getField("errorMessage");
+            errorMessageMapField.setAccessible(true);
+            errorMessageMapField.set(o, errorMessage);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            log.error("请求出错:", e);
+        }
+    }
+
+    private boolean validData(T o, AnalysisContext analysisContext) {
+        List<String> errorMessage = new ArrayList<>();
+        Field[] fields = o.getClass().getDeclaredFields();
+        Object object = null;
+        for (int i = 0; i < fields.length; i++) {
+            fields[i].setAccessible(true);
+            try {
+                object = fields[i].get(o);
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+            ExcelProperty excelProperty = fields[i].getDeclaredAnnotation(ExcelProperty.class);
+            if (Objects.isNull(excelProperty)) {
+                continue;
+            }
+            Annotation[] annotations = fields[i].getDeclaredAnnotations();
+            NotBlank notBlank = null;
+            Length length = null;
+            Min min = null;
+            Max max = null;
+            DecimalMin decimalMin = null;
+            DecimalMax decimalMax = null;
+            NotNull notNull = null;
+            Null isnull = null;
+            NotEmpty notEmpty = null;
+            Size size = null;
+            Range range = null;
+            AssertTrue assertTrue = null;
+            AssertFalse assertFalse = null;
+            for (Annotation annotation : annotations) {
+                if (annotation instanceof NotBlank) {
+                    notBlank = (NotBlank) annotation;
+                    if (Objects.isNull(object) || Objects.equals(object, " ")) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + notBlank.message());
+                    }
+                } else if (annotation instanceof Length) {
+                    length = (Length) annotation;
+                    if (Objects.nonNull(object) && (object.toString().length() < length.min() || object.toString().length() > length.max())) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + length.message());
+                    }
+                } else if (annotation instanceof Min) {
+                    min = (Min) annotation;
+                    if (Objects.nonNull(object) && Long.parseLong(object.toString()) < min.value()) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + min.message());
+                    }
+                } else if (annotation instanceof Max) {
+                    max = (Max) annotation;
+                    if (Objects.nonNull(object) && Long.parseLong(object.toString()) > max.value()) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + max.message());
+                    }
+                } else if (annotation instanceof DecimalMin) {
+                    decimalMin = (DecimalMin) annotation;
+                    if (Objects.nonNull(object) && new BigDecimal(object.toString()).compareTo(new BigDecimal(decimalMin.value())) == -1) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + decimalMin.message());
+                    }
+                } else if (annotation instanceof DecimalMax) {
+                    decimalMax = (DecimalMax) annotation;
+                    if (Objects.nonNull(object) && new BigDecimal(object.toString()).compareTo(new BigDecimal(decimalMax.value())) == 1) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + decimalMax.message());
+                    }
+                } else if (annotation instanceof NotNull) {
+                    notNull = (NotNull) annotation;
+                    if (Objects.isNull(object)) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + notNull.message());
+                    }
+                } else if (annotation instanceof Null) {
+                    isnull = (Null) annotation;
+                    if (Objects.nonNull(object)) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + isnull.message());
+                    }
+                } else if (annotation instanceof NotEmpty) {
+                    notEmpty = (NotEmpty) annotation;
+                    if (Objects.isNull(object)) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + notEmpty.message());
+                    }
+                } else if (annotation instanceof Size) {
+                    size = (Size) annotation;
+                    if (Objects.nonNull(object) && (object.toString().length() < size.min() || object.toString().length() > size.max())) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + size.message());
+                    }
+                } else if (annotation instanceof Range) {
+                    range = (Range) annotation;
+                    if (Objects.nonNull(object) && (Long.parseLong(object.toString()) < range.min() || Long.parseLong(object.toString()) > range.max())) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + range.message());
+                    }
+                } else if (annotation instanceof AssertTrue) {
+                    assertTrue = (AssertTrue) annotation;
+                    if (Objects.nonNull(object) && Boolean.valueOf(object.toString())) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + assertTrue.message());
+                    }
+                } else if (annotation instanceof AssertFalse) {
+                    assertFalse = (AssertFalse) annotation;
+                    if (Objects.nonNull(object) && !Boolean.valueOf(object.toString())) {
+                        errorMessage.add("列名[" + excelProperty.value()[0] + "]:" + assertFalse.message());
+                    }
+                }
+            }
+            if (errorMessage.size() > 0) {
+                extendBasicExcelField(o, analysisContext, errorMessage);
+            }
+        }
+        return errorMessage.size() > 0 ? true : false;
+    }
+
+    //可重写的方法:
+//	void invoke(T data, AnalysisContext context); //处理一行数据
+//	void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) //处理表头的一行数据
+//	void extra(CellExtra extra, AnalysisContext context); //获取单元格的额外信息
+//	void doAfterAllAnalysed(AnalysisContext context) //全部读取结束后的操作
+//	boolean hasNext(AnalysisContext context); //是否读取下一行
+//	void onException(Exception exception, AnalysisContext context) //发生异常时调用
+}

+ 53 - 0
distributed-print-business/src/main/java/com/qmth/distributed/print/business/util/excel/BasicExcelRow.java

@@ -0,0 +1,53 @@
+package com.qmth.distributed.print.business.util.excel;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Description: easyexcel基础列
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2022/5/14
+ */
+public class BasicExcelRow implements Serializable {
+
+    @ApiModelProperty(value = "sheet页")
+    @ExcelIgnore
+    public Integer sheet;
+
+    @ApiModelProperty(value = "行号")
+    @ExcelIgnore
+    public Integer row;
+
+    @ApiModelProperty(value = "列名和错误原因")
+    @ExcelIgnore
+    public List<String> errorMessage;
+
+    public Integer getSheet() {
+        return sheet;
+    }
+
+    public void setSheet(Integer sheet) {
+        this.sheet = sheet;
+    }
+
+    public Integer getRow() {
+        return row;
+    }
+
+    public void setRow(Integer row) {
+        this.row = row;
+    }
+
+    public List<String> getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(List<String> errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 5 - 2
distributed-print/install/mysql/upgrade/3.3.1.sql

@@ -150,7 +150,8 @@ CREATE TABLE `t_c_score_end_exam` (
                                       `create_time` bigint DEFAULT NULL COMMENT '创建时间',
                                       `update_id` bigint DEFAULT NULL COMMENT '更新人id',
                                       `update_time` bigint DEFAULT NULL COMMENT '更新时间',
-                                      PRIMARY KEY (`id`)
+                                      PRIMARY KEY (`id`),
+                                      UNIQUE KEY `t_c_score_end_exam_unique` (`exam_id`,`course_code`,`course_name`,`paper_number`,`paper_type`,`name`,`exam_number`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='期末考试成绩表';
 
 DROP TABLE IF EXISTS `t_c_score_normal`;
@@ -169,7 +170,8 @@ CREATE TABLE `t_c_score_normal` (
                                     `create_time` bigint DEFAULT NULL COMMENT '创建时间',
                                     `update_id` bigint DEFAULT NULL COMMENT '更新人id',
                                     `update_time` bigint DEFAULT NULL COMMENT '更新时间',
-                                    PRIMARY KEY (`id`)
+                                    PRIMARY KEY (`id`),
+                                    UNIQUE KEY `t_c_score_normal_unique` (`exam_id`,`course_code`,`course_name`,`paper_number`,`paper_type`,`name`,`exam_number`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='平常作业成绩表';
 
 DROP TABLE IF EXISTS `t_r_basic_info`;
@@ -209,6 +211,7 @@ CREATE TABLE `t_r_exam_student` (
                                     `name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '考生姓名',
                                     `exam_number` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学号',
                                     `clazz` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '行政班级',
+                                    `score` double COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '学生成绩',
                                     `result_detail` mediumtext DEFAULT NULL COMMENT '考生课程考核成绩评价明细结果',
                                     PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='报告考生表';

+ 73 - 8
distributed-print/src/main/java/com/qmth/distributed/print/api/TCScoreNormalController.java

@@ -1,15 +1,21 @@
 package com.qmth.distributed.print.api;
 
 import com.alibaba.excel.EasyExcel;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qmth.boot.api.constant.ApiConstant;
+import com.qmth.boot.api.exception.ApiException;
 import com.qmth.distributed.print.business.bean.excel.ExcelField;
 import com.qmth.distributed.print.business.bean.result.EditResult;
 import com.qmth.distributed.print.business.entity.TCScoreNormal;
 import com.qmth.distributed.print.business.service.TCScoreNormalService;
 import com.qmth.teachcloud.common.annotation.OperationLogDetail;
 import com.qmth.teachcloud.common.contant.SystemConstant;
+import com.qmth.teachcloud.common.entity.SysUser;
 import com.qmth.teachcloud.common.enums.ExceptionResultEnum;
+import com.qmth.teachcloud.common.enums.FieldUniqueEnum;
 import com.qmth.teachcloud.common.enums.log.CustomizedOperationTypeEnum;
 import com.qmth.teachcloud.common.util.JacksonUtil;
 import com.qmth.teachcloud.common.util.ResultUtil;
@@ -20,7 +26,9 @@ import io.swagger.annotations.*;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -105,30 +113,87 @@ public class TCScoreNormalController {
         MarkPaper markPaper = markPaperService.getByExamIdAndPaperNumberAndPaperType(examId, paperNumber, paperType);
         Objects.requireNonNull(markPaper, "未找到科目信息");
 
-        List<Map<String, String>> list = null;
+        Map<String, String> messageMap = new LinkedHashMap<>();
         try {
             StringJoiner errorData = new StringJoiner("");
-            list = EasyExcel.read(file.getInputStream()).headRowNumber(1).sheet(0).doReadSync();
+            StringJoiner successData = new StringJoiner("");
+            List<Map<String, String>> list = EasyExcel.read(file.getInputStream()).headRowNumber(1).sheet(0).doReadSync();
+
+            SysUser sysUser = (SysUser) ServletUtil.getRequestUser();
             List<TCScoreNormal> tcScoreNormalList = new ArrayList<>(list.size());
             log.info("list:{}", JacksonUtil.parseJson(list));
             Map<String, String> headMap = list.get(0);
-            log.info("headMap:{}", JacksonUtil.parseJson(headMap));
+            for (Map.Entry<String, String> entry : headMap.entrySet()) {
+                if (Objects.equals(entry.getKey(), 0) && Objects.nonNull(entry.getValue()) &&
+                        !Objects.equals(entry.getValue().trim(), "学号")) {
+                    throw ExceptionResultEnum.ERROR.exception("excel表头第一行为学号");
+                } else if (Objects.equals(entry.getKey(), 1) && Objects.nonNull(entry.getValue()) &&
+                        !Objects.equals(entry.getValue().trim(), "姓名")) {
+                    throw ExceptionResultEnum.ERROR.exception("excel表头第二行为姓名");
+                }
+            }
+
             for (int i = 1; i < list.size(); i++) {
                 Map<String, String> objectMap = list.get(i);
+                boolean error = false;
+                JSONArray jsonArray = new JSONArray();
+                TCScoreNormal tcScoreNormal = new TCScoreNormal(examId, courseCode, markPaper.getCourseName(), paperNumber, paperType, sysUser.getId());
                 for (Map.Entry<String, String> entry : objectMap.entrySet()) {
-                    if (Objects.isNull(entry) || Objects.equals(entry, "")) {
-                        errorData.add("第" + i + "行").add(headMap.get(entry.getKey()) + "为空\n");
+                    JSONObject jsonObject = new JSONObject();
+                    if (Objects.isNull(entry.getValue()) || Objects.equals(entry.getValue().trim(), "")) {
+                        errorData.add("excel第" + i + "行[").add(headMap.get(entry.getKey()) + "]为空;").add("\r\n");
+                        error = true;
+                    } else {
+                        String head = headMap.get(entry.getKey());
+                        Objects.requireNonNull(head, "表头信息异常");
+                        if (Objects.equals(head.trim(), "学号")) {
+                            tcScoreNormal.setExamNumber(entry.getValue());
+                        } else if (Objects.equals(head.trim(), "姓名")) {
+                            tcScoreNormal.setName(entry.getValue());
+                        } else {
+                            jsonObject.put("name", headMap.get(entry.getKey()));
+                            jsonObject.put("score", entry.getValue());
+                            jsonArray.add(jsonObject);
+                        }
                     }
                 }
-                log.info("objectMap:{}", JacksonUtil.parseJson(objectMap));
+                if (jsonArray.size() > 0) {
+                    tcScoreNormal.setScoreNormal(jsonArray.toJSONString());
+                }
+                if (!error) {
+                    tcScoreNormalList.add(tcScoreNormal);
+                }
+            }
+            if (!CollectionUtils.isEmpty(tcScoreNormalList)) {
+                successData.add("共导入" + tcScoreNormalList.size() + "条数据");
+
+                QueryWrapper<TCScoreNormal> tcScoreNormalQueryWrapper = new QueryWrapper<>();
+                tcScoreNormalQueryWrapper.lambda().eq(TCScoreNormal::getExamId, examId)
+                        .eq(TCScoreNormal::getCourseCode, courseCode)
+                        .eq(TCScoreNormal::getCourseName, markPaper.getCourseName())
+                        .eq(TCScoreNormal::getPaperNumber, paperNumber)
+                        .eq(TCScoreNormal::getPaperType, paperType);
+                tcScoreNormalService.remove(tcScoreNormalQueryWrapper);
+                tcScoreNormalService.saveBatch(tcScoreNormalList);
             }
+            messageMap.put("正确信息", successData.length() > 0 ? successData.toString() : "无");
+            messageMap.put("错误信息", errorData.length() > 0 ? errorData.toString() : "无");
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error(SystemConstant.LOG_ERROR, e);
+            if (e instanceof DuplicateKeyException) {
+                String errorColumn = e.getCause().toString();
+                String columnStr = errorColumn.substring(errorColumn.lastIndexOf("key") + 3, errorColumn.length()).replaceAll("'", "");
+                throw ExceptionResultEnum.SQL_ERROR.exception("[" + FieldUniqueEnum.convertToTitle(columnStr) + "]数据不允许重复插入");
+            } else if (e instanceof ApiException) {
+                ResultUtil.error((ApiException) e, ((ApiException) e).getCode(), e.getMessage());
+            } else {
+                ResultUtil.error(e.getMessage());
+            }
         }
         log.debug("导入Excel结束...");
         long end = System.currentTimeMillis();
         log.info("============耗时{}秒============:", (end - start) / 1000);
-        return ResultUtil.ok(list);
+        return ResultUtil.ok(messageMap);
     }
 
     @ApiOperation(value = "平时成绩列表")

+ 5 - 1
teachcloud-common/src/main/java/com/qmth/teachcloud/common/enums/FieldUniqueEnum.java

@@ -37,7 +37,11 @@ public enum FieldUniqueEnum {
 
     role_group_roleId_memberId_idx("角色成员数据重复,同角色其它用户已绑定"),
 
-    unique_ticket_number_idx("学校准考证号");
+    unique_ticket_number_idx("学校准考证号"),
+
+    t_c_score_normal_unique("考生"),
+
+    t_c_score_end_exam_unique("考生");
 
     private String title;