Преглед на файлове

移除examcloud-commons模块

deason преди 2 години
родител
ревизия
e6de6d8aa1
променени са 100 файла, в които са добавени 3874 реда и са изтрити 5430 реда
  1. 0 216
      examcloud-commons/pom.xml
  2. 0 50
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/exception/ExamCloudRuntimeException.java
  3. 0 87
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/exception/StatusException.java
  4. 0 63
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/BlackHolePrintStreamBuilder.java
  5. 0 79
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/Counter.java
  6. 0 109
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnum.java
  7. 0 145
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnumManager.java
  8. 0 134
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/FileChangeWatchdog.java
  9. 0 58
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/FormFilePart.java
  10. 0 44
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/JsonHttpResponseHolder.java
  11. 0 52
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/KeyValuePair.java
  12. 0 46
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/ObjectHolder.java
  13. 0 98
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/XStreamBuilder.java
  14. 0 205
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/ConcurrentTask.java
  15. 0 27
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/WorkerController.java
  16. 0 43
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Counter.java
  17. 0 59
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Node.java
  18. 0 40
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Storer.java
  19. 0 34
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/TaskContext.java
  20. 0 185
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelReader.java
  21. 0 137
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelWriter.java
  22. 0 224
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/XlsxHandler.java
  23. 0 110
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLog.java
  24. 0 78
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLogFactory.java
  25. 0 70
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/NoLoggingImpl.java
  26. 0 67
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/Resources.java
  27. 0 111
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/SLF4JImpl.java
  28. 0 137
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/AES.java
  29. 0 89
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/AsciiUtil.java
  30. 0 54
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/BooleanUtil.java
  31. 0 116
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ByteUtil.java
  32. 0 212
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/DateUtil.java
  33. 0 63
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/FreeMarkerUtil.java
  34. 0 176
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/HttpClientUtil.java
  35. 0 115
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/HttpMethod.java
  36. 0 105
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/IOUtil.java
  37. 0 171
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/JsonUtil.java
  38. 0 59
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/MD5.java
  39. 0 46
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/MapUtil.java
  40. 0 69
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ObjectUtil.java
  41. 0 180
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/PathUtil.java
  42. 0 103
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/RegExpUtil.java
  43. 0 67
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ResourceLoader.java
  44. 0 43
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/SHA256.java
  45. 0 390
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/StringUtil.java
  46. 0 121
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ThreadLocalUtil.java
  47. 0 160
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/UrlUtil.java
  48. 0 126
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/Util.java
  49. 0 147
      examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ZipUtil.java
  50. 0 34
      examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/FileReaderExecuter.java
  51. 0 18
      examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/PrintExecuter.java
  52. 0 33
      examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/Test.java
  53. 199 5
      examcloud-support/pom.xml
  54. 51 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/exception/ExamCloudRuntimeException.java
  55. 89 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/exception/StatusException.java
  56. 1 1
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/BasicDataType.java
  57. 63 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/BlackHolePrintStreamBuilder.java
  58. 80 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/Counter.java
  59. 108 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnum.java
  60. 142 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnumManager.java
  61. 136 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/FileChangeWatchdog.java
  62. 58 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/FormFilePart.java
  63. 44 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/JsonHttpResponseHolder.java
  64. 51 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/KeyValuePair.java
  65. 46 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/ObjectHolder.java
  66. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/QuestionOptionHelper.java
  67. 101 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/XStreamBuilder.java
  68. 207 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/ConcurrentTask.java
  69. 1 1
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/Worker.java
  70. 27 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/WorkerController.java
  71. 44 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Counter.java
  72. 59 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Node.java
  73. 18 18
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/NodeExecuter.java
  74. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/SimpleNode.java
  75. 40 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Storer.java
  76. 35 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/TaskContext.java
  77. 180 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelReader.java
  78. 130 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelWriter.java
  79. 224 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/XlsxHandler.java
  80. 98 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLog.java
  81. 78 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLogFactory.java
  82. 70 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/NoLoggingImpl.java
  83. 64 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/Resources.java
  84. 111 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/SLF4JImpl.java
  85. 133 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/AES.java
  86. 89 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/AsciiUtil.java
  87. 54 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/BooleanUtil.java
  88. 117 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/ByteUtil.java
  89. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/Calculator.java
  90. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/CollectionUtil.java
  91. 213 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/DateUtil.java
  92. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/FileUtil.java
  93. 63 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/FreeMarkerUtil.java
  94. 170 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/HttpClientUtil.java
  95. 115 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/HttpMethod.java
  96. 98 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/IOUtil.java
  97. 0 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/JsonMapper.java
  98. 164 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/JsonUtil.java
  99. 58 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/MD5.java
  100. 45 0
      examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/MapUtil.java

+ 0 - 216
examcloud-commons/pom.xml

@@ -1,216 +0,0 @@
-<?xml version="1.0"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
-         xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>examcloud-commons</artifactId>
-    <packaging>jar</packaging>
-
-    <parent>
-        <groupId>cn.com.qmth.examcloud</groupId>
-        <artifactId>examcloud-components</artifactId>
-        <version>${revision}</version>
-    </parent>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter-logging</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-mail</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>compile</scope>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-log4j2</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>jcl-over-slf4j</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-1.2-api</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-beanutils</groupId>
-            <artifactId>commons-beanutils</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-net</groupId>
-            <artifactId>commons-net</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-codec</groupId>
-            <artifactId>commons-codec</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-collections</groupId>
-            <artifactId>commons-collections</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-pool2</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>commons-fileupload</groupId>
-            <artifactId>commons-fileupload</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-compress</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-text</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpmime</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.squareup.okhttp3</groupId>
-            <artifactId>okhttp</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi-ooxml</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>net.sf.json-lib</groupId>
-            <artifactId>json-lib</artifactId>
-            <classifier>jdk15</classifier>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.dataformat</groupId>
-            <artifactId>jackson-dataformat-yaml</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-core</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-annotations</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.mchange</groupId>
-            <artifactId>c3p0</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>redis.clients</groupId>
-            <artifactId>jedis</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>dom4j</groupId>
-            <artifactId>dom4j</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.freemarker</groupId>
-            <artifactId>freemarker</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.quartz-scheduler</groupId>
-            <artifactId>quartz</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.jsoup</groupId>
-            <artifactId>jsoup</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.jcraft</groupId>
-            <artifactId>jsch</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.thoughtworks.xstream</groupId>
-            <artifactId>xstream</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.googlecode.aviator</groupId>
-            <artifactId>aviator</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>junit</groupId>
-                    <artifactId>junit</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>commons-beanutils</groupId>
-                    <artifactId>commons-beanutils</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.springframework</groupId>
-                    <artifactId>spring-context</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-    </dependencies>
-
-</project>

+ 0 - 50
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/exception/ExamCloudRuntimeException.java

@@ -1,50 +0,0 @@
-package cn.com.qmth.examcloud.commons.exception;
-
-/**
- * 通用异常类<br>
- *
- * @author WANG
- */
-public class ExamCloudRuntimeException extends RuntimeException {
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 7992796744711512927L;
-
-	/**
-	 * 构造函数
-	 */
-	public ExamCloudRuntimeException() {
-		super();
-	}
-
-	/**
-	 * 构造函数
-	 */
-	public ExamCloudRuntimeException(String message) {
-		super(message);
-	}
-
-	/**
-	 * 构造函数
-	 */
-	public ExamCloudRuntimeException(String message, Throwable cause) {
-		super(message, cause);
-	}
-
-	/**
-	 * 构造函数
-	 */
-	public ExamCloudRuntimeException(Throwable cause) {
-		super(cause);
-	}
-
-	/**
-	 * 构造函数
-	 */
-	protected ExamCloudRuntimeException(String message, Throwable cause, boolean enableSuppression,
-			boolean writableStackTrace) {
-		super(message, cause, enableSuppression, writableStackTrace);
-	}
-
-}

+ 0 - 87
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/exception/StatusException.java

@@ -1,87 +0,0 @@
-package cn.com.qmth.examcloud.commons.exception;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import cn.com.qmth.examcloud.commons.util.JsonUtil;
-
-/**
- * 状态异常类<br>
- *
- * @author WANG
- */
-public class StatusException extends RuntimeException {
-	private static final long serialVersionUID = 5003047488500388819L;
-
-	private static final String DEF_CODE="500";
-	/**
-	 * 追踪ID
-	 */
-	private String traceId;
-
-	/**
-	 * 状态码
-	 */
-	private String code;
-
-	/**
-	 * 状态描述
-	 */
-	private String desc;
-
-	/**
-	 * 构造函数
-	 */
-	public StatusException(String code, String desc) {
-		super("[code: " + code + "; desc: " + desc + "]");
-		this.code = code;
-		this.desc = desc;
-	}
-
-	/**
-	 * 构造函数
-	 */
-	public StatusException(String code, String desc, Throwable cause) {
-		super("[code: " + code + "; desc: " + desc + "]", cause);
-		this.code = code;
-		this.desc = desc;
-	}
-	
-	public StatusException( String desc) {
-		super("[code: " + DEF_CODE + "; desc: " + desc + "]");
-		this.code = DEF_CODE;
-		this.desc = desc;
-	}
-
-	public String getCode() {
-		return code;
-	}
-
-	public String getDesc() {
-		return desc;
-	}
-
-	public String getTraceId() {
-		return traceId;
-	}
-
-	public void setTraceId(String traceId) {
-		this.traceId = traceId;
-	}
-
-	/**
-	 * @return
-	 */
-	public String toJson() {
-		Map<String, Object> map = new HashMap<String, Object>();
-		map.put("code", code);
-		map.put("desc", desc);
-		return JsonUtil.toJson(map);
-	}
-
-	@Override
-	public String toString() {
-		return toJson();
-	}
-
-}

+ 0 - 63
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/BlackHolePrintStreamBuilder.java

@@ -1,63 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-
-/**
- * 黑洞(PrintStream)构建器
- *
- * @author WANGWEI
- * @date 2019年3月28日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class BlackHolePrintStreamBuilder {
-
-	/**
-	 * 创建BlackHolePrintStream
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public static PrintStream build() {
-		return new BlackHolePrintStream(new ByteArrayOutputStream());
-	}
-
-	/**
-	 * 黑洞(PrintStream)
-	 *
-	 * @author WANGWEI
-	 * @date 2019年3月28日
-	 * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
-	 */
-	private static class BlackHolePrintStream extends PrintStream {
-
-		@Override
-		public void close() {
-			super.close();
-		}
-
-		ByteArrayOutputStream outputStream;
-
-		/**
-		 * 私有构造函数
-		 *
-		 * @param out
-		 */
-		private BlackHolePrintStream(ByteArrayOutputStream outputStream) {
-			super(outputStream);
-			this.outputStream = outputStream;
-		}
-
-		@Override
-		public void println(String x) {
-			outputStream.reset();
-		}
-
-		@Override
-		public void print(String x) {
-			outputStream.reset();
-		}
-
-	}
-
-}

+ 0 - 79
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/Counter.java

