deason před 6 roky
rodič
revize
aab92fd753
67 změnil soubory, kde provedl 3785 přidání a 0 odebrání
  1. 1 0
      .gitignore
  2. 80 0
      examcloud-core-print-common/pom.xml
  3. 33 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/Constants.java
  4. 91 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Model.java
  5. 20 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Op.java
  6. 70 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Order.java
  7. 146 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Searcher.java
  8. 135 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SpecUtils.java
  9. 265 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SqlWrapper.java
  10. 96 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/Check.java
  11. 76 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/DateUtils.java
  12. 227 0
      examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/JsonMapper.java
  13. 20 0
      examcloud-core-print-dao/pom.xml
  14. 132 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/CoursePaper.java
  15. 96 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/CourseStatistics.java
  16. 105 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ExamStructure.java
  17. 55 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/IdEntity.java
  18. 162 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ObjectiveQuestionStructure.java
  19. 203 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/PrintingProject.java
  20. 120 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/PrintingTemplate.java
  21. 125 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ProjectBackupSetting.java
  22. 44 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ProjectOtherSetting.java
  23. 57 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/QuestionTypeNum.java
  24. 148 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/SubjectiveQuestionStructure.java
  25. 33 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/BackupGroupType.java
  26. 35 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/CoursePaperStatus.java
  27. 37 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/ProjectStatType.java
  28. 56 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/TemplateType.java
  29. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/CoursePaperRepository.java
  30. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/CourseStatisticsRepository.java
  31. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ExamStructureRepository.java
  32. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ObjectiveQuestionStructureRepository.java
  33. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/PrintingProjectRepository.java
  34. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/PrintingTemplateRepository.java
  35. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ProjectBackupSettingRepository.java
  36. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ProjectOtherSettingRepository.java
  37. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/QuestionTypeNumRepository.java
  38. 18 0
      examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/SubjectiveQuestionStructureRepository.java
  39. 1 0
      examcloud-core-print-dao/src/main/resources/db-schema.sql
  40. 21 0
      examcloud-core-print-provider/pom.xml
  41. 30 0
      examcloud-core-print-provider/src/main/java/cn/com/qmth/examcloud/core/print/api/controller/PrintingProjectController.java
  42. 30 0
      examcloud-core-print-provider/src/main/java/cn/com/qmth/examcloud/core/print/api/provider/PrintingProjectCloudServiceProvider.java
  43. 21 0
      examcloud-core-print-service/pom.xml
  44. 18 0
      examcloud-core-print-service/src/main/java/cn/com/qmth/examcloud/core/print/service/PrintingProjectService.java
  45. 26 0
      examcloud-core-print-service/src/main/java/cn/com/qmth/examcloud/core/print/service/impl/PrintingProjectServiceImpl.java
  46. 31 0
      examcloud-core-print-starter/assembly.xml
  47. 82 0
      examcloud-core-print-starter/pom.xml
  48. 1 0
      examcloud-core-print-starter/shell/start.args
  49. 26 0
      examcloud-core-print-starter/shell/start.sh
  50. 1 0
      examcloud-core-print-starter/shell/start.vmoptions
  51. 18 0
      examcloud-core-print-starter/shell/stop.sh
  52. 61 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/PrintApplication.java
  53. 81 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/InterceptorConfig.java
  54. 32 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/PropertiesConfig.java
  55. 62 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/RedisConfig.java
  56. 48 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/SwaggerConfig.java
  57. 28 0
      examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/controller/IndexController.java
  58. 16 0
      examcloud-core-print-starter/src/main/resources/application-dev.properties
  59. 16 0
      examcloud-core-print-starter/src/main/resources/application-prod.properties
  60. 16 0
      examcloud-core-print-starter/src/main/resources/application-test.properties
  61. 29 0
      examcloud-core-print-starter/src/main/resources/application.properties
  62. 57 0
      examcloud-core-print-starter/src/main/resources/logback-spring.xml
  63. 7 0
      examcloud-core-print-starter/src/main/resources/security-exclusions.conf
  64. 0 0
      examcloud-core-print-starter/src/main/resources/security-mapping.properties
  65. 23 0
      examcloud-core-print-starter/src/test/java/cn/com/qmth/examcloud/core/print/test/ApplicationTest.java
  66. 32 0
      examcloud-core-print-starter/src/test/java/cn/com/qmth/examcloud/core/print/test/PrintingProjectServiceTest.java
  67. 123 0
      pom.xml

+ 1 - 0
.gitignore

@@ -8,5 +8,6 @@
 *.jar
 *.war
 *.ear
+log/
 logs/
 target/

+ 80 - 0
examcloud-core-print-common/pom.xml

@@ -0,0 +1,80 @@
+<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print-common</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-print</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+        </dependency>
+
+        <!-- fix conflicted jars -->
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud.commons</groupId>
+            <artifactId>examcloud-commons-web</artifactId>
+            <version>${examcloud.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.code.findbugs</groupId>
+                    <artifactId>jsr305</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>io.springfox</groupId>
+                    <artifactId>springfox-swagger2</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>io.springfox</groupId>
+                    <artifactId>springfox-swagger-ui</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+</project>

+ 33 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/Constants.java

@@ -0,0 +1,33 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common;
+
+/**
+ * 系统常量
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public interface Constants {
+
+    /**
+     * 系统错误
+     */
+    String OE_CODE_500 = "PRT-000500";
+
+    /**
+     * 参数错误
+     */
+    String OE_CODE_400 = "PRT-000400";
+
+    /**
+     * 权限错误
+     */
+    String OE_CODE_403 = "PRT-000403";
+
+}

+ 91 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Model.java

@@ -0,0 +1,91 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class Model {
+
+    public static <T> T of(Optional<T> optional) {
+        try {
+            if (optional != null) {
+                return optional.get();
+            }
+        } catch (NoSuchElementException e) {
+            //ignore
+        }
+        return null;
+    }
+
+    public static String splitFieldName(String fieldName) {
+        if (fieldName == null) {
+            return null;
+        }
+        StringBuffer result = new StringBuffer();
+        char[] chars = fieldName.toCharArray();
+        final int A = 65, Z = 90, DOT = 46;
+        for (int i = 0; i < chars.length; i++) {
+            Character c = chars[i];
+            if (i == 0) {
+                result.append(c);
+                continue;
+            }
+            if (c == DOT) {
+                result.append("_");
+                continue;
+            }
+            if (c >= A && c <= Z) {
+                result.append("_");
+            }
+            result.append(c);
+        }
+        return result.toString().toUpperCase();
+    }
+
+    public static List<String> parseFields(final Class clazz) {
+        return parseFields(clazz, null);
+    }
+
+    public static List<String> parseFields(final Class clazz, final Class rootClazz) {
+        List<String> fieldNames = new ArrayList<>();
+        Field[] fields = clazz.getDeclaredFields();
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+            if (Modifier.isFinal(field.getModifiers())) {
+                continue;
+            }
+            Class<?> fieldType = field.getType();
+            String fieldName = field.getName();
+            if (rootClazz != null && rootClazz.isAssignableFrom(fieldType)) {
+                List<String> subFieldNames = parseFields(fieldType, rootClazz);
+                if (subFieldNames.size() == 0) {
+                    continue;
+                }
+                fieldNames.addAll(subFieldNames.stream()
+                        .map(subName -> subName = fieldName + "." + subName)
+                        .collect(Collectors.toList()));
+            } else {
+                fieldNames.add(fieldName);
+            }
+        }
+        return fieldNames;
+    }
+
+}

+ 20 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Op.java

