Browse Source

试卷结构导入

xiatian 2 years ago
parent
commit
8168df68f5

+ 102 - 111
pom.xml

@@ -1,123 +1,114 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>cn.com.qmth.scancloud</groupId>
-    <artifactId>cet-tools</artifactId>
-    <version>1.0.0</version>
-    <packaging>jar</packaging>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>cn.com.qmth.scancloud</groupId>
+	<artifactId>cet-tools</artifactId>
+	<version>1.0.0</version>
+	<packaging>jar</packaging>
 
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.3.12.RELEASE</version>
-        <relativePath/>
-    </parent>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.3.12.RELEASE</version>
+		<relativePath />
+	</parent>
 
-    <properties>
-        <java.version>1.8</java.version>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    </properties>
+	<properties>
+		<java.version>1.8</java.version>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<qmth-boot-version>1.0.3</qmth-boot-version>
+	</properties>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
+	<dependencies>
+		<dependency>
+			<groupId>com.qmth.boot</groupId>
+			<artifactId>tools-poi</artifactId>
+			<version>${qmth-boot-version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
 
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>3.12.0</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-collections4</artifactId>
-            <version>4.4</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-            <version>2.11.0</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>31.1-jre</version>
-        </dependency>
-        <dependency>
-            <groupId>com.squareup.okhttp3</groupId>
-            <artifactId>okhttp</artifactId>
-            <version>4.9.3</version>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>easyexcel</artifactId>
-            <version>3.0.5</version>
-        </dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-collections4</artifactId>
+			<version>4.4</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.11.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>31.1-jre</version>
+		</dependency>
+		<dependency>
+			<groupId>com.squareup.okhttp3</groupId>
+			<artifactId>okhttp</artifactId>
+			<version>4.9.3</version><!--$NO-MVN-MAN-VER$-->
+		</dependency>
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>easyexcel</artifactId>
+			<version>3.0.5</version>
+		</dependency>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
 
-    <build>
-        <finalName>${project.artifactId}</finalName>
+	<build>
+		<finalName>${project.artifactId}</finalName>
 
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-                <configuration>
-                    <layout>ZIP</layout>
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>repackage</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<layout>ZIP</layout>
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
 
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>${java.version}</source>
-                    <target>${java.version}</target>
-                    <encoding>${project.build.sourceEncoding}</encoding>
-                </configuration>
-            </plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>${java.version}</source>
+					<target>${java.version}</target>
+					<encoding>${project.build.sourceEncoding}</encoding>
+				</configuration>
+			</plugin>
 
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <testFailureIgnore>true</testFailureIgnore>
-                    <skipTests>true</skipTests>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <!--<repositories>
-        <repository>
-            <id>nexus</id>
-            <name>nexus</name>
-            <url>http://192.168.10.201:8081/repository/maven-public/</url>
-        </repository>
-    </repositories>
-    <pluginRepositories>
-        <pluginRepository>
-            <id>nexus</id>
-            <name>nexus</name>
-            <url>http://192.168.10.201:8081/repository/maven-public/</url>
-        </pluginRepository>
-    </pluginRepositories>-->
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<testFailureIgnore>true</testFailureIgnore>
+					<skipTests>true</skipTests>
+					<skip>true</skip>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
 
 </project>

+ 8 - 0
src/main/java/cn/com/qmth/scancloud/tools/config/SysProperty.java

@@ -50,6 +50,10 @@ public class SysProperty {
     
     //评卷点数据
     public static String MARKING_PLACE;
+    
+    //试卷结构导入文件
+    public static String STRUCT_IMPORT;
+    
 
     @Value("${scan.server.url}")
     public void scanServerUrl(String scanServerUrl) {
@@ -125,5 +129,9 @@ public class SysProperty {
     public void markingPlace(String markingPlace) {
         MARKING_PLACE = markingPlace;
     }
+    @Value("${scan.tool.struct-import}")
+    public void structImport(String structImport) {
+        STRUCT_IMPORT = structImport;
+    }
     
 }

+ 1 - 0
src/main/java/cn/com/qmth/scancloud/tools/config/TaskConfig.java

@@ -16,6 +16,7 @@ public class TaskConfig {
         log.info("scan.tool.dataDir={}", SysProperty.DATA_DIR);
         log.info("scan.tool.dataFile={}", SysProperty.DATA_FILE);
         log.info("scan.tool.marking-place={}", SysProperty.MARKING_PLACE);
+        log.info("scan.tool.struct-import={}", SysProperty.MARKING_PLACE);
         log.info("scan.tool.taskType={}", SysProperty.TASK_TYPE);
         log.info("scan.tool.schoolId={}", SysProperty.SCHOOL_ID);
         log.info("scan.tool.schoolName={}", SysProperty.SCHOOL_NAME);

+ 2 - 0
src/main/java/cn/com/qmth/scancloud/tools/enums/TaskType.java

@@ -9,6 +9,7 @@ import cn.com.qmth.scancloud.tools.service.impl.ExamStudentImportTask;
 import cn.com.qmth.scancloud.tools.service.impl.ExcelToTxtTask;
 import cn.com.qmth.scancloud.tools.service.impl.ObjectiveQuestionExportTask;
 import cn.com.qmth.scancloud.tools.service.impl.ScanImageCheckTask;
+import cn.com.qmth.scancloud.tools.service.impl.StructImportTask;
 import cn.com.qmth.scancloud.tools.service.impl.UserImportTask;
 
 public enum TaskType {
@@ -33,6 +34,7 @@ public enum TaskType {
     
     ABSENT_IMPORT("缺考导入", AbsentImportTask.class),
     
+    STRUCT_IMPORT("试卷结构导入", StructImportTask.class),
     ;
 
     private String title;

+ 78 - 0
src/main/java/cn/com/qmth/scancloud/tools/model/Struct.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.scancloud.tools.model;
+
+public class Struct {
+    private Long examId;
+    private String subjectCode;
+    private String paperType;
+    private Boolean objective;
+    private Integer mainNumber;
+    private String subNumber;
+    private String mainTitle;
+    private Double totalScore;
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public Boolean getObjective() {
+        return objective;
+    }
+
+    public void setObjective(Boolean objective) {
+        this.objective = objective;
+    }
+
+    public Integer getMainNumber() {
+        return mainNumber;
+    }
+
+    public void setMainNumber(Integer mainNumber) {
+        this.mainNumber = mainNumber;
+    }
+
+    public String getSubNumber() {
+        return subNumber;
+    }
+
+    public void setSubNumber(String subNumber) {
+        this.subNumber = subNumber;
+    }
+
+    public String getMainTitle() {
+        return mainTitle;
+    }
+
+    public void setMainTitle(String mainTitle) {
+        this.mainTitle = mainTitle;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    
+    public Long getExamId() {
+        return examId;
+    }
+
+    
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+}

+ 222 - 0
src/main/java/cn/com/qmth/scancloud/tools/service/impl/StructImportTask.java

@@ -0,0 +1,222 @@
+package cn.com.qmth.scancloud.tools.service.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.qmth.boot.tools.excel.ExcelReader;
+import com.qmth.boot.tools.excel.enums.ExcelType;
+import com.qmth.boot.tools.excel.model.DataMap;
+
+import cn.com.qmth.scancloud.tools.config.SysProperty;
+import cn.com.qmth.scancloud.tools.enums.TaskType;
+import cn.com.qmth.scancloud.tools.model.Struct;
+import cn.com.qmth.scancloud.tools.service.AbstractTask;
+import cn.com.qmth.scancloud.tools.service.CommonService;
+import cn.com.qmth.scancloud.tools.utils.HttpHelper;
+import cn.com.qmth.scancloud.tools.utils.JsonHelper;
+import cn.com.qmth.scancloud.tools.utils.StatusException;
+
+/**
+ * 缺考导入
+ */
+public class StructImportTask extends AbstractTask {
+
+    private static final Logger log = LoggerFactory.getLogger(StructImportTask.class);
+
+    private static final String[] EXCEL_HEADER = new String[] { "科目代码", "条形码值", "是否客观题", "大题名称", "大题号", "小题号", "小题满分" };
+
+    @Override
+    protected String getTaskName() {
+        return TaskType.STRUCT_IMPORT.getTitle();
+    }
+
+    @Override
+    protected void execute() {
+        Long examId = SysProperty.EXAM_ID;
+        if (examId == null) {
+            throw new StatusException("【scan.tool.examId】未配置!");
+        }
+
+        if (CommonService.findExam(examId) == null) {
+            throw new StatusException("当前考试不存在!examId = " + examId);
+        }
+
+        List<Struct> structs = readData(examId);
+        String url = SysProperty.SCAN_SERVER_URL + "/api/tool/import/cet/absent";// TODO
+        String json = JsonHelper.toJson(structs);
+        HttpHelper.post(url, json);
+        log.info("处理完毕");
+    }
+
+    private List<Struct> readData(Long examId) {
+        if (StringUtils.isBlank(SysProperty.STRUCT_IMPORT)) {
+            throw new StatusException("【scan.tool.struct-import】未配置!");
+        }
+        File file = new File(SysProperty.DATA_DIR + "/" + SysProperty.STRUCT_IMPORT);
+        if (!file.exists()) {
+            throw new StatusException("文件不存在:" + SysProperty.STRUCT_IMPORT);
+        }
+        InputStream inputStream = null;
+        try {
+            inputStream = new FileInputStream(file);
+            ExcelReader reader = ExcelReader.create(ExcelType.XLSX, inputStream, 0);
+            List<DataMap> lineList = reader.getDataMapList();
+            if (!Arrays.equals(EXCEL_HEADER, reader.getColumnNames())) {
+                throw new StatusException("Excel表头错误");
+            }
+            if (CollectionUtils.isEmpty(lineList)) {
+                throw new StatusException("Excel无内容");
+            }
+            if (10001 < lineList.size()) {
+                throw new StatusException("数据行数不能超过10000");
+            }
+            List<String> failRecords = new ArrayList<>();
+            List<Struct> ret = new ArrayList<>();
+            for (int i = 0; i < lineList.size(); i++) {
+                DataMap line = lineList.get(i);
+
+                StringBuilder msg = new StringBuilder();
+
+                Struct imp = new Struct();
+                imp.setExamId(examId);
+                String code = trimAndNullIfBlank(line.getValue(0));
+                if (StringUtils.isBlank(code)) {
+                    msg.append("  科目代码不能为空");
+                } else if (code.length() > 50) {
+                    msg.append("  科目代码不能超过50个字符");
+                }
+                imp.setSubjectCode(code);
+
+                String paperType = trimAndNullIfBlank(line.getValue(1));
+                if (StringUtils.isBlank(paperType)) {
+                    msg.append("  条形码值不能为空");
+                } else if (paperType.length() > 50) {
+                    msg.append("  条形码值不能超过50个字符");
+                }
+                imp.setPaperType(paperType);
+
+                String objective = trimAndNullIfBlank(line.getValue(2));
+                if (StringUtils.isBlank(objective)) {
+                    msg.append("  是否客观题不能为空");
+                } else {
+                    if (!"是".equals(objective) && !"否".equals(objective)) {
+                        msg.append("  是否客观题填写错误");
+                    } else {
+                        if ("是".equals(objective)) {
+                            imp.setObjective(true);
+                        } else {
+                            imp.setObjective(false);
+                        }
+                    }
+                }
+
+                String detailName = trimAndNullIfBlank(line.getValue(3));
+                if (StringUtils.isBlank(detailName)) {
+                    msg.append("  大题名称不能为空");
+                } else if (detailName.length() > 50) {
+                    msg.append("  大题名称不能超过50个字符");
+                }
+                imp.setMainTitle(detailName);
+
+                String detailNumber = trimAndNullIfBlank(line.getValue(4));
+                if (StringUtils.isBlank(detailNumber)) {
+                    msg.append("  大题号不能为空");
+                } else {
+                    try {
+                        int n = Integer.valueOf(detailNumber);
+                        if (n <= 0) {
+                            msg.append("  大题号不能小于0");
+                        } else {
+                            imp.setMainNumber(n);
+                        }
+                    } catch (Exception e) {
+                        msg.append("  大题号只能是整数");
+                    }
+
+                }
+
+                String unitNumber = trimAndNullIfBlank(line.getValue(5));
+                if (StringUtils.isBlank(unitNumber)) {
+                    msg.append("  小题号不能为空");
+                } else {
+                    try {
+                        int n = Integer.valueOf(unitNumber);
+                        if (n <= 0) {
+                            msg.append("  小题号不能小于0");
+                        } else {
+                            imp.setSubNumber(n + "");
+                        }
+                    } catch (Exception e) {
+                        msg.append("  小题号只能是整数");
+                    }
+
+                }
+
+                String score = trimAndNullIfBlank(line.getValue(6));
+                if (StringUtils.isBlank(score)) {
+                    msg.append("  小题满分不能为空");
+                } else {
+                    try {
+                        Double n = Double.valueOf(score);
+                        if (n <= 0) {
+                            msg.append("  小题满分不能小于0");
+                        } else {
+                            if (score.indexOf(".") >= 0 && score.indexOf(".") < score.length() - 2) {
+                                msg.append("小题满分只能有一位小数");
+                            } else {
+                                imp.setTotalScore(n);
+                            }
+                        }
+                    } catch (Exception e) {
+                        msg.append("  小题满分格式错误");
+                    }
+
+                }
+
+                if (msg.length() > 0) {
+                    failRecords.add(newError(i + 1, msg.toString()));
+                } else {
+                    ret.add(imp);
+                }
+
+            }
+            if (CollectionUtils.isNotEmpty(failRecords)) {
+                for (String err : failRecords) {
+                    log.error(err);
+                }
+                throw new StatusException("请检查填写信息");
+            }
+            return ret;
+        } catch (Exception e) {
+            throw new RuntimeException("系统错误", e);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    private String trimAndNullIfBlank(String s) {
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        return s.trim();
+    }
+
+    private String newError(int lineNum, String msg) {
+        return "第" + lineNum + "行" + msg;
+    }
+}

+ 3 - 2
src/main/resources/application.properties

@@ -17,10 +17,11 @@ scan.tool.more-params=
 scan.tool.template.columns=
 
 #############params config###############
-scan.tool.marking-place=${scan.tool.data-dir}/marking-place.xlsx
-scan.tool.template.separator=,
 scan.tool.school-id=1
 scan.tool.school-name=\u5b66\u68211
+scan.tool.marking-place=marking-place.xlsx
+scan.tool.struct-import=struct-import.xlsx
+scan.tool.template.separator=,
 scan.tool.exam-id=
 scan.tool.paper-type-barcode=
 scan.tool.year=22

BIN
template/struct-import.xlsx