@@ -1,79 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * 计数器
- *
- * @author WANGWEI
- * @date 2018年1月26日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class Counter {
-
-	private AtomicLong counter;
-
-	/**
-	 * 最小值
-	 */
-	private long min;
-
-	/**
-	 * 最大值
-	 */
-	private long max;
-
-	/**
-	 * 循环计数回合数
-	 */
-	private int bout = 0;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param min
-	 * @param max
-	 */
-	public Counter(long min, long max) {
-		this.min = min;
-		this.max = max;
-		bout();
-	}
-
-	/**
-	 * 初始化循环
-	 *
-	 * @author WANGWEI
-	 */
-	private void bout() {
-		int cur = bout;
-		synchronized (this) {
-			if (cur < bout) {
-				return;
-			}
-			counter = new AtomicLong(min);
-			bout++;
-		}
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public long next() {
-		long next = counter.getAndIncrement();
-
-		if (next > max) {
-			bout();
-			return next();
-		}
-
-		return next;
-	}
-
-	public long get() {
-		return counter.get();
-	}
-}

+ 0 - 109
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnum.java

@@ -1,109 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.Serializable;
-
-import org.apache.commons.lang3.StringUtils;
-
-import cn.com.qmth.examcloud.commons.util.StringUtil;
-
-/**
- * 动态枚举
- *
- * @author WANGWEI
- * @date 2018年8月23日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public final class DynamicEnum implements Serializable {
-
-	private static final long serialVersionUID = -694709140246715214L;
-
-	/**
-	 * ID
-	 */
-	private Long id;
-
-	/**
-	 * name
-	 */
-	private String name;
-
-	/**
-	 * 描述
-	 */
-	private String desc;
-
-	/**
-	 * 值类型
-	 */
-	private String valueType;
-
-	public Long getId() {
-		return id;
-	}
-
-	public void setId(Long id) {
-		this.id = id;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public String getDesc() {
-		return desc;
-	}
-
-	public void setDesc(String desc) {
-		this.desc = desc;
-	}
-
-	public String getValueType() {
-		return valueType;
-	}
-
-	public void setValueType(String valueType) {
-		this.valueType = valueType;
-	}
-
-	/**
-	 * 是否合法
-	 *
-	 * @author WANGWEI
-	 * @param value
-	 * @return
-	 */
-	public Boolean isLegal(String value) {
-		if (StringUtils.isNotBlank(value) && null != valueType) {
-			BasicDataType dataType = BasicDataType.valueOf(valueType);
-			if (dataType.equals(BasicDataType.BOOLEAN)) {
-				try {
-					StringUtil.toBoolean(value);
-					return true;
-				} catch (Exception e) {
-					return false;
-				}
-			} else if (dataType.equals(BasicDataType.INTEGER)) {
-				try {
-					StringUtil.toInteger(value);
-					return true;
-				} catch (Exception e) {
-					return false;
-				}
-			} else if (dataType.equals(BasicDataType.LONG)) {
-				try {
-					StringUtil.toLong(value);
-					return true;
-				} catch (Exception e) {
-					return false;
-				}
-			}
-		}
-
-		return true;
-	}
-
-}

+ 0 - 145
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnumManager.java

@@ -1,145 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.lang3.StringUtils;
-
-import com.google.common.collect.Maps;
-import com.thoughtworks.xstream.XStream;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import cn.com.qmth.examcloud.commons.util.PathUtil;
-
-/**
- * 动态属性管理器
- *
- * @author WANGWEI
- * @date 2018年8月23日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class DynamicEnumManager {
-
-	private List<DynamicEnum> enums;
-
-	private Map<String, DynamicEnum> nameIndex;
-
-	private Map<Long, DynamicEnum> idIndex;
-
-	/**
-	 * 构造函数
-	 *
-	 */
-	private DynamicEnumManager() {
-		super();
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param xmlResourcePath
-	 * @return
-	 */
-	public static DynamicEnumManager newInstance(String xmlResourcePath) {
-		DynamicEnumManager manager = new DynamicEnumManager();
-
-		String resoucePath = PathUtil.getResoucePath(xmlResourcePath);
-		File file = new File(resoucePath);
-
-		XStream xStream = XStreamBuilder.newInstance().build();
-		xStream.allowTypes(new Class[]{DynamicEnum.class, List.class});
-		xStream.alias("enums", List.class);
-		xStream.alias("enum", DynamicEnum.class);
-
-		@SuppressWarnings("unchecked")
-		List<DynamicEnum> list = (List<DynamicEnum>) xStream.fromXML(file);
-		manager.enums = list;
-
-		manager.nameIndex = Maps.newHashMap();
-		manager.idIndex = Maps.newHashMap();
-
-		for (DynamicEnum cur : manager.enums) {
-			String valueTpye = cur.getValueType();
-			if (StringUtils.isBlank(valueTpye)) {
-				cur.setValueType(null);
-			} else {
-				try {
-					BasicDataType dataType = BasicDataType.valueOf(valueTpye);
-					cur.setValueType(dataType.name());
-				} catch (Exception e) {
-					throw new RuntimeException("valueTpye is wrong. valueTpye=" + valueTpye);
-				}
-
-			}
-			cur.setName(cur.getName().trim());
-			cur.setDesc(cur.getDesc().trim());
-			manager.nameIndex.put(cur.getName(), cur);
-			manager.idIndex.put(cur.getId(), cur);
-		}
-
-		return manager;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param name
-	 * @return
-	 */
-	public DynamicEnum getByName(String name) {
-		DynamicEnum dynamicEnum = nameIndex.get(name);
-		if (null != dynamicEnum) {
-			return dynamicEnum;
-		}
-		throw new ExamCloudRuntimeException("动态枚举不存在. name=" + name);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param name
-	 * @return
-	 */
-	public Long getIdByName(String name) {
-		DynamicEnum dynamicEnum = nameIndex.get(name);
-		if (null != dynamicEnum) {
-			return dynamicEnum.getId();
-		}
-		throw new ExamCloudRuntimeException("动态枚举不存在. name=" + name);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param id
-	 * @return
-	 */
-	public DynamicEnum getById(Long id) {
-		DynamicEnum dynamicEnum = idIndex.get(id);
-		if (null != dynamicEnum) {
-			return dynamicEnum;
-		}
-		throw new ExamCloudRuntimeException("动态枚举不存在. id=" + id);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param id
-	 * @return
-	 */
-	public String getNameById(Long id) {
-		DynamicEnum dynamicEnum = idIndex.get(id);
-		if (null != dynamicEnum) {
-			return dynamicEnum.getName();
-		}
-		throw new ExamCloudRuntimeException("动态枚举不存在. id=" + id);
-	}
-
-}

+ 0 - 134
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/FileChangeWatchdog.java

@@ -1,134 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.File;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 文件变更监视器
- *
- * @author WANGWEI
- */
-public abstract class FileChangeWatchdog extends Thread {
-	/**
-	 * 属性注释
-	 */
-	private static final Logger LOG = LoggerFactory.getLogger(FileChangeWatchdog.class);
-
-	/**
-	 * 属性注释
-	 */
-	static final public long DEFAULT_DELAY = 60000;
-
-	/**
-	 * 属性注释
-	 */
-	protected String path;
-
-	/**
-	 * 属性注释
-	 */
-	protected long delay = DEFAULT_DELAY;
-
-	/**
-	 * 属性注释
-	 */
-	protected File file;
-
-	/**
-	 * 属性注释
-	 */
-	protected long lastModif = 0;
-
-	/**
-	 * 属性注释
-	 */
-	protected boolean warnedAlready = false;
-
-	/**
-	 * 属性注释
-	 */
-	protected boolean interrupted = false;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param path
-	 */
-	protected FileChangeWatchdog(String path) {
-		super("FileChangeWatchdog");
-		LOG.info("new a FileChangeWatchdog. path=" + path);
-		this.path = path;
-		file = new File(path);
-		setDaemon(true);
-		checkAndConfigure();
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param delay
-	 */
-	public void setDelay(long delay) {
-		this.delay = delay;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 */
-	abstract protected void doOnChange();
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 */
-	protected void checkAndConfigure() {
-		boolean fileExists;
-		try {
-			fileExists = file.exists();
-		} catch (SecurityException e) {
-			LOG.warn("Was not allowed to read check file existance, file:[" + path + "].");
-			interrupted = true;
-			return;
-		}
-
-		if (fileExists) {
-			long l = file.lastModified();
-
-			if (l > lastModif) {
-				lastModif = l;
-				doOnChange();
-				warnedAlready = false;
-			}
-		} else {
-			if (!warnedAlready) {
-				LOG.debug("[" + path + "] does not exist.");
-				warnedAlready = true;
-			}
-		}
-	}
-
-	/*
-	 * 实现
-	 *
-	 * @author WANGWEI
-	 * 
-	 * @see java.lang.Thread#run()
-	 */
-	@Override
-	public void run() {
-		while (!interrupted) {
-			try {
-				Thread.sleep(delay);
-			} catch (InterruptedException e) {
-				LOG.error("unexpected interruption.", e);
-			}
-			checkAndConfigure();
-		}
-	}
-}

+ 0 - 58
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/FormFilePart.java

@@ -1,58 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.File;
-
-/**
- * 表单文件参数
- *
- * @author WANGWEI
- * @date 2019年5月9日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class FormFilePart {
-
-	private String paramName;
-
-	private String filename;
-
-	private File file;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param paramName
-	 * @param filename
-	 * @param file
-	 */
-	public FormFilePart(String paramName, String filename, File file) {
-		super();
-		this.paramName = paramName;
-		this.filename = filename;
-		this.file = file;
-	}
-
-	public String getParamName() {
-		return paramName;
-	}
-
-	public void setParamName(String paramName) {
-		this.paramName = paramName;
-	}
-
-	public String getFilename() {
-		return filename;
-	}
-
-	public void setFilename(String filename) {
-		this.filename = filename;
-	}
-
-	public File getFile() {
-		return file;
-	}
-
-	public void setFile(File file) {
-		this.file = file;
-	}
-
-}

+ 0 - 44
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/JsonHttpResponseHolder.java

@@ -1,44 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import com.alibaba.fastjson.JSONObject;
-
-/**
- * http json 响应
- *
- * @author WANGWEI
- * @date 2019年9月16日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class JsonHttpResponseHolder {
-
-	private int statusCode;
-
-	private JSONObject respBody;
-
-	public JsonHttpResponseHolder() {
-		super();
-	}
-
-	public JsonHttpResponseHolder(int statusCode, JSONObject respBody) {
-		super();
-		this.statusCode = statusCode;
-		this.respBody = respBody;
-	}
-
-	public int getStatusCode() {
-		return statusCode;
-	}
-
-	public void setStatusCode(int statusCode) {
-		this.statusCode = statusCode;
-	}
-
-	public JSONObject getRespBody() {
-		return respBody;
-	}
-
-	public void setRespBody(JSONObject respBody) {
-		this.respBody = respBody;
-	}
-
-}

+ 0 - 52
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/KeyValuePair.java

@@ -1,52 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.io.Serializable;
-
-import com.alibaba.fastjson.JSONObject;
-
-/**
- * 键值对
- * 
- * @author WANGWEI
- *
- * @param <V>
- */
-public class KeyValuePair<K, V> implements Serializable {
-
-	private static final long serialVersionUID = 5140216132754119367L;
-
-	private K key;
-
-	private V value;
-
-	public KeyValuePair(K key, V value) {
-		super();
-		this.key = key;
-		this.value = value;
-
-	}
-
-	public JSONObject toJsonObject(String keyAlias, String valueAlias) {
-		JSONObject obj = new JSONObject();
-		obj.put(keyAlias, key);
-		obj.put(valueAlias, value);
-		return obj;
-	}
-
-	public K getKey() {
-		return key;
-	}
-
-	public void setKey(K key) {
-		this.key = key;
-	}
-
-	public V getValue() {
-		return value;
-	}
-
-	public void setValue(V value) {
-		this.value = value;
-	}
-
-}

+ 0 - 46
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/ObjectHolder.java

@@ -1,46 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-/**
- * 基本类型对象化
- *
- * @author WANGWEI
- * @date 2019年1月16日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- * @param <T>
- */
-public class ObjectHolder<T> {
-
-	private T t;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param t
-	 */
-	public ObjectHolder(T t) {
-		super();
-		this.t = t;
-	}
-
-	public T get() {
-		return t;
-	}
-
-	public void set(T t) {
-		this.t = t;
-	}
-
-	public boolean isNull() {
-		return null == t;
-	}
-
-	@Override
-	public String toString() {
-		if (isNull()) {
-			return super.toString();
-		} else {
-			return t.toString();
-		}
-	}
-
-}

+ 0 - 98
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/XStreamBuilder.java

@@ -1,98 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers;
-
-import java.util.TimeZone;
-
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.converters.basic.DateConverter;
-import com.thoughtworks.xstream.converters.basic.DoubleConverter;
-import com.thoughtworks.xstream.converters.basic.FloatConverter;
-
-/**
- * 类注释
- *
- * @author WANGWEI
- */
-public class XStreamBuilder {
-
-	/**
-	 * 属性注释
-	 */
-	private XStream xs;
-
-	/**
-	 * 构造函数
-	 *
-	 */
-	private XStreamBuilder() {
-		this.xs = new XStream();
-		XStream.setupDefaultSecurity(this.xs);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public static XStreamBuilder newInstance() {
-		XStreamBuilder builder = new XStreamBuilder();
-		return builder;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param defaultFormat
-	 * @return
-	 */
-	public XStreamBuilder registerDateConverter(final String defaultFormat) {
-		xs.registerConverter(new DateConverter(defaultFormat, null, TimeZone.getTimeZone("GMT+8")));
-		return this;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public XStreamBuilder registerNormalNumberConverter() {
-		xs.registerConverter(new NormalDoubleConverter());
-		xs.registerConverter(new NormalFloatConverter());
-		return this;
-	}
-
-	/**
-	 * 类注释
-	 *
-	 * @author WANGWEI
-	 */
-	private class NormalDoubleConverter extends DoubleConverter {
-		public String toString(Object obj) {
-			return String.valueOf(obj);
-		}
-	}
-
-	/**
-	 * 类注释
-	 *
-	 * @author WANGWEI
-	 */
-	private class NormalFloatConverter extends FloatConverter {
-		public String toString(Object obj) {
-			return String.valueOf(obj);
-		}
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public XStream build() {
-		return xs;
-	}
-
-}

+ 0 - 205
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/ConcurrentTask.java

@@ -1,205 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.concurrency.simple;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-
-import cn.com.qmth.examcloud.commons.util.Util;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 并发任务
- *
- * @author WANGWEI
- * @date 2019年6月19日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class ConcurrentTask<T> {
-
-	private static final Logger LOG = LoggerFactory.getLogger(ConcurrentTask.class);
-
-	private BlockingQueue<T> queue = new LinkedBlockingQueue<T>(10000);
-
-	private BlockingQueue<Integer> workerMessages = new LinkedBlockingQueue<Integer>(10000);
-
-	private final WorkerController workerController = new WorkerController();
-
-	/**
-	 * 最大线程数
-	 */
-	private int maxActiveThreadSize = 5;
-
-	/**
-	 * 不死线程数
-	 */
-	private int minThreadSize = 2;
-
-	private ThreadPoolExecutor threadPoolExecutor;
-
-	/**
-	 * 处理者
-	 */
-	private Worker<T> worker;
-
-	/**
-	 * 巡检周期
-	 */
-	private int inspectionPeriod = 30;
-
-	/**
-	 * 任务名称
-	 */
-	private String taskName;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param taskName
-	 */
-	public ConcurrentTask(String taskName) {
-		super();
-		this.taskName = taskName;
-	}
-
-	/**
-	 * 添加处理元素
-	 *
-	 * @author WANGWEI
-	 * @param e
-	 * @return
-	 */
-	public boolean offerElement(T e) {
-		boolean offer = queue.offer(e);
-		if (LOG.isDebugEnabled()) {
-			LOG.debug("offerElement. result=" + offer + ";element=" + e.toString());
-		}
-		return offer;
-	}
-
-	/**
-	 * 启动任务
-	 *
-	 * @author WANGWEI
-	 */
-	public void start() {
-		threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxActiveThreadSize);
-
-		// 创建不死线程
-		for (int i = 0; i < minThreadSize; i++) {
-			addWorkerThread(true);
-		}
-
-		// 巡检线程
-		Thread inspectionThread = new Thread() {
-
-			@Override
-			public void run() {
-				Util.sleep(inspectionPeriod);
-
-				while (true) {
-
-					int size = queue.size();
-					int activeCount = threadPoolExecutor.getActiveCount();
-					int warnCount = workerController.getWarnCount();
-
-					if (LOG.isInfoEnabled()) {
-						LOG.info("taskName [" + taskName + "]. activeCount = " + activeCount
-								+ "; warnCount = " + warnCount);
-					}
-
-					// 巡检周期内(因并发超出限制导致的)警告数量未超过100时,增加一个worker
-					if (warnCount <= 100) {
-						if (100 < size && maxActiveThreadSize > activeCount) {
-							addWorkerThread(false);
-						}
-					} else {
-						// 巡检周期内(因并发超出限制导致的)警告数量超过100时,减少一个worker
-						workerMessages.offer(warnCount);
-					}
-
-					workerController.resetWarnCount();
-					Util.sleep(inspectionPeriod);
-				}
-
-			};
-
-		};
-
-		inspectionThread.setDaemon(true);
-		inspectionThread.start();
-	}
-
-	/**
-	 * 添加处理线程
-	 *
-	 * @author WANGWEI
-	 * @param immortal
-	 */
-	private void addWorkerThread(final boolean immortal) {
-		LOG.info("create a new worker. immortal=" + immortal);
-		Thread thread = new Thread() {
-
-			long nullTimes = 0;
-
-			@Override
-			public void run() {
-				while (true) {
-					T el = queue.poll();
-					if (null == el) {
-						nullTimes++;
-						if (10 <= nullTimes) {
-							if (immortal) {
-								Util.sleep(2);
-								continue;
-							} else {
-								LOG.info("no element.worker exist.");
-								break;
-							}
-						} else {
-							Util.sleep(2);
-							continue;
-						}
-					} else {
-						nullTimes = 0;
-					}
-
-					try {
-						if (LOG.isDebugEnabled()) {
-							LOG.debug("process. element=" + el.toString());
-						}
-						worker.process(workerController, el);
-					} catch (Exception e) {
-						LOG.error("unexpected exception", e);
-					}
-
-					// 非不死线程在抢到终止消息时,结束线程
-					if (!immortal) {
-						Integer warnCount = workerMessages.poll();
-						if (null != warnCount) {
-							LOG.info("worker exist. warnCount=" + warnCount);
-							break;
-						}
-					}
-
-				}
-			}
-		};
-
-		threadPoolExecutor.execute(thread);
-	}
-
-	public void setMaxActiveThreadSize(int maxActiveThreadSize) {
-		this.maxActiveThreadSize = maxActiveThreadSize;
-	}
-
-	public void setMinThreadSize(int minThreadSize) {
-		this.minThreadSize = minThreadSize;
-	}
-
-	public void setWorker(Worker<T> worker) {
-		this.worker = worker;
-	}
-
-}

+ 0 - 27
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/WorkerController.java

@@ -1,27 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.concurrency.simple;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class WorkerController {
-
-	private static final Logger LOG = LoggerFactory.getLogger(WorkerController.class);
-
-	private AtomicInteger warnCount = new AtomicInteger(0);
-
-	public void addConcurrencyWarn() {
-		LOG.info("warn count ++");
-		this.warnCount.incrementAndGet();
-	}
-
-	public int getWarnCount() {
-		return this.warnCount.get();
-	}
-
-	public void resetWarnCount() {
-		warnCount.set(0);
-	}
-
-}

+ 0 - 43
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Counter.java

@@ -1,43 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.pipeline;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * 输出计数器
- *
- * @author WANGWEI
- * @date 2019年12月12日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class Counter {
-
-	private AtomicLong total = new AtomicLong(0);
-
-	private AtomicLong successAmount = new AtomicLong(0);
-
-	private AtomicLong failureAmount = new AtomicLong(0);
-
-	public long getTotal() {
-		return total.get();
-	}
-
-	public long getSuccessAmount() {
-		return successAmount.get();
-	}
-
-	public long getFailureAmount() {
-		return failureAmount.get();
-	}
-
-	public long incrementTotal() {
-		return this.total.incrementAndGet();
-	}
-
-	public long incrementSuccessAmount() {
-		return this.successAmount.incrementAndGet();
-	}
-
-	public long incrementFailureAmount() {
-		return this.failureAmount.incrementAndGet();
-	}
-}

+ 0 - 59
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Node.java

@@ -1,59 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.pipeline;
-
-/**
- * 节点
- *
- * @author WANGWEI
- * @date 2019年12月12日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public interface Node<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
-
-	/**
-	 * 启动
-	 *
-	 * @author WANGWEI
-	 */
-	void start();
-
-	/**
-	 * 设置下级节点
-	 *
-	 * @author WANGWEI
-	 * @param subNode
-	 */
-	void setLowerNode(Node<KEYOUT, VALUEOUT, ?, ?> lowerNode);
-
-	/**
-	 * 获取下级节点
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	Node<KEYOUT, VALUEOUT, ?, ?> getLowerNode();
-
-	/**
-	 * 获取存储器
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	Storer<KEYIN, VALUEIN> getStorer();
-
-	/**
-	 * 设置是否是首节点
-	 *
-	 * @author WANGWEI
-	 * @param first
-	 */
-	void setFirst(boolean first);
-
-	/**
-	 * 设置循环间隔
-	 *
-	 * @author WANGWEI
-	 * @param sleep
-	 */
-	void setSleep(int sleep);
-
-}

+ 0 - 40
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Storer.java

@@ -1,40 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.pipeline;
-
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import com.google.common.collect.Maps;
-
-/**
- * 节点存储器
- *
- * @author WANGWEI
- * @date 2019年12月12日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class Storer<KEY, VALUE> {
-
-	private Map<KEY, VALUE> MAP = Maps.newConcurrentMap();
-
-	private Map<KEY, VALUE> BUFFER_MAP = Maps.newConcurrentMap();
-
-	public synchronized Set<Entry<KEY, VALUE>> getEntrySet() {
-		MAP.putAll(BUFFER_MAP);
-		BUFFER_MAP.clear();
-		return MAP.entrySet();
-	}
-
-	public synchronized void putElement(KEY key, VALUE value) {
-		BUFFER_MAP.put(key, value);
-	}
-
-	public synchronized boolean isEmpty() {
-		return MAP.isEmpty();
-	}
-
-	public synchronized void remove(KEY key) {
-		MAP.remove(key);
-	}
-
-}

+ 0 - 34
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/TaskContext.java

@@ -1,34 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.pipeline;
-
-import java.io.Serializable;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 任务上下文(任务参数)
- *
- * @author WANGWEI
- * @date 2019年12月12日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class TaskContext implements Serializable {
-	private static final long serialVersionUID = 4979254175922604943L;
-
-	private final Map<String, Object> props = new ConcurrentHashMap<String, Object>();
-
-	public String get(String name) {
-		return get(name, String.class);
-	}
-
-	public <T> T get(String name, Class<T> t) {
-		Object value = props.get(name);
-		@SuppressWarnings("unchecked")
-		T ret = (T) value;
-		return ret;
-	}
-
-	public void put(String name, Object bean) {
-		props.put(name, bean);
-	}
-
-}

+ 0 - 185
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelReader.java

@@ -1,185 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.poi;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.List;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-import com.google.common.collect.Lists;
-
-/**
- * Excel解析器
- *
- * @author WANGWEI
- * @date 2018年3月30日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class ExcelReader {
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param sheet
-	 * @param columSize
-	 * @return
-	 */
-	public static List<String[]> readSheet(Sheet sheet, int columSize) {
-		List<String[]> list = Lists.newArrayList();
-		int firstRowNum = sheet.getFirstRowNum();
-		int lastRowNum = sheet.getLastRowNum();
-		for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) {
-			Row row = sheet.getRow(rowNum);
-			if (row == null) {
-				continue;
-			}
-			String[] cells = new String[columSize];
-
-			for (int index = 0; index < columSize; index++) {
-				Cell cell = row.getCell(index);
-				cells[index] = getCellValue(cell);
-			}
-
-			list.add(cells);
-		}
-
-		return list;
-	}
-
-	/**
-	 * 获取sheet
-	 *
-	 * @author WANGWEI
-	 * @param workbook
-	 * @return
-	 */
-	public static List<Sheet> getSheet(Workbook workbook) {
-
-		List<Sheet> sheets = Lists.newArrayList();
-		for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
-			Sheet sheet = workbook.getSheetAt(sheetNum);
-			sheets.add(sheet);
-		}
-		return sheets;
-	}
-
-	/**
-	 * 获取 Workbook 对象
-	 *
-	 * @author WANGWEI
-	 * @param file
-	 */
-	public static Workbook getWorkBook(File file) {
-
-		Workbook workbook = null;
-		try {
-			// 2007
-			workbook = new XSSFWorkbook(new FileInputStream(file));
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-
-		return workbook;
-	}
-
-	/**
-	 * 获取单元格的字符串值
-	 *
-	 * @author WANGWEI
-	 * @param cell
-	 * @return
-	 */
-	public static String getCellValue(Cell cell) {
-		String value = "";
-		if (null == cell) {
-			return value;
-		}
-		cell.setCellType(CellType.STRING);
-		switch (cell.getCellTypeEnum()) {
-			case _NONE :
-				break;
-			case STRING :
-				value = cell.getStringCellValue();
-				break;
-			case NUMERIC :
-				// 待完善
-				value = String.valueOf(cell.getNumericCellValue());
-				break;
-			case BOOLEAN :
-				value = String.valueOf(cell.getBooleanCellValue());
-				break;
-			case BLANK :
-				value = "";
-				break;
-			default :
-				value = cell.toString();
-		}
-		return value.trim();
-	}
-
-	/**
-	 * 关闭资源
-	 *
-	 * @author WANGWEI
-	 * @param workbook
-	 */
-	public static void close(Workbook workbook) {
-		IOUtils.closeQuietly(workbook);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param filePath
-	 * @param sheetId
-	 * @param columnSize
-	 * @return
-	 */
-	public static List<String[]> readSheetBySax(String filePath, int sheetId, int columnSize) {
-		List<String[]> list = Lists.newArrayList();
-
-		XlsxHandler xlsxHandler = new XlsxHandler(columnSize) {
-			@Override
-			public void optRows(int sheetIndex, int curRow, String[] row) {
-				list.add(row);
-			}
-		};
-
-		try {
-			xlsxHandler.processOneSheet(filePath, sheetId);
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-
-		return list;
-	}
-	
-	public static List<String[]> readSheetBySax(InputStream is, int sheetId, int columnSize) {
-		List<String[]> list = Lists.newArrayList();
-
-		XlsxHandler xlsxHandler = new XlsxHandler(columnSize) {
-			@Override
-			public void optRows(int sheetIndex, int curRow, String[] row) {
-				list.add(row);
-			}
-		};
-
-		try {
-			xlsxHandler.processOneSheet(is, sheetId);
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-
-		return list;
-	}
-
-}

+ 0 - 137
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelWriter.java

@@ -1,137 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.poi;
-
-import java.awt.Color;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.usermodel.XSSFCell;
-import org.apache.poi.xssf.usermodel.XSSFCellStyle;
-import org.apache.poi.xssf.usermodel.XSSFColor;
-import org.apache.poi.xssf.usermodel.XSSFDataFormat;
-import org.apache.poi.xssf.usermodel.XSSFRow;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
-import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
-
-/**
- * Excel 生成器
- *
- * @author WANGWEI
- * @date 2018年9月7日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class ExcelWriter {
-
-	/**
-	 * 写入excel文件
-	 *
-	 * @author WANGWEI
-	 * @param tableHeader
-	 * @param datas
-	 * @param file
-	 */
-	public static void write(String[] tableHeader, Class<?>[] types, List<Object[]> datas,
-			File file) {
-		// 2007
-		XSSFWorkbook workbook = null;
-		FileOutputStream out = null;
-		try {
-			// 2007
-			workbook = new XSSFWorkbook();
-
-			XSSFSheet sheet = workbook.createSheet();
-
-			XSSFCellStyle style = workbook.createCellStyle();
-			style.setFillForegroundColor(new XSSFColor(new Color(227, 239, 217)));
-			style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-
-			XSSFRow firstRow = sheet.createRow(0);
-			for (int i = 0; i < tableHeader.length; i++) {
-				XSSFCell cell = firstRow.createCell(i);
-				cell.setCellStyle(style);
-				cell.setCellType(CellType.STRING);
-				cell.setCellValue(tableHeader[i]);
-			}
-
-			for (int k = 0; k < datas.size(); k++) {
-				XSSFRow nextRow = sheet.createRow(k + 1);
-				Object[] rowDatas = datas.get(k);
-
-				for (int j = 0; j < types.length; j++) {
-					Class<?> type = types[j];
-					Object value = rowDatas[j];
-
-					XSSFCell cell = nextRow.createCell(j);
-
-					if (type.equals(String.class)) {
-						cell.setCellType(CellType.STRING);
-						if (null != value) {
-							cell.setCellValue((String) value);
-						}
-					} else if (type.equals(Long.class)) {
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Long) value);
-						}
-					} else if (type.equals(Integer.class)) {
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Integer) value);
-						}
-					} else if (type.equals(Short.class)) {
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Short) value);
-						}
-					} else if (type.equals(Float.class)) {
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Float) value);
-						}
-					} else if (type.equals(Double.class)) {
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Double) value);
-						}
-					} else if (type.equals(Date.class)) {
-						CellStyle cs = workbook.createCellStyle();
-						XSSFDataFormat format = workbook.createDataFormat();
-						cs.setDataFormat(format.getFormat(DatePatterns.CHINA_DEFAULT));
-						cell.setCellStyle(cs);
-						cell.setCellType(CellType.NUMERIC);
-						if (null != value) {
-							cell.setCellValue((Date) value);
-						}
-					} else if (type.equals(Boolean.class)) {
-						cell.setCellType(CellType.BOOLEAN);
-						if (null != value) {
-							cell.setCellValue((Boolean) value);
-						}
-					} else {
-						IOUtils.closeQuietly(workbook);
-						throw new RuntimeException("cell type is wrong");
-					}
-				}
-			}
-
-			out = FileUtils.openOutputStream(file);
-			workbook.write(out);
-		} catch (RuntimeException e) {
-			throw e;
-		} catch (Throwable e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(out);
-			IOUtils.closeQuietly(workbook);
-		}
-	}
-
-}

+ 0 - 224
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/XlsxHandler.java

@@ -1,224 +0,0 @@
-package cn.com.qmth.examcloud.commons.helpers.poi;
-
-import java.io.InputStream;
-import java.util.Iterator;
-
-import org.apache.commons.compress.utils.IOUtils;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.xssf.eventusermodel.XSSFReader;
-import org.apache.poi.xssf.model.SharedStringsTable;
-import org.apache.poi.xssf.usermodel.XSSFRichTextString;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-/**
- * excel xlsx 文件解析
- *
- * @author WANGWEI
- * @date 2018年8月1日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public abstract class XlsxHandler extends DefaultHandler {
-
-	private String[] row;
-
-	private SharedStringsTable sst;
-
-	private String cellValue;
-
-	private boolean isString;
-
-	private int sheetIndex = -1;
-
-	private int curRow = 0;
-
-	private int curColumnIndex = 0;
-
-	private int columnSize = 0;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param columnSize
-	 */
-	public XlsxHandler(int columnSize) {
-		super();
-		this.columnSize = columnSize;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param sheetIndex
-	 * @param curRow
-	 * @param row
-	 */
-	public abstract void optRows(int sheetIndex, int curRow, String[] row);
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param filePath
-	 * @param sheetId
-	 * @throws Exception
-	 */
-	public void processOneSheet(String filePath, int sheetId) throws Exception {
-		OPCPackage pkg = null;
-		InputStream is = null;
-		try {
-			pkg = OPCPackage.open(filePath);
-			XSSFReader r = new XSSFReader(pkg);
-			SharedStringsTable sst = r.getSharedStringsTable();
-
-			XMLReader parser = XMLReaderFactory.createXMLReader();
-			this.sst = sst;
-			parser.setContentHandler(this);
-			is = r.getSheet("rId" + sheetId);
-			sheetIndex++;
-			InputSource sheetSource = new InputSource(is);
-			parser.parse(sheetSource);
-		} finally {
-			IOUtils.closeQuietly(is);
-			IOUtils.closeQuietly(pkg);
-		}
-	}
-	
-	public void processOneSheet(InputStream is, int sheetId) throws Exception {
-		OPCPackage pkg = null;
-		try {
-			pkg = OPCPackage.open(is);
-			XSSFReader r = new XSSFReader(pkg);
-			SharedStringsTable sst = r.getSharedStringsTable();
-
-			XMLReader parser = XMLReaderFactory.createXMLReader();
-			this.sst = sst;
-			parser.setContentHandler(this);
-			is = r.getSheet("rId" + sheetId);
-			sheetIndex++;
-			InputSource sheetSource = new InputSource(is);
-			parser.parse(sheetSource);
-		} finally {
-			IOUtils.closeQuietly(is);
-			IOUtils.closeQuietly(pkg);
-		}
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param filePath
-	 * @throws Exception
-	 */
-	public void process(String filePath) throws Exception {
-		OPCPackage pkg = null;
-		try {
-			pkg = OPCPackage.open(filePath);
-			XSSFReader r = new XSSFReader(pkg);
-			SharedStringsTable sst = r.getSharedStringsTable();
-
-			XMLReader parser = XMLReaderFactory.createXMLReader();
-			this.sst = sst;
-			parser.setContentHandler(this);
-
-			Iterator<InputStream> sheets = r.getSheetsData();
-			while (sheets.hasNext()) {
-				curRow = 0;
-				sheetIndex++;
-				InputStream sheet = null;
-				try {
-					sheet = sheets.next();
-					InputSource sheetSource = new InputSource(sheet);
-					parser.parse(sheetSource);
-				} finally {
-					IOUtils.closeQuietly(sheet);
-				}
-			}
-		} finally {
-			IOUtils.closeQuietly(pkg);
-		}
-	}
-
-	@Override
-	public void startElement(String uri, String localName, String name, Attributes attributes)
-			throws SAXException {
-		if (name.equals("c")) {
-			String cellType = attributes.getValue("t");
-			String x = attributes.getValue("r");
-			curColumnIndex = this.getColunmIndex(x);
-			if (cellType != null && cellType.equals("s")) {
-				isString = true;
-			} else {
-				isString = false;
-			}
-		}
-		cellValue = "";
-	}
-
-	@Override
-	public void characters(char[] ch, int start, int length) throws SAXException {
-		cellValue += new String(ch, start, length);
-	}
-
-	@Override
-	public void endElement(String uri, String localName, String name) throws SAXException {
-		if (isString) {
-			try {
-				int idx = Integer.parseInt(cellValue);
-				cellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
-			} catch (Exception e) {
-
-			}
-		}
-
-		if (null == row) {
-			row = new String[columnSize];
-		}
-
-		if (name.equals("v")) {
-			String value = cellValue.trim();
-			if (curColumnIndex - 1 < columnSize) {
-				row[curColumnIndex - 1] = value;
-			}
-		} else if (name.equals("row")) {
-			optRows(sheetIndex, curRow, row);
-			row = null;
-			curRow++;
-			curColumnIndex = 0;
-		}
-
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param x
-	 * @return
-	 */
-	private int getColunmIndex(String x) {
-		x = x.replaceAll("[^A-Z]", "");
-		byte[] bytes = x.getBytes();
-		int len = bytes.length;
-		float num = 0;
-		for (int i = 0; i < len; i++) {
-			num += (bytes[i] - 'A' + 1) * Math.pow(26, len - i - 1);
-		}
-		return (int) num;
-	}
-
-	public int getColumnSize() {
-		return columnSize;
-	}
-
-	public void setColumnSize(int columnSize) {
-		this.columnSize = columnSize;
-	}
-
-}

+ 0 - 110
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLog.java

@@ -1,110 +0,0 @@
-package cn.com.qmth.examcloud.commons.logging;
-
-/**
- * 通用日志写入器
- * 
- * @author WANGWEI
- */
-public interface ExamCloudLog {
-
-	/**
-	 * Is the logger instance enabled for the DEBUG level?
-	 *
-	 * @return True if this Logger is enabled for the DEBUG level, false otherwise.
-	 */
-	public boolean isDebugEnabled();
-
-	/**
-	 * Log a message at the DEBUG level.
-	 *
-	 * @param msg
-	 *            the message string to be logged
-	 */
-	public void debug(String msg);
-
-	/**
-	 * Log an exception (throwable) at the DEBUG level with an accompanying message.
-	 *
-	 * @param msg
-	 *            the message accompanying the exception
-	 * @param t
-	 *            the exception (throwable) to log
-	 */
-	public void debug(String msg, Throwable t);
-
-	/**
-	 * Is the logger instance enabled for the INFO level?
-	 *
-	 * @return True if this Logger is enabled for the INFO level, false otherwise.
-	 */
-	public boolean isInfoEnabled();
-
-	/**
-	 * Log a message at the INFO level.
-	 *
-	 * @param msg
-	 *            the message string to be logged
-	 */
-	public void info(String msg);
-
-	/**
-	 * Log an exception (throwable) at the INFO level with an accompanying message.
-	 *
-	 * @param msg
-	 *            the message accompanying the exception
-	 * @param t
-	 *            the exception (throwable) to log
-	 */
-	public void info(String msg, Throwable t);
-
-	/**
-	 * Is the logger instance enabled for the WARN level?
-	 *
-	 * @return True if this Logger is enabled for the WARN level, false otherwise.
-	 */
-	public boolean isWarnEnabled();
-
-	/**
-	 * Log a message at the WARN level.
-	 *
-	 * @param msg
-	 *            the message string to be logged
-	 */
-	public void warn(String msg);
-
-	/**
-	 * Log an exception (throwable) at the WARN level with an accompanying message.
-	 *
-	 * @param msg
-	 *            the message accompanying the exception
-	 * @param t
-	 *            the exception (throwable) to log
-	 */
-	public void warn(String msg, Throwable t);
-
-	/**
-	 * Is the logger instance enabled for the ERROR level?
-	 *
-	 * @return True if this Logger is enabled for the ERROR level, false otherwise.
-	 */
-	public boolean isErrorEnabled();
-
-	/**
-	 * Log a message at the ERROR level.
-	 *
-	 * @param msg
-	 *            the message string to be logged
-	 */
-	public void error(String msg);
-
-	/**
-	 * Log an exception (throwable) at the ERROR level with an accompanying message.
-	 *
-	 * @param msg
-	 *            the message accompanying the exception
-	 * @param t
-	 *            the exception (throwable) to log
-	 */
-	public void error(String msg, Throwable t);
-
-}

+ 0 - 78
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLogFactory.java

@@ -1,78 +0,0 @@
-package cn.com.qmth.examcloud.commons.logging;
-
-import java.lang.reflect.Constructor;
-
-/**
- * 通用日志写入器工厂
- * 
- * @author WANGWEI
- */
-public class ExamCloudLogFactory {
-
-	private static Constructor<?> logConstructor;
-
-	static {
-		tryImplementation("org.slf4j.Logger", SLF4JImpl.class.getName());
-
-		if (logConstructor == null) {
-			try {
-				logConstructor = NoLoggingImpl.class.getConstructor(String.class);
-			} catch (Exception e) {
-				throw new IllegalStateException(e.getMessage(), e);
-			}
-		}
-	}
-
-	/**
-	 * @param testClassName
-	 * @param implClassName
-	 */
-	private static void tryImplementation(String testClassName, String implClassName) {
-		if (logConstructor != null) {
-			return;
-		}
-
-		try {
-			Resources.classForName(testClassName);
-			Class<?> implClass = Resources.classForName(implClassName);
-			logConstructor = implClass.getConstructor(new Class[] { String.class });
-
-			Class<?> declareClass = logConstructor.getDeclaringClass();
-			if (!ExamCloudLog.class.isAssignableFrom(declareClass)) {
-				logConstructor = null;
-			}
-
-			try {
-				if (null != logConstructor) {
-					logConstructor.newInstance(ExamCloudLogFactory.class.getName());
-				}
-			} catch (Throwable t) {
-				logConstructor = null;
-			}
-
-		} catch (Throwable t) {
-			// skip
-		}
-	}
-
-	/**
-	 * @param clazz
-	 * @return
-	 */
-	public static ExamCloudLog getLog(Class<?> clazz) {
-		return getLog(clazz.getName());
-	}
-
-	/**
-	 * @param loggerName
-	 * @return
-	 */
-	public static ExamCloudLog getLog(String loggerName) {
-		try {
-			return (ExamCloudLog) logConstructor.newInstance(loggerName);
-		} catch (Throwable t) {
-			throw new RuntimeException("Error creating logger for logger '" + loggerName + "'.  Cause: " + t, t);
-		}
-	}
-
-}

+ 0 - 70
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/NoLoggingImpl.java

@@ -1,70 +0,0 @@
-package cn.com.qmth.examcloud.commons.logging;
-
-/**
- * no logging
- * 
- * @author WANGWEI
- */
-public class NoLoggingImpl implements ExamCloudLog {
-
-	/**
-	 * 构造函数
-	 * 
-	 * @param loggerName
-	 */
-	public NoLoggingImpl(String loggerName) {
-	}
-
-	@Override
-	public boolean isDebugEnabled() {
-		return false;
-	}
-
-	@Override
-	public void debug(String msg) {
-	}
-
-	@Override
-	public void debug(String msg, Throwable t) {
-	}
-
-	@Override
-	public boolean isInfoEnabled() {
-		return false;
-	}
-
-	@Override
-	public void info(String msg) {
-	}
-
-	@Override
-	public void info(String msg, Throwable t) {
-	}
-
-	@Override
-	public boolean isWarnEnabled() {
-		return false;
-	}
-
-	@Override
-	public void warn(String msg) {
-	}
-
-	@Override
-	public void warn(String msg, Throwable t) {
-	}
-
-	@Override
-	public boolean isErrorEnabled() {
-		return false;
-	}
-
-	@Override
-	public void error(String msg) {
-	}
-
-	@Override
-	public void error(String msg, Throwable t) {
-	}
-
-}

+ 0 - 67
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/Resources.java

@@ -1,67 +0,0 @@
-package cn.com.qmth.examcloud.commons.logging;
-
-/**
- * A class to simplify access to resources through the classloader.
- *
- * @author WANGWEI
- */
-public final class Resources extends Object {
-
-	private static ClassLoader defaultClassLoader;
-
-	/**
-	 * 构造函数
-	 */
-	private Resources() {
-	}
-
-	/**
-	 * Returns the default classloader (may be null).
-	 * 
-	 * @return The default classloader
-	 */
-	public static ClassLoader getDefaultClassLoader() {
-		return defaultClassLoader;
-	}
-
-	/**
-	 * Sets the default classloader
-	 * 
-	 * @param defaultClassLoader
-	 *            - the new default ClassLoader
-	 */
-	public static void setDefaultClassLoader(ClassLoader defaultClassLoader) {
-		Resources.defaultClassLoader = defaultClassLoader;
-	}
-
-	/**
-	 * Loads a class
-	 * 
-	 * @param className
-	 *            - the class to load
-	 * @return The loaded class
-	 * @throws ClassNotFoundException
-	 *             If the class cannot be found (duh!)
-	 */
-	public static Class<?> classForName(String className) throws ClassNotFoundException {
-		Class<?> clazz = null;
-		try {
-			clazz = getClassLoader().loadClass(className);
-		} catch (Exception e) {
-			// Ignore.
-		}
-		if (clazz == null) {
-			clazz = Class.forName(className);
-		}
-		return clazz;
-	}
-
-	private static ClassLoader getClassLoader() {
-		if (defaultClassLoader != null) {
-			return defaultClassLoader;
-		} else {
-			return Thread.currentThread().getContextClassLoader();
-		}
-	}
-
-}

+ 0 - 111
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/logging/SLF4JImpl.java

@@ -1,111 +0,0 @@
-package cn.com.qmth.examcloud.commons.logging;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.spi.LocationAwareLogger;
-
-/**
- * slf4j
- * 
- * @author WANGWEI
- */
-public class SLF4JImpl implements ExamCloudLog {
-
-	/**
-	 * 属性注释
-	 */
-	private static final String callerFQCN = SLF4JImpl.class.getName();
-
-	/**
-	 * 属性注释
-	 */
-	private static final Logger testLogger = LoggerFactory.getLogger(SLF4JImpl.class);
-
-	/**
-	 * 属性注释
-	 */
-	private LocationAwareLogger log;
-
-	static {
-		if (!(testLogger instanceof LocationAwareLogger)) {
-			throw new UnsupportedOperationException(testLogger.getClass() + " is not a suitable logger");
-		}
-	}
-
-	/**
-	 * 构造函数
-	 * 
-	 * @param log
-	 */
-	public SLF4JImpl(LocationAwareLogger log) {
-		this.log = log;
-	}
-
-	/**
-	 * 构造函数
-	 */
-	public SLF4JImpl(String loggerName) {
-		this.log = (LocationAwareLogger) LoggerFactory.getLogger(loggerName);
-	}
-
-	@Override
-	public boolean isDebugEnabled() {
-		return log.isDebugEnabled();
-	}
-
-	@Override
-	public void debug(String msg) {
-		log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, null);
-	}
-
-	@Override
-	public void debug(String msg, Throwable e) {
-		log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e);
-	}
-
-	@Override
-	public boolean isInfoEnabled() {
-		return log.isInfoEnabled();
-	}
-
-	@Override
-	public void info(String msg) {
-		log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null);
-	}
-
-	@Override
-	public void info(String msg, Throwable t) {
-		log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, t);
-	}
-
-	@Override
-	public boolean isWarnEnabled() {
-		return log.isWarnEnabled();
-	}
-
-	@Override
-	public void warn(String msg) {
-		log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, null);
-	}
-
-	@Override
-	public void warn(String msg, Throwable t) {
-		log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, t);
-	}
-
-	@Override
-	public boolean isErrorEnabled() {
-		return log.isErrorEnabled();
-	}
-
-	@Override
-	public void error(String msg) {
-		log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, null);
-	}
-
-	@Override
-	public void error(String msg, Throwable t) {
-		log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, t);
-	}
-
-}