@@ -0,0 +1,20 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+/**
+ * 操作枚举类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public enum Op {
+
+    EQ, NOT_EQ, GT, LT, GTE, LTE, LIKE, L_LIKE, R_LIKE, IS_NULL, NOT_NULL, IN, NOT_IN
+
+}

+ 70 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Order.java

@@ -0,0 +1,70 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import org.springframework.data.domain.Sort;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 排序条件类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class Order implements Serializable {
+    protected static final long serialVersionUID = -1L;
+    private String fieldName;
+    private Sort.Direction direction;
+
+    private List<Order> orders = new ArrayList<>();
+
+    public Order asc(String fieldName) {
+        orders.add(new Order(fieldName, Sort.Direction.ASC));
+        return this;
+    }
+
+    public Order desc(String fieldName) {
+        orders.add(new Order(fieldName, Sort.Direction.DESC));
+        return this;
+    }
+
+    public Sort build() {
+        if (orders.size() == 0) {
+            return null;
+        }
+        List<Sort.Order> list = new ArrayList<>();
+        for (Order order : orders) {
+            list.add(new Sort.Order(order.getDirection(), order.getFieldName()));
+        }
+        return new Sort(list);
+    }
+
+    private Order(String fieldName, Sort.Direction direction) {
+        if (fieldName == null || "".equals(fieldName.trim())) {
+            throw new IllegalArgumentException("FieldName must be not empty.");
+        }
+        this.fieldName = fieldName.trim();
+        this.direction = direction;
+    }
+
+    public Order() {
+
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public Sort.Direction getDirection() {
+        return direction;
+    }
+
+}

+ 146 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/Searcher.java

@@ -0,0 +1,146 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 查询条件类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class Searcher implements Serializable {
+    protected static final long serialVersionUID = -1L;
+    /**
+     * 属性名
+     */
+    private String fieldName;
+    /**
+     * 属性值
+     */
+    private Object value;
+    /**
+     * 操作的表达式
+     */
+    private Op op;
+
+    private List<Searcher> searchers = new ArrayList<>();
+
+    public <T> Searcher eq(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.EQ));
+        return this;
+    }
+
+    public <T> Searcher notEq(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.NOT_EQ));
+        return this;
+    }
+
+    public <T> Searcher gt(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.GT));
+        return this;
+    }
+
+    public <T> Searcher gte(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.GTE));
+        return this;
+    }
+
+    public <T> Searcher lt(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LT));
+        return this;
+    }
+
+    public <T> Searcher lte(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LTE));
+        return this;
+    }
+
+    public <T> Searcher like(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.LIKE));
+        return this;
+    }
+
+    public <T> Searcher leftLike(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.L_LIKE));
+        return this;
+    }
+
+    public <T> Searcher rightLike(String fieldName, T value) {
+        searchers.add(new Searcher(fieldName, value, Op.R_LIKE));
+        return this;
+    }
+
+    public Searcher in(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.EQ));
+        } else {
+            searchers.add(new Searcher(fieldName, values.toArray(), Op.IN));
+        }
+        return this;
+    }
+
+    public Searcher notIn(String fieldName, Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("Values must be not empty.");
+        }
+        if (values.size() == 1) {
+            searchers.add(new Searcher(fieldName, values.iterator().next(), Op.NOT_EQ));
+        } else {
+            searchers.add(new Searcher(fieldName, values.toArray(), Op.NOT_IN));
+        }
+        return this;
+    }
+
+    public Searcher isNull(String fieldName) {
+        searchers.add(new Searcher(fieldName, null, Op.IS_NULL));
+        return this;
+    }
+
+    public Searcher notNull(String fieldName) {
+        searchers.add(new Searcher(fieldName, null, Op.NOT_NULL));
+        return this;
+    }
+
+    public List<Searcher> build() {
+        return searchers;
+    }
+
+    private Searcher(String fieldName, Object value, Op op) {
+        if (fieldName == null || "".equals(fieldName.trim())) {
+            throw new IllegalArgumentException("FieldName must be not empty.");
+        }
+        this.fieldName = fieldName.trim();
+        this.value = value;
+        this.op = op;
+    }
+
+    public Searcher() {
+
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public Op getOp() {
+        return op;
+    }
+
+}

+ 135 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SpecUtils.java

@@ -0,0 +1,135 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.data.jpa.domain.Specifications;
+
+import javax.persistence.criteria.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JPA查询工具类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class SpecUtils {
+    /**
+     * 默认当前页数
+     */
+    public static final int DEFAULT_PAGE_NO = 1;
+    /**
+     * 默认每页条数
+     */
+    public static final int DEFAULT_PAGE_SIZE = 10;
+
+    public static Pageable buildPageable(Integer pageNo, Integer pageSize) {
+        return buildPageable(pageNo, pageSize, null);
+    }
+
+    public static Pageable buildPageable(Integer pageNo, Integer pageSize, Sort sort) {
+        if (pageNo == null || pageNo < 1) {
+            pageNo = DEFAULT_PAGE_NO;
+        }
+        if (pageSize == null || pageSize < 1) {
+            pageSize = DEFAULT_PAGE_SIZE;
+        }
+        return new PageRequest(pageNo - 1, pageSize, sort);
+    }
+
+    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<Searcher> searchers) {
+        return buildSearchers(clazz, searchers, false);
+    }
+
+    public static <T> Specification<T> buildSearchers(final Class<T> clazz, final List<Searcher> searchers, final boolean isOR) {
+        if (searchers == null || searchers.size() == 0) {
+            return null;
+        }
+        return new Specification<T>() {
+            @Override
+            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
+                List<Predicate> predicates = new ArrayList<>();
+                for (Searcher filter : searchers) {
+                    if (filter.getFieldName() == null || "".equals(filter.getFieldName())) {
+                        continue;
+                    }
+                    String[] names = filter.getFieldName().split("\\.");
+                    Path expression = root.get(names[0]);
+                    for (int i = 1; i < names.length; i++) {
+                        expression = expression.get(names[i]);
+                    }
+                    switch (filter.getOp()) {
+                        case EQ:
+                            predicates.add(builder.equal(expression, filter.getValue()));
+                            break;
+                        case NOT_EQ:
+                            predicates.add(builder.notEqual(expression, filter.getValue()));
+                            break;
+                        case GT:
+                            predicates.add(builder.greaterThan(expression, (Comparable) filter.getValue()));
+                            break;
+                        case LT:
+                            predicates.add(builder.lessThan(expression, (Comparable) filter.getValue()));
+                            break;
+                        case GTE:
+                            predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.getValue()));
+                            break;
+                        case LTE:
+                            predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.getValue()));
+                            break;
+                        case LIKE:
+                            predicates.add(builder.like(expression, "%" + filter.getValue() + "%"));
+                            break;
+                        case L_LIKE:
+                            predicates.add(builder.like(expression, "%" + filter.getValue()));
+                            break;
+                        case R_LIKE:
+                            predicates.add(builder.like(expression, filter.getValue() + "%"));
+                            break;
+                        case IS_NULL:
+                            predicates.add(builder.isNull(expression));
+                            break;
+                        case NOT_NULL:
+                            predicates.add(builder.isNotNull(expression));
+                            break;
+                        case IN:
+                            predicates.add(expression.in((Object[]) filter.getValue()));
+                            break;
+                        case NOT_IN:
+                            predicates.add(expression.in((Object[]) filter.getValue()).not());
+                            break;
+                    }
+                }
+                if (!predicates.isEmpty()) {
+                    if (isOR) {
+                        //将所有条件用 or 联合起来
+                        return builder.or(predicates.toArray(new Predicate[predicates.size()]));
+                    } else {
+                        //将所有条件用 and 联合起来
+                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
+                    }
+                }
+                return builder.conjunction();
+            }
+        };
+    }
+
+    public static Specification andMerge(Specification target1, Specification target2) {
+        return Specifications.where(target1).and(target2);
+    }
+
+    public static Specification orMerge(Specification target1, Specification target2) {
+        return Specifications.where(target1).or(target2);
+    }
+
+}

+ 265 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/jpa/SqlWrapper.java

@@ -0,0 +1,265 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.jpa;
+
+import java.util.Collection;
+
+/**
+ * 原生SQL包装类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class SqlWrapper {
+    private static final String SELECT = "SELECT ";
+    private static final String UPDATE = "UPDATE ";
+    private static final String DELETE = "DELETE ";
+    private static final String SET = " SET ";
+    private static final String COUNT = " COUNT ";
+    private static final String SUM = " SUM ";
+    private static final String DISTINCT = " DISTINCT ";
+    private static final String FROM = " FROM ";
+    private static final String WHERE = " WHERE ";
+    private static final String INNER_JOIN = " INNER JOIN ";
+    private static final String LEFT_JOIN = " LEFT JOIN ";
+    private static final String UNION_ALL = " UNION ALL ";
+    private static final String UNION = " UNION ";
+    private static final String ON = " ON ";
+    private static final String AS = " AS ";
+    private static final String AND = " AND ";
+    private static final String OR = " OR ";
+    private static final String LIKE = " LIKE ";
+    private static final String IN = " IN ";
+    private static final String NOT_IN = " NOT IN ";
+    private static final String IS_NULL = " IS NULL ";
+    private static final String IS_NOT_NULL = " IS NOT NULL ";
+    private static final String GROUP_BY = " GROUP BY ";
+    private static final String ORDER_BY = " ORDER BY ";
+    private static final String ASC = " ASC ";
+    private static final String DESC = " DESC ";
+
+    private StringBuilder sql = new StringBuilder();
+
+    public SqlWrapper select() {
+        sql.append(SELECT).append("*");
+        return this;
+    }
+
+    public SqlWrapper select(String columns) {
+        /* 多个按逗号分隔 */
+        sql.append(SELECT).append(columns);
+        return this;
+    }
+
+    public SqlWrapper delete() {
+        sql.append(DELETE);
+        return this;
+    }
+
+    public SqlWrapper update(String tableName) {
+        sql.append(UPDATE).append(tableName);
+        return this;
+    }
+
+    public SqlWrapper set() {
+        sql.append(SET);
+        return this;
+    }
+
+    public SqlWrapper count(String fieldName) {
+        sql.append(COUNT).append("(").append(fieldName).append(")");
+        return this;
+    }
+
+    public SqlWrapper sum(String fieldName) {
+        sql.append(SUM).append("(").append(fieldName).append(")");
+        return this;
+    }
+
+    public SqlWrapper distinct(String fieldName) {
+        sql.append(DISTINCT).append(fieldName);
+        return this;
+    }
+
+    public SqlWrapper from(String tableName) {
+        sql.append(FROM).append(tableName);
+        return this;
+    }
+
+    public SqlWrapper innerJoin(String tableName) {
+        sql.append(INNER_JOIN).append(tableName);
+        return this;
+    }
+
+    public SqlWrapper leftJoin(String tableName) {
+        sql.append(LEFT_JOIN).append(tableName);
+        return this;
+    }
+
+    public SqlWrapper on(String fieldName, String refFieldName) {
+        sql.append(ON).append(fieldName).append(" = ").append(refFieldName);
+        return this;
+    }
+
+    public SqlWrapper where() {
+        sql.append(WHERE);
+        return this;
+    }
+
+    public SqlWrapper and() {
+        sql.append(AND);
+        return this;
+    }
+
+    public SqlWrapper or() {
+        sql.append(OR);
+        return this;
+    }
+
+    public SqlWrapper like(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(LIKE).append("'%").append(value).append("%'");
+        return this;
+    }
+
+    public SqlWrapper like(String fieldName, Number value) {
+        sql.append(fieldName).append(LIKE).append("'%").append(value).append("%'");
+        return this;
+    }
+
+    public SqlWrapper eq(String fieldName, Number value) {
+        sql.append(fieldName).append(" = ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper eq(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" = ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper notEq(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" != ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper notEq(String fieldName, Number value) {
+        sql.append(fieldName).append(" != ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper gt(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" > ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper gt(String fieldName, Number value) {
+        sql.append(fieldName).append(" > ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper gte(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" >= ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper gte(String fieldName, Number value) {
+        sql.append(fieldName).append(" >= ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper lt(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" < ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper lt(String fieldName, Number value) {
+        sql.append(fieldName).append(" < ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper lte(String fieldName, CharSequence value) {
+        sql.append(fieldName).append(" <= ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper lte(String fieldName, Number value) {
+        sql.append(fieldName).append(" <= ").append("'").append(value).append("'");
+        return this;
+    }
+
+    public SqlWrapper in(String fieldName, Collection<?> values) {
+        String str = this.spilt(values);
+        sql.append(fieldName).append(IN).append("(").append(str).append(")");
+        return this;
+    }
+
+    public SqlWrapper notIn(String fieldName, Collection<?> values) {
+        String str = this.spilt(values);
+        sql.append(fieldName).append(NOT_IN).append("(").append(str).append(")");
+        return this;
+    }
+
+    public SqlWrapper isNull(String fieldName) {
+        sql.append(fieldName).append(IS_NULL);
+        return this;
+    }
+
+    public SqlWrapper isNotNull(String fieldName) {
+        sql.append(fieldName).append(IS_NOT_NULL);
+        return this;
+    }
+
+    public SqlWrapper orderBy(String columns, boolean isDesc) {
+        /* 多个按逗号分隔 */
+        if (isDesc) {
+            sql.append(ORDER_BY).append(columns).append(DESC);
+        } else {
+            sql.append(ORDER_BY).append(columns).append(ASC);
+        }
+        return this;
+    }
+
+    public SqlWrapper groupBy(String columns) {
+        /* 多个按逗号分隔 */
+        sql.append(GROUP_BY).append(columns);
+        return this;
+    }
+
+    public SqlWrapper as(String name) {
+        sql.append(AS).append(name);
+        return this;
+    }
+
+    public SqlWrapper append(String str) {
+        sql.append(str);
+        return this;
+    }
+
+    public String build() {
+        return sql.toString();
+    }
+
+    private String spilt(Collection<?> values) {
+        if (values == null || values.size() == 0) {
+            throw new IllegalArgumentException("Values must be not empty.");
+        }
+        int index = 0, total = values.size();
+        StringBuilder str = new StringBuilder();
+        for (Object value : values) {
+            if (!(value instanceof CharSequence || value instanceof Number)) {
+                throw new IllegalArgumentException("Values must be charSequence or number.");
+            }
+            str.append(value.toString());
+            if (index < (total - 1)) {
+                str.append(",");
+            }
+            index++;
+        }
+        return str.toString();
+    }
+
+}

+ 96 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/Check.java

@@ -0,0 +1,96 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.utils;
+
+import cn.com.qmth.examcloud.commons.base.exception.StatusException;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Map;
+
+import static cn.com.qmth.examcloud.core.print.common.Constants.OE_CODE_400;
+
+/**
+ * 参数校验类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class Check {
+
+    public static void isNull(Object obj, String message) {
+        if (obj == null) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isEmpty(Object obj, String message) {
+        if (isEmpty(obj)) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isEmpty(Object[] array, String message) {
+        if (isEmpty(array)) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isEmpty(Collection<?> collection, String message) {
+        if (isEmpty(collection)) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isEmpty(Map<?, ?> map, String message) {
+        if (isEmpty(map)) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isBlank(CharSequence str, String message) {
+        if (isBlank(str)) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    public static void isFalse(Boolean expression, String message) {
+        if (expression == null || !expression) {
+            throw new StatusException(OE_CODE_400, message);
+        }
+    }
+
+    private static boolean isEmpty(Object obj) {
+        if (obj == null) {
+            return true;
+        } else if (obj instanceof CharSequence) {
+            return ((CharSequence) obj).length() == 0;
+        } else if (obj.getClass().isArray()) {
+            return Array.getLength(obj) == 0;
+        } else if (obj instanceof Collection) {
+            return ((Collection) obj).isEmpty();
+        } else {
+            return obj instanceof Map ? ((Map) obj).isEmpty() : false;
+        }
+    }
+
+    private static boolean isBlank(CharSequence cs) {
+        int strLen;
+        if (cs != null && (strLen = cs.length()) != 0) {
+            for (int i = 0; i < strLen; ++i) {
+                if (!Character.isWhitespace(cs.charAt(i))) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return true;
+        }
+    }
+
+}

+ 76 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/DateUtils.java

@@ -0,0 +1,76 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * 日期工具类
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class DateUtils {
+    private static final String YYYY_MM_DD = "yyyy-MM-dd";
+    private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    public static Date parse(String dateStr) {
+        if (dateStr == null) {
+            return null;
+        }
+        try {
+            final int len = 10;
+            if (dateStr.length() == len) {
+                return new SimpleDateFormat(YYYY_MM_DD).parse(dateStr);
+            }
+            return new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS).parse(dateStr);
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String format(Date date) {
+        if (date == null) {
+            return null;
+        }
+        return new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS).format(date);
+    }
+
+    public static Date changeMinute(Date date, int minute) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(Calendar.MINUTE, minute);
+        return calendar.getTime();
+    }
+
+    /**
+     * 计算时间差
+     */
+    public static String diff(Date begin, Date end) {
+        long diff = end.getTime() - begin.getTime();
+        long day = diff / (24 * 60 * 60 * 1000);
+        long hour = (diff / (60 * 60 * 1000) - day * 24);
+        long minute = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60);
+        long second = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
+        StringBuffer result = new StringBuffer();
+        if (day > 0) {
+            result.append(day).append("天");
+        }
+        if (hour > 0) {
+            result.append(hour).append("小时");
+        }
+        result.append(minute).append("分");
+        result.append(second).append("秒");
+        return result.toString();
+    }
+
+}

+ 227 - 0
examcloud-core-print-common/src/main/java/cn/com/qmth/examcloud/core/print/common/utils/JsonMapper.java

@@ -0,0 +1,227 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 15:18:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.common.utils;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.util.JSONPObject;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 简单封装Jackson,实现JSON 与 Java Object互相转换的Mapper
+ * 封装不同的输出风格, 使用不同的builder函数创建实例
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@SuppressWarnings("unchecked")
+public class JsonMapper {
+    private static Logger log = LoggerFactory.getLogger(JsonMapper.class);
+    private ObjectMapper mapper;
+
+    public JsonMapper() {
+        this(null);
+    }
+
+    public JsonMapper(Include include) {
+        mapper = new ObjectMapper();
+        //设置输出时包含属性的风格
+        if (include != null) {
+            mapper.setSerializationInclusion(include);
+        }
+        //设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
+        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+    }
+
+    /**
+     * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用
+     */
+    public static JsonMapper nonEmptyMapper() {
+        return new JsonMapper(Include.NON_EMPTY);
+    }
+
+    public static JsonMapper nonNullMapper() {
+        return new JsonMapper(Include.NON_NULL);
+    }
+
+    /**
+     * 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用
+     */
+    public static JsonMapper nonDefaultMapper() {
+        return new JsonMapper(Include.NON_DEFAULT);
+    }
+
+    /**
+     * Object可以是POJO,也可以是Collection或数组
+     * 如果对象为Null, 返回"null"
+     * 如果集合为空集合, 返回"[]"
+     */
+    public String toJson(Object object) {
+        try {
+            return mapper.writeValueAsString(object);
+        } catch (IOException e) {
+            log.error("write to json string error:" + object);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化POJO或简单Collection如List<String>
+     * 如果JSON字符串为Null或"null"字符串, 返回Null
+     * 如果JSON字符串为"[]", 返回空集合
+     * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
+     */
+    public <T> T fromJson(String jsonString, Class<T> clazz) {
+        if (StringUtils.isEmpty(jsonString)) {
+            return null;
+        }
+        try {
+            return mapper.readValue(jsonString, clazz);
+        } catch (IOException e) {
+            log.error("parse json string error", e);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化复杂Collection如List<Bean>, 先使用createCollectionType()或constructMapType()构造类型, 然后调用本函数
+     */
+    public <T> T fromJson(String jsonString, JavaType javaType) {
+        if (StringUtils.isEmpty(jsonString)) {
+            return null;
+        }
+        try {
+            return (T) mapper.readValue(jsonString, javaType);
+        } catch (IOException e) {
+            log.error("parse json string error", e);
+            return null;
+        }
+    }
+
+    /**
+     * 反序列化复杂的对象,如Page<Bean>
+     */
+    public <T> T fromJson(String jsonString, TypeReference javaType) {
+        if (StringUtils.isEmpty(jsonString)) {
+            return null;
+        }
+        try {
+            return (T) mapper.readValue(jsonString, javaType);
+        } catch (IOException e) {
+            log.error("parse json string error", e);
+            return null;
+        }
+    }
+
+    /**
+     * json to list
+     */
+    public <T> List<T> toList(String jsonString, Class<T> bean) {
+        if (StringUtils.isEmpty(jsonString)) {
+            return null;
+        }
+        try {
+            JavaType javaType = constructCollectionType(List.class, bean);
+            return mapper.readValue(jsonString, javaType);
+        } catch (IOException e) {
+            log.error("parse json string error", e);
+            return null;
+        }
+    }
+
+    /**
+     * json to simple HashMap
+     */
+    public <T> Map<String, T> toHashMap(String jsonString, Class<T> bean) {
+        if (StringUtils.isEmpty(jsonString)) {
+            return null;
+        }
+        try {
+            JavaType javaType = constructMapType(HashMap.class, String.class, bean);
+            return mapper.readValue(jsonString, javaType);
+        } catch (IOException e) {
+            log.error("parse json string error:", e);
+            return null;
+        }
+    }
+
+    /**
+     * 构造Collection类型
+     */
+    public JavaType constructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
+        return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
+    }
+
+    /**
+     * 构造Map类型
+     */
+    public JavaType constructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
+        return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
+    }
+
+    /**
+     * 当JSON里只含有Bean的部分屬性時,更新一個已存在Bean,只覆盖該部分的屬性
+     */
+    public void update(String jsonString, Object object) {
+        try {
+            mapper.readerForUpdating(object).readValue(jsonString);
+        } catch (JsonProcessingException e) {
+            log.error("update json string:" + jsonString + " to object:" + object + " error.");
+        } catch (IOException e) {
+            log.error("update json string:" + jsonString + " to object:" + object + " error.");
+        }
+    }
+
+    /**
+     * 輸出JSONP格式数据
+     */
+    public String toJsonP(String functionName, Object object) {
+        return toJson(new JSONPObject(functionName, object));
+    }
+
+    /**
+     * 設定是否使用Enum的toString函數來读写Enum
+     * 為False時使用Enum的name()函數來读写Enum, 默認為False
+     * 注意本函數一定要在Mapper創建後, 所有的读写動作之前調用
+     */
+    public void enableEnumUseToString() {
+        mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
+        mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+    }
+
+    /**
+     * 取出Mapper做进一步的设置或使用其他序列化API
+     */
+    public ObjectMapper getMapper() {
+        return mapper;
+    }
+
+    /***
+     * 把Json字符串转换成Node对象
+     */
+    public JsonNode getNode(String jsonStr) {
+        try {
+            //mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
+            return mapper.readTree(jsonStr);
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+}

+ 20 - 0
examcloud-core-print-dao/pom.xml

@@ -0,0 +1,20 @@
+<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print-dao</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-print</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-print-common</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 132 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/CoursePaper.java

@@ -0,0 +1,132 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+/**
+ * 课程试卷关联表
+ */
+@Entity
+@Table(name = "ec_prt_course_paper", indexes = {
+        @Index(name = "IDX_PRT_COURSE_PAPER_001001", columnList = "orgId"),
+        @Index(name = "IDX_PRT_COURSE_PAPER_001002", columnList = "examId"),
+        @Index(name = "IDX_PRT_COURSE_PAPER_001003", columnList = "courseCode")})
+public class CoursePaper extends IdEntity {
+    /**
+     * 机构ID
+     */
+    private Long orgId;
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 试卷id
+     */
+    private String paperId;
+    /**
+     * 课程code
+     */
+    private String courseCode;
+    /**
+     * 课程名称
+     */
+    private String courseName;
+    /**
+     * 试卷名称
+     */
+    private String paperName;
+    /**
+     * 试卷P数
+     */
+    private Integer pNum;
+    /**
+     * 试卷文件URL
+     */
+    private String paperFileUrl;
+    /**
+     * 答案文件URL
+     */
+    private String answerFileUrl;
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(String paperId) {
+        this.paperId = paperId;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperName() {
+        return paperName;
+    }
+
+    public void setPaperName(String paperName) {
+        this.paperName = paperName;
+    }
+
+    public Integer getpNum() {
+        return pNum;
+    }
+
+    public void setpNum(Integer pNum) {
+        this.pNum = pNum;
+    }
+
+    public String getPaperFileUrl() {
+        return paperFileUrl;
+    }
+
+    public void setPaperFileUrl(String paperFileUrl) {
+        this.paperFileUrl = paperFileUrl;
+    }
+
+    public String getAnswerFileUrl() {
+        return answerFileUrl;
+    }
+
+    public void setAnswerFileUrl(String answerFileUrl) {
+        this.answerFileUrl = answerFileUrl;
+    }
+
+}

+ 96 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/CourseStatistics.java

@@ -0,0 +1,96 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+/**
+ * 课程统计
+ */
+@Entity
+@Table(name = "ec_prt_course_statistics", indexes = {
+        @Index(name = "IDX_PRT_COURSE_STATISTICS_001001", columnList = "orgId"),
+        @Index(name = "IDX_PRT_COURSE_STATISTICS_001002", columnList = "examId"),
+        @Index(name = "IDX_PRT_COURSE_STATISTICS_001003", columnList = "coursePaperId")})
+public class CourseStatistics extends IdEntity {
+    /**
+     * 机构ID
+     */
+    private Long orgId;
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 绑定试卷ID :printing_course_paper 的ID
+     */
+    private Long coursePaperId;
+    /**
+     * 课程code
+     */
+    private String courseCode;
+    /**
+     * 课程名称
+     */
+    private String courseName;
+    /**
+     * 试卷类型
+     */
+    private String paperType;
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getCoursePaperId() {
+        return coursePaperId;
+    }
+
+    public void setCoursePaperId(Long coursePaperId) {
+        this.coursePaperId = coursePaperId;
+    }
+
+    public String getCourseCode() {
+        return courseCode;
+    }
+
+    public void setCourseCode(String courseCode) {
+        this.courseCode = courseCode;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+}

+ 105 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ExamStructure.java

@@ -0,0 +1,105 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 导出结构设置
+ */
+@Entity
+@Table(name = "ec_prt_exam_structure")
+public class ExamStructure extends IdEntity {
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 机构ID
+     */
+    private Long orgId;
+    /**
+     * 学校id (对应机构表 ecs_core_org)
+     */
+    private Long schoolId;
+    /**
+     * 学校名称
+     */
+    private String schoolName;
+    /**
+     * 机构名
+     */
+    private String orgName;
+    /**
+     * 考试名称
+     */
+    private String examName;
+    /**
+     * 考试类型
+     * See ExamType.java
+     */
+    private String examType;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
+
+    public Long getSchoolId() {
+        return schoolId;
+    }
+
+    public void setSchoolId(Long schoolId) {
+        this.schoolId = schoolId;
+    }
+
+    public String getSchoolName() {
+        return schoolName;
+    }
+
+    public void setSchoolName(String schoolName) {
+        this.schoolName = schoolName;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public String getExamType() {
+        return examType;
+    }
+
+    public void setExamType(String examType) {
+        this.examType = examType;
+    }
+
+}

+ 55 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/IdEntity.java

@@ -0,0 +1,55 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import cn.com.qmth.examcloud.commons.web.jpa.JpaEntity;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import java.util.Date;
+
+/**
+ * ID Entity
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@MappedSuperclass
+public abstract class IdEntity extends JpaEntity {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    protected Long id;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public IdEntity() {
+        super();
+    }
+
+    @Override
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    public Date getUpdateTime() {
+        return super.getUpdateTime();
+    }
+
+    @Override
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    public Date getCreationTime() {
+        return super.getCreationTime();
+    }
+
+}

+ 162 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ObjectiveQuestionStructure.java

@@ -0,0 +1,162 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 客观题数据--用于Excel导出
+ */
+@Entity
+@Table(name = "ec_prt_objective_question_structure")
+public class ObjectiveQuestionStructure extends IdEntity {
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 试卷id
+     */
+    private String paperId;
+    /**
+     * 课程代码
+     */
+    //@ExcelProperty(name = "课程代码", index = 0)
+    private String courseNo;
+    /**
+     * 课程名称
+     */
+    //@ExcelProperty(name = "课程名称", index = 1)
+    private String courseName;
+    /**
+     * 试卷名称
+     */
+    //@ExcelProperty(name = "试卷名称", index = 2)
+    private String paperName;
+    /**
+     * 试卷类型
+     */
+    //@ExcelProperty(name = "试卷类型", index = 3)
+    private String paperType;
+    /**
+     * 大题号
+     */
+    //@ExcelProperty(name = "大题号", index = 4)
+    private Integer bigQuestionNo;
+    /**
+     * 小题号
+     */
+    //@ExcelProperty(name = "小题号", index = 5)
+    private Integer smallQuestionNo;
+    /**
+     * 题目类型
+     * See QuesStructType.java
+     */
+    //@ExcelProperty(name = "题目类型", index = 6)
+    private String questionType;
+    /**
+     * 标准答案
+     */
+    //@ExcelProperty(name = "标准答案", index = 7)
+    private String answer;
+    /**
+     * 小题分数
+     */
+    //@ExcelProperty(name = "小题分数", index = 8)
+    private Double smallQuestionScore;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(String paperId) {
+        this.paperId = paperId;
+    }
+
+    public String getCourseNo() {
+        return courseNo;
+    }
+
+    public void setCourseNo(String courseNo) {
+        this.courseNo = courseNo;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperName() {
+        return paperName;
+    }
+
+    public void setPaperName(String paperName) {
+        this.paperName = paperName;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public Integer getBigQuestionNo() {
+        return bigQuestionNo;
+    }
+
+    public void setBigQuestionNo(Integer bigQuestionNo) {
+        this.bigQuestionNo = bigQuestionNo;
+    }
+
+    public Integer getSmallQuestionNo() {
+        return smallQuestionNo;
+    }
+
+    public void setSmallQuestionNo(Integer smallQuestionNo) {
+        this.smallQuestionNo = smallQuestionNo;
+    }
+
+    public String getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(String questionType) {
+        this.questionType = questionType;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+
+    public Double getSmallQuestionScore() {
+        return smallQuestionScore;
+    }
+
+    public void setSmallQuestionScore(Double smallQuestionScore) {
+        this.smallQuestionScore = smallQuestionScore;
+    }
+
+}

+ 203 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/PrintingProject.java

@@ -0,0 +1,203 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * 印刷项目实体类
+ */
+@Entity
+@Table(name = "ec_prt_project")
+public class PrintingProject extends IdEntity {
+    /**
+     * 机构ID
+     */
+    private Long orgId;
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 考试名称
+     */
+    private String examName;
+    /**
+     * 机构名称
+     */
+    private String orgName;
+    /**
+     * 供应商ID (对应机构表 ecs_core_org)
+     */
+    private Long supplierId;
+    /**
+     * 供应商名称
+     */
+    private String supplierName;
+    /**
+     * 项目经理ID (对应用户表 ecs_core_user)
+     */
+    private Long pmId;
+    /**
+     * 项目经理名称
+     */
+    private String pmName;
+    /**
+     * 印刷数据准备开始时间
+     */
+    private Date prepareStartTime;
+    /**
+     * 印刷数据准备结束时间
+     */
+    private Date prepareEndTime;
+    /**
+     * 具体印刷开始时间
+     */
+    private Date printStartTime;
+    /**
+     * 具体印刷结束时间
+     */
+    private Date printEndTime;
+    /**
+     * 邮寄开始时间
+     */
+    private Date mailStartTime;
+    /**
+     * 邮寄结束时间
+     */
+    private Date mailEndTime;
+    /**
+     * 项目是否已完成
+     * 1:完成
+     * 0/null:未完成
+     */
+    private Integer completed;
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public Long getSupplierId() {
+        return supplierId;
+    }
+
+    public void setSupplierId(Long supplierId) {
+        this.supplierId = supplierId;
+    }
+
+    public String getSupplierName() {
+        return supplierName;
+    }
+
+    public void setSupplierName(String supplierName) {
+        this.supplierName = supplierName;
+    }
+
+    public Long getPmId() {
+        return pmId;
+    }
+
+    public void setPmId(Long pmId) {
+        this.pmId = pmId;
+    }
+
+    public String getPmName() {
+        return pmName;
+    }
+
+    public void setPmName(String pmName) {
+        this.pmName = pmName;
+    }
+
+    public Date getPrepareStartTime() {
+        return prepareStartTime;
+    }
+
+    public void setPrepareStartTime(Date prepareStartTime) {
+        this.prepareStartTime = prepareStartTime;
+    }
+
+    public Date getPrepareEndTime() {
+        return prepareEndTime;
+    }
+
+    public void setPrepareEndTime(Date prepareEndTime) {
+        this.prepareEndTime = prepareEndTime;
+    }
+
+    public Date getPrintStartTime() {
+        return printStartTime;
+    }
+
+    public void setPrintStartTime(Date printStartTime) {
+        this.printStartTime = printStartTime;
+    }
+
+    public Date getPrintEndTime() {
+        return printEndTime;
+    }
+
+    public void setPrintEndTime(Date printEndTime) {
+        this.printEndTime = printEndTime;
+    }
+
+    public Date getMailStartTime() {
+        return mailStartTime;
+    }
+
+    public void setMailStartTime(Date mailStartTime) {
+        this.mailStartTime = mailStartTime;
+    }
+
+    public Date getMailEndTime() {
+        return mailEndTime;
+    }
+
+    public void setMailEndTime(Date mailEndTime) {
+        this.mailEndTime = mailEndTime;
+    }
+
+    public Integer getCompleted() {
+        return completed;
+    }
+
+    public void setCompleted(Integer completed) {
+        this.completed = completed;
+    }
+
+}

+ 120 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/PrintingTemplate.java

@@ -0,0 +1,120 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import cn.com.qmth.examcloud.core.print.enums.TemplateType;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+
+/**
+ * 印刷模板
+ */
+@Entity
+@Table(name = "ec_prt_template")
+public class PrintingTemplate extends IdEntity {
+    /**
+     * 机构ID
+     */
+    private Long orgId;
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 机构名称
+     */
+    private String orgName;
+
+    /**
+     * 考试名称
+     */
+    private String examName;
+    /**
+     * 模板类型
+     */
+    @Enumerated(EnumType.STRING)
+    private TemplateType templateType;
+    /**
+     * 序号
+     */
+    private Integer orderNum;
+    /**
+     * 文件地址
+     */
+    private String templateUrl;
+
+    private String fileName;
+
+    public Long getOrgId() {
+        return orgId;
+    }
+
+    public void setOrgId(Long orgId) {
+        this.orgId = orgId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getOrgName() {
+        return orgName;
+    }
+
+    public void setOrgName(String orgName) {
+        this.orgName = orgName;
+    }
+
+    public String getExamName() {
+        return examName;
+    }
+
+    public void setExamName(String examName) {
+        this.examName = examName;
+    }
+
+    public TemplateType getTemplateType() {
+        return templateType;
+    }
+
+    public void setTemplateType(TemplateType templateType) {
+        this.templateType = templateType;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getTemplateUrl() {
+        return templateUrl;
+    }
+
+    public void setTemplateUrl(String templateUrl) {
+        this.templateUrl = templateUrl;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+}

+ 125 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ProjectBackupSetting.java

@@ -0,0 +1,125 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import cn.com.qmth.examcloud.core.print.enums.BackupGroupType;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+
+/**
+ * 印刷项目备份设置
+ */
+@Entity
+@Table(name = "ec_prt_project_backup_setting")
+public class ProjectBackupSetting extends IdEntity {
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /* 每袋冗余设置 */
+    /**
+     * 每袋备份比例
+     */
+    private Double perPackageRatio;
+    /**
+     * 每袋备份最大值
+     */
+    private Double perPackageMax;
+    /**
+     * 每袋备份最小值
+     */
+    private Double perPackageMin;
+
+    /* 单独备份袋 */
+    /**
+     * 归集类型
+     */
+    @Enumerated(EnumType.STRING)
+    private BackupGroupType groupType;
+    /**
+     * 单独备份比例
+     */
+    private Double independentRatio;
+    /**
+     * 单独备份最大值
+     */
+    private Double independentMax;
+    /**
+     * 单独备份最小值
+     */
+    private Double independentMin;
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Long projectId) {
+        this.projectId = projectId;
+    }
+
+    public Double getPerPackageRatio() {
+        return perPackageRatio;
+    }
+
+    public void setPerPackageRatio(Double perPackageRatio) {
+        this.perPackageRatio = perPackageRatio;
+    }
+
+    public Double getPerPackageMax() {
+        return perPackageMax;
+    }
+
+    public void setPerPackageMax(Double perPackageMax) {
+        this.perPackageMax = perPackageMax;
+    }
+
+    public Double getPerPackageMin() {
+        return perPackageMin;
+    }
+
+    public void setPerPackageMin(Double perPackageMin) {
+        this.perPackageMin = perPackageMin;
+    }
+
+    public BackupGroupType getGroupType() {
+        return groupType;
+    }
+
+    public void setGroupType(BackupGroupType groupType) {
+        this.groupType = groupType;
+    }
+
+    public Double getIndependentRatio() {
+        return independentRatio;
+    }
+
+    public void setIndependentRatio(Double independentRatio) {
+        this.independentRatio = independentRatio;
+    }
+
+    public Double getIndependentMax() {
+        return independentMax;
+    }
+
+    public void setIndependentMax(Double independentMax) {
+        this.independentMax = independentMax;
+    }
+
+    public Double getIndependentMin() {
+        return independentMin;
+    }
+
+    public void setIndependentMin(Double independentMin) {
+        this.independentMin = independentMin;
+    }
+
+}

+ 44 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/ProjectOtherSetting.java

@@ -0,0 +1,44 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 印刷项目其他设置
+ */
+@Entity
+@Table(name = "ec_prt_project_other_setting")
+public class ProjectOtherSetting extends IdEntity {
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+    /**
+     * 备注
+     */
+    private String remark;
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Long projectId) {
+        this.projectId = projectId;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+}

+ 57 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/QuestionTypeNum.java

@@ -0,0 +1,57 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 试题类型----试题数量
+ */
+@Entity
+@Table(name = "ec_prt_question_type_num")
+public class QuestionTypeNum extends IdEntity {
+    /**
+     * 考试试卷结构
+     */
+    private Long examStructureId;
+    /**
+     * 试题类型
+     * See QuesStructType.java
+     */
+    private String questionType;
+    /**
+     * 试题数量
+     */
+    private Integer quantity;
+
+    public Long getExamStructureId() {
+        return examStructureId;
+    }
+
+    public void setExamStructureId(Long examStructureId) {
+        this.examStructureId = examStructureId;
+    }
+
+    public String getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(String questionType) {
+        this.questionType = questionType;
+    }
+
+    public Integer getQuantity() {
+        return quantity;
+    }
+
+    public void setQuantity(Integer quantity) {
+        this.quantity = quantity;
+    }
+
+}

+ 148 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/entity/SubjectiveQuestionStructure.java

@@ -0,0 +1,148 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+/**
+ * 主观题数据--用于Excel导出
+ */
+@Entity
+@Table(name = "ec_prt_subjective_question_structure")
+public class SubjectiveQuestionStructure extends IdEntity {
+    /**
+     * 考试ID
+     */
+    private Long examId;
+    /**
+     * 试卷id
+     */
+    private String paperId;
+    /**
+     * 课程代码
+     */
+    //@ExcelProperty(name = "科目代码", index = 0)
+    private String courseNo;
+    /**
+     * 课程名称
+     */
+    //@ExcelProperty(name = "科目名称", index = 1)
+    private String courseName;
+    /**
+     * 试卷名称
+     */
+    //@ExcelProperty(name = "试卷名称", index = 2)
+    private String paperName;
+    /**
+     * 试卷类型
+     */
+    //@ExcelProperty(name = "试卷类型", index = 3)
+    private String paperType;
+    /**
+     * 大题号
+     */
+    //@ExcelProperty(name = "大题号", index = 4)
+    private Integer bigQuestionNo;
+    /**
+     * 大题名称
+     */
+    //@ExcelProperty(name = "大题名称", index = 5)
+    private String bigQuestionName;
+    /**
+     * 小题号
+     */
+    //@ExcelProperty(name = "小题号", index = 6)
+    private Integer smallQuestionNo;
+    /**
+     * 小题分数
+     */
+    //@ExcelProperty(name = "满分", index = 7)
+    private Double questionScore;
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(String paperId) {
+        this.paperId = paperId;
+    }
+
+    public String getCourseNo() {
+        return courseNo;
+    }
+
+    public void setCourseNo(String courseNo) {
+        this.courseNo = courseNo;
+    }
+
+    public String getCourseName() {
+        return courseName;
+    }
+
+    public void setCourseName(String courseName) {
+        this.courseName = courseName;
+    }
+
+    public String getPaperName() {
+        return paperName;
+    }
+
+    public void setPaperName(String paperName) {
+        this.paperName = paperName;
+    }
+
+    public String getPaperType() {
+        return paperType;
+    }
+
+    public void setPaperType(String paperType) {
+        this.paperType = paperType;
+    }
+
+    public Integer getBigQuestionNo() {
+        return bigQuestionNo;
+    }
+
+    public void setBigQuestionNo(Integer bigQuestionNo) {
+        this.bigQuestionNo = bigQuestionNo;
+    }
+
+    public String getBigQuestionName() {
+        return bigQuestionName;
+    }
+
+    public void setBigQuestionName(String bigQuestionName) {
+        this.bigQuestionName = bigQuestionName;
+    }
+
+    public Integer getSmallQuestionNo() {
+        return smallQuestionNo;
+    }
+
+    public void setSmallQuestionNo(Integer smallQuestionNo) {
+        this.smallQuestionNo = smallQuestionNo;
+    }
+
+    public Double getQuestionScore() {
+        return questionScore;
+    }
+
+    public void setQuestionScore(Double questionScore) {
+        this.questionScore = questionScore;
+    }
+
+}

+ 33 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/BackupGroupType.java

@@ -0,0 +1,33 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.enums;
+
+/**
+ * 印刷项目备份归集类型
+ */
+public enum BackupGroupType {
+
+    LEARNING_CENTER("学习中心"),
+
+    EXAM_SITE("考点");
+
+    private String name;
+
+    BackupGroupType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+}

+ 35 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/CoursePaperStatus.java

@@ -0,0 +1,35 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.enums;
+
+/**
+ * 课程试卷状态
+ */
+public enum CoursePaperStatus {
+
+    NONE("无"),
+
+    EXIST("已有"),
+
+    NOT_FORMULATED("未指定");
+
+    private String desc;
+
+    CoursePaperStatus(String desc) {
+        this.desc = desc;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+
+}

+ 37 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/ProjectStatType.java

@@ -0,0 +1,37 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.enums;
+
+/**
+ * 功能类型
+ */
+public enum ProjectStatType {
+
+    NORMAL("常规"),
+
+    BACKUP("备份"),
+
+    TOTAL("合计"),
+
+    OTHER("其他");
+
+    private String name;
+
+    ProjectStatType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+}

+ 56 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/enums/TemplateType.java

@@ -0,0 +1,56 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.enums;
+
+/**
+ * Excel模板类型
+ */
+public enum TemplateType {
+
+    EXAM_STUDENT_DATA("考生数据表", 1),
+
+    EXAMINATION_ROOM_DATA("考场数据表", 2),
+
+    PAPER_PACKAGE("卷袋贴模板", 3),
+
+    CHECKIN_TABLE("签到表模板", 4),
+
+    NORMAL_ANSWER_CARD("常规题卡模板", 5),
+
+    SPECIAL_ANSWER_CARD("特殊题卡模板", 6),
+
+    BACKUP_PAPER_PACKAGE("备份卷贴模板", 7),
+
+    PAPER_PACKAGE_STYLE("试卷袋样式", 8);
+
+    private String name;
+
+    private Integer num;
+
+    TemplateType(String name, Integer num) {
+        this.name = name;
+        this.num = num;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getNum() {
+        return num;
+    }
+
+    public void setNum(Integer num) {
+        this.num = num;
+    }
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/CoursePaperRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.CoursePaper;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CoursePaperRepository extends JpaRepository<CoursePaper, Long>, JpaSpecificationExecutor<CoursePaper> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/CourseStatisticsRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.CourseStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CourseStatisticsRepository extends JpaRepository<CourseStatistics, Long>, JpaSpecificationExecutor<CourseStatistics> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ExamStructureRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.ExamStructure;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ExamStructureRepository extends JpaRepository<ExamStructure, Long>, JpaSpecificationExecutor<ExamStructure> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ObjectiveQuestionStructureRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.ObjectiveQuestionStructure;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ObjectiveQuestionStructureRepository extends JpaRepository<ObjectiveQuestionStructure, Long>, JpaSpecificationExecutor<ObjectiveQuestionStructure> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/PrintingProjectRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.PrintingProject;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface PrintingProjectRepository extends JpaRepository<PrintingProject, Long>, JpaSpecificationExecutor<PrintingProject> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/PrintingTemplateRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.PrintingTemplate;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface PrintingTemplateRepository extends JpaRepository<PrintingTemplate, Long>, JpaSpecificationExecutor<PrintingTemplate> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ProjectBackupSettingRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.ProjectBackupSetting;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ProjectBackupSettingRepository extends JpaRepository<ProjectBackupSetting, Long>, JpaSpecificationExecutor<ProjectBackupSetting> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/ProjectOtherSettingRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.ProjectOtherSetting;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ProjectOtherSettingRepository extends JpaRepository<ProjectOtherSetting, Long>, JpaSpecificationExecutor<ProjectOtherSetting> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/QuestionTypeNumRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.QuestionTypeNum;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface QuestionTypeNumRepository extends JpaRepository<QuestionTypeNum, Long>, JpaSpecificationExecutor<QuestionTypeNum> {
+
+}

+ 18 - 0
examcloud-core-print-dao/src/main/java/cn/com/qmth/examcloud/core/print/repository/SubjectiveQuestionStructureRepository.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:28:20.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.repository;
+
+import cn.com.qmth.examcloud.core.print.entity.SubjectiveQuestionStructure;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface SubjectiveQuestionStructureRepository extends JpaRepository<SubjectiveQuestionStructure, Long>, JpaSpecificationExecutor<SubjectiveQuestionStructure> {
+
+}

+ 1 - 0
examcloud-core-print-dao/src/main/resources/db-schema.sql

@@ -0,0 +1 @@
+/* todo */

+ 21 - 0
examcloud-core-print-provider/pom.xml

@@ -0,0 +1,21 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print-provider</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-print</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-print-service</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 30 - 0
examcloud-core-print-provider/src/main/java/cn/com/qmth/examcloud/core/print/api/controller/PrintingProjectController.java

@@ -0,0 +1,30 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:33:36.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.api.controller;
+
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.core.print.service.PrintingProjectService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 印刷项目相关接口
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@RestController
+@Api(tags = "印刷项目相关接口")
+@RequestMapping("${$rmp.ctrl.print}/printing/project")
+public class PrintingProjectController extends ControllerSupport {
+    @Autowired
+    private PrintingProjectService printingProjectService;
+
+}

+ 30 - 0
examcloud-core-print-provider/src/main/java/cn/com/qmth/examcloud/core/print/api/provider/PrintingProjectCloudServiceProvider.java

@@ -0,0 +1,30 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:33:36.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.api.provider;
+
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.core.print.service.PrintingProjectService;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 印刷项目相关接口
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@RestController
+@Api(tags = "印刷项目相关接口")
+@RequestMapping("${$rmp.cloud.print}/printing/project")
+public class PrintingProjectCloudServiceProvider extends ControllerSupport {
+    @Autowired
+    private PrintingProjectService printingProjectService;
+
+}

+ 21 - 0
examcloud-core-print-service/pom.xml

@@ -0,0 +1,21 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print-service</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-print</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-print-dao</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 18 - 0
examcloud-core-print-service/src/main/java/cn/com/qmth/examcloud/core/print/service/PrintingProjectService.java

@@ -0,0 +1,18 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:31:14.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.service;
+
+/**
+ * 印刷项目相关接口
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public interface PrintingProjectService {
+
+}

+ 26 - 0
examcloud-core-print-service/src/main/java/cn/com/qmth/examcloud/core/print/service/impl/PrintingProjectServiceImpl.java

@@ -0,0 +1,26 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:31:14.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.service.impl;
+
+import cn.com.qmth.examcloud.core.print.repository.PrintingProjectRepository;
+import cn.com.qmth.examcloud.core.print.service.PrintingProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 印刷项目相关接口
+ *
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Service
+public class PrintingProjectServiceImpl implements PrintingProjectService {
+    @Autowired
+    private PrintingProjectRepository printingProjectRepository;
+
+}

+ 31 - 0
examcloud-core-print-starter/assembly.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <id>distribution</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}/src/main/resources</directory>
+            <outputDirectory>/config</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/shell</directory>
+            <excludes>
+                <exclude>start.args</exclude>
+                <exclude>start.vmoptions</exclude>
+            </excludes>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0777</fileMode>
+        </fileSet>
+    </fileSets>
+    <dependencySets>
+        <dependencySet>
+            <useProjectArtifact>true</useProjectArtifact>
+            <outputDirectory>lib</outputDirectory>
+            <scope>runtime</scope>
+        </dependencySet>
+    </dependencySets>
+</assembly>

+ 82 - 0
examcloud-core-print-starter/pom.xml

@@ -0,0 +1,82 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print-starter</artifactId>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-core-print</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.com.qmth.examcloud</groupId>
+            <artifactId>examcloud-core-print-provider</artifactId>
+            <version>${examcloud.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>cn.com.qmth.examcloud.core.print.stater.PrintApplication</mainClass>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>./</classpathPrefix>
+                        </manifest>
+                        <manifestEntries>
+                            <Class-Path>../config/</Class-Path>
+                        </manifestEntries>
+                    </archive>
+                    <excludes>
+                        <exclude>*.properties</exclude>
+                        <exclude>*.xml</exclude>
+                        <exclude>*.conf</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <finalName>examcloud-core-print</finalName>
+                    <descriptors>
+                        <descriptor>assembly.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>install</phase>
+                        <goals>
+                            <goal>assembly</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 1 - 0
examcloud-core-print-starter/shell/start.args

@@ -0,0 +1 @@
+--spring.profiles.active=test

+ 26 - 0
examcloud-core-print-starter/shell/start.sh

@@ -0,0 +1,26 @@
+#!/bin/bash
+
+APP_MAIN_JAR="examcloud-core-print-starter-2.0-SNAPSHOT.jar"
+
+FILE_PATH=$(cd `dirname $0`; pwd)
+
+JAVA_OPTS=`cat $FILE_PATH/start.vmoptions`
+APP_ARGS=`cat $FILE_PATH/start.args`
+
+PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
+
+if [ ! -z "$PID_LIST" ]; then
+    echo "[ERROR] : APP is already running!"
+    exit -1
+fi
+
+echo "java options:"
+echo "$JAVA_OPTS"
+echo "args:"
+echo "$APP_ARGS"
+
+nohup java $JAVA_OPTS -jar $FILE_PATH/lib/$APP_MAIN_JAR $APP_ARGS >/dev/null 2>&1 &
+
+echo "starting......"
+
+exit 0

+ 1 - 0
examcloud-core-print-starter/shell/start.vmoptions

@@ -0,0 +1 @@
+-server -Xms512m -Xmx512m

+ 18 - 0
examcloud-core-print-starter/shell/stop.sh

@@ -0,0 +1,18 @@
+#!/bin/bash
+
+APP_MAIN_JAR="examcloud-core-print-starter-2.0-SNAPSHOT.jar"
+
+FILE_PATH=$(cd `dirname $0`; pwd)
+
+PID_LIST=`ps -ef|grep $APP_MAIN_JAR|grep java|awk '{print $2}'`
+
+if [ ! -z "$PID_LIST" ]; then
+    echo "Runnable jar is $APP_MAIN_JAR."
+    for PID in $PID_LIST 
+    do
+        kill -9 $PID
+    done
+    echo "stopped !"
+fi
+
+exit 0

+ 61 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/PrintApplication.java

@@ -0,0 +1,61 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater;
+
+import cn.com.qmth.examcloud.commons.base.logging.ExamCloudLog;
+import cn.com.qmth.examcloud.commons.base.logging.ExamCloudLogFactory;
+import cn.com.qmth.examcloud.commons.base.logging.SLF4JImpl;
+import org.slf4j.MDC;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.web.multipart.MultipartResolver;
+import org.springframework.web.multipart.commons.CommonsMultipartResolver;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@EnableJpaAuditing
+@EnableEurekaClient
+@EnableDiscoveryClient
+@SpringBootApplication
+@ComponentScan(basePackages = {"cn.com.qmth"})
+@EntityScan(basePackages = {"cn.com.qmth"})
+@EnableJpaRepositories(basePackages = {"cn.com.qmth"})
+@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
+public class PrintApplication extends SpringBootServletInitializer {
+    private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(PrintApplication.class);
+
+    public static void main(String[] args) throws Exception {
+        if (LOG instanceof SLF4JImpl) {
+            MDC.put("TRACE_ID", Thread.currentThread().getName());
+        }
+        SpringApplication.run(PrintApplication.class, args);
+    }
+
+    @Bean(name = "multipartResolver")
+    public MultipartResolver multipartResolver() {
+        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
+        resolver.setDefaultEncoding("UTF-8");
+        resolver.setResolveLazily(true);
+        resolver.setMaxInMemorySize(50 * 1024);
+        resolver.setMaxUploadSize(100 * 1024 * 1024);
+        return resolver;
+    }
+
+}

+ 81 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/InterceptorConfig.java

@@ -0,0 +1,81 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater.config;
+
+import cn.com.qmth.examcloud.commons.base.util.PathUtil;
+import cn.com.qmth.examcloud.commons.base.util.PropertiesUtil;
+import cn.com.qmth.examcloud.commons.web.interceptor.FirstInterceptor;
+import cn.com.qmth.examcloud.commons.web.redis.RedisClient;
+import cn.com.qmth.examcloud.commons.web.security.RequestPermissionInterceptor;
+import cn.com.qmth.examcloud.commons.web.security.SpringCloudInterceptor;
+import cn.com.qmth.examcloud.commons.web.security.bean.Role;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+import java.util.List;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Configuration
+public class InterceptorConfig extends WebMvcConfigurerAdapter {
+    @Autowired
+    private RedisClient redisClient;
+
+    static {
+        PropertiesUtil.configureAndWatch(PathUtil.getResoucePath("security-mapping.properties"));
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
+        SpringCloudInterceptor springCloudInterceptor = new SpringCloudInterceptor();
+        springCloudInterceptor.setRedisClient(redisClient);
+        registry.addInterceptor(springCloudInterceptor).addPathPatterns("/**");
+
+        RequestPermissionInterceptor requestPermissionInterceptor = getRequestPermissionInterceptor();
+        requestPermissionInterceptor.configureAndWatch("security-exclusions.conf");
+        registry.addInterceptor(requestPermissionInterceptor).addPathPatterns("/**");
+        super.addInterceptors(registry);
+    }
+
+    @Bean
+    public RequestPermissionInterceptor getRequestPermissionInterceptor() {
+        return new RequestPermissionInterceptor(redisClient) {
+            @Override
+            public boolean hasPermission(String mappingPath, User user) {
+                List<Role> roleList = user.getRoleList();
+                if (CollectionUtils.isEmpty(roleList)) {
+                    return false;
+                }
+
+                String roles = PropertiesUtil.getString(mappingPath);
+                if (StringUtils.isBlank(roles)) {
+                    return true;
+                }
+
+                roles = "," + roles + ",";
+
+                for (Role role : roleList) {
+                    if (roles.contains("," + role.getRoleCode() + ",")) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+    }
+
+}

+ 32 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/PropertiesConfig.java

@@ -0,0 +1,32 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater.config;
+
+import cn.com.qmth.examcloud.commons.base.util.PathUtil;
+import cn.com.qmth.examcloud.commons.base.util.PropertiesUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Configuration
+public class PropertiesConfig implements ApplicationListener<ContextRefreshedEvent> {
+    @Value("${spring.profiles.active}")
+    private String springProfilesActive;
+
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        String resourceName = "application-" + springProfilesActive + ".properties";
+        PropertiesUtil.configureAndWatch(PathUtil.getResoucePath(resourceName));
+    }
+
+}

+ 62 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/RedisConfig.java

@@ -0,0 +1,62 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 17:02:09.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater.config;
+
+import cn.com.qmth.examcloud.commons.web.redis.RedisClient;
+import cn.com.qmth.examcloud.commons.web.redis.RedisClientImpl;
+import cn.com.qmth.examcloud.commons.web.support.CustomResponseErrorHandler;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Configuration
+public class RedisConfig {
+
+    @Bean
+    @LoadBalanced
+    public RestTemplate restTemplate() {
+        RestTemplate restTemplate = new RestTemplate();
+        restTemplate.setErrorHandler(new CustomResponseErrorHandler());
+        return restTemplate;
+    }
+
+    @Bean
+    @Autowired
+    public RedisClient redisClient(RedisTemplate<String, Object> redisTemplate) {
+        return new RedisClientImpl(redisTemplate);
+    }
+
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+
+}

+ 48 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/config/SwaggerConfig.java

@@ -0,0 +1,48 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater.config;
+
+import io.swagger.annotations.ApiOperation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+    @Bean
+    public Docket buildDocket() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .groupName("Version 2.0")
+                .apiInfo(buildApiInfo())
+                .useDefaultResponseMessages(false)
+                .select()
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    public ApiInfo buildApiInfo() {
+        return new ApiInfoBuilder()
+                .title("印刷平台接口文档")
+                .version("2.0")
+                .build();
+    }
+
+}

+ 28 - 0
examcloud-core-print-starter/src/main/java/cn/com/qmth/examcloud/core/print/stater/controller/IndexController.java

@@ -0,0 +1,28 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:17.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.stater.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@Controller
+public class IndexController {
+
+    @RequestMapping(value = "/", method = RequestMethod.GET)
+    public String index(HttpServletRequest request) throws Exception {
+        return "redirect:/doc.html";
+    }
+
+}

+ 16 - 0
examcloud-core-print-starter/src/main/resources/application-dev.properties

@@ -0,0 +1,16 @@
+# datasource config
+spring.datasource.url=jdbc:mysql://db-host:3306/exam_cloud_kf?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
+spring.datasource.username=root
+spring.datasource.password=root
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.show-sql=true
+# mongodb config
+spring.data.mongodb.uri=mongodb://db-host:27017/examcloud-core-print
+spring.data.mongodb.grid-fs-database=examcloud-core-print
+spring.data.mongodb.database=examcloud-core-print
+# redis config
+spring.redis.host=redis-host
+spring.redis.port=6379
+# spring cloud config
+spring.application.name=EC-CORE-PRINT
+eureka.client.serviceUrl.defaultZone=http://eureka-host:1111/eureka/

+ 16 - 0
examcloud-core-print-starter/src/main/resources/application-prod.properties

@@ -0,0 +1,16 @@
+# datasource config
+spring.datasource.url=jdbc:mysql://db-host:3306/exam_cloud_kf?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
+spring.datasource.username=root
+spring.datasource.password=root
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.show-sql=true
+# mongodb config
+spring.data.mongodb.uri=mongodb://db-host:27017/examcloud-core-print
+spring.data.mongodb.grid-fs-database=examcloud-core-print
+spring.data.mongodb.database=examcloud-core-print
+# redis config
+spring.redis.host=redis-host
+spring.redis.port=6379
+# spring cloud config
+spring.application.name=EC-CORE-PRINT
+eureka.client.serviceUrl.defaultZone=http://eureka-host:1111/eureka/

+ 16 - 0
examcloud-core-print-starter/src/main/resources/application-test.properties

@@ -0,0 +1,16 @@
+# datasource config
+spring.datasource.url=jdbc:mysql://db-host:3306/exam_cloud_kf?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
+spring.datasource.username=root
+spring.datasource.password=root
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.show-sql=true
+# mongodb config
+spring.data.mongodb.uri=mongodb://db-host:27017/examcloud-core-print
+spring.data.mongodb.grid-fs-database=examcloud-core-print
+spring.data.mongodb.database=examcloud-core-print
+# redis config
+spring.redis.host=redis-host
+spring.redis.port=6379
+# spring cloud config
+spring.application.name=EC-CORE-PRINT
+eureka.client.serviceUrl.defaultZone=http://eureka-host:1111/eureka/

+ 29 - 0
examcloud-core-print-starter/src/main/resources/application.properties

@@ -0,0 +1,29 @@
+# profile config
+spring.profiles.active=dev
+# mvc config
+server.port=8013
+spring.http.multipart.max-file-size=50Mb
+spring.http.multipart.max-request-size=50Mb
+# jackson config
+spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
+spring.jackson.time-zone=GMT+8
+# feign config
+feign.httpclient.enabled=false
+feign.okhttp.enabled=true
+# eureka config
+eureka.instance.lease-renewal-interval-in-seconds=1
+eureka.instance.lease-expiration-duration-in-seconds=2
+eureka.instance.prefer-ip-address=true
+eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port}
+eureka.client.healthcheck.enabled=true
+# log config
+logging.file=logs/debug.log
+logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
+logging.level.org.springframework.data.mongodb=DEBUG
+logging.level.org.springframework=WARN
+logging.level.org.hibernate=WARN
+logging.level.org.apache=WARN
+logging.level.cn.com.qmth=DEBUG
+# api config
+$rmp.cloud.print=/api/cloud/ecs_prt
+$rmp.ctrl.print=/api/ecs_prt

+ 57 - 0
examcloud-core-print-starter/src/main/resources/logback-spring.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="true" scan="true" scanPeriod="30 seconds">
+    <springProperty scope="context" name="logdir" source="logback.logdir"/>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{KEY} | %m | [%class:%line]%n</pattern>
+        </encoder>
+    </appender>
+
+    <!-- debug 日志 -->
+    <appender name="DEBUG_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>log/debug.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{KEY} | %m | [%class:%line]%n</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>logs/debug.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
+            <maxHistory>100</maxHistory>
+            <maxFileSize>100MB</maxFileSize>
+        </rollingPolicy>
+    </appender>
+
+    <!-- 接口日志 -->
+    <appender name="INTERFACE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>log/interface.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{KEY} | %m%n</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>logs/interface.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
+            <maxHistory>100</maxHistory>
+            <maxFileSize>100MB</maxFileSize>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="cn.com.qmth.examcloud" level="DEBUG" additivity="false">
+        <appender-ref ref="DEBUG_APPENDER"/>
+        <appender-ref ref="STDOUT"/>
+    </logger>
+
+    <logger name="INTERFACE_LOGGER" level="DEBUG" additivity="false">
+        <appender-ref ref="INTERFACE_APPENDER"/>
+        <appender-ref ref="STDOUT"/>
+    </logger>
+
+    <logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>
+    <logger name="org.springframework.data.mongodb" level="DEBUG"/>
+    <logger name="org.springframework" level="WARN"/>
+    <logger name="org.hibernate" level="WARN"/>
+    <logger name="org.apache" level="WARN"/>
+
+    <root level="INFO">
+        <appender-ref ref="DEBUG_APPENDER"/>
+        <appender-ref ref="STDOUT"/>
+    </root>
+</configuration>

+ 7 - 0
examcloud-core-print-starter/src/main/resources/security-exclusions.conf

@@ -0,0 +1,7 @@
+[][/][GET]
+[][/swagger/ui/index][GET]
+[/swagger-resources][][GET]
+[/swagger-resources][/configuration/ui][GET]
+[/swagger-resources][/configuration/security][GET]
+[][${springfox.documentation.swagger.v2.path:/v2/api-docs}][GET]
+[][/doc.html][GET]

+ 0 - 0
examcloud-core-print-starter/src/main/resources/security-mapping.properties


+ 23 - 0
examcloud-core-print-starter/src/test/java/cn/com/qmth/examcloud/core/print/test/ApplicationTest.java

@@ -0,0 +1,23 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 16:34:34.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.test;
+
+import org.junit.Test;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+public class ApplicationTest {
+
+    @Test
+    public void demoTest() throws Exception {
+
+    }
+
+}

+ 32 - 0
examcloud-core-print-starter/src/test/java/cn/com/qmth/examcloud/core/print/test/PrintingProjectServiceTest.java

@@ -0,0 +1,32 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-10-17 17:16:01.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.print.test;
+
+import cn.com.qmth.examcloud.core.print.service.PrintingProjectService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * @author: fengdesheng
+ * @since: 2018/10/17
+ */
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class PrintingProjectServiceTest {
+    @Autowired
+    private PrintingProjectService printingProjectService;
+
+    @Test
+    public void demoTest() throws Exception {
+
+    }
+
+}

+ 123 - 0
pom.xml

@@ -0,0 +1,123 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>examcloud-core-print</artifactId>
+    <version>2.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <parent>
+        <groupId>cn.com.qmth.examcloud</groupId>
+        <artifactId>examcloud-parent</artifactId>
+        <version>2.0-SNAPSHOT</version>
+    </parent>
+
+    <modules>
+        <module>examcloud-core-print-common</module>
+        <module>examcloud-core-print-dao</module>
+        <module>examcloud-core-print-service</module>
+        <module>examcloud-core-print-provider</module>
+        <module>examcloud-core-print-starter</module>
+    </modules>
+
+    <properties>
+        <examcloud.version>2.0-SNAPSHOT</examcloud.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>6.0.6</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.guava</groupId>
+                <artifactId>guava</artifactId>
+                <version>26.0-jre</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version>3.8.1</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-codec</groupId>
+                <artifactId>commons-codec</artifactId>
+                <version>1.11</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-beanutils</groupId>
+                <artifactId>commons-beanutils</artifactId>
+                <version>1.9.3</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>2.6</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-fileupload</groupId>
+                <artifactId>commons-fileupload</artifactId>
+                <version>1.3.3</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>1.2.51</version>
+            </dependency>
+            <dependency>
+                <groupId>org.jsoup</groupId>
+                <artifactId>jsoup</artifactId>
+                <version>1.11.3</version>
+            </dependency>
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>3.11.0</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.code.findbugs</groupId>
+                <artifactId>jsr305</artifactId>
+                <version>3.0.2</version>
+            </dependency>
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger2</artifactId>
+                <version>2.9.2</version>
+            </dependency>
+            <dependency>
+                <groupId>com.github.xiaoymin</groupId>
+                <artifactId>swagger-bootstrap-ui</artifactId>
+                <version>1.8.1</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>