+ 0 - 137
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/AES.java

@@ -1,137 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.security.GeneralSecurityException;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.lang3.StringUtils;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * AES算法<br>
- * CBC(密码块链)模式<br>
- * 警告:每次加解密都要创建一个{@link AES}
- *
- * @author WANGWEI
- * @date 2018年11月21日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class AES {
-
-	private static final Logger LOG = LoggerFactory.getLogger(AES.class);
-
-	private static final String KEY_ALGORITHM = "AES";
-
-	private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
-
-	private static final String DEFAULT_KEY = "7&*5690)%#6#)7!-9*52@*#^&*$%";
-
-	private Cipher encryptCipher = null;
-
-	private Cipher decryptCipher = null;
-
-	public static void main(String[] args) {
-		String s = "";
-		System.out.println(new AES().decrypt(s));
-	}
-
-	/**
-	 * 默认构造方法
-	 * 
-	 */
-	public AES() {
-		this(DEFAULT_KEY);
-	}
-
-	/**
-	 * 指定密钥构造方法
-	 * 
-	 * @param keyStr
-	 *            指定的密钥
-	 */
-	public AES(String keyStr) {
-		try {
-			SecretKey secretKey = getSecretKey(keyStr);
-			keyStr = StringUtils.rightPad(keyStr, 30, (char) 48);
-			final byte[] iv = keyStr.substring(2, 18).getBytes();
-
-			encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
-			decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
-
-			encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
-			decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
-		} catch (GeneralSecurityException e) {
-			LOG.error("fail to new instance of AES.", e);
-		}
-	}
-
-	/**
-	 * 加密
-	 * 
-	 * @param bytes
-	 * @return
-	 */
-	public String encrypt(byte[] bytes) {
-		try {
-			byte[] enc = encryptCipher.doFinal(bytes);
-			return Hex.encodeHexString(enc);
-		} catch (IllegalBlockSizeException e) {
-			throw new ExamCloudRuntimeException(e);
-		} catch (BadPaddingException e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * 加密
-	 * 
-	 * @param str
-	 * @return
-	 */
-	public String encrypt(String str) {
-		return encrypt(str.getBytes());
-	}
-
-	/**
-	 * 解密
-	 * 
-	 * @param str
-	 * @return
-	 */
-	public String decrypt(String str) {
-		try {
-			byte[] dec = decryptCipher.doFinal(Hex.decodeHex(str));
-			return new String(dec);
-		} catch (IllegalBlockSizeException e) {
-			throw new ExamCloudRuntimeException(e);
-		} catch (BadPaddingException e) {
-			throw new ExamCloudRuntimeException(e);
-		} catch (DecoderException e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * @param key
-	 * @return
-	 */
-	private SecretKey getSecretKey(String key) {
-		byte[] bytes = key.getBytes();
-		byte[] target = new byte[16];
-
-		int length = bytes.length;
-		System.arraycopy(bytes, 0, target, 0, length < 16 ? length : 16);
-		return new SecretKeySpec(target, KEY_ALGORITHM);
-	}
-
-}

+ 0 - 89
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/AsciiUtil.java

@@ -1,89 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-/**
- * Ascii转换
- *
- * @author WANGWEI
- * @date 2018年12月3日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class AsciiUtil {
-
-	private static String PREFIX = "\\u";
-
-	/**
-	 * native to ASCII
-	 *
-	 * @author WANGWEI
-	 * @param str
-	 * @return
-	 */
-	public static String native2Ascii(String str) {
-		char[] chars = str.toCharArray();
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < chars.length; i++) {
-			sb.append(char2Ascii(chars[i]));
-		}
-		return sb.toString();
-	}
-
-	private static String char2Ascii(char c) {
-		if (c > 255) {
-			StringBuilder sb = new StringBuilder();
-			sb.append(PREFIX);
-			int code = (c >> 8);
-			String tmp = Integer.toHexString(code);
-			if (tmp.length() == 1) {
-				sb.append("0");
-			}
-			sb.append(tmp);
-			code = (c & 0xFF);
-			tmp = Integer.toHexString(code);
-			if (tmp.length() == 1) {
-				sb.append("0");
-			}
-			sb.append(tmp);
-			return sb.toString();
-		} else {
-			return Character.toString(c);
-		}
-	}
-
-	/**
-	 * ASCII to native
-	 *
-	 * @author WANGWEI
-	 * @param str
-	 * @return
-	 */
-	public static String ascii2Native(String str) {
-		StringBuilder sb = new StringBuilder();
-		int begin = 0;
-		int index = str.indexOf(PREFIX);
-		while (index != -1) {
-			sb.append(str.substring(begin, index));
-			sb.append(ascii2Char(str.substring(index, index + 6)));
-			begin = index + 6;
-			index = str.indexOf(PREFIX, begin);
-		}
-		sb.append(str.substring(begin));
-		return sb.toString();
-	}
-
-	private static char ascii2Char(String str) {
-		if (str.length() != 6) {
-			throw new IllegalArgumentException(
-					"Ascii string of a native character must be 6 character.");
-		}
-		if (!PREFIX.equals(str.substring(0, 2))) {
-			throw new IllegalArgumentException(
-					"Ascii string of a native character must start with \"\\u\".");
-		}
-		String tmp = str.substring(2, 4);
-		int code = Integer.parseInt(tmp, 16) << 8;
-		tmp = str.substring(4, 6);
-		code += Integer.parseInt(tmp, 16);
-		return (char) code;
-	}
-
-}

+ 0 - 54
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/BooleanUtil.java

@@ -1,54 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import org.apache.commons.lang3.BooleanUtils;
-
-/**
- * boolean 工具
- *
- * @author WANGWEI
- * @date 2019年10月21日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class BooleanUtil {
-
-	/**
-	 * 统计true的数量
-	 *
-	 * @author WANGWEI
-	 * @param values
-	 * @return
-	 */
-	public static int countTrue(boolean... values) {
-		if (null == values) {
-			return 0;
-		}
-		int count = 0;
-		for (boolean b : values) {
-			if (BooleanUtils.isTrue(b)) {
-				count++;
-			}
-		}
-		return count;
-	}
-
-	/**
-	 * 统计false的数量
-	 *
-	 * @author WANGWEI
-	 * @param values
-	 * @return
-	 */
-	public static int countFalse(boolean... values) {
-		if (null == values) {
-			return 0;
-		}
-		int count = 0;
-		for (boolean b : values) {
-			if (BooleanUtils.isFalse(b)) {
-				count++;
-			}
-		}
-		return count;
-	}
-
-}

+ 0 - 116
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ByteUtil.java

@@ -1,116 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-
-/**
- * 字节转换工具
- *
- * @author WANGWEI
- * @date 2018年4月27日
- */
-public class ByteUtil {
-	public final static short UNSIGNED_MAX_VALUE = (Byte.MAX_VALUE * 2) + 1;
-
-	private ByteUtil() {
-	}
-
-	public static int unsignedPromote(byte b) {
-		return b & 0xff;
-	}
-
-	public static String toHexAscii(byte b) {
-		StringWriter sw = new StringWriter(2);
-		addHexAscii(b, sw);
-		return sw.toString();
-	}
-
-	public static String toLowercaseHexAscii(byte b) {
-		StringWriter sw = new StringWriter(2);
-		addLowercaseHexAscii(b, sw);
-		return sw.toString();
-	}
-
-	public static String toHexAscii(byte[] bytes) {
-		int len = bytes.length;
-		StringWriter sw = new StringWriter(len * 2);
-		for (int i = 0; i < len; ++i)
-			addHexAscii(bytes[i], sw);
-		return sw.toString();
-	}
-
-	public static String toLowercaseHexAscii(byte[] bytes) {
-		int len = bytes.length;
-		StringWriter sw = new StringWriter(len * 2);
-		for (int i = 0; i < len; ++i)
-			addLowercaseHexAscii(bytes[i], sw);
-		return sw.toString();
-	}
-
-	public static byte[] fromHexAscii(String s) throws NumberFormatException {
-		try {
-			int len = s.length();
-			if ((len % 2) != 0)
-				throw new NumberFormatException("Hex ascii must be exactly two digits per byte.");
-
-			int out_len = len / 2;
-			byte[] out = new byte[out_len];
-			int i = 0;
-			StringReader sr = new StringReader(s);
-			while (i < out_len) {
-				int val = (16 * fromHexDigit(sr.read())) + fromHexDigit(sr.read());
-				out[i++] = (byte) val;
-			}
-			return out;
-		} catch (IOException e) {
-			throw new InternalError("IOException reading from StringReader?!?!");
-		}
-	}
-
-	static void addHexAscii(byte b, StringWriter sw) {
-		int ub = unsignedPromote(b);
-		int h1 = ub / 16;
-		int h2 = ub % 16;
-		sw.write(toHexDigit(h1));
-		sw.write(toHexDigit(h2));
-	}
-
-	static void addLowercaseHexAscii(byte b, StringWriter sw) {
-		int ub = unsignedPromote(b);
-		int h1 = ub / 16;
-		int h2 = ub % 16;
-		sw.write(toLowercaseHexDigit(h1));
-		sw.write(toLowercaseHexDigit(h2));
-	}
-
-	private static int fromHexDigit(int c) throws NumberFormatException {
-		if (c >= 0x30 && c < 0x3A)
-			return c - 0x30;
-		else if (c >= 0x41 && c < 0x47)
-			return c - 0x37;
-		else if (c >= 0x61 && c < 0x67)
-			return c - 0x57;
-		else
-			throw new NumberFormatException('\'' + c + "' is not a valid hexadecimal digit.");
-	}
-
-	private static char toHexDigit(int h) {
-		char out;
-		if (h <= 9)
-			out = (char) (h + 0x30);
-		else
-			out = (char) (h + 0x37);
-		return out;
-	}
-
-	private static char toLowercaseHexDigit(int h) {
-		char out;
-		if (h <= 9)
-			out = (char) (h + 0x30);
-		else
-			out = (char) (h + 0x57);
-		return out;
-	}
-
-}

+ 0 - 212
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/DateUtil.java

@@ -1,212 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.math.BigDecimal;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-
-/**
- * 日期工具
- * 
- * @author WANGWEI
- */
-public class DateUtil {
-
-	/**
-	 * patterns describing the date and time format
-	 *
-	 * @author WANGWEI
-	 */
-	public interface DatePatterns {
-
-		public static final String DEFAULT = "yyyyMMddHHmmss";
-
-		public static final String YYYY = "yyyy";
-
-		public static final String YYYYMM = "yyyyMM";
-
-		public static final String YYYYMMDD = "yyyyMMdd";
-
-		public static final String YYYYMMDDHH = "yyyyMMddHH";
-
-		public static final String YYYYMMDDHHMM = "yyyyMMddHHmm";
-
-		public static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
-
-		public static final String CHINA_DEFAULT = "yyyy-MM-dd HH:mm:ss";
-
-		public static final String YYYY_MM = "yyyy-MM";
-
-		public static final String YYYY_MM_DD = "yyyy-MM-dd";
-
-		public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
-
-		public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
-	}
-
-	/**
-	 * get now date.
-	 * 
-	 * @param pattern
-	 * @return
-	 */
-	public static String now(String pattern) {
-		return format(new Date(), pattern);
-	}
-
-	/**
-	 * get now china date.
-	 * 
-	 * @return
-	 */
-	public static String chinaNow() {
-		return format(new Date(), DatePatterns.CHINA_DEFAULT);
-	}
-
-	/**
-	 * format date.
-	 * 
-	 * @param date
-	 * @param pattern
-	 * @return
-	 */
-	public static String format(Date date, String pattern) {
-		try {
-			SimpleDateFormat df = new SimpleDateFormat(pattern);
-			return df.format(date);
-		} catch (Exception e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * format now date.
-	 *
-	 * @author WANGWEI
-	 * @param pattern
-	 * @return
-	 */
-	public static String formatNow(String pattern) {
-		try {
-			SimpleDateFormat df = new SimpleDateFormat(pattern);
-			return df.format(new Date());
-		} catch (Exception e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * parse date.
-	 * 
-	 * @param source
-	 * @param pattern
-	 * @return
-	 */
-	public static Date parse(String source, String pattern) {
-		SimpleDateFormat df = new SimpleDateFormat(pattern);
-		try {
-			return df.parse(source);
-		} catch (ParseException e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * parse date randomly.
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static Date parseRandomly(String s) {
-		if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
-			return parse(s, "yyyy/MM/dd HH:mm:ss");
-		} else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
-			return parse(s, "yyyy/MM/dd HH:mm");
-		} else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
-			return parse(s, "yyyy/MM/dd");
-		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
-			return parse(s, "yyyy-MM-dd HH:mm:ss");
-		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
-			return parse(s, "yyyy-MM-dd HH:mm");
-		} else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
-			return parse(s, "yyyy-MM-dd");
-		} else {
-			throw new ExamCloudRuntimeException("unsupported date string.");
-		}
-	}
-
-	/**
-	 * 解析excel日期
-	 *
-	 * @author WANGWEI
-	 * @param number
-	 * @return
-	 */
-	public static Date parseExcel(String number) {
-
-		BigDecimal bd = new BigDecimal(number);
-		int days = bd.intValue();
-		int mills = (int) Math.round(bd.subtract(new BigDecimal(days)).doubleValue() * 24 * 3600);
-
-		Calendar c = Calendar.getInstance();
-		c.set(1900, 0, 1);
-		c.add(Calendar.DATE, days - 2);
-		int hour = mills / 3600;
-		int minute = (mills - hour * 3600) / 60;
-		int second = mills - hour * 3600 - minute * 60;
-		c.set(Calendar.HOUR_OF_DAY, hour);
-		c.set(Calendar.MINUTE, minute);
-		c.set(Calendar.SECOND, second);
-
-		Date date = c.getTime();
-
-		return date;
-	}
-
-	/**
-	 * 是否同一天
-	 *
-	 * @author WANGWEI
-	 * @param date1
-	 * @param date2
-	 * @return
-	 */
-	public static boolean isSameDay(Date date1, Date date2) {
-		if (null == date1) {
-			throw new ExamCloudRuntimeException("first argument must not be null");
-		}
-		if (null == date2) {
-			throw new ExamCloudRuntimeException("second argument must not be null");
-		}
-
-		Calendar cal1 = Calendar.getInstance();
-		cal1.setTime(date1);
-		Calendar cal2 = Calendar.getInstance();
-		cal2.setTime(date2);
-		return isSameDay(cal1, cal2);
-	}
-
-	/**
-	 * 是否同一天
-	 *
-	 * @author WANGWEI
-	 * @param calendar1
-	 * @param calendar2
-	 * @return
-	 */
-	public static boolean isSameDay(Calendar calendar1, Calendar calendar2) {
-		if (null == calendar1) {
-			throw new ExamCloudRuntimeException("first argument must not be null");
-		}
-		if (null == calendar2) {
-			throw new ExamCloudRuntimeException("second argument must not be null");
-		}
-		return calendar1.get(0) == calendar2.get(0) && calendar1.get(1) == calendar2.get(1)
-				&& calendar1.get(6) == calendar2.get(6);
-	}
-
-}

+ 0 - 63
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/FreeMarkerUtil.java

@@ -1,63 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Locale;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-
-/**
- * FreeMarker 工具
- *
- * @author WANGWEI
- * @date 2018年11月21日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class FreeMarkerUtil {
-
-	private static final String ENCODING = "UTF-8";
-
-	private static Configuration configuration;
-
-	static {
-		configuration = new Configuration(Configuration.VERSION_2_3_23);
-		configuration.setEncoding(Locale.US, ENCODING);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param template
-	 * @param dataModel
-	 * @return
-	 */
-	public static String process(String template, Object dataModel) {
-		return process("$$$$$", template, dataModel);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param name
-	 * @param template
-	 * @param dataModel
-	 * @return
-	 */
-	public static String process(String name, String template, Object dataModel) {
-		StringWriter result = null;
-		try {
-			result = new StringWriter();
-			Template t = new Template(name, new StringReader(template), configuration);
-			t.process(dataModel, result);
-
-			return result.toString();
-		} catch (Exception e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-}

+ 0 - 176
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/HttpClientUtil.java

@@ -1,176 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.InputStream;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.config.CookieSpecs;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.util.EntityUtils;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-
-import cn.com.qmth.examcloud.commons.helpers.JsonHttpResponseHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * httpclient
- *
- * @author WANGWEI
- * @date 2019年9月17日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class HttpClientUtil {
-
-	private static final Logger LOG = LoggerFactory.getLogger(HttpClientUtil.class);
-
-	private static CloseableHttpClient httpclient;
-
-	private static RequestConfig requestConfig;
-
-	static {
-		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(60,
-				TimeUnit.SECONDS);
-		cm.setValidateAfterInactivity(1000);
-		cm.setMaxTotal(8000);
-		cm.setDefaultMaxPerRoute(200);
-
-		requestConfig = RequestConfig.custom().setConnectionRequestTimeout(500)
-				.setSocketTimeout(10000).setConnectTimeout(10000)
-				.setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
-
-		httpclient = HttpClients.custom().setConnectionManager(cm).disableAutomaticRetries()
-				.setDefaultRequestConfig(requestConfig).build();
-
-	}
-
-	public static CloseableHttpClient getHttpClient() {
-		return httpclient;
-	}
-
-	public static HttpPost buildHttpPost(String url) {
-		HttpPost httpPost = new HttpPost(url);
-		httpPost.setConfig(requestConfig);
-
-		return httpPost;
-	}
-
-	public static HttpPut buildHttpPut(String url) {
-		HttpPut httpPut = new HttpPut(url);
-		httpPut.setConfig(requestConfig);
-
-		return httpPut;
-	}
-
-	public static HttpGet buildHttpGet(String url) {
-		HttpGet httpGet = new HttpGet(url);
-		httpGet.setConfig(requestConfig);
-
-		return httpGet;
-	}
-
-	public static JsonHttpResponseHolder execute(final HttpUriRequest request) {
-
-		CloseableHttpResponse response = null;
-		JsonHttpResponseHolder responseHolder = null;
-		long s = System.currentTimeMillis();
-		try {
-
-			response = httpclient.execute(request);
-			int statusCode = response.getStatusLine().getStatusCode();
-			String entityStr = EntityUtils.toString(response.getEntity(), "UTF-8");
-			JSONObject obj = JSON.parseObject(entityStr);
-			responseHolder = new JsonHttpResponseHolder(statusCode, obj);
-
-			if (HttpStatus.SC_OK != responseHolder.getStatusCode()) {
-				LOG.error("[HTTP-FAIL]. statusCode=" + statusCode + "; responseEntity="
-						+ entityStr + "; uri=" + request.getURI());
-			} else {
-				if (LOG.isDebugEnabled()) {
-					LOG.debug("[HTTP-OK]. statusCode=" + statusCode + "; responseEntity="
-							+ entityStr + "; uri=" + request.getURI());
-				}
-			}
-
-		} catch (Exception e) {
-			LOG.error("[HTTP-ERROR]. uri=" + request.getURI(), e);
-		} finally {
-			IOUtils.closeQuietly(response);
-			LOG.debug("[HTTP-COST]. cost = " + (System.currentTimeMillis() - s) + " ms; uri="
-					+ request.getURI());
-		}
-		return responseHolder;
-	}
-
-	/**
-	 * 关闭流
-	 *
-	 * @author WANGWEI
-	 * @param resp
-	 */
-	public static void close(CloseableHttpResponse resp) {
-		if (null != resp) {
-			try {
-				EntityUtils.consumeQuietly(resp.getEntity());
-				resp.close();
-			} catch (Exception e) {
-				LOG.error("fail to close http response stream.", e);
-			}
-		}
-	}
-
-	/**
-	 * GET 请求
-	 *
-	 * @author WANGWEI
-	 * @param url
-	 * @return
-	 */
-	public static byte[] get(String url) {
-		return get(url, 1048576L);
-	}
-
-	/**
-	 * GET 请求
-	 *
-	 * @author WANGWEI
-	 * @param url
-	 * @param maxByteSize
-	 * @return
-	 */
-	public static byte[] get(String url, long maxByteSize) {
-
-		CloseableHttpClient httpclient = HttpClientBuilder.create().build();
-
-		HttpGet get = new HttpGet(url);
-		get.setConfig(RequestConfig.custom().setConnectTimeout(10000).build());
-
-		CloseableHttpResponse response = null;
-		try {
-			response = httpclient.execute(get);
-			InputStream in = response.getEntity().getContent();
-
-			byte[] byteArray = IOUtil.toLimitedByteArray(in, maxByteSize);
-			return byteArray;
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		} finally {
-			close(response);
-			IOUtils.closeQuietly(httpclient);
-		}
-
-	}
-
-}

+ 0 - 115
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/HttpMethod.java

@@ -1,115 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * HTTP method
- *
- * @author WANGWEI
- * @date 2019年4月10日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class HttpMethod {
-
-	public static final HttpMethod OPTIONS = new HttpMethod("OPTIONS");
-
-	public static final HttpMethod GET = new HttpMethod("GET");
-
-	public static final HttpMethod HEAD = new HttpMethod("HEAD");
-
-	public static final HttpMethod POST = new HttpMethod("POST");
-
-	public static final HttpMethod PUT = new HttpMethod("PUT");
-
-	public static final HttpMethod PATCH = new HttpMethod("PATCH");
-
-	public static final HttpMethod DELETE = new HttpMethod("DELETE");
-
-	public static final HttpMethod TRACE = new HttpMethod("TRACE");
-
-	public static final HttpMethod CONNECT = new HttpMethod("CONNECT");
-
-	private static final Map<String, HttpMethod> METHOD_MAP = new HashMap<String, HttpMethod>();
-
-	static {
-		METHOD_MAP.put(OPTIONS.toString(), OPTIONS);
-		METHOD_MAP.put(GET.toString(), GET);
-		METHOD_MAP.put(HEAD.toString(), HEAD);
-		METHOD_MAP.put(POST.toString(), POST);
-		METHOD_MAP.put(PUT.toString(), PUT);
-		METHOD_MAP.put(PATCH.toString(), PATCH);
-		METHOD_MAP.put(DELETE.toString(), DELETE);
-		METHOD_MAP.put(TRACE.toString(), TRACE);
-		METHOD_MAP.put(CONNECT.toString(), CONNECT);
-	}
-
-	private final String name;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param name
-	 */
-	private HttpMethod(String name) {
-		if (name == null) {
-			throw new NullPointerException("name");
-		}
-
-		name = name.trim();
-		if (name.length() == 0) {
-			throw new IllegalArgumentException("empty name");
-		}
-
-		for (int i = 0; i < name.length(); i++) {
-			if (Character.isISOControl(name.charAt(i)) || Character.isWhitespace(name.charAt(i))) {
-				throw new IllegalArgumentException("invalid character in name");
-			}
-		}
-
-		this.name = name;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public static HttpMethod valueOf(String name) {
-		if (name == null) {
-			throw new NullPointerException("name");
-		}
-
-		name = name.trim();
-		if (name.length() == 0) {
-			throw new IllegalArgumentException("empty name");
-		}
-
-		HttpMethod result = METHOD_MAP.get(name);
-		if (result != null) {
-			return result;
-		} else {
-			throw new IllegalArgumentException("undefined name");
-		}
-	}
-
-	@Override
-	public int hashCode() {
-		return getName().hashCode();
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (!(o instanceof HttpMethod)) {
-			return false;
-		}
-
-		HttpMethod that = (HttpMethod) o;
-		return getName().equals(that.getName());
-	}
-
-	@Override
-	public String toString() {
-		return getName();
-	}
-
-}

+ 0 - 105
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/IOUtil.java

@@ -1,105 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-
-/**
- * IO
- *
- * @author WANGWEI
- * @date 2018年6月29日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class IOUtil {
-
-	/**
-	 * 文件转字节数组
-	 *
-	 * @author WANGWEI
-	 * @param file
-	 * @return
-	 */
-	public static byte[] toByteArray(File file) {
-		FileInputStream is = null;
-		try {
-			is = new FileInputStream(file);
-			byte[] byteArray = IOUtils.toByteArray(is);
-			return byteArray;
-		} catch (FileNotFoundException e) {
-			throw new RuntimeException(e);
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(is);
-		}
-	}
-
-	/**
-	 * 字节数组转文件
-	 *
-	 * @author WANGWEI
-	 * @param bfile
-	 * @param filePath
-	 */
-	public static void toFile(byte[] bfile, String filePath) {
-		BufferedOutputStream bos = null;
-		FileOutputStream fos = null;
-		try {
-			File file = new File(filePath);
-			FileUtils.forceMkdir(file.getParentFile());
-			fos = new FileOutputStream(file);
-			bos = new BufferedOutputStream(fos);
-			bos.write(bfile);
-		} catch (Exception e) {
-			throw new RuntimeException("", e);
-		} finally {
-			IOUtils.closeQuietly(bos);
-			IOUtils.closeQuietly(fos);
-		}
-	}
-
-	/**
-	 * 输入流转换为限制大小的字节
-	 *
-	 * @author WANGWEI
-	 * @param in
-	 * @param maxByteSize
-	 * @return
-	 */
-	public static byte[] toLimitedByteArray(InputStream in, long maxByteSize) {
-		ByteArrayOutputStream out = null;
-		int bufferSize = 1024 * 4;
-		int totalSize = 0;
-		byte[] buffer = new byte[bufferSize];
-		try {
-			out = new ByteArrayOutputStream();
-			int n = 0;
-			while ((n = in.read(buffer)) != -1) {
-				out.write(buffer, 0, n);
-				totalSize += n;
-
-				if (maxByteSize < totalSize) {
-					throw new RuntimeException("文件大小超过" + (maxByteSize / 1024) + "KB限制");
-				}
-			}
-			return out.toByteArray();
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		} catch (RuntimeException e) {
-			throw e;
-		} finally {
-			IOUtils.closeQuietly(out);
-			IOUtils.closeQuietly(in);
-		}
-	}
-
-}

+ 0 - 171
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/JsonUtil.java

@@ -1,171 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.lang.reflect.Type;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import com.google.common.collect.Maps;
-import com.google.gson.ExclusionStrategy;
-import com.google.gson.FieldAttributes;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-
-import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
-
-/**
- * json tool
- *
- * @author WANGWEI
- * @param <T>
- * @date 2019年1月16日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class JsonUtil {
-
-	/**
-	 * to json
-	 *
-	 * @author WANGWEI
-	 * @param obj
-	 * @return
-	 */
-	public static String toJson(Object obj) {
-		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
-				.setDateFormat(DatePatterns.CHINA_DEFAULT);
-		return builder.create().toJson(obj);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param obj
-	 * @param excludeFields
-	 * @return
-	 */
-	public static String toJson(Object obj, String... excludeFields) {
-		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
-				.setDateFormat(DatePatterns.CHINA_DEFAULT);
-
-		builder.setExclusionStrategies(new ExclusionStrategy() {
-			@Override
-			public boolean shouldSkipField(FieldAttributes f) {
-				for (String field : excludeFields) {
-					if (f.getName().matches(field)) {
-						return true;
-					}
-				}
-
-				return false;
-			}
-
-			@Override
-			public boolean shouldSkipClass(Class<?> clazz) {
-				return false;
-			}
-		});
-
-		return builder.create().toJson(obj);
-	}
-
-	/**
-	 * to pretty json
-	 *
-	 * @author WANGWEI
-	 * @param obj
-	 * @return
-	 */
-	public static String toPrettyJson(Object obj) {
-		GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
-				.serializeNulls().setDateFormat(DatePatterns.CHINA_DEFAULT);
-		return builder.create().toJson(obj);
-	}
-
-	/**
-	 * 格式化json
-	 *
-	 * @author WANGWEI
-	 * @param json
-	 * @return
-	 */
-	public static String format(String json) {
-		if (null == json) {
-			return json;
-		}
-		JsonElement jsonEl = JsonParser.parseString(json);
-		return toPrettyJson(jsonEl);
-	}
-
-	/**
-	 * json转对象
-	 *
-	 * @author WANGWEI
-	 * @param json
-	 * @param c
-	 * @return
-	 */
-	public static <T> T fromJson(String json, Class<T> c) {
-		Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
-				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
-		return gson.fromJson(json, c);
-	}
-
-	/**
-	 * json数组转list
-	 *
-	 * @author WANGWEI
-	 * @param json
-	 * @param elementType
-	 * @return
-	 */
-	public static <T> List<T> fromJsonArray(String json, Class<T[]> elementType) {
-		Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
-				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
-		T[] array = gson.fromJson(json, elementType);
-		return Arrays.asList(array);
-	}
-
-	/**
-	 * simple json to map
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static Map<String, String> json2Map(String s) {
-		JsonElement jsonElement = JsonParser.parseString(s);
-		JsonObject jsonObject = jsonElement.getAsJsonObject();
-		Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
-
-		Map<String, String> map = Maps.newHashMap();
-		for (Entry<String, JsonElement> entry : entrySet) {
-			JsonElement e = entry.getValue();
-			if (!e.isJsonNull()) {
-				String v = e.getAsString();
-				map.put(entry.getKey(), v);
-			}
-		}
-		return map;
-	}
-
-	/**
-	 * json转对象
-	 *
-	 * @author WANGWEI
-	 * @param json
-	 * @param type
-	 * @return
-	 */
-	public static <T> T fromJson(String json, Type type) {
-		Gson gson = new GsonBuilder().disableHtmlEscaping()
-				.setDateFormat(DatePatterns.CHINA_DEFAULT).create();
-		return gson.fromJson(json, type);
-	}
-
-}

+ 0 - 59
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/MD5.java

@@ -1,59 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.File;
-import java.io.FileInputStream;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.IOUtils;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-
-/**
- * 类注释
- *
- * @author WANGWEI
- */
-public class MD5 {
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param str
-	 * @return
-	 */
-	public static String encrypt32(String str) {
-		return DigestUtils.md5Hex(str);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param str
-	 * @return
-	 */
-	public static String encrypt16(String str) {
-		return DigestUtils.md5Hex(str).substring(8, 24);
-	}
-
-	/**
-	 * 文件md5
-	 *
-	 * @author WANGWEI
-	 * @param file
-	 * @return
-	 */
-	public static String md5Hex(File file) {
-		FileInputStream in = null;
-		try {
-			in = new FileInputStream(file);
-			return DigestUtils.md5Hex(in);
-		} catch (Exception e) {
-			throw new ExamCloudRuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(in);
-		}
-	}
-
-}

+ 0 - 46
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/MapUtil.java

@@ -1,46 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.util.Comparator;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * map 工具
- *
- * @author WANGWEI
- * @date 2019年5月15日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class MapUtil {
-
-	/**
-	 * map按key排序
-	 *
-	 * @author WANGWEI
-	 * @param map
-	 * @param asc
-	 *            升序
-	 * @return
-	 */
-	public static <T> Map<String, T> sortMapByKey(Map<String, T> map, boolean asc) {
-		if (map == null) {
-			return null;
-		}
-		Map<String, T> sortMap = new TreeMap<String, T>(new Comparator<String>() {
-
-			@Override
-			public int compare(String o1, String o2) {
-
-				if (asc) {
-					return ((String) o1).compareTo((String) o2);
-				} else {
-					return ((String) o2).compareTo((String) o1);
-				}
-			}
-		});
-
-		sortMap.putAll(map);
-		return sortMap;
-	}
-
-}

+ 0 - 69
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ObjectUtil.java

@@ -1,69 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Map;
-
-/**
- * 对象工具
- *
- * @author WANGWEI
- */
-public final class ObjectUtil {
-
-	/**
-	 * 判断对象或对象数组中每一个对象是否为空: 对象为null,字符序列长度为0,集合类、Map为empty
-	 *
-	 * @author WANGWEI
-	 * @param obj
-	 * @return
-	 */
-	public static boolean isNullOrEmpty(Object obj) {
-		if (obj == null)
-			return true;
-
-		if (obj instanceof CharSequence)
-			return ((CharSequence) obj).length() == 0;
-
-		if (obj instanceof Collection)
-			return ((Collection<?>) obj).isEmpty();
-
-		if (obj instanceof Map)
-			return ((Map<?, ?>) obj).isEmpty();
-
-		if (obj instanceof Object[]) {
-			Object[] object = (Object[]) obj;
-			if (object.length == 0) {
-				return true;
-			}
-			boolean empty = true;
-			for (int i = 0; i < object.length; i++) {
-				if (!isNullOrEmpty(object[i])) {
-					empty = false;
-					break;
-				}
-			}
-			return empty;
-		}
-		return false;
-	}
-
-	/**
-	 * 判断一个类是否为基本数据类型
-	 *
-	 * @author WANGWEI
-	 * @param clazz
-	 * @return
-	 */
-	public static boolean isBaseDataType(Class<?> clazz) {
-		Boolean isBaseType = (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)
-				|| clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
-				|| clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
-				|| clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
-				|| clazz.isPrimitive());
-		return isBaseType;
-	}
-
-}

+ 0 - 180
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/PathUtil.java

@@ -1,180 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLDecoder;
-
-/**
- * 路径工具
- *
- * @author WANGWEI
- */
-public class PathUtil {
-
-	/**
-	 * 获取标准路径
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String getCanonicalPath(String path) {
-		path = path.replaceAll("\\\\+", "/");
-		path = path.replaceAll("/+", "/");
-		return path;
-	}
-
-	/**
-	 * 以"/"开头
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String startsWithSeparator(String path) {
-		path = getCanonicalPath(path);
-		if (path.startsWith("/")) {
-			return path;
-		}
-		return "/" + path;
-	}
-
-	/**
-	 * 不以"/"开头
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String startsWithoutSeparator(String path) {
-		path = getCanonicalPath(path);
-		if (path.startsWith("/")) {
-			return path.substring(1);
-		}
-		return path;
-	}
-
-	/**
-	 * 以"/"结尾
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String endsWithSeparator(String path) {
-		path = getCanonicalPath(path);
-		if (path.endsWith("/")) {
-			return path;
-		}
-		return path + "/";
-	}
-
-	/**
-	 * 不以"/"结尾
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String endsWithoutSeparator(String path) {
-		path = getCanonicalPath(path);
-		if (path.endsWith("/")) {
-			return path.substring(0, path.length() - 1);
-		}
-		return path;
-	}
-
-	/**
-	 * 获取路径
-	 *
-	 * @author WANGWEI
-	 * @param file
-	 * @return
-	 */
-	public static String getCanonicalPath(File file) {
-		try {
-			return file.getCanonicalPath();
-		} catch (IOException e) {
-			throw new RuntimeException("Fail to get canonical path.", e);
-		}
-
-	}
-
-	/**
-	 * 获取当前路径
-	 *
-	 * @author WANGWEI
-	 * @return
-	 * @throws IOException
-	 */
-	public static String currentPath() {
-		File directory = new File(". ");
-		return getCanonicalPath(directory);
-	}
-
-	/**
-	 * 获取资源路径
-	 *
-	 * @author WANGWEI
-	 * @param resourceName
-	 * @return
-	 */
-	public static String getResoucePath(String resourceName) {
-		try {
-			ClassLoader classLoader = PathUtil.class.getClassLoader();
-
-			URL url = classLoader.getResource(resourceName);
-			if (null != url) {
-				String path = URLDecoder.decode(url.getPath(), "UTF-8");
-				return path;
-			} else {
-				return null;
-			}
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 * 获取windows盘符
-	 *
-	 * @author WANGWEI
-	 * @param path
-	 * @return
-	 */
-	public static String getDrive(String path) {
-		if (path.matches("[a-zA-Z]:[\\\\/].*")) {
-			return path.substring(0, 2);
-		} else {
-			throw new RuntimeException("Path is not a windows path.");
-		}
-	}
-
-	/**
-	 * 拼接路径
-	 *
-	 * @author WANGWEI
-	 * @param fragments
-	 * @return
-	 */
-	public static String joinUrl(String... fragments) {
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < fragments.length; i++) {
-			String cur = fragments[i].trim();
-			if (cur.endsWith("/")) {
-				cur = cur.substring(0, cur.length() - 1);
-			}
-			if (0 == i) {
-				sb.append(cur);
-			} else if (cur.startsWith("/")) {
-				sb.append(cur);
-			} else {
-				sb.append("/").append(cur);
-			}
-		}
-
-		return sb.toString();
-	}
-
-}

+ 0 - 103
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/RegExpUtil.java

@@ -1,103 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * 正则表达式处理工具
- *
- * @author WANGWEI
- * @date 2018年5月24日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class RegExpUtil {
-	/**
-	 * 特殊字符
-	 */
-	private static final char[] SPECIFIC_CHAR_ARRAY = new char[]{'\\', '$', '(', ')', '*', '+', '.',
-			'[', ']', '?', '^', '{', '}', '|', ','};
-
-	/**
-	 * 转义.
-	 *
-	 * @author WANGWEI
-	 * @param input
-	 * @return
-	 */
-	public static String escape(String input) {
-		// '\'必须第一个转义
-		for (char c : SPECIFIC_CHAR_ARRAY) {
-			input = StringUtils.replace(input, String.valueOf(c), "\\" + c);
-		}
-
-		input = input.replaceAll("\\s+", "\\\\s+");
-
-		return input;
-	}
-
-	/**
-	 * find一次,取出匹配的字符串.<br>
-	 * <功能详细描述>
-	 * 
-	 * @param target
-	 * @param regex
-	 * @return
-	 * @see [类、类#方法、类#成员]
-	 */
-	public static String find(String target, String regex) {
-		return find(target, regex, 0);
-	}
-
-	/**
-	 * find一次,取出匹配的字符串的第index组子串.
-	 * 
-	 * @param target
-	 * @param regex
-	 * @param index
-	 * @return
-	 * @see [类、类#方法、类#成员]
-	 */
-	public static String find(String target, String regex, Integer index) {
-		Pattern p = Pattern.compile(regex);
-		Matcher m = p.matcher(target);
-		return m.find() ? m.group(index) : null;
-	}
-
-	/**
-	 * 取出所有匹配的字符串<br>
-	 * <功能详细描述>
-	 * 
-	 * @param target
-	 * @param regex
-	 * @return
-	 * @see [类、类#方法、类#成员]
-	 */
-	public static List<String> findAll(String target, String regex) {
-		return findAll(target, regex, 0);
-	}
-
-	/**
-	 * 取出所有匹配的字符串的第index组子串.<br>
-	 * <功能详细描述>
-	 * 
-	 * @param target
-	 * @param regex
-	 * @param index
-	 * @return
-	 * @see [类、类#方法、类#成员]
-	 */
-	public static List<String> findAll(String target, String regex, Integer index) {
-		Pattern p = Pattern.compile(regex);
-		Matcher m = p.matcher(target);
-		List<String> list = new ArrayList<String>();
-		while (m.find()) {
-			list.add(m.group(index));
-		}
-		return list;
-	}
-
-}

+ 0 - 67
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ResourceLoader.java

@@ -1,67 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-import org.apache.commons.io.IOUtils;
-
-/**
- * 资源加载器
- *
- * @author WANGWEI
- */
-public class ResourceLoader {
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param resourceName
-	 * @return
-	 */
-	public static String getResource(String resourceName) {
-		InputStream is = null;
-		try {
-			is = ResourceLoader.class.getClassLoader().getResourceAsStream(resourceName);
-			if (null == is) {
-				throw new RuntimeException(
-						"Resource could not be found. resource name is '" + resourceName + "'.");
-			}
-			return IOUtils.toString(is, "UTF-8");
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(is);
-		}
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param resourceName
-	 * @return
-	 */
-	public static String getResourceWithoutBlank(String resourceName) {
-		InputStream is = null;
-		BufferedReader br = null;
-		try {
-			is = ResourceLoader.class.getClassLoader().getResourceAsStream(resourceName);
-			br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-			StringBuilder sb = new StringBuilder();
-			String line = null;
-			while (null != (line = br.readLine())) {
-				sb.append(line.trim());
-			}
-
-			return sb.toString();
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(br);
-			IOUtils.closeQuietly(is);
-		}
-	}
-}

+ 0 - 43
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/SHA256.java

@@ -1,43 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-/**
- * SHA256加密
- * 
- * @author WANGWEI
- *
- */
-public class SHA256 {
-
-	/**
-	 * main
-	 *
-	 * @author WANGWEI
-	 * @param args
-	 */
-	public static void main(String[] args) {
-		String s = "";
-		System.out.println(ByteUtil.toHexAscii(SHA256.encode(s)));
-	}
-
-	/**
-	 * 加密
-	 *
-	 * @author WANGWEI
-	 * @param str
-	 * @return
-	 */
-	public static byte[] encode(String str) {
-		MessageDigest messageDigest;
-		try {
-			messageDigest = MessageDigest.getInstance("SHA-256");
-		} catch (NoSuchAlgorithmException e) {
-			throw new RuntimeException(e);
-		}
-		messageDigest.update(str.getBytes());
-		return messageDigest.digest();
-	}
-
-}

+ 0 - 390
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/StringUtil.java

@@ -1,390 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.util.List;
-
-import org.apache.commons.lang3.StringUtils;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-
-/**
- *
- * @author WANGWEI
- */
-public class StringUtil {
-
-	/**
-	 * 是否是ACSII码组成的字符串
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static boolean isAscString(String s) {
-		char[] arr = s.toCharArray();
-		for (char c : arr) {
-			if (c < 0 || c > 127) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Example: subString("12345","1","4")=23
-	 * 
-	 * @param src
-	 * @param start
-	 * @param to
-	 * @return
-	 */
-	public static Integer subStringToInteger(String src, String start, String to) {
-		return stringToInteger(subString(src, start, to));
-	}
-
-	/**
-	 * Example: subString("abcd","a","c")="b"
-	 * 
-	 * @param src
-	 * @param start
-	 *            null while start from index=0
-	 * @param to
-	 *            null while to index=src.length
-	 * @return
-	 */
-	public static String subString(String src, String start, String to) {
-		int indexFrom = start == null ? 0 : src.indexOf(start);
-		int indexTo = to == null ? src.length() : src.indexOf(to);
-		if (indexFrom < 0 || indexTo < 0 || indexFrom > indexTo) {
-			return null;
-		}
-
-		if (null != start) {
-			indexFrom += start.length();
-		}
-
-		return src.substring(indexFrom, indexTo);
-
-	}
-
-	/**
-	 * Example: subString("abcdc","a","c",true)="bcd"
-	 * 
-	 * @param src
-	 * @param start
-	 *            null while start from index=0
-	 * @param to
-	 *            null while to index=src.length
-	 * @param toLast
-	 *            true while to index=src.lastIndexOf(to)
-	 * @return
-	 */
-	public static String subString(String src, String start, String to, boolean toLast) {
-		if (!toLast) {
-			return subString(src, start, to);
-		}
-		int indexFrom = start == null ? 0 : src.indexOf(start);
-		int indexTo = to == null ? src.length() : src.lastIndexOf(to);
-		if (indexFrom < 0 || indexTo < 0 || indexFrom > indexTo) {
-			return null;
-		}
-
-		if (null != start) {
-			indexFrom += start.length();
-		}
-
-		return src.substring(indexFrom, indexTo);
-
-	}
-
-	/**
-	 * @param in
-	 * @return
-	 */
-	public static Integer stringToInteger(String in) {
-		if (in == null) {
-			return null;
-		}
-		in = in.trim();
-		if (in.length() == 0) {
-			return null;
-		}
-
-		try {
-			return Integer.parseInt(in);
-		} catch (NumberFormatException e) {
-			throw new ExamCloudRuntimeException(e);
-		}
-	}
-
-	/**
-	 * @param a
-	 * @param b
-	 * @return
-	 */
-	public static boolean equals(String a, String b) {
-		if (a == null) {
-			return b == null;
-		}
-		return a.equals(b);
-	}
-
-	/**
-	 * @param a
-	 * @param b
-	 * @return
-	 */
-	public static boolean equalsIgnoreCase(String a, String b) {
-		if (a == null) {
-			return b == null;
-		}
-		return a.equalsIgnoreCase(b);
-	}
-
-	/**
-	 * @param str
-	 * @return
-	 */
-	public static boolean isNumber(String str) {
-		if (str.length() == 0) {
-			return false;
-		}
-		int sz = str.length();
-		boolean hasExp = false;
-		boolean hasDecPoint = false;
-		boolean allowSigns = false;
-		boolean foundDigit = false;
-		int start = (str.charAt(0) == '-') ? 1 : 0;
-		if (sz > start + 1) {
-			if (str.charAt(start) == '0' && str.charAt(start + 1) == 'x') {
-				int i = start + 2;
-				if (i == sz) {
-					return false;
-				}
-				for (; i < str.length(); i++) {
-					char ch = str.charAt(i);
-					if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f')
-							&& (ch < 'A' || ch > 'F')) {
-						return false;
-					}
-				}
-				return true;
-			}
-		}
-		sz--;
-		int i = start;
-		while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
-			char ch = str.charAt(i);
-			if (ch >= '0' && ch <= '9') {
-				foundDigit = true;
-				allowSigns = false;
-
-			} else if (ch == '.') {
-				if (hasDecPoint || hasExp) {
-					return false;
-				}
-				hasDecPoint = true;
-			} else if (ch == 'e' || ch == 'E') {
-				if (hasExp) {
-					return false;
-				}
-				if (!foundDigit) {
-					return false;
-				}
-				hasExp = true;
-				allowSigns = true;
-			} else if (ch == '+' || ch == '-') {
-				if (!allowSigns) {
-					return false;
-				}
-				allowSigns = false;
-				foundDigit = false;
-			} else {
-				return false;
-			}
-			i++;
-		}
-		if (i < str.length()) {
-			char ch = str.charAt(i);
-
-			if (ch >= '0' && ch <= '9') {
-				return true;
-			}
-			if (ch == 'e' || ch == 'E') {
-				return false;
-			}
-			if (!allowSigns && (ch == 'd' || ch == 'D' || ch == 'f' || ch == 'F')) {
-				return foundDigit;
-			}
-			if (ch == 'l' || ch == 'L') {
-				return foundDigit && !hasExp;
-			}
-			return false;
-		}
-
-		return !allowSigns && foundDigit;
-	}
-
-	/**
-	 * 拼接
-	 * 
-	 * @param elements
-	 * @return
-	 */
-	public static String join(Object... elements) {
-		StringBuilder sb = new StringBuilder();
-		for (Object e : elements) {
-			if (e == null) {
-				e = "null";
-			}
-			sb.append(e.toString());
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * 拼接
-	 * 
-	 * @param elements
-	 * @return
-	 */
-	public static String join(List<Object> elements) {
-		StringBuilder sb = new StringBuilder();
-		for (Object e : elements) {
-			if (e == null) {
-				e = "null";
-			}
-			sb.append(e.toString());
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * 拼接
-	 * 
-	 * @param sep
-	 * @param elements
-	 * @return
-	 */
-	public static String joinWithSep(String sep, Object... elements) {
-		StringBuilder sb = new StringBuilder();
-		boolean first = true;
-		for (Object e : elements) {
-			if (e == null) {
-				e = "null";
-			}
-			if (first) {
-				sb.append(e.toString());
-				first = false;
-			} else {
-				sb.append(sep).append(e.toString());
-			}
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * 拼接
-	 * 
-	 * @param sep
-	 * @param elements
-	 * @return
-	 */
-	public static String joinWithSep(String sep, List<Object> elements) {
-		StringBuilder sb = new StringBuilder();
-		boolean first = true;
-		for (Object e : elements) {
-			if (e == null) {
-				e = "null";
-			}
-			if (first) {
-				sb.append(e.toString());
-				first = false;
-			} else {
-				sb.append(sep).append(e.toString());
-			}
-		}
-		return sb.toString();
-	}
-
-	/**
-	 * 转换成Boolean
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static Boolean toBoolean(String s) {
-		if (StringUtils.isBlank(s)) {
-			return null;
-		}
-		s = s.trim();
-		if (s.equals("true")) {
-			return true;
-		} else if (s.equals("false")) {
-			return false;
-		} else {
-			throw new ExamCloudRuntimeException("[" + s + "] must be  \"true\\\" or \\\"false\\\"");
-		}
-	}
-
-	/**
-	 * 转换成Integer
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static Integer toInteger(String s) {
-		if (StringUtils.isBlank(s)) {
-			return null;
-		}
-		s = s.trim();
-		int i = Integer.parseInt(s);
-		return i;
-	}
-
-	/**
-	 * 转换成Long
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static Long toLong(String s) {
-		if (StringUtils.isBlank(s)) {
-			return null;
-		}
-		s = s.trim();
-		Long l = Long.parseLong(s);
-		return l;
-	}
-
-	/**
-	 * 字符串是否为"true"
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static boolean isTrue(String s) {
-		if (null == s) {
-			return false;
-		}
-		return s.equalsIgnoreCase("true");
-	}
-
-	/**
-	 * 字符串是否为"false"
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static boolean isFalse(String s) {
-		if (null == s) {
-			return false;
-		}
-		return s.equalsIgnoreCase("false");
-	}
-
-}

+ 0 - 121
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ThreadLocalUtil.java

@@ -1,121 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.util.Map;
-import java.util.UUID;
-
-import org.apache.commons.lang.StringUtils;
-
-import com.google.common.collect.Maps;
-
-/**
- * 线程本地化工具
- *
- * @author WANGWEI
- */
-public class ThreadLocalUtil {
-	/**
-	 * trace ID
-	 */
-	private static final ThreadLocal<String> LOCAL_TRACE_ID = new ThreadLocal<String>() {
-		@Override
-		public String initialValue() {
-			return null;
-		}
-	};
-
-	/**
-	 * map
-	 */
-	private static final ThreadLocal<Map<String, Object>> LOCAL_TRACE_MAP = new ThreadLocal<Map<String, Object>>() {
-		@Override
-		public Map<String, Object> initialValue() {
-			return null;
-		}
-	};
-
-	/**
-	 * 重新初始化
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public static String next() {
-		LOCAL_TRACE_MAP.set(null);
-		String traceID = UUID.randomUUID().toString().replace("-", "");
-		setTraceId(traceID);
-		return traceID;
-	}
-
-	/**
-	 * 获取 trace ID
-	 *
-	 * @author WANGWEI
-	 * @return
-	 */
-	public static String getTraceId() {
-		String traceID = LOCAL_TRACE_ID.get();
-		if (traceID == null) {
-			traceID = next();
-		} else {
-			return traceID;
-		}
-
-		return traceID;
-	}
-
-	/**
-	 * 设置 trace ID
-	 *
-	 * @author WANGWEI
-	 * @param traceId
-	 */
-	public static void setTraceId(String traceId) {
-		if (!(StringUtils.isNotBlank(traceId)))
-			return;
-		LOCAL_TRACE_ID.set(traceId);
-	}
-
-	/**
-	 * 设置属性
-	 *
-	 * @author WANGWEI
-	 * @param key
-	 * @param value
-	 */
-	public static void set(String key, Object value) {
-		Map<String, Object> map = LOCAL_TRACE_MAP.get();
-
-		if (null == map) {
-			map = Maps.newHashMap();
-			LOCAL_TRACE_MAP.set(map);
-		}
-		map.put(key, value);
-	}
-
-	/**
-	 * 获取属性
-	 *
-	 * @author WANGWEI
-	 * @param key
-	 * @return
-	 */
-	public static Object get(String key) {
-		Map<String, Object> map = LOCAL_TRACE_MAP.get();
-		if (null == map) {
-			return null;
-		}
-		return map.get(key);
-	}
-
-	/**
-	 * 清理属性
-	 *
-	 * @author WANGWEI
-	 */
-	public static void clearAll() {
-		Map<String, Object> map = LOCAL_TRACE_MAP.get();
-		if (null != map) {
-			map.clear();
-		}
-	}
-}

+ 0 - 160
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/UrlUtil.java

@@ -1,160 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * url 处理工具
- *
- * @author WANGWEI
- */
-public class UrlUtil {
-	/**
-	 * 获取url参数
-	 *
-	 * @author WANG WEI
-	 *
-	 * @param str
-	 * @return
-	 */
-	public static Map<String, String> getUrlParams(String url) {
-		Map<String, String> params = new HashMap<String, String>();
-
-		try {
-			int indexOf = url.lastIndexOf('?');
-
-			if (0 < indexOf) {
-				url = url.substring(indexOf + 1);
-			}
-			String[] pairs = url.trim().split("&");
-			for (String pair : pairs) {
-				String[] kv = pair.split("=");
-				if (2 != kv.length) {
-					continue;
-				}
-				params.put(kv[0], URLDecoder.decode(kv[1], "UTF-8"));
-			}
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
-
-		return params;
-	}
-
-	/**
-	 * 编码
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static String encode(String s) {
-		return encode(s, "UTF-8");
-	}
-
-	/**
-	 * 编码
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @param enc
-	 * @return
-	 */
-	public static String encode(String s, String enc) {
-		try {
-			return URLEncoder.encode(s, enc).replaceAll("\\+", "%20");
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 * 解码
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @return
-	 */
-	public static String decode(String s) {
-		return decode(s, "UTF-8");
-	}
-
-	/**
-	 * 解码
-	 *
-	 * @author WANGWEI
-	 * @param s
-	 * @param enc
-	 * @return
-	 */
-	public static String decode(String s, String enc) {
-		try {
-			return URLDecoder.decode(s, enc);
-		} catch (UnsupportedEncodingException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 * url拼接参数
-	 *
-	 * @author WANGWEI
-	 * @param url
-	 * @param params
-	 * @return
-	 */
-	public static String joinParams(String url, Map<String, String> params) {
-		Map<String, String> urlParams = getUrlParams(url);
-		urlParams.putAll(params);
-
-		int indexOf = url.lastIndexOf('?');
-
-		if (0 < indexOf) {
-			url = url.substring(0, indexOf);
-		}
-
-		StringBuilder sb = new StringBuilder();
-		sb.append(url).append("?");
-		boolean hasParams = false;
-		for (Entry<String, String> entry : urlParams.entrySet()) {
-			sb.append(entry.getKey()).append("=").append(encode(entry.getValue())).append("&");
-			hasParams = true;
-		}
-		if (hasParams) {
-			sb.deleteCharAt(sb.length() - 1);
-		}
-
-		return sb.toString();
-	}
-
-	/**
-	 * 拼接url片段
-	 *
-	 * @author WANGWEI
-	 * @param fragments
-	 * @return
-	 */
-	public static String joinUrl(String... fragments) {
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < fragments.length; i++) {
-			String cur = fragments[i].trim();
-			if (cur.endsWith("/")) {
-				cur = cur.substring(0, cur.length() - 1);
-			}
-			if (0 == i) {
-				sb.append(cur);
-			} else if (cur.startsWith("/")) {
-				sb.append(cur);
-			} else {
-				sb.append("/").append(cur);
-			}
-		}
-
-		return sb.toString();
-	}
-
-}

+ 0 - 126
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/Util.java

@@ -1,126 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.poi.util.IOUtils;
-
-/**
- * 工具集
- *
- * @author WANGWEI
- * @date 2018年12月6日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
- */
-public class Util {
-
-	/**
-	 * @param elements
-	 * @return
-	 */
-	public static List<String> buildList(String... elements) {
-		return Arrays.asList(elements);
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param timeout
-	 */
-	public static void sleep(int timeout) {
-		sleep(TimeUnit.SECONDS, timeout);
-	}
-
-	/**
-	 * 
-	 * @param timeUnit
-	 * @param timeout
-	 */
-	public static void sleep(TimeUnit timeUnit, int timeout) {
-		try {
-			timeUnit.sleep(timeout);
-		} catch (InterruptedException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	/**
-	 * 获取堆栈信息
-	 *
-	 * @author WANGWEI
-	 * @param e
-	 * @return
-	 */
-	public static String getStackTrace(Exception e) {
-		PrintWriter pw = null;
-		StringWriter sw = null;
-		try {
-			sw = new StringWriter();
-			pw = new PrintWriter(sw);
-			e.printStackTrace(pw);
-			return sw.toString();
-		} catch (Exception ex) {
-			throw new RuntimeException(ex);
-		} finally {
-			IOUtils.closeQuietly(pw);
-			IOUtils.closeQuietly(sw);
-		}
-	}
-
-	/**
-	 * 所有元素 equals
-	 *
-	 * @author WANGWEI
-	 * @param elements
-	 * @return
-	 */
-	public static boolean equals(Object... elements) {
-		List<?> list = Arrays.asList(elements);
-		return equals(list);
-	}
-
-	/**
-	 * 所有元素 equals
-	 *
-	 * @author WANGWEI
-	 * @param elements
-	 * @return
-	 */
-	public static boolean equals(List<?> elements) {
-		Object firstElement = null;
-		boolean isFirst = true;
-		for (Object cur : elements) {
-
-			if (isFirst) {
-				firstElement = cur;
-				isFirst = false;
-			} else {
-				try {
-					if (!firstElement.equals(cur)) {
-						return false;
-					}
-				} catch (Exception e) {
-					return false;
-				}
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * 数组转List
-	 *
-	 * @author WANGWEI
-	 * @param t
-	 * @return
-	 */
-	@SafeVarargs
-	public static <T> List<T> toList(T... t) {
-		return Arrays.asList(t);
-	}
-
-}

+ 0 - 147
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/ZipUtil.java

@@ -1,147 +0,0 @@
-package cn.com.qmth.examcloud.commons.util;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.compress.archivers.ArchiveEntry;
-import org.apache.commons.compress.archivers.zip.Zip64Mode;
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.apache.commons.compress.utils.IOUtils;
-import org.apache.commons.io.FileUtils;
-
-/**
- * 类注释
- *
- * @author WANGWEI
- */
-public class ZipUtil {
-
-	/**
-	 * 压缩
-	 * 
-	 * @param dir
-	 *            压缩的文件夹
-	 * @param zipFile
-	 *            压缩文件
-	 */
-	public static void zip(File dir, File zipFile) {
-		List<File> files = getAllFiles(dir);
-		if (CollectionUtils.isEmpty(files)) {
-			return;
-		}
-
-		ZipArchiveOutputStream zipOut = null;
-
-		try {
-			zipOut = new ZipArchiveOutputStream(zipFile);
-			zipOut.setUseZip64(Zip64Mode.AsNeeded);
-
-			for (File file : files) {
-				if (file.isDirectory()) {
-					continue;
-				}
-
-				String filePath = file.getCanonicalPath()
-						.replace(dir.getCanonicalPath() + File.separator, "");
-
-				ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(file, filePath);
-				zipOut.putArchiveEntry(zipArchiveEntry);
-
-				InputStream in = null;
-				try {
-					in = new BufferedInputStream(new FileInputStream(file));
-					IOUtils.copy(in, zipOut);
-					zipOut.closeArchiveEntry();
-				} finally {
-					IOUtils.closeQuietly(in);
-				}
-			}
-
-			zipOut.finish();
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(zipOut);
-		}
-
-	}
-
-	/**
-	 * @param dir
-	 * @return
-	 */
-	private static List<File> getAllFiles(File dir) {
-		List<File> ret = new ArrayList<File>();
-		File[] files = dir.listFiles();
-		for (File f : files) {
-			if (f.isDirectory()) {
-				ret.addAll(getAllFiles(f));
-			}
-			ret.add(f);
-		}
-		return ret;
-	}
-
-	/**
-	 * 解压
-	 * 
-	 * @param file
-	 *            解压的文件
-	 * @param dir
-	 *            解压的文件夹
-	 */
-	public static void unzip(File file, File dir) {
-		try {
-			FileUtils.forceMkdir(dir);
-		} catch (IOException e) {
-			throw new RuntimeException(e);
-		}
-
-		if (!file.exists()) {
-			throw new RuntimeException("file is not existing.");
-		}
-
-		ZipArchiveInputStream zipIn = null;
-
-		try {
-			zipIn = new ZipArchiveInputStream(new FileInputStream(file));
-			ArchiveEntry entry = null;
-
-			while (null != (entry = zipIn.getNextEntry())) {
-				String entryName = entry.getName();
-				String entryPath = dir.getCanonicalPath() + File.separator + entryName;
-
-				OutputStream out = null;
-				try {
-					File entryFile = new File(entryPath);
-					if (entryName.endsWith("/")) {
-						entryFile.mkdirs();
-					} else {
-						out = new FileOutputStream(entryFile);
-						IOUtils.copy(zipIn, out);
-					}
-				} finally {
-					IOUtils.closeQuietly(out);
-				}
-
-			}
-
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		} finally {
-			IOUtils.closeQuietly(zipIn);
-		}
-
-	}
-
-}

+ 0 - 34
examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/FileReaderExecuter.java

@@ -1,34 +0,0 @@
-package cn.com.qmth.examcloud.test.pipeline;
-
-import java.io.File;
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.RandomUtils;
-
-import cn.com.qmth.examcloud.commons.helpers.KeyValuePair;
-import cn.com.qmth.examcloud.commons.helpers.ObjectHolder;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.NodeExecuter;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.TaskContext;
-
-public class FileReaderExecuter implements NodeExecuter<String, String, String, String> {
-
-	@Override
-	public void execute(String key, String value, List<KeyValuePair<String, String>> outList,
-			ObjectHolder<Boolean> removable, TaskContext context) throws Exception {
-
-		String path = (String) context.get("path");
-
-		List<String> readLines = FileUtils.readLines(new File(path), "UTF-8");
-
-		readLines.forEach(e -> {
-			outList.add(new KeyValuePair<String, String>(Objects.toString((RandomUtils.nextLong())),
-					e));
-		});
-
-		removable.set(false);
-		outList.clear();
-	}
-
-}

+ 0 - 18
examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/PrintExecuter.java

@@ -1,18 +0,0 @@
-package cn.com.qmth.examcloud.test.pipeline;
-
-import java.util.List;
-
-import cn.com.qmth.examcloud.commons.helpers.KeyValuePair;
-import cn.com.qmth.examcloud.commons.helpers.ObjectHolder;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.NodeExecuter;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.TaskContext;
-
-public class PrintExecuter implements NodeExecuter<String, String, String, String> {
-
-	@Override
-	public void execute(String key, String value, List<KeyValuePair<String, String>> outList,
-			ObjectHolder<Boolean> removable, TaskContext context) throws Exception {
-		System.out.println("Print: " + key + " -> " + value);
-	}
-
-}

+ 0 - 33
examcloud-commons/src/test/java/cn/com/qmth/examcloud/test/pipeline/Test.java

@@ -1,33 +0,0 @@
-package cn.com.qmth.examcloud.test.pipeline;
-
-import cn.com.qmth.examcloud.commons.helpers.pipeline.Node;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.SimpleNode;
-import cn.com.qmth.examcloud.commons.helpers.pipeline.TaskContext;
-
-public class Test {
-
-	public static void main(String[] args) {
-		TaskContext context = new TaskContext();
-		context.put("path", "D:/Temp/test.txt");
-
-		FileReaderExecuter fileReaderExecuter = new FileReaderExecuter();
-		PrintExecuter printExecuter = new PrintExecuter();
-
-		Node<String, String, String, String> node1 = new SimpleNode<String, String, String, String>(
-				"reader", fileReaderExecuter, context);
-
-		Node<String, String, String, String> node2 = new SimpleNode<String, String, String, String>(
-				"print", printExecuter, context);
-
-		node1.setLowerNode(node2);
-
-		node1.setFirst(true);
-		node1.setSleep(10);
-
-		node2.setSleep(5);
-
-		node1.start();
-		node2.start();
-	}
-
-}

+ 199 - 5
examcloud-support/pom.xml

@@ -12,11 +12,6 @@
     </parent>
 
     <dependencies>
-        <dependency>
-            <groupId>cn.com.qmth.examcloud</groupId>
-            <artifactId>examcloud-commons</artifactId>
-            <version>${project.version}</version>
-        </dependency>
         <dependency>
             <groupId>cn.com.qmth.examcloud</groupId>
             <artifactId>examcloud-api-commons</artifactId>
@@ -26,6 +21,205 @@
             <groupId>cn.com.qmth.framework</groupId>
             <artifactId>config-center-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-1.2-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-net</groupId>
+            <artifactId>commons-net</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.sf.json-lib</groupId>
+            <artifactId>json-lib</artifactId>
+            <classifier>jdk15</classifier>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.mchange</groupId>
+            <artifactId>c3p0</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.quartz-scheduler</groupId>
+            <artifactId>quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jcraft</groupId>
+            <artifactId>jsch</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.googlecode.aviator</groupId>
+            <artifactId>aviator</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-beanutils</groupId>
+                    <artifactId>commons-beanutils</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-context</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 51 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/exception/ExamCloudRuntimeException.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.examcloud.commons.exception;
+
+/**
+ * 通用异常类<br>
+ *
+ * @author WANG
+ */
+public class ExamCloudRuntimeException extends RuntimeException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 7992796744711512927L;
+
+    /**
+     * 构造函数
+     */
+    public ExamCloudRuntimeException() {
+        super();
+    }
+
+    /**
+     * 构造函数
+     */
+    public ExamCloudRuntimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * 构造函数
+     */
+    public ExamCloudRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * 构造函数
+     */
+    public ExamCloudRuntimeException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * 构造函数
+     */
+    protected ExamCloudRuntimeException(String message, Throwable cause, boolean enableSuppression,
+                                        boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+}

+ 89 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/exception/StatusException.java

@@ -0,0 +1,89 @@
+package cn.com.qmth.examcloud.commons.exception;
+
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 状态异常类<br>
+ *
+ * @author WANG
+ */
+public class StatusException extends RuntimeException {
+
+    private static final long serialVersionUID = 5003047488500388819L;
+
+    private static final String DEF_CODE = "500";
+
+    /**
+     * 追踪ID
+     */
+    private String traceId;
+
+    /**
+     * 状态码
+     */
+    private String code;
+
+    /**
+     * 状态描述
+     */
+    private String desc;
+
+    /**
+     * 构造函数
+     */
+    public StatusException(String code, String desc) {
+        super("[code: " + code + "; desc: " + desc + "]");
+        this.code = code;
+        this.desc = desc;
+    }
+
+    /**
+     * 构造函数
+     */
+    public StatusException(String code, String desc, Throwable cause) {
+        super("[code: " + code + "; desc: " + desc + "]", cause);
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public StatusException(String desc) {
+        super("[code: " + DEF_CODE + "; desc: " + desc + "]");
+        this.code = DEF_CODE;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public String getTraceId() {
+        return traceId;
+    }
+
+    public void setTraceId(String traceId) {
+        this.traceId = traceId;
+    }
+
+    /**
+     * @return
+     */
+    public String toJson() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("code", code);
+        map.put("desc", desc);
+        return JsonUtil.toJson(map);
+    }
+
+    @Override
+    public String toString() {
+        return toJson();
+    }
+
+}

+ 1 - 1
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/BasicDataType.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/BasicDataType.java

@@ -9,6 +9,6 @@ package cn.com.qmth.examcloud.commons.helpers;
  */
 public enum BasicDataType {
 
-	STRING, INTEGER, BOOLEAN, LONG;
+    STRING, INTEGER, BOOLEAN, LONG;
 
 }

+ 63 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/BlackHolePrintStreamBuilder.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+/**
+ * 黑洞(PrintStream)构建器
+ *
+ * @author WANGWEI
+ * @date 2019年3月28日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class BlackHolePrintStreamBuilder {
+
+    /**
+     * 创建BlackHolePrintStream
+     *
+     * @return
+     * @author WANGWEI
+     */
+    public static PrintStream build() {
+        return new BlackHolePrintStream(new ByteArrayOutputStream());
+    }
+
+    /**
+     * 黑洞(PrintStream)
+     *
+     * @author WANGWEI
+     * @date 2019年3月28日
+     * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+     */
+    private static class BlackHolePrintStream extends PrintStream {
+
+        @Override
+        public void close() {
+            super.close();
+        }
+
+        ByteArrayOutputStream outputStream;
+
+        /**
+         * 私有构造函数
+         *
+         * @param out
+         */
+        private BlackHolePrintStream(ByteArrayOutputStream outputStream) {
+            super(outputStream);
+            this.outputStream = outputStream;
+        }
+
+        @Override
+        public void println(String x) {
+            outputStream.reset();
+        }
+
+        @Override
+        public void print(String x) {
+            outputStream.reset();
+        }
+
+    }
+
+}

+ 80 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/Counter.java

@@ -0,0 +1,80 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 计数器
+ *
+ * @author WANGWEI
+ * @date 2018年1月26日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class Counter {
+
+    private AtomicLong counter;
+
+    /**
+     * 最小值
+     */
+    private long min;
+
+    /**
+     * 最大值
+     */
+    private long max;
+
+    /**
+     * 循环计数回合数
+     */
+    private int bout = 0;
+
+    /**
+     * 构造函数
+     *
+     * @param min
+     * @param max
+     */
+    public Counter(long min, long max) {
+        this.min = min;
+        this.max = max;
+        bout();
+    }
+
+    /**
+     * 初始化循环
+     *
+     * @author WANGWEI
+     */
+    private void bout() {
+        int cur = bout;
+        synchronized (this) {
+            if (cur < bout) {
+                return;
+            }
+            counter = new AtomicLong(min);
+            bout++;
+        }
+    }
+
+    /**
+     * 方法注释
+     *
+     * @return
+     * @author WANGWEI
+     */
+    public long next() {
+        long next = counter.getAndIncrement();
+
+        if (next > max) {
+            bout();
+            return next();
+        }
+
+        return next;
+    }
+
+    public long get() {
+        return counter.get();
+    }
+
+}

+ 108 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnum.java

@@ -0,0 +1,108 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import cn.com.qmth.examcloud.commons.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+
+/**
+ * 动态枚举
+ *
+ * @author WANGWEI
+ * @date 2018年8月23日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public final class DynamicEnum implements Serializable {
+
+    private static final long serialVersionUID = -694709140246715214L;
+
+    /**
+     * ID
+     */
+    private Long id;
+
+    /**
+     * name
+     */
+    private String name;
+
+    /**
+     * 描述
+     */
+    private String desc;
+
+    /**
+     * 值类型
+     */
+    private String valueType;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+
+    public String getValueType() {
+        return valueType;
+    }
+
+    public void setValueType(String valueType) {
+        this.valueType = valueType;
+    }
+
+    /**
+     * 是否合法
+     *
+     * @param value
+     * @return
+     * @author WANGWEI
+     */
+    public Boolean isLegal(String value) {
+        if (StringUtils.isNotBlank(value) && null != valueType) {
+            BasicDataType dataType = BasicDataType.valueOf(valueType);
+            if (dataType.equals(BasicDataType.BOOLEAN)) {
+                try {
+                    StringUtil.toBoolean(value);
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            } else if (dataType.equals(BasicDataType.INTEGER)) {
+                try {
+                    StringUtil.toInteger(value);
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            } else if (dataType.equals(BasicDataType.LONG)) {
+                try {
+                    StringUtil.toLong(value);
+                    return true;
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+}

+ 142 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/DynamicEnumManager.java

@@ -0,0 +1,142 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import com.google.common.collect.Maps;
+import com.thoughtworks.xstream.XStream;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 动态属性管理器
+ *
+ * @author WANGWEI
+ * @date 2018年8月23日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class DynamicEnumManager {
+
+    private List<DynamicEnum> enums;
+
+    private Map<String, DynamicEnum> nameIndex;
+
+    private Map<Long, DynamicEnum> idIndex;
+
+    /**
+     * 构造函数
+     */
+    private DynamicEnumManager() {
+        super();
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param xmlResourcePath
+     * @return
+     * @author WANGWEI
+     */
+    public static DynamicEnumManager newInstance(String xmlResourcePath) {
+        DynamicEnumManager manager = new DynamicEnumManager();
+
+        String resoucePath = PathUtil.getResoucePath(xmlResourcePath);
+        File file = new File(resoucePath);
+
+        XStream xStream = XStreamBuilder.newInstance().build();
+        xStream.allowTypes(new Class[]{DynamicEnum.class, List.class});
+        xStream.alias("enums", List.class);
+        xStream.alias("enum", DynamicEnum.class);
+
+        @SuppressWarnings("unchecked")
+        List<DynamicEnum> list = (List<DynamicEnum>) xStream.fromXML(file);
+        manager.enums = list;
+
+        manager.nameIndex = Maps.newHashMap();
+        manager.idIndex = Maps.newHashMap();
+
+        for (DynamicEnum cur : manager.enums) {
+            String valueTpye = cur.getValueType();
+            if (StringUtils.isBlank(valueTpye)) {
+                cur.setValueType(null);
+            } else {
+                try {
+                    BasicDataType dataType = BasicDataType.valueOf(valueTpye);
+                    cur.setValueType(dataType.name());
+                } catch (Exception e) {
+                    throw new RuntimeException("valueTpye is wrong. valueTpye=" + valueTpye);
+                }
+
+            }
+            cur.setName(cur.getName().trim());
+            cur.setDesc(cur.getDesc().trim());
+            manager.nameIndex.put(cur.getName(), cur);
+            manager.idIndex.put(cur.getId(), cur);
+        }
+
+        return manager;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param name
+     * @return
+     * @author WANGWEI
+     */
+    public DynamicEnum getByName(String name) {
+        DynamicEnum dynamicEnum = nameIndex.get(name);
+        if (null != dynamicEnum) {
+            return dynamicEnum;
+        }
+        throw new ExamCloudRuntimeException("动态枚举不存在. name=" + name);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param name
+     * @return
+     * @author WANGWEI
+     */
+    public Long getIdByName(String name) {
+        DynamicEnum dynamicEnum = nameIndex.get(name);
+        if (null != dynamicEnum) {
+            return dynamicEnum.getId();
+        }
+        throw new ExamCloudRuntimeException("动态枚举不存在. name=" + name);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param id
+     * @return
+     * @author WANGWEI
+     */
+    public DynamicEnum getById(Long id) {
+        DynamicEnum dynamicEnum = idIndex.get(id);
+        if (null != dynamicEnum) {
+            return dynamicEnum;
+        }
+        throw new ExamCloudRuntimeException("动态枚举不存在. id=" + id);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param id
+     * @return
+     * @author WANGWEI
+     */
+    public String getNameById(Long id) {
+        DynamicEnum dynamicEnum = idIndex.get(id);
+        if (null != dynamicEnum) {
+            return dynamicEnum.getName();
+        }
+        throw new ExamCloudRuntimeException("动态枚举不存在. id=" + id);
+    }
+
+}

+ 136 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/FileChangeWatchdog.java

@@ -0,0 +1,136 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * 文件变更监视器
+ *
+ * @author WANGWEI
+ */
+public abstract class FileChangeWatchdog extends Thread {
+
+    /**
+     * 属性注释
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(FileChangeWatchdog.class);
+
+    /**
+     * 属性注释
+     */
+    static final public long DEFAULT_DELAY = 60000;
+
+    /**
+     * 属性注释
+     */
+    protected String path;
+
+    /**
+     * 属性注释
+     */
+    protected long delay = DEFAULT_DELAY;
+
+    /**
+     * 属性注释
+     */
+    protected File file;
+
+    /**
+     * 属性注释
+     */
+    protected long lastModif = 0;
+
+    /**
+     * 属性注释
+     */
+    protected boolean warnedAlready = false;
+
+    /**
+     * 属性注释
+     */
+    protected boolean interrupted = false;
+
+    /**
+     * 构造函数
+     *
+     * @param path
+     */
+    protected FileChangeWatchdog(String path) {
+        super("FileChangeWatchdog");
+        LOG.info("new a FileChangeWatchdog. path=" + path);
+        this.path = path;
+        file = new File(path);
+        setDaemon(true);
+        checkAndConfigure();
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param delay
+     * @author WANGWEI
+     */
+    public void setDelay(long delay) {
+        this.delay = delay;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @author WANGWEI
+     */
+    abstract protected void doOnChange();
+
+    /**
+     * 方法注释
+     *
+     * @author WANGWEI
+     */
+    protected void checkAndConfigure() {
+        boolean fileExists;
+        try {
+            fileExists = file.exists();
+        } catch (SecurityException e) {
+            LOG.warn("Was not allowed to read check file existance, file:[" + path + "].");
+            interrupted = true;
+            return;
+        }
+
+        if (fileExists) {
+            long l = file.lastModified();
+
+            if (l > lastModif) {
+                lastModif = l;
+                doOnChange();
+                warnedAlready = false;
+            }
+        } else {
+            if (!warnedAlready) {
+                LOG.debug("[" + path + "] does not exist.");
+                warnedAlready = true;
+            }
+        }
+    }
+
+    /*
+     * 实现
+     *
+     * @author WANGWEI
+     *
+     * @see java.lang.Thread#run()
+     */
+    @Override
+    public void run() {
+        while (!interrupted) {
+            try {
+                Thread.sleep(delay);
+            } catch (InterruptedException e) {
+                LOG.error("unexpected interruption.", e);
+            }
+            checkAndConfigure();
+        }
+    }
+
+}

+ 58 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/FormFilePart.java

@@ -0,0 +1,58 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import java.io.File;
+
+/**
+ * 表单文件参数
+ *
+ * @author WANGWEI
+ * @date 2019年5月9日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class FormFilePart {
+
+    private String paramName;
+
+    private String filename;
+
+    private File file;
+
+    /**
+     * 构造函数
+     *
+     * @param paramName
+     * @param filename
+     * @param file
+     */
+    public FormFilePart(String paramName, String filename, File file) {
+        super();
+        this.paramName = paramName;
+        this.filename = filename;
+        this.file = file;
+    }
+
+    public String getParamName() {
+        return paramName;
+    }
+
+    public void setParamName(String paramName) {
+        this.paramName = paramName;
+    }
+
+    public String getFilename() {
+        return filename;
+    }
+
+    public void setFilename(String filename) {
+        this.filename = filename;
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+}

+ 44 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/JsonHttpResponseHolder.java

@@ -0,0 +1,44 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * http json 响应
+ *
+ * @author WANGWEI
+ * @date 2019年9月16日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class JsonHttpResponseHolder {
+
+    private int statusCode;
+
+    private JSONObject respBody;
+
+    public JsonHttpResponseHolder() {
+        super();
+    }
+
+    public JsonHttpResponseHolder(int statusCode, JSONObject respBody) {
+        super();
+        this.statusCode = statusCode;
+        this.respBody = respBody;
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    public void setStatusCode(int statusCode) {
+        this.statusCode = statusCode;
+    }
+
+    public JSONObject getRespBody() {
+        return respBody;
+    }
+
+    public void setRespBody(JSONObject respBody) {
+        this.respBody = respBody;
+    }
+
+}

+ 51 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/KeyValuePair.java

@@ -0,0 +1,51 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.io.Serializable;
+
+/**
+ * 键值对
+ *
+ * @param <V>
+ * @author WANGWEI
+ */
+public class KeyValuePair<K, V> implements Serializable {
+
+    private static final long serialVersionUID = 5140216132754119367L;
+
+    private K key;
+
+    private V value;
+
+    public KeyValuePair(K key, V value) {
+        super();
+        this.key = key;
+        this.value = value;
+
+    }
+
+    public JSONObject toJsonObject(String keyAlias, String valueAlias) {
+        JSONObject obj = new JSONObject();
+        obj.put(keyAlias, key);
+        obj.put(valueAlias, value);
+        return obj;
+    }
+
+    public K getKey() {
+        return key;
+    }
+
+    public void setKey(K key) {
+        this.key = key;
+    }
+
+    public V getValue() {
+        return value;
+    }
+
+    public void setValue(V value) {
+        this.value = value;
+    }
+
+}

+ 46 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/ObjectHolder.java

@@ -0,0 +1,46 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+/**
+ * 基本类型对象化
+ *
+ * @param <T>
+ * @author WANGWEI
+ * @date 2019年1月16日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class ObjectHolder<T> {
+
+    private T t;
+
+    /**
+     * 构造函数
+     *
+     * @param t
+     */
+    public ObjectHolder(T t) {
+        super();
+        this.t = t;
+    }
+
+    public T get() {
+        return t;
+    }
+
+    public void set(T t) {
+        this.t = t;
+    }
+
+    public boolean isNull() {
+        return null == t;
+    }
+
+    @Override
+    public String toString() {
+        if (isNull()) {
+            return super.toString();
+        } else {
+            return t.toString();
+        }
+    }
+
+}

+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/QuestionOptionHelper.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/QuestionOptionHelper.java


+ 101 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/XStreamBuilder.java

@@ -0,0 +1,101 @@
+package cn.com.qmth.examcloud.commons.helpers;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.converters.basic.DateConverter;
+import com.thoughtworks.xstream.converters.basic.DoubleConverter;
+import com.thoughtworks.xstream.converters.basic.FloatConverter;
+
+import java.util.TimeZone;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ */
+public class XStreamBuilder {
+
+    /**
+     * 属性注释
+     */
+    private XStream xs;
+
+    /**
+     * 构造函数
+     */
+    private XStreamBuilder() {
+        this.xs = new XStream();
+        XStream.setupDefaultSecurity(this.xs);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @return
+     * @author WANGWEI
+     */
+    public static XStreamBuilder newInstance() {
+        XStreamBuilder builder = new XStreamBuilder();
+        return builder;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param defaultFormat
+     * @return
+     * @author WANGWEI
+     */
+    public XStreamBuilder registerDateConverter(final String defaultFormat) {
+        xs.registerConverter(new DateConverter(defaultFormat, null, TimeZone.getTimeZone("GMT+8")));
+        return this;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @return
+     * @author WANGWEI
+     */
+    public XStreamBuilder registerNormalNumberConverter() {
+        xs.registerConverter(new NormalDoubleConverter());
+        xs.registerConverter(new NormalFloatConverter());
+        return this;
+    }
+
+    /**
+     * 类注释
+     *
+     * @author WANGWEI
+     */
+    private class NormalDoubleConverter extends DoubleConverter {
+
+        public String toString(Object obj) {
+            return String.valueOf(obj);
+        }
+
+    }
+
+    /**
+     * 类注释
+     *
+     * @author WANGWEI
+     */
+    private class NormalFloatConverter extends FloatConverter {
+
+        public String toString(Object obj) {
+            return String.valueOf(obj);
+        }
+
+    }
+
+    /**
+     * 方法注释
+     *
+     * @return
+     * @author WANGWEI
+     */
+    public XStream build() {
+        return xs;
+    }
+
+}

+ 207 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/ConcurrentTask.java

@@ -0,0 +1,207 @@
+package cn.com.qmth.examcloud.commons.helpers.concurrency.simple;
+
+import cn.com.qmth.examcloud.commons.util.Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 并发任务
+ *
+ * @author WANGWEI
+ * @date 2019年6月19日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class ConcurrentTask<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConcurrentTask.class);
+
+    private BlockingQueue<T> queue = new LinkedBlockingQueue<T>(10000);
+
+    private BlockingQueue<Integer> workerMessages = new LinkedBlockingQueue<Integer>(10000);
+
+    private final WorkerController workerController = new WorkerController();
+
+    /**
+     * 最大线程数
+     */
+    private int maxActiveThreadSize = 5;
+
+    /**
+     * 不死线程数
+     */
+    private int minThreadSize = 2;
+
+    private ThreadPoolExecutor threadPoolExecutor;
+
+    /**
+     * 处理者
+     */
+    private Worker<T> worker;
+
+    /**
+     * 巡检周期
+     */
+    private int inspectionPeriod = 30;
+
+    /**
+     * 任务名称
+     */
+    private String taskName;
+
+    /**
+     * 构造函数
+     *
+     * @param taskName
+     */
+    public ConcurrentTask(String taskName) {
+        super();
+        this.taskName = taskName;
+    }
+
+    /**
+     * 添加处理元素
+     *
+     * @param e
+     * @return
+     * @author WANGWEI
+     */
+    public boolean offerElement(T e) {
+        boolean offer = queue.offer(e);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("offerElement. result=" + offer + ";element=" + e.toString());
+        }
+        return offer;
+    }
+
+    /**
+     * 启动任务
+     *
+     * @author WANGWEI
+     */
+    public void start() {
+        threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(maxActiveThreadSize);
+
+        // 创建不死线程
+        for (int i = 0; i < minThreadSize; i++) {
+            addWorkerThread(true);
+        }
+
+        // 巡检线程
+        Thread inspectionThread = new Thread() {
+
+            @Override
+            public void run() {
+                Util.sleep(inspectionPeriod);
+
+                while (true) {
+
+                    int size = queue.size();
+                    int activeCount = threadPoolExecutor.getActiveCount();
+                    int warnCount = workerController.getWarnCount();
+
+                    if (LOG.isInfoEnabled()) {
+                        LOG.info("taskName [" + taskName + "]. activeCount = " + activeCount
+                                + "; warnCount = " + warnCount);
+                    }
+
+                    // 巡检周期内(因并发超出限制导致的)警告数量未超过100时,增加一个worker
+                    if (warnCount <= 100) {
+                        if (100 < size && maxActiveThreadSize > activeCount) {
+                            addWorkerThread(false);
+                        }
+                    } else {
+                        // 巡检周期内(因并发超出限制导致的)警告数量超过100时,减少一个worker
+                        workerMessages.offer(warnCount);
+                    }
+
+                    workerController.resetWarnCount();
+                    Util.sleep(inspectionPeriod);
+                }
+
+            }
+
+            ;
+
+        };
+
+        inspectionThread.setDaemon(true);
+        inspectionThread.start();
+    }
+
+    /**
+     * 添加处理线程
+     *
+     * @param immortal
+     * @author WANGWEI
+     */
+    private void addWorkerThread(final boolean immortal) {
+        LOG.info("create a new worker. immortal=" + immortal);
+        Thread thread = new Thread() {
+
+            long nullTimes = 0;
+
+            @Override
+            public void run() {
+                while (true) {
+                    T el = queue.poll();
+                    if (null == el) {
+                        nullTimes++;
+                        if (10 <= nullTimes) {
+                            if (immortal) {
+                                Util.sleep(2);
+                                continue;
+                            } else {
+                                LOG.info("no element.worker exist.");
+                                break;
+                            }
+                        } else {
+                            Util.sleep(2);
+                            continue;
+                        }
+                    } else {
+                        nullTimes = 0;
+                    }
+
+                    try {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("process. element=" + el.toString());
+                        }
+                        worker.process(workerController, el);
+                    } catch (Exception e) {
+                        LOG.error("unexpected exception", e);
+                    }
+
+                    // 非不死线程在抢到终止消息时,结束线程
+                    if (!immortal) {
+                        Integer warnCount = workerMessages.poll();
+                        if (null != warnCount) {
+                            LOG.info("worker exist. warnCount=" + warnCount);
+                            break;
+                        }
+                    }
+
+                }
+            }
+        };
+
+        threadPoolExecutor.execute(thread);
+    }
+
+    public void setMaxActiveThreadSize(int maxActiveThreadSize) {
+        this.maxActiveThreadSize = maxActiveThreadSize;
+    }
+
+    public void setMinThreadSize(int minThreadSize) {
+        this.minThreadSize = minThreadSize;
+    }
+
+    public void setWorker(Worker<T> worker) {
+        this.worker = worker;
+    }
+
+}

+ 1 - 1
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/Worker.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/Worker.java

@@ -2,6 +2,6 @@ package cn.com.qmth.examcloud.commons.helpers.concurrency.simple;
 
 public interface Worker<T> {
 
-	void process(final WorkerController controller, T element);
+    void process(final WorkerController controller, T element);
 
 }

+ 27 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/concurrency/simple/WorkerController.java

@@ -0,0 +1,27 @@
+package cn.com.qmth.examcloud.commons.helpers.concurrency.simple;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class WorkerController {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WorkerController.class);
+
+    private AtomicInteger warnCount = new AtomicInteger(0);
+
+    public void addConcurrencyWarn() {
+        LOG.info("warn count ++");
+        this.warnCount.incrementAndGet();
+    }
+
+    public int getWarnCount() {
+        return this.warnCount.get();
+    }
+
+    public void resetWarnCount() {
+        warnCount.set(0);
+    }
+
+}

+ 44 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Counter.java

@@ -0,0 +1,44 @@
+package cn.com.qmth.examcloud.commons.helpers.pipeline;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 输出计数器
+ *
+ * @author WANGWEI
+ * @date 2019年12月12日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class Counter {
+
+    private AtomicLong total = new AtomicLong(0);
+
+    private AtomicLong successAmount = new AtomicLong(0);
+
+    private AtomicLong failureAmount = new AtomicLong(0);
+
+    public long getTotal() {
+        return total.get();
+    }
+
+    public long getSuccessAmount() {
+        return successAmount.get();
+    }
+
+    public long getFailureAmount() {
+        return failureAmount.get();
+    }
+
+    public long incrementTotal() {
+        return this.total.incrementAndGet();
+    }
+
+    public long incrementSuccessAmount() {
+        return this.successAmount.incrementAndGet();
+    }
+
+    public long incrementFailureAmount() {
+        return this.failureAmount.incrementAndGet();
+    }
+
+}

+ 59 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Node.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.examcloud.commons.helpers.pipeline;
+
+/**
+ * 节点
+ *
+ * @author WANGWEI
+ * @date 2019年12月12日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public interface Node<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
+
+    /**
+     * 启动
+     *
+     * @author WANGWEI
+     */
+    void start();
+
+    /**
+     * 设置下级节点
+     *
+     * @param subNode
+     * @author WANGWEI
+     */
+    void setLowerNode(Node<KEYOUT, VALUEOUT, ?, ?> lowerNode);
+
+    /**
+     * 获取下级节点
+     *
+     * @return
+     * @author WANGWEI
+     */
+    Node<KEYOUT, VALUEOUT, ?, ?> getLowerNode();
+
+    /**
+     * 获取存储器
+     *
+     * @return
+     * @author WANGWEI
+     */
+    Storer<KEYIN, VALUEIN> getStorer();
+
+    /**
+     * 设置是否是首节点
+     *
+     * @param first
+     * @author WANGWEI
+     */
+    void setFirst(boolean first);
+
+    /**
+     * 设置循环间隔
+     *
+     * @param sleep
+     * @author WANGWEI
+     */
+    void setSleep(int sleep);
+
+}

+ 18 - 18
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/NodeExecuter.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/NodeExecuter.java

@@ -1,35 +1,35 @@
 package cn.com.qmth.examcloud.commons.helpers.pipeline;
 
-import java.util.List;
-
 import cn.com.qmth.examcloud.commons.helpers.KeyValuePair;
 import cn.com.qmth.examcloud.commons.helpers.ObjectHolder;
 
+import java.util.List;
+
 /**
  * 节点执行器
  *
- * @author WANGWEI
- * @date 2019年12月12日
- * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
  * @param <KEYIN>
  * @param <VALUEIN>
  * @param <KEYOUT>
  * @param <VALUEOUT>
+ * @author WANGWEI
+ * @date 2019年12月12日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
  */
 public interface NodeExecuter<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
 
-	/**
-	 * 执行
-	 *
-	 * @author WANGWEI
-	 * @param key
-	 * @param value
-	 * @param outList
-	 * @param removable
-	 * @param context
-	 * @throws Exception
-	 */
-	void execute(KEYIN key, VALUEIN value, final List<KeyValuePair<KEYOUT, VALUEOUT>> outList,
-			final ObjectHolder<Boolean> removable, TaskContext context) throws Exception;
+    /**
+     * 执行
+     *
+     * @param key
+     * @param value
+     * @param outList
+     * @param removable
+     * @param context
+     * @throws Exception
+     * @author WANGWEI
+     */
+    void execute(KEYIN key, VALUEIN value, final List<KeyValuePair<KEYOUT, VALUEOUT>> outList,
+                 final ObjectHolder<Boolean> removable, TaskContext context) throws Exception;
 
 }

+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/SimpleNode.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/SimpleNode.java


+ 40 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/Storer.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.examcloud.commons.helpers.pipeline;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 节点存储器
+ *
+ * @author WANGWEI
+ * @date 2019年12月12日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class Storer<KEY, VALUE> {
+
+    private Map<KEY, VALUE> MAP = Maps.newConcurrentMap();
+
+    private Map<KEY, VALUE> BUFFER_MAP = Maps.newConcurrentMap();
+
+    public synchronized Set<Entry<KEY, VALUE>> getEntrySet() {
+        MAP.putAll(BUFFER_MAP);
+        BUFFER_MAP.clear();
+        return MAP.entrySet();
+    }
+
+    public synchronized void putElement(KEY key, VALUE value) {
+        BUFFER_MAP.put(key, value);
+    }
+
+    public synchronized boolean isEmpty() {
+        return MAP.isEmpty();
+    }
+
+    public synchronized void remove(KEY key) {
+        MAP.remove(key);
+    }
+
+}

+ 35 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/pipeline/TaskContext.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.examcloud.commons.helpers.pipeline;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 任务上下文(任务参数)
+ *
+ * @author WANGWEI
+ * @date 2019年12月12日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class TaskContext implements Serializable {
+
+    private static final long serialVersionUID = 4979254175922604943L;
+
+    private final Map<String, Object> props = new ConcurrentHashMap<String, Object>();
+
+    public String get(String name) {
+        return get(name, String.class);
+    }
+
+    public <T> T get(String name, Class<T> t) {
+        Object value = props.get(name);
+        @SuppressWarnings("unchecked")
+        T ret = (T) value;
+        return ret;
+    }
+
+    public void put(String name, Object bean) {
+        props.put(name, bean);
+    }
+
+}

+ 180 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelReader.java

@@ -0,0 +1,180 @@
+package cn.com.qmth.examcloud.commons.helpers.poi;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.io.IOUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * Excel解析器
+ *
+ * @author WANGWEI
+ * @date 2018年3月30日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class ExcelReader {
+
+    /**
+     * 方法注释
+     *
+     * @param sheet
+     * @param columSize
+     * @return
+     * @author WANGWEI
+     */
+    public static List<String[]> readSheet(Sheet sheet, int columSize) {
+        List<String[]> list = Lists.newArrayList();
+        int firstRowNum = sheet.getFirstRowNum();
+        int lastRowNum = sheet.getLastRowNum();
+        for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) {
+            Row row = sheet.getRow(rowNum);
+            if (row == null) {
+                continue;
+            }
+            String[] cells = new String[columSize];
+
+            for (int index = 0; index < columSize; index++) {
+                Cell cell = row.getCell(index);
+                cells[index] = getCellValue(cell);
+            }
+
+            list.add(cells);
+        }
+
+        return list;
+    }
+
+    /**
+     * 获取sheet
+     *
+     * @param workbook
+     * @return
+     * @author WANGWEI
+     */
+    public static List<Sheet> getSheet(Workbook workbook) {
+
+        List<Sheet> sheets = Lists.newArrayList();
+        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
+            Sheet sheet = workbook.getSheetAt(sheetNum);
+            sheets.add(sheet);
+        }
+        return sheets;
+    }
+
+    /**
+     * 获取 Workbook 对象
+     *
+     * @param file
+     * @author WANGWEI
+     */
+    public static Workbook getWorkBook(File file) {
+
+        Workbook workbook = null;
+        try {
+            // 2007
+            workbook = new XSSFWorkbook(new FileInputStream(file));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return workbook;
+    }
+
+    /**
+     * 获取单元格的字符串值
+     *
+     * @param cell
+     * @return
+     * @author WANGWEI
+     */
+    public static String getCellValue(Cell cell) {
+        String value = "";
+        if (null == cell) {
+            return value;
+        }
+        cell.setCellType(CellType.STRING);
+        switch (cell.getCellTypeEnum()) {
+            case _NONE:
+                break;
+            case STRING:
+                value = cell.getStringCellValue();
+                break;
+            case NUMERIC:
+                // 待完善
+                value = String.valueOf(cell.getNumericCellValue());
+                break;
+            case BOOLEAN:
+                value = String.valueOf(cell.getBooleanCellValue());
+                break;
+            case BLANK:
+                value = "";
+                break;
+            default:
+                value = cell.toString();
+        }
+        return value.trim();
+    }
+
+    /**
+     * 关闭资源
+     *
+     * @param workbook
+     * @author WANGWEI
+     */
+    public static void close(Workbook workbook) {
+        IOUtils.closeQuietly(workbook);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param filePath
+     * @param sheetId
+     * @param columnSize
+     * @return
+     * @author WANGWEI
+     */
+    public static List<String[]> readSheetBySax(String filePath, int sheetId, int columnSize) {
+        List<String[]> list = Lists.newArrayList();
+
+        XlsxHandler xlsxHandler = new XlsxHandler(columnSize) {
+            @Override
+            public void optRows(int sheetIndex, int curRow, String[] row) {
+                list.add(row);
+            }
+        };
+
+        try {
+            xlsxHandler.processOneSheet(filePath, sheetId);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return list;
+    }
+
+    public static List<String[]> readSheetBySax(InputStream is, int sheetId, int columnSize) {
+        List<String[]> list = Lists.newArrayList();
+
+        XlsxHandler xlsxHandler = new XlsxHandler(columnSize) {
+            @Override
+            public void optRows(int sheetIndex, int curRow, String[] row) {
+                list.add(row);
+            }
+        };
+
+        try {
+            xlsxHandler.processOneSheet(is, sheetId);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return list;
+    }
+
+}

+ 130 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/ExcelWriter.java

@@ -0,0 +1,130 @@
+package cn.com.qmth.examcloud.commons.helpers.poi;
+
+import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
+import org.apache.commons.io.FileUtils;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.usermodel.*;
+
+import java.awt.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Excel 生成器
+ *
+ * @author WANGWEI
+ * @date 2018年9月7日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class ExcelWriter {
+
+    /**
+     * 写入excel文件
+     *
+     * @param tableHeader
+     * @param datas
+     * @param file
+     * @author WANGWEI
+     */
+    public static void write(String[] tableHeader, Class<?>[] types, List<Object[]> datas,
+                             File file) {
+        // 2007
+        XSSFWorkbook workbook = null;
+        FileOutputStream out = null;
+        try {
+            // 2007
+            workbook = new XSSFWorkbook();
+
+            XSSFSheet sheet = workbook.createSheet();
+
+            XSSFCellStyle style = workbook.createCellStyle();
+            style.setFillForegroundColor(new XSSFColor(new Color(227, 239, 217)));
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+
+            XSSFRow firstRow = sheet.createRow(0);
+            for (int i = 0; i < tableHeader.length; i++) {
+                XSSFCell cell = firstRow.createCell(i);
+                cell.setCellStyle(style);
+                cell.setCellType(CellType.STRING);
+                cell.setCellValue(tableHeader[i]);
+            }
+
+            for (int k = 0; k < datas.size(); k++) {
+                XSSFRow nextRow = sheet.createRow(k + 1);
+                Object[] rowDatas = datas.get(k);
+
+                for (int j = 0; j < types.length; j++) {
+                    Class<?> type = types[j];
+                    Object value = rowDatas[j];
+
+                    XSSFCell cell = nextRow.createCell(j);
+
+                    if (type.equals(String.class)) {
+                        cell.setCellType(CellType.STRING);
+                        if (null != value) {
+                            cell.setCellValue((String) value);
+                        }
+                    } else if (type.equals(Long.class)) {
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Long) value);
+                        }
+                    } else if (type.equals(Integer.class)) {
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Integer) value);
+                        }
+                    } else if (type.equals(Short.class)) {
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Short) value);
+                        }
+                    } else if (type.equals(Float.class)) {
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Float) value);
+                        }
+                    } else if (type.equals(Double.class)) {
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Double) value);
+                        }
+                    } else if (type.equals(Date.class)) {
+                        CellStyle cs = workbook.createCellStyle();
+                        XSSFDataFormat format = workbook.createDataFormat();
+                        cs.setDataFormat(format.getFormat(DatePatterns.CHINA_DEFAULT));
+                        cell.setCellStyle(cs);
+                        cell.setCellType(CellType.NUMERIC);
+                        if (null != value) {
+                            cell.setCellValue((Date) value);
+                        }
+                    } else if (type.equals(Boolean.class)) {
+                        cell.setCellType(CellType.BOOLEAN);
+                        if (null != value) {
+                            cell.setCellValue((Boolean) value);
+                        }
+                    } else {
+                        IOUtils.closeQuietly(workbook);
+                        throw new RuntimeException("cell type is wrong");
+                    }
+                }
+            }
+
+            out = FileUtils.openOutputStream(file);
+            workbook.write(out);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        } finally {
+            IOUtils.closeQuietly(out);
+            IOUtils.closeQuietly(workbook);
+        }
+    }
+
+}

+ 224 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/helpers/poi/XlsxHandler.java

@@ -0,0 +1,224 @@
+package cn.com.qmth.examcloud.commons.helpers.poi;
+
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * excel xlsx 文件解析
+ *
+ * @author WANGWEI
+ * @date 2018年8月1日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public abstract class XlsxHandler extends DefaultHandler {
+
+    private String[] row;
+
+    private SharedStringsTable sst;
+
+    private String cellValue;
+
+    private boolean isString;
+
+    private int sheetIndex = -1;
+
+    private int curRow = 0;
+
+    private int curColumnIndex = 0;
+
+    private int columnSize = 0;
+
+    /**
+     * 构造函数
+     *
+     * @param columnSize
+     */
+    public XlsxHandler(int columnSize) {
+        super();
+        this.columnSize = columnSize;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param sheetIndex
+     * @param curRow
+     * @param row
+     * @author WANGWEI
+     */
+    public abstract void optRows(int sheetIndex, int curRow, String[] row);
+
+    /**
+     * 方法注释
+     *
+     * @param filePath
+     * @param sheetId
+     * @throws Exception
+     * @author WANGWEI
+     */
+    public void processOneSheet(String filePath, int sheetId) throws Exception {
+        OPCPackage pkg = null;
+        InputStream is = null;
+        try {
+            pkg = OPCPackage.open(filePath);
+            XSSFReader r = new XSSFReader(pkg);
+            SharedStringsTable sst = r.getSharedStringsTable();
+
+            XMLReader parser = XMLReaderFactory.createXMLReader();
+            this.sst = sst;
+            parser.setContentHandler(this);
+            is = r.getSheet("rId" + sheetId);
+            sheetIndex++;
+            InputSource sheetSource = new InputSource(is);
+            parser.parse(sheetSource);
+        } finally {
+            IOUtils.closeQuietly(is);
+            IOUtils.closeQuietly(pkg);
+        }
+    }
+
+    public void processOneSheet(InputStream is, int sheetId) throws Exception {
+        OPCPackage pkg = null;
+        try {
+            pkg = OPCPackage.open(is);
+            XSSFReader r = new XSSFReader(pkg);
+            SharedStringsTable sst = r.getSharedStringsTable();
+
+            XMLReader parser = XMLReaderFactory.createXMLReader();
+            this.sst = sst;
+            parser.setContentHandler(this);
+            is = r.getSheet("rId" + sheetId);
+            sheetIndex++;
+            InputSource sheetSource = new InputSource(is);
+            parser.parse(sheetSource);
+        } finally {
+            IOUtils.closeQuietly(is);
+            IOUtils.closeQuietly(pkg);
+        }
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param filePath
+     * @throws Exception
+     * @author WANGWEI
+     */
+    public void process(String filePath) throws Exception {
+        OPCPackage pkg = null;
+        try {
+            pkg = OPCPackage.open(filePath);
+            XSSFReader r = new XSSFReader(pkg);
+            SharedStringsTable sst = r.getSharedStringsTable();
+
+            XMLReader parser = XMLReaderFactory.createXMLReader();
+            this.sst = sst;
+            parser.setContentHandler(this);
+
+            Iterator<InputStream> sheets = r.getSheetsData();
+            while (sheets.hasNext()) {
+                curRow = 0;
+                sheetIndex++;
+                InputStream sheet = null;
+                try {
+                    sheet = sheets.next();
+                    InputSource sheetSource = new InputSource(sheet);
+                    parser.parse(sheetSource);
+                } finally {
+                    IOUtils.closeQuietly(sheet);
+                }
+            }
+        } finally {
+            IOUtils.closeQuietly(pkg);
+        }
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String name, Attributes attributes)
+            throws SAXException {
+        if (name.equals("c")) {
+            String cellType = attributes.getValue("t");
+            String x = attributes.getValue("r");
+            curColumnIndex = this.getColunmIndex(x);
+            if (cellType != null && cellType.equals("s")) {
+                isString = true;
+            } else {
+                isString = false;
+            }
+        }
+        cellValue = "";
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        cellValue += new String(ch, start, length);
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String name) throws SAXException {
+        if (isString) {
+            try {
+                int idx = Integer.parseInt(cellValue);
+                cellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
+            } catch (Exception e) {
+
+            }
+        }
+
+        if (null == row) {
+            row = new String[columnSize];
+        }
+
+        if (name.equals("v")) {
+            String value = cellValue.trim();
+            if (curColumnIndex - 1 < columnSize) {
+                row[curColumnIndex - 1] = value;
+            }
+        } else if (name.equals("row")) {
+            optRows(sheetIndex, curRow, row);
+            row = null;
+            curRow++;
+            curColumnIndex = 0;
+        }
+
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param x
+     * @return
+     * @author WANGWEI
+     */
+    private int getColunmIndex(String x) {
+        x = x.replaceAll("[^A-Z]", "");
+        byte[] bytes = x.getBytes();
+        int len = bytes.length;
+        float num = 0;
+        for (int i = 0; i < len; i++) {
+            num += (bytes[i] - 'A' + 1) * Math.pow(26, len - i - 1);
+        }
+        return (int) num;
+    }
+
+    public int getColumnSize() {
+        return columnSize;
+    }
+
+    public void setColumnSize(int columnSize) {
+        this.columnSize = columnSize;
+    }
+
+}

+ 98 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLog.java

@@ -0,0 +1,98 @@
+package cn.com.qmth.examcloud.commons.logging;
+
+/**
+ * 通用日志写入器
+ *
+ * @author WANGWEI
+ */
+public interface ExamCloudLog {
+
+    /**
+     * Is the logger instance enabled for the DEBUG level?
+     *
+     * @return True if this Logger is enabled for the DEBUG level, false otherwise.
+     */
+    public boolean isDebugEnabled();
+
+    /**
+     * Log a message at the DEBUG level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void debug(String msg);
+
+    /**
+     * Log an exception (throwable) at the DEBUG level with an accompanying message.
+     *
+     * @param msg the message accompanying the exception
+     * @param t   the exception (throwable) to log
+     */
+    public void debug(String msg, Throwable t);
+
+    /**
+     * Is the logger instance enabled for the INFO level?
+     *
+     * @return True if this Logger is enabled for the INFO level, false otherwise.
+     */
+    public boolean isInfoEnabled();
+
+    /**
+     * Log a message at the INFO level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void info(String msg);
+
+    /**
+     * Log an exception (throwable) at the INFO level with an accompanying message.
+     *
+     * @param msg the message accompanying the exception
+     * @param t   the exception (throwable) to log
+     */
+    public void info(String msg, Throwable t);
+
+    /**
+     * Is the logger instance enabled for the WARN level?
+     *
+     * @return True if this Logger is enabled for the WARN level, false otherwise.
+     */
+    public boolean isWarnEnabled();
+
+    /**
+     * Log a message at the WARN level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void warn(String msg);
+
+    /**
+     * Log an exception (throwable) at the WARN level with an accompanying message.
+     *
+     * @param msg the message accompanying the exception
+     * @param t   the exception (throwable) to log
+     */
+    public void warn(String msg, Throwable t);
+
+    /**
+     * Is the logger instance enabled for the ERROR level?
+     *
+     * @return True if this Logger is enabled for the ERROR level, false otherwise.
+     */
+    public boolean isErrorEnabled();
+
+    /**
+     * Log a message at the ERROR level.
+     *
+     * @param msg the message string to be logged
+     */
+    public void error(String msg);
+
+    /**
+     * Log an exception (throwable) at the ERROR level with an accompanying message.
+     *
+     * @param msg the message accompanying the exception
+     * @param t   the exception (throwable) to log
+     */
+    public void error(String msg, Throwable t);
+
+}

+ 78 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/ExamCloudLogFactory.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.commons.logging;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * 通用日志写入器工厂
+ *
+ * @author WANGWEI
+ */
+public class ExamCloudLogFactory {
+
+    private static Constructor<?> logConstructor;
+
+    static {
+        tryImplementation("org.slf4j.Logger", SLF4JImpl.class.getName());
+
+        if (logConstructor == null) {
+            try {
+                logConstructor = NoLoggingImpl.class.getConstructor(String.class);
+            } catch (Exception e) {
+                throw new IllegalStateException(e.getMessage(), e);
+            }
+        }
+    }
+
+    /**
+     * @param testClassName
+     * @param implClassName
+     */
+    private static void tryImplementation(String testClassName, String implClassName) {
+        if (logConstructor != null) {
+            return;
+        }
+
+        try {
+            Resources.classForName(testClassName);
+            Class<?> implClass = Resources.classForName(implClassName);
+            logConstructor = implClass.getConstructor(new Class[]{String.class});
+
+            Class<?> declareClass = logConstructor.getDeclaringClass();
+            if (!ExamCloudLog.class.isAssignableFrom(declareClass)) {
+                logConstructor = null;
+            }
+
+            try {
+                if (null != logConstructor) {
+                    logConstructor.newInstance(ExamCloudLogFactory.class.getName());
+                }
+            } catch (Throwable t) {
+                logConstructor = null;
+            }
+
+        } catch (Throwable t) {
+            // skip
+        }
+    }
+
+    /**
+     * @param clazz
+     * @return
+     */
+    public static ExamCloudLog getLog(Class<?> clazz) {
+        return getLog(clazz.getName());
+    }
+
+    /**
+     * @param loggerName
+     * @return
+     */
+    public static ExamCloudLog getLog(String loggerName) {
+        try {
+            return (ExamCloudLog) logConstructor.newInstance(loggerName);
+        } catch (Throwable t) {
+            throw new RuntimeException("Error creating logger for logger '" + loggerName + "'.  Cause: " + t, t);
+        }
+    }
+
+}

+ 70 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/NoLoggingImpl.java

@@ -0,0 +1,70 @@
+package cn.com.qmth.examcloud.commons.logging;
+
+/**
+ * no logging
+ *
+ * @author WANGWEI
+ */
+public class NoLoggingImpl implements ExamCloudLog {
+
+    /**
+     * 构造函数
+     *
+     * @param loggerName
+     */
+    public NoLoggingImpl(String loggerName) {
+    }
+
+    @Override
+    public boolean isDebugEnabled() {
+        return false;
+    }
+
+    @Override
+    public void debug(String msg) {
+    }
+
+    @Override
+    public void debug(String msg, Throwable t) {
+    }
+
+    @Override
+    public boolean isInfoEnabled() {
+        return false;
+    }
+
+    @Override
+    public void info(String msg) {
+    }
+
+    @Override
+    public void info(String msg, Throwable t) {
+    }
+
+    @Override
+    public boolean isWarnEnabled() {
+        return false;
+    }
+
+    @Override
+    public void warn(String msg) {
+    }
+
+    @Override
+    public void warn(String msg, Throwable t) {
+    }
+
+    @Override
+    public boolean isErrorEnabled() {
+        return false;
+    }
+
+    @Override
+    public void error(String msg) {
+    }
+
+    @Override
+    public void error(String msg, Throwable t) {
+    }
+
+}

+ 64 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/Resources.java

@@ -0,0 +1,64 @@
+package cn.com.qmth.examcloud.commons.logging;
+
+/**
+ * A class to simplify access to resources through the classloader.
+ *
+ * @author WANGWEI
+ */
+public final class Resources extends Object {
+
+    private static ClassLoader defaultClassLoader;
+
+    /**
+     * 构造函数
+     */
+    private Resources() {
+    }
+
+    /**
+     * Returns the default classloader (may be null).
+     *
+     * @return The default classloader
+     */
+    public static ClassLoader getDefaultClassLoader() {
+        return defaultClassLoader;
+    }
+
+    /**
+     * Sets the default classloader
+     *
+     * @param defaultClassLoader - the new default ClassLoader
+     */
+    public static void setDefaultClassLoader(ClassLoader defaultClassLoader) {
+        Resources.defaultClassLoader = defaultClassLoader;
+    }
+
+    /**
+     * Loads a class
+     *
+     * @param className - the class to load
+     * @return The loaded class
+     * @throws ClassNotFoundException If the class cannot be found (duh!)
+     */
+    public static Class<?> classForName(String className) throws ClassNotFoundException {
+        Class<?> clazz = null;
+        try {
+            clazz = getClassLoader().loadClass(className);
+        } catch (Exception e) {
+            // Ignore.
+        }
+        if (clazz == null) {
+            clazz = Class.forName(className);
+        }
+        return clazz;
+    }
+
+    private static ClassLoader getClassLoader() {
+        if (defaultClassLoader != null) {
+            return defaultClassLoader;
+        } else {
+            return Thread.currentThread().getContextClassLoader();
+        }
+    }
+
+}

+ 111 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/logging/SLF4JImpl.java

@@ -0,0 +1,111 @@
+package cn.com.qmth.examcloud.commons.logging;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.spi.LocationAwareLogger;
+
+/**
+ * slf4j
+ *
+ * @author WANGWEI
+ */
+public class SLF4JImpl implements ExamCloudLog {
+
+    /**
+     * 属性注释
+     */
+    private static final String callerFQCN = SLF4JImpl.class.getName();
+
+    /**
+     * 属性注释
+     */
+    private static final Logger testLogger = LoggerFactory.getLogger(SLF4JImpl.class);
+
+    /**
+     * 属性注释
+     */
+    private LocationAwareLogger log;
+
+    static {
+        if (!(testLogger instanceof LocationAwareLogger)) {
+            throw new UnsupportedOperationException(testLogger.getClass() + " is not a suitable logger");
+        }
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param log
+     */
+    public SLF4JImpl(LocationAwareLogger log) {
+        this.log = log;
+    }
+
+    /**
+     * 构造函数
+     */
+    public SLF4JImpl(String loggerName) {
+        this.log = (LocationAwareLogger) LoggerFactory.getLogger(loggerName);
+    }
+
+    @Override
+    public boolean isDebugEnabled() {
+        return log.isDebugEnabled();
+    }
+
+    @Override
+    public void debug(String msg) {
+        log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, null);
+    }
+
+    @Override
+    public void debug(String msg, Throwable e) {
+        log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e);
+    }
+
+    @Override
+    public boolean isInfoEnabled() {
+        return log.isInfoEnabled();
+    }
+
+    @Override
+    public void info(String msg) {
+        log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null);
+    }
+
+    @Override
+    public void info(String msg, Throwable t) {
+        log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, t);
+    }
+
+    @Override
+    public boolean isWarnEnabled() {
+        return log.isWarnEnabled();
+    }
+
+    @Override
+    public void warn(String msg) {
+        log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, null);
+    }
+
+    @Override
+    public void warn(String msg, Throwable t) {
+        log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, t);
+    }
+
+    @Override
+    public boolean isErrorEnabled() {
+        return log.isErrorEnabled();
+    }
+
+    @Override
+    public void error(String msg) {
+        log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, null);
+    }
+
+    @Override
+    public void error(String msg, Throwable t) {
+        log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, t);
+    }
+
+}

+ 133 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/AES.java

@@ -0,0 +1,133 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.GeneralSecurityException;
+
+/**
+ * AES算法<br>
+ * CBC(密码块链)模式<br>
+ * 警告:每次加解密都要创建一个{@link AES}
+ *
+ * @author WANGWEI
+ * @date 2018年11月21日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class AES {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AES.class);
+
+    private static final String KEY_ALGORITHM = "AES";
+
+    private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
+
+    private static final String DEFAULT_KEY = "7&*5690)%#6#)7!-9*52@*#^&*$%";
+
+    private Cipher encryptCipher = null;
+
+    private Cipher decryptCipher = null;
+
+    public static void main(String[] args) {
+        String s = "";
+        System.out.println(new AES().decrypt(s));
+    }
+
+    /**
+     * 默认构造方法
+     */
+    public AES() {
+        this(DEFAULT_KEY);
+    }
+
+    /**
+     * 指定密钥构造方法
+     *
+     * @param keyStr 指定的密钥
+     */
+    public AES(String keyStr) {
+        try {
+            SecretKey secretKey = getSecretKey(keyStr);
+            keyStr = StringUtils.rightPad(keyStr, 30, (char) 48);
+            final byte[] iv = keyStr.substring(2, 18).getBytes();
+
+            encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
+            decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
+
+            encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
+            decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
+        } catch (GeneralSecurityException e) {
+            LOG.error("fail to new instance of AES.", e);
+        }
+    }
+
+    /**
+     * 加密
+     *
+     * @param bytes
+     * @return
+     */
+    public String encrypt(byte[] bytes) {
+        try {
+            byte[] enc = encryptCipher.doFinal(bytes);
+            return Hex.encodeHexString(enc);
+        } catch (IllegalBlockSizeException e) {
+            throw new ExamCloudRuntimeException(e);
+        } catch (BadPaddingException e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    /**
+     * 加密
+     *
+     * @param str
+     * @return
+     */
+    public String encrypt(String str) {
+        return encrypt(str.getBytes());
+    }
+
+    /**
+     * 解密
+     *
+     * @param str
+     * @return
+     */
+    public String decrypt(String str) {
+        try {
+            byte[] dec = decryptCipher.doFinal(Hex.decodeHex(str));
+            return new String(dec);
+        } catch (IllegalBlockSizeException e) {
+            throw new ExamCloudRuntimeException(e);
+        } catch (BadPaddingException e) {
+            throw new ExamCloudRuntimeException(e);
+        } catch (DecoderException e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    /**
+     * @param key
+     * @return
+     */
+    private SecretKey getSecretKey(String key) {
+        byte[] bytes = key.getBytes();
+        byte[] target = new byte[16];
+
+        int length = bytes.length;
+        System.arraycopy(bytes, 0, target, 0, length < 16 ? length : 16);
+        return new SecretKeySpec(target, KEY_ALGORITHM);
+    }
+
+}

+ 89 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/AsciiUtil.java

@@ -0,0 +1,89 @@
+package cn.com.qmth.examcloud.commons.util;
+
+/**
+ * Ascii转换
+ *
+ * @author WANGWEI
+ * @date 2018年12月3日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class AsciiUtil {
+
+    private static String PREFIX = "\\u";
+
+    /**
+     * native to ASCII
+     *
+     * @param str
+     * @return
+     * @author WANGWEI
+     */
+    public static String native2Ascii(String str) {
+        char[] chars = str.toCharArray();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < chars.length; i++) {
+            sb.append(char2Ascii(chars[i]));
+        }
+        return sb.toString();
+    }
+
+    private static String char2Ascii(char c) {
+        if (c > 255) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(PREFIX);
+            int code = (c >> 8);
+            String tmp = Integer.toHexString(code);
+            if (tmp.length() == 1) {
+                sb.append("0");
+            }
+            sb.append(tmp);
+            code = (c & 0xFF);
+            tmp = Integer.toHexString(code);
+            if (tmp.length() == 1) {
+                sb.append("0");
+            }
+            sb.append(tmp);
+            return sb.toString();
+        } else {
+            return Character.toString(c);
+        }
+    }
+
+    /**
+     * ASCII to native
+     *
+     * @param str
+     * @return
+     * @author WANGWEI
+     */
+    public static String ascii2Native(String str) {
+        StringBuilder sb = new StringBuilder();
+        int begin = 0;
+        int index = str.indexOf(PREFIX);
+        while (index != -1) {
+            sb.append(str.substring(begin, index));
+            sb.append(ascii2Char(str.substring(index, index + 6)));
+            begin = index + 6;
+            index = str.indexOf(PREFIX, begin);
+        }
+        sb.append(str.substring(begin));
+        return sb.toString();
+    }
+
+    private static char ascii2Char(String str) {
+        if (str.length() != 6) {
+            throw new IllegalArgumentException(
+                    "Ascii string of a native character must be 6 character.");
+        }
+        if (!PREFIX.equals(str.substring(0, 2))) {
+            throw new IllegalArgumentException(
+                    "Ascii string of a native character must start with \"\\u\".");
+        }
+        String tmp = str.substring(2, 4);
+        int code = Integer.parseInt(tmp, 16) << 8;
+        tmp = str.substring(4, 6);
+        code += Integer.parseInt(tmp, 16);
+        return (char) code;
+    }
+
+}

+ 54 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/BooleanUtil.java

@@ -0,0 +1,54 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import org.apache.commons.lang3.BooleanUtils;
+
+/**
+ * boolean 工具
+ *
+ * @author WANGWEI
+ * @date 2019年10月21日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class BooleanUtil {
+
+    /**
+     * 统计true的数量
+     *
+     * @param values
+     * @return
+     * @author WANGWEI
+     */
+    public static int countTrue(boolean... values) {
+        if (null == values) {
+            return 0;
+        }
+        int count = 0;
+        for (boolean b : values) {
+            if (BooleanUtils.isTrue(b)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * 统计false的数量
+     *
+     * @param values
+     * @return
+     * @author WANGWEI
+     */
+    public static int countFalse(boolean... values) {
+        if (null == values) {
+            return 0;
+        }
+        int count = 0;
+        for (boolean b : values) {
+            if (BooleanUtils.isFalse(b)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+}

+ 117 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/ByteUtil.java

@@ -0,0 +1,117 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+/**
+ * 字节转换工具
+ *
+ * @author WANGWEI
+ * @date 2018年4月27日
+ */
+public class ByteUtil {
+
+    public final static short UNSIGNED_MAX_VALUE = (Byte.MAX_VALUE * 2) + 1;
+
+    private ByteUtil() {
+    }
+
+    public static int unsignedPromote(byte b) {
+        return b & 0xff;
+    }
+
+    public static String toHexAscii(byte b) {
+        StringWriter sw = new StringWriter(2);
+        addHexAscii(b, sw);
+        return sw.toString();
+    }
+
+    public static String toLowercaseHexAscii(byte b) {
+        StringWriter sw = new StringWriter(2);
+        addLowercaseHexAscii(b, sw);
+        return sw.toString();
+    }
+
+    public static String toHexAscii(byte[] bytes) {
+        int len = bytes.length;
+        StringWriter sw = new StringWriter(len * 2);
+        for (int i = 0; i < len; ++i)
+            addHexAscii(bytes[i], sw);
+        return sw.toString();
+    }
+
+    public static String toLowercaseHexAscii(byte[] bytes) {
+        int len = bytes.length;
+        StringWriter sw = new StringWriter(len * 2);
+        for (int i = 0; i < len; ++i)
+            addLowercaseHexAscii(bytes[i], sw);
+        return sw.toString();
+    }
+
+    public static byte[] fromHexAscii(String s) throws NumberFormatException {
+        try {
+            int len = s.length();
+            if ((len % 2) != 0)
+                throw new NumberFormatException("Hex ascii must be exactly two digits per byte.");
+
+            int out_len = len / 2;
+            byte[] out = new byte[out_len];
+            int i = 0;
+            StringReader sr = new StringReader(s);
+            while (i < out_len) {
+                int val = (16 * fromHexDigit(sr.read())) + fromHexDigit(sr.read());
+                out[i++] = (byte) val;
+            }
+            return out;
+        } catch (IOException e) {
+            throw new InternalError("IOException reading from StringReader?!?!");
+        }
+    }
+
+    static void addHexAscii(byte b, StringWriter sw) {
+        int ub = unsignedPromote(b);
+        int h1 = ub / 16;
+        int h2 = ub % 16;
+        sw.write(toHexDigit(h1));
+        sw.write(toHexDigit(h2));
+    }
+
+    static void addLowercaseHexAscii(byte b, StringWriter sw) {
+        int ub = unsignedPromote(b);
+        int h1 = ub / 16;
+        int h2 = ub % 16;
+        sw.write(toLowercaseHexDigit(h1));
+        sw.write(toLowercaseHexDigit(h2));
+    }
+
+    private static int fromHexDigit(int c) throws NumberFormatException {
+        if (c >= 0x30 && c < 0x3A)
+            return c - 0x30;
+        else if (c >= 0x41 && c < 0x47)
+            return c - 0x37;
+        else if (c >= 0x61 && c < 0x67)
+            return c - 0x57;
+        else
+            throw new NumberFormatException('\'' + c + "' is not a valid hexadecimal digit.");
+    }
+
+    private static char toHexDigit(int h) {
+        char out;
+        if (h <= 9)
+            out = (char) (h + 0x30);
+        else
+            out = (char) (h + 0x37);
+        return out;
+    }
+
+    private static char toLowercaseHexDigit(int h) {
+        char out;
+        if (h <= 9)
+            out = (char) (h + 0x30);
+        else
+            out = (char) (h + 0x57);
+        return out;
+    }
+
+}

+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/Calculator.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/Calculator.java


+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/CollectionUtil.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/CollectionUtil.java


+ 213 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/DateUtil.java

@@ -0,0 +1,213 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * 日期工具
+ *
+ * @author WANGWEI
+ */
+public class DateUtil {
+
+    /**
+     * patterns describing the date and time format
+     *
+     * @author WANGWEI
+     */
+    public interface DatePatterns {
+
+        public static final String DEFAULT = "yyyyMMddHHmmss";
+
+        public static final String YYYY = "yyyy";
+
+        public static final String YYYYMM = "yyyyMM";
+
+        public static final String YYYYMMDD = "yyyyMMdd";
+
+        public static final String YYYYMMDDHH = "yyyyMMddHH";
+
+        public static final String YYYYMMDDHHMM = "yyyyMMddHHmm";
+
+        public static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
+
+        public static final String CHINA_DEFAULT = "yyyy-MM-dd HH:mm:ss";
+
+        public static final String YYYY_MM = "yyyy-MM";
+
+        public static final String YYYY_MM_DD = "yyyy-MM-dd";
+
+        public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
+
+        public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
+
+    }
+
+    /**
+     * get now date.
+     *
+     * @param pattern
+     * @return
+     */
+    public static String now(String pattern) {
+        return format(new Date(), pattern);
+    }
+
+    /**
+     * get now china date.
+     *
+     * @return
+     */
+    public static String chinaNow() {
+        return format(new Date(), DatePatterns.CHINA_DEFAULT);
+    }
+
+    /**
+     * format date.
+     *
+     * @param date
+     * @param pattern
+     * @return
+     */
+    public static String format(Date date, String pattern) {
+        try {
+            SimpleDateFormat df = new SimpleDateFormat(pattern);
+            return df.format(date);
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    /**
+     * format now date.
+     *
+     * @param pattern
+     * @return
+     * @author WANGWEI
+     */
+    public static String formatNow(String pattern) {
+        try {
+            SimpleDateFormat df = new SimpleDateFormat(pattern);
+            return df.format(new Date());
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    /**
+     * parse date.
+     *
+     * @param source
+     * @param pattern
+     * @return
+     */
+    public static Date parse(String source, String pattern) {
+        SimpleDateFormat df = new SimpleDateFormat(pattern);
+        try {
+            return df.parse(source);
+        } catch (ParseException e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+    /**
+     * parse date randomly.
+     *
+     * @param s
+     * @return
+     * @author WANGWEI
+     */
+    public static Date parseRandomly(String s) {
+        if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
+            return parse(s, "yyyy/MM/dd HH:mm:ss");
+        } else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
+            return parse(s, "yyyy/MM/dd HH:mm");
+        } else if (s.matches("\\d{4}/\\d{1,2}/\\d{1,2}")) {
+            return parse(s, "yyyy/MM/dd");
+        } else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}:\\d{1,2}")) {
+            return parse(s, "yyyy-MM-dd HH:mm:ss");
+        } else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}\\s+\\d{1,2}:\\d{1,2}")) {
+            return parse(s, "yyyy-MM-dd HH:mm");
+        } else if (s.matches("\\d{4}-\\d{1,2}-\\d{1,2}")) {
+            return parse(s, "yyyy-MM-dd");
+        } else {
+            throw new ExamCloudRuntimeException("unsupported date string.");
+        }
+    }
+
+    /**
+     * 解析excel日期
+     *
+     * @param number
+     * @return
+     * @author WANGWEI
+     */
+    public static Date parseExcel(String number) {
+
+        BigDecimal bd = new BigDecimal(number);
+        int days = bd.intValue();
+        int mills = (int) Math.round(bd.subtract(new BigDecimal(days)).doubleValue() * 24 * 3600);
+
+        Calendar c = Calendar.getInstance();
+        c.set(1900, 0, 1);
+        c.add(Calendar.DATE, days - 2);
+        int hour = mills / 3600;
+        int minute = (mills - hour * 3600) / 60;
+        int second = mills - hour * 3600 - minute * 60;
+        c.set(Calendar.HOUR_OF_DAY, hour);
+        c.set(Calendar.MINUTE, minute);
+        c.set(Calendar.SECOND, second);
+
+        Date date = c.getTime();
+
+        return date;
+    }
+
+    /**
+     * 是否同一天
+     *
+     * @param date1
+     * @param date2
+     * @return
+     * @author WANGWEI
+     */
+    public static boolean isSameDay(Date date1, Date date2) {
+        if (null == date1) {
+            throw new ExamCloudRuntimeException("first argument must not be null");
+        }
+        if (null == date2) {
+            throw new ExamCloudRuntimeException("second argument must not be null");
+        }
+
+        Calendar cal1 = Calendar.getInstance();
+        cal1.setTime(date1);
+        Calendar cal2 = Calendar.getInstance();
+        cal2.setTime(date2);
+        return isSameDay(cal1, cal2);
+    }
+
+    /**
+     * 是否同一天
+     *
+     * @param calendar1
+     * @param calendar2
+     * @return
+     * @author WANGWEI
+     */
+    public static boolean isSameDay(Calendar calendar1, Calendar calendar2) {
+        if (null == calendar1) {
+            throw new ExamCloudRuntimeException("first argument must not be null");
+        }
+        if (null == calendar2) {
+            throw new ExamCloudRuntimeException("second argument must not be null");
+        }
+        return calendar1.get(0) == calendar2.get(0) && calendar1.get(1) == calendar2.get(1)
+                && calendar1.get(6) == calendar2.get(6);
+    }
+
+}

+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/FileUtil.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/FileUtil.java


+ 63 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/FreeMarkerUtil.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Locale;
+
+/**
+ * FreeMarker 工具
+ *
+ * @author WANGWEI
+ * @date 2018年11月21日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class FreeMarkerUtil {
+
+    private static final String ENCODING = "UTF-8";
+
+    private static Configuration configuration;
+
+    static {
+        configuration = new Configuration(Configuration.VERSION_2_3_23);
+        configuration.setEncoding(Locale.US, ENCODING);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param template
+     * @param dataModel
+     * @return
+     * @author WANGWEI
+     */
+    public static String process(String template, Object dataModel) {
+        return process("$$$$$", template, dataModel);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param name
+     * @param template
+     * @param dataModel
+     * @return
+     * @author WANGWEI
+     */
+    public static String process(String name, String template, Object dataModel) {
+        StringWriter result = null;
+        try {
+            result = new StringWriter();
+            Template t = new Template(name, new StringReader(template), configuration);
+            t.process(dataModel, result);
+
+            return result.toString();
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        }
+    }
+
+}

+ 170 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/HttpClientUtil.java

@@ -0,0 +1,170 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.helpers.JsonHttpResponseHolder;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * httpclient
+ *
+ * @author WANGWEI
+ * @date 2019年9月17日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class HttpClientUtil {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpClientUtil.class);
+
+    private static CloseableHttpClient httpclient;
+
+    private static RequestConfig requestConfig;
+
+    static {
+        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(60,
+                TimeUnit.SECONDS);
+        cm.setValidateAfterInactivity(1000);
+        cm.setMaxTotal(8000);
+        cm.setDefaultMaxPerRoute(200);
+
+        requestConfig = RequestConfig.custom().setConnectionRequestTimeout(500)
+                .setSocketTimeout(10000).setConnectTimeout(10000)
+                .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();
+
+        httpclient = HttpClients.custom().setConnectionManager(cm).disableAutomaticRetries()
+                .setDefaultRequestConfig(requestConfig).build();
+
+    }
+
+    public static CloseableHttpClient getHttpClient() {
+        return httpclient;
+    }
+
+    public static HttpPost buildHttpPost(String url) {
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setConfig(requestConfig);
+
+        return httpPost;
+    }
+
+    public static HttpPut buildHttpPut(String url) {
+        HttpPut httpPut = new HttpPut(url);
+        httpPut.setConfig(requestConfig);
+
+        return httpPut;
+    }
+
+    public static HttpGet buildHttpGet(String url) {
+        HttpGet httpGet = new HttpGet(url);
+        httpGet.setConfig(requestConfig);
+
+        return httpGet;
+    }
+
+    public static JsonHttpResponseHolder execute(final HttpUriRequest request) {
+
+        CloseableHttpResponse response = null;
+        JsonHttpResponseHolder responseHolder = null;
+        long s = System.currentTimeMillis();
+        try {
+
+            response = httpclient.execute(request);
+            int statusCode = response.getStatusLine().getStatusCode();
+            String entityStr = EntityUtils.toString(response.getEntity(), "UTF-8");
+            JSONObject obj = JSON.parseObject(entityStr);
+            responseHolder = new JsonHttpResponseHolder(statusCode, obj);
+
+            if (HttpStatus.SC_OK != responseHolder.getStatusCode()) {
+                LOG.error("[HTTP-FAIL]. statusCode=" + statusCode + "; responseEntity="
+                        + entityStr + "; uri=" + request.getURI());
+            } else {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("[HTTP-OK]. statusCode=" + statusCode + "; responseEntity="
+                            + entityStr + "; uri=" + request.getURI());
+                }
+            }
+
+        } catch (Exception e) {
+            LOG.error("[HTTP-ERROR]. uri=" + request.getURI(), e);
+        } finally {
+            IOUtils.closeQuietly(response);
+            LOG.debug("[HTTP-COST]. cost = " + (System.currentTimeMillis() - s) + " ms; uri="
+                    + request.getURI());
+        }
+        return responseHolder;
+    }
+
+    /**
+     * 关闭流
+     *
+     * @param resp
+     * @author WANGWEI
+     */
+    public static void close(CloseableHttpResponse resp) {
+        if (null != resp) {
+            try {
+                EntityUtils.consumeQuietly(resp.getEntity());
+                resp.close();
+            } catch (Exception e) {
+                LOG.error("fail to close http response stream.", e);
+            }
+        }
+    }
+
+    /**
+     * GET 请求
+     *
+     * @param url
+     * @return
+     * @author WANGWEI
+     */
+    public static byte[] get(String url) {
+        return get(url, 1048576L);
+    }
+
+    /**
+     * GET 请求
+     *
+     * @param url
+     * @param maxByteSize
+     * @return
+     * @author WANGWEI
+     */
+    public static byte[] get(String url, long maxByteSize) {
+
+        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
+
+        HttpGet get = new HttpGet(url);
+        get.setConfig(RequestConfig.custom().setConnectTimeout(10000).build());
+
+        CloseableHttpResponse response = null;
+        try {
+            response = httpclient.execute(get);
+            InputStream in = response.getEntity().getContent();
+
+            byte[] byteArray = IOUtil.toLimitedByteArray(in, maxByteSize);
+            return byteArray;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            close(response);
+            IOUtils.closeQuietly(httpclient);
+        }
+
+    }
+
+}

+ 115 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/HttpMethod.java

@@ -0,0 +1,115 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * HTTP method
+ *
+ * @author WANGWEI
+ * @date 2019年4月10日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class HttpMethod {
+
+    public static final HttpMethod OPTIONS = new HttpMethod("OPTIONS");
+
+    public static final HttpMethod GET = new HttpMethod("GET");
+
+    public static final HttpMethod HEAD = new HttpMethod("HEAD");
+
+    public static final HttpMethod POST = new HttpMethod("POST");
+
+    public static final HttpMethod PUT = new HttpMethod("PUT");
+
+    public static final HttpMethod PATCH = new HttpMethod("PATCH");
+
+    public static final HttpMethod DELETE = new HttpMethod("DELETE");
+
+    public static final HttpMethod TRACE = new HttpMethod("TRACE");
+
+    public static final HttpMethod CONNECT = new HttpMethod("CONNECT");
+
+    private static final Map<String, HttpMethod> METHOD_MAP = new HashMap<String, HttpMethod>();
+
+    static {
+        METHOD_MAP.put(OPTIONS.toString(), OPTIONS);
+        METHOD_MAP.put(GET.toString(), GET);
+        METHOD_MAP.put(HEAD.toString(), HEAD);
+        METHOD_MAP.put(POST.toString(), POST);
+        METHOD_MAP.put(PUT.toString(), PUT);
+        METHOD_MAP.put(PATCH.toString(), PATCH);
+        METHOD_MAP.put(DELETE.toString(), DELETE);
+        METHOD_MAP.put(TRACE.toString(), TRACE);
+        METHOD_MAP.put(CONNECT.toString(), CONNECT);
+    }
+
+    private final String name;
+
+    /**
+     * 构造函数
+     *
+     * @param name
+     */
+    private HttpMethod(String name) {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        name = name.trim();
+        if (name.length() == 0) {
+            throw new IllegalArgumentException("empty name");
+        }
+
+        for (int i = 0; i < name.length(); i++) {
+            if (Character.isISOControl(name.charAt(i)) || Character.isWhitespace(name.charAt(i))) {
+                throw new IllegalArgumentException("invalid character in name");
+            }
+        }
+
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public static HttpMethod valueOf(String name) {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+
+        name = name.trim();
+        if (name.length() == 0) {
+            throw new IllegalArgumentException("empty name");
+        }
+
+        HttpMethod result = METHOD_MAP.get(name);
+        if (result != null) {
+            return result;
+        } else {
+            throw new IllegalArgumentException("undefined name");
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof HttpMethod)) {
+            return false;
+        }
+
+        HttpMethod that = (HttpMethod) o;
+        return getName().equals(that.getName());
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+}

+ 98 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/IOUtil.java

@@ -0,0 +1,98 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+
+/**
+ * IO
+ *
+ * @author WANGWEI
+ * @date 2018年6月29日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class IOUtil {
+
+    /**
+     * 文件转字节数组
+     *
+     * @param file
+     * @return
+     * @author WANGWEI
+     */
+    public static byte[] toByteArray(File file) {
+        FileInputStream is = null;
+        try {
+            is = new FileInputStream(file);
+            byte[] byteArray = IOUtils.toByteArray(is);
+            return byteArray;
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            IOUtils.closeQuietly(is);
+        }
+    }
+
+    /**
+     * 字节数组转文件
+     *
+     * @param bfile
+     * @param filePath
+     * @author WANGWEI
+     */
+    public static void toFile(byte[] bfile, String filePath) {
+        BufferedOutputStream bos = null;
+        FileOutputStream fos = null;
+        try {
+            File file = new File(filePath);
+            FileUtils.forceMkdir(file.getParentFile());
+            fos = new FileOutputStream(file);
+            bos = new BufferedOutputStream(fos);
+            bos.write(bfile);
+        } catch (Exception e) {
+            throw new RuntimeException("", e);
+        } finally {
+            IOUtils.closeQuietly(bos);
+            IOUtils.closeQuietly(fos);
+        }
+    }
+
+    /**
+     * 输入流转换为限制大小的字节
+     *
+     * @param in
+     * @param maxByteSize
+     * @return
+     * @author WANGWEI
+     */
+    public static byte[] toLimitedByteArray(InputStream in, long maxByteSize) {
+        ByteArrayOutputStream out = null;
+        int bufferSize = 1024 * 4;
+        int totalSize = 0;
+        byte[] buffer = new byte[bufferSize];
+        try {
+            out = new ByteArrayOutputStream();
+            int n = 0;
+            while ((n = in.read(buffer)) != -1) {
+                out.write(buffer, 0, n);
+                totalSize += n;
+
+                if (maxByteSize < totalSize) {
+                    throw new RuntimeException("文件大小超过" + (maxByteSize / 1024) + "KB限制");
+                }
+            }
+            return out.toByteArray();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } catch (RuntimeException e) {
+            throw e;
+        } finally {
+            IOUtils.closeQuietly(out);
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+}

+ 0 - 0
examcloud-commons/src/main/java/cn/com/qmth/examcloud/commons/util/JsonMapper.java → examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/JsonMapper.java


+ 164 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/JsonUtil.java

@@ -0,0 +1,164 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
+import com.google.common.collect.Maps;
+import com.google.gson.*;
+
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * json tool
+ *
+ * @param <T>
+ * @author WANGWEI
+ * @date 2019年1月16日
+ * @Copyright (c) 2018-2020 http://www.qmth.com.cn/ All Rights Reserved.
+ */
+public class JsonUtil {
+
+    /**
+     * to json
+     *
+     * @param obj
+     * @return
+     * @author WANGWEI
+     */
+    public static String toJson(Object obj) {
+        GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
+                .setDateFormat(DatePatterns.CHINA_DEFAULT);
+        return builder.create().toJson(obj);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param obj
+     * @param excludeFields
+     * @return
+     * @author WANGWEI
+     */
+    public static String toJson(Object obj, String... excludeFields) {
+        GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().serializeNulls()
+                .setDateFormat(DatePatterns.CHINA_DEFAULT);
+
+        builder.setExclusionStrategies(new ExclusionStrategy() {
+            @Override
+            public boolean shouldSkipField(FieldAttributes f) {
+                for (String field : excludeFields) {
+                    if (f.getName().matches(field)) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            @Override
+            public boolean shouldSkipClass(Class<?> clazz) {
+                return false;
+            }
+        });
+
+        return builder.create().toJson(obj);
+    }
+
+    /**
+     * to pretty json
+     *
+     * @param obj
+     * @return
+     * @author WANGWEI
+     */
+    public static String toPrettyJson(Object obj) {
+        GsonBuilder builder = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+                .serializeNulls().setDateFormat(DatePatterns.CHINA_DEFAULT);
+        return builder.create().toJson(obj);
+    }
+
+    /**
+     * 格式化json
+     *
+     * @param json
+     * @return
+     * @author WANGWEI
+     */
+    public static String format(String json) {
+        if (null == json) {
+            return json;
+        }
+        JsonElement jsonEl = JsonParser.parseString(json);
+        return toPrettyJson(jsonEl);
+    }
+
+    /**
+     * json转对象
+     *
+     * @param json
+     * @param c
+     * @return
+     * @author WANGWEI
+     */
+    public static <T> T fromJson(String json, Class<T> c) {
+        Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+                .setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+        return gson.fromJson(json, c);
+    }
+
+    /**
+     * json数组转list
+     *
+     * @param json
+     * @param elementType
+     * @return
+     * @author WANGWEI
+     */
+    public static <T> List<T> fromJsonArray(String json, Class<T[]> elementType) {
+        Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting()
+                .setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+        T[] array = gson.fromJson(json, elementType);
+        return Arrays.asList(array);
+    }
+
+    /**
+     * simple json to map
+     *
+     * @param s
+     * @return
+     * @author WANGWEI
+     */
+    public static Map<String, String> json2Map(String s) {
+        JsonElement jsonElement = JsonParser.parseString(s);
+        JsonObject jsonObject = jsonElement.getAsJsonObject();
+        Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
+
+        Map<String, String> map = Maps.newHashMap();
+        for (Entry<String, JsonElement> entry : entrySet) {
+            JsonElement e = entry.getValue();
+            if (!e.isJsonNull()) {
+                String v = e.getAsString();
+                map.put(entry.getKey(), v);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * json转对象
+     *
+     * @param json
+     * @param type
+     * @return
+     * @author WANGWEI
+     */
+    public static <T> T fromJson(String json, Type type) {
+        Gson gson = new GsonBuilder().disableHtmlEscaping()
+                .setDateFormat(DatePatterns.CHINA_DEFAULT).create();
+        return gson.fromJson(json, type);
+    }
+
+}

+ 58 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/MD5.java

@@ -0,0 +1,58 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ */
+public class MD5 {
+
+    /**
+     * 方法注释
+     *
+     * @param str
+     * @return
+     * @author WANGWEI
+     */
+    public static String encrypt32(String str) {
+        return DigestUtils.md5Hex(str);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param str
+     * @return
+     * @author WANGWEI
+     */
+    public static String encrypt16(String str) {
+        return DigestUtils.md5Hex(str).substring(8, 24);
+    }
+
+    /**
+     * 文件md5
+     *
+     * @param file
+     * @return
+     * @author WANGWEI
+     */
+    public static String md5Hex(File file) {
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            return DigestUtils.md5Hex(in);
+        } catch (Exception e) {
+            throw new ExamCloudRuntimeException(e);
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+}

+ 45 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/commons/util/MapUtil.java

@@ -0,0 +1,45 @@
+package cn.com.qmth.examcloud.commons.util;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * map 工具
+ *
+ * @author WANGWEI
+ * @date 2019年5月15日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public class MapUtil {
+
+    /**
+     * map按key排序
+     *
+     * @param map
+     * @param asc 升序
+     * @return
+     * @author WANGWEI
+     */
+    public static <T> Map<String, T> sortMapByKey(Map<String, T> map, boolean asc) {
+        if (map == null) {
+            return null;
+        }
+        Map<String, T> sortMap = new TreeMap<String, T>(new Comparator<String>() {
+
+            @Override
+            public int compare(String o1, String o2) {
+
+                if (asc) {
+                    return ((String) o1).compareTo((String) o2);
+                } else {
+                    return ((String) o2).compareTo((String) o1);
+                }
+            }
+        });
+
+        sortMap.putAll(map);
+        return sortMap;
+    }
+
+}

Някои файлове не бяха показани, защото твърде много файлове са промени