Selaa lähdekoodia

merge from examcloud-R

deason 5 vuotta sitten
vanhempi
commit
5c45a59793
33 muutettua tiedostoa jossa 441 lisäystä ja 2096 poistoa
  1. 0 4
      examcloud-api-commons/src/main/java/cn/com/qmth/examcloud/api/commons/enums/ExamType.java
  2. 0 32
      examcloud-api-commons/src/main/java/cn/com/qmth/examcloud/api/commons/enums/PrivilegeGroupType.java
  3. 64 68
      examcloud-java-sdk/src/main/java/cn/com/qmth/sdk/request/OuterQueryScoreDataReq.java
  4. 20 28
      examcloud-java-sdk/src/main/resources/log4j2.xml
  5. 22 24
      examcloud-java-sdk/src/test/java/cn/com/qmth/sdk/test/QueryScoreData.java
  6. 5 5
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/Constants.java
  7. 7 8
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/cache/CacheHelper.java
  8. 0 6
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/BlockType.java
  9. 0 21
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/DataCategory.java
  10. 6 7
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/ExamProperties.java
  11. 0 65
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/AudioTextHandler.java
  12. 0 145
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/ComplexTextHandler.java
  13. 0 193
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/HtmlTextHandler.java
  14. 0 172
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/ImageTextHandler.java
  15. 0 13
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/RichTextHandler.java
  16. 0 41
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/RichTextHandlerFactory.java
  17. 0 70
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/BlockBean.java
  18. 0 31
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/SectionBean.java
  19. 0 25
      examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/SectionCollectionBean.java
  20. 0 49
      examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Block.java
  21. 0 6
      examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/BlockType.java
  22. 0 162
      examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Context.java
  23. 0 21
      examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Section.java
  24. 0 19
      examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Test.java
  25. 0 58
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/CacheCloudServiceProvider.java
  26. 0 41
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashCache.java
  27. 0 89
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCache.java
  28. 0 134
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCacheProcessor.java
  29. 0 109
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCacheTrigger.java
  30. 0 76
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/RefreshHashCacheReq.java
  31. 0 26
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/redis/RedisClient.java
  32. 3 39
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/redis/SimpleRedisClient.java
  33. 314 309
      examcloud-web/src/main/java/cn/com/qmth/examcloud/web/support/ControllerSupport.java

+ 0 - 4
examcloud-api-commons/src/main/java/cn/com/qmth/examcloud/api/commons/enums/ExamType.java

@@ -32,8 +32,4 @@ public enum ExamType {
 	 */
 	PRINT_EXAM,
 
-	/**
-	 * 在线作业
-	 */
-	ONLINE_HOMEWORK
 }

+ 0 - 32
examcloud-api-commons/src/main/java/cn/com/qmth/examcloud/api/commons/enums/PrivilegeGroupType.java

@@ -1,32 +0,0 @@
-package cn.com.qmth.examcloud.api.commons.enums;
-
-/**
- * 权限组类型
- *
- * @author WANGWEI
- * @date 2020年2月14日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public enum PrivilegeGroupType {
-
-	/**
-	 * 菜单
-	 */
-	ADMIN_MENU,
-
-	/**
-	 * 功能
-	 */
-	FUNCTION,
-
-	/**
-	 * 数据权限
-	 */
-	DATA_ACCESS,
-
-	/**
-	 * 学生端菜单
-	 */
-	STUDENT_CLIENT_MENU
-
-}

+ 64 - 68
examcloud-java-sdk/src/main/java/cn/com/qmth/sdk/request/OuterQueryScoreDataReq.java

@@ -2,73 +2,69 @@ package cn.com.qmth.sdk.request;
 
 import cn.com.qmth.sdk.exchange.EnterpriseRequest;
 
+
 /**
- * @author chenken
- * @date 2018年11月27日 下午5:51:08
- * @company QMTH
+ * 
+ * @author  	chenken
+ * @date    	2018年11月27日 下午5:51:08
+ * @company 	QMTH
+ * @description OuterQueryScoreDataReq.java
  */
-public class OuterQueryScoreDataReq extends EnterpriseRequest {
-
-    private static final long serialVersionUID = -5033520077132433253L;
-
-    private String examCode;
-
-    private String examName;
-
-    private Long rootOrgId;
-
-    private String studentCode;
-
-    private String identityNumber;
-
-    private String courseCode;
-
-    public String getExamCode() {
-        return examCode;
-    }
-
-    public void setExamCode(String examCode) {
-        this.examCode = examCode;
-    }
-
-    public String getExamName() {
-        return examName;
-    }
-
-    public void setExamName(String examName) {
-        this.examName = examName;
-    }
-
-    public Long getRootOrgId() {
-        return rootOrgId;
-    }
-
-    public void setRootOrgId(Long rootOrgId) {
-        this.rootOrgId = rootOrgId;
-    }
-
-    public String getStudentCode() {
-        return studentCode;
-    }
-
-    public void setStudentCode(String studentCode) {
-        this.studentCode = studentCode;
-    }
-
-    public String getIdentityNumber() {
-        return identityNumber;
-    }
-
-    public void setIdentityNumber(String identityNumber) {
-        this.identityNumber = identityNumber;
-    }
-
-    public String getCourseCode() {
-        return courseCode;
-    }
-
-    public void setCourseCode(String courseCode) {
-        this.courseCode = courseCode;
-    }
-
-}
+public class OuterQueryScoreDataReq extends EnterpriseRequest{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -5033520077132433253L;
+
+	private String examName;
+	
+	private Long rootOrgId;
+	
+	private String studentCode;
+	
+	private String identityNumber;
+	
+	private String courseCode;
+
+	public String getExamName() {
+		return examName;
+	}
+
+	public void setExamName(String examName) {
+		this.examName = examName;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+	
+}

+ 20 - 28
examcloud-java-sdk/src/main/resources/log4j2.xml

@@ -1,34 +1,26 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Configuration status="WARN" monitorInterval="30">
 
-    <Properties>
-        <Property name="logPattern">
-            %d{yyyy-MM-dd HH:mm:ss.SSS} | %level | %m%n
-        </Property>
-    </Properties>
+	<Appenders>
+		<Console name="CONSOLE" target="SYSTEM_OUT">
+			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %-5level | %t | %m | %l %n" />
+		</Console>
+		<RollingFile name="DEBUG_APPERDER" fileName="D:/Temp/logs/debug.log" filePattern="D:/Temp/logs/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log">
+			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %-5level | %t | %m | %l %n" />
+			<SizeBasedTriggeringPolicy size="10MB" />
+			<DefaultRolloverStrategy max="50" />
+		</RollingFile>
+	</Appenders>
 
-    <Appenders>
-        <Console name="CONSOLE" target="SYSTEM_OUT">
-            <PatternLayout pattern="${logPattern}"/>
-        </Console>
 
-        <RollingFile name="DEBUG_APPERDER" fileName="./logs/debug/debug.log"
-                     filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
-            <PatternLayout pattern="${logPattern}"/>
-            <SizeBasedTriggeringPolicy size="10MB"/>
-            <DefaultRolloverStrategy max="50"/>
-        </RollingFile>
-    </Appenders>
+	<Loggers>
+		<Logger name="cn.com.qmth" level="DEBUG" additivity="false">
+			<AppenderRef ref="DEBUG_APPERDER" />
+			<AppenderRef ref="CONSOLE" />
+		</Logger>
+		<Root level="ERROR">
+			<AppenderRef ref="CONSOLE" />
+		</Root>
+	</Loggers>
 
-    <Loggers>
-        <Logger name="cn.com.qmth" level="DEBUG" additivity="false">
-            <AppenderRef ref="DEBUG_APPERDER"/>
-            <AppenderRef ref="CONSOLE"/>
-        </Logger>
-
-        <Root level="ERROR">
-            <AppenderRef ref="CONSOLE"/>
-        </Root>
-    </Loggers>
-
-</Configuration>
+</Configuration>

+ 22 - 24
examcloud-java-sdk/src/test/java/cn/com/qmth/sdk/test/QueryScoreData.java

@@ -1,35 +1,33 @@
 package cn.com.qmth.sdk.test;
 
+import org.apache.commons.io.IOUtils;
+
 import cn.com.qmth.sdk.request.OuterQueryScoreDataReq;
 import cn.com.qmth.sdk.util.HttpMethod;
 import cn.com.qmth.sdk.util.JsonUtil;
 import cn.com.qmth.sdk.util.OKHttpUtil;
 import cn.com.qmth.sdk.util.QmthUtil;
 import okhttp3.Response;
-import org.apache.commons.io.IOUtils;
 
 public class QueryScoreData {
-
-    public static void main(String[] args) {
-        OuterQueryScoreDataReq reqBody = new OuterQueryScoreDataReq();
-        reqBody.setRootOrgId(QmthUtil.getRootOrgId());
-        // reqBody.setExamCode("1491");
-        reqBody.setExamName("华南理工大学-测试考试");
-        reqBody.setCourseCode("A004");
-        // reqBody.setIdentityNumber("201715143170048");
-        reqBody.setStudentCode("201715143170048");
-
-        String url = QmthUtil.buildUrl("/api/exchange/outer/score/queryScoreData");
-        Response resp = null;
-        try {
-            resp = OKHttpUtil.call(HttpMethod.POST, url, QmthUtil.getSecurityHeaders(), JsonUtil.toJson(reqBody));
-            System.out.println(resp.code());
-            System.out.println(resp.body().string());
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            IOUtils.closeQuietly(resp);
-        }
-    }
-
+	public static void main(String[] args) {
+		OuterQueryScoreDataReq reqBody = new OuterQueryScoreDataReq();
+		reqBody.setRootOrgId(QmthUtil.getRootOrgId());
+		reqBody.setExamName("测试新库");
+		reqBody.setCourseCode("W00001");
+		reqBody.setIdentityNumber("chenken001");
+		// reqBody.setStudentCode("chenken001");
+		String url = QmthUtil.buildUrl("/api/exchange/outer/score/queryScoreData");
+		Response resp = null;
+		try {
+			resp = OKHttpUtil.call(HttpMethod.POST, url, QmthUtil.getSecurityHeaders(),
+					JsonUtil.toJson(reqBody));
+			System.out.println(resp.code());
+			System.out.println(resp.body().string());
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			IOUtils.closeQuietly(resp);
+		}
+	}
 }

+ 5 - 5
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/Constants.java

@@ -201,6 +201,11 @@ public interface Constants {
 	 */
 	String IDENTIFICATION_OF_LIVING_BODY_SCHEME_KEY = "IDENTIFICATION_OF_LIVING_BODY_SCHEME";
 
+	/**
+	 * 证件隐私模式key
+	 */
+	String ID_NUMBER_PRIVATE_MODE_KEY = "ID_NUMBER_PRIVATE_MODE";
+
 	/**
 	 * 默认的百度活检阈值
 	 */
@@ -210,9 +215,4 @@ public interface Constants {
 	 * 小程序作答文件上传id
 	 */
 	String MINI_PROGRAM_ANWSER_SITEID = "miniProgramAnwser";
-
-	/**
-	 * 证件隐私模式key
-	 */
-	String ID_NUMBER_PRIVATE_MODE_KEY = "ID_NUMBER_PRIVATE_MODE";
 }

+ 7 - 8
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/cache/CacheHelper.java

@@ -24,7 +24,6 @@ import cn.com.qmth.examcloud.support.cache.bean.SmsAssemblyCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.StudentCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
 import cn.com.qmth.examcloud.support.cache.bean.ThirdPartyAccessCacheBean;
-import cn.com.qmth.examcloud.web.cache.HashRedisCacheProcessor;
 import cn.com.qmth.examcloud.web.cache.ObjectRedisCacheProcessor;
 
 /**
@@ -137,9 +136,9 @@ public class CacheHelper {
 	 * @return
 	 */
 	public static ExtractConfigPaperCacheBean getExtractConfigPaper(Long examId, String courseCode,
-																	String groupCode, String paperId) {
-		return HashRedisCacheProcessor.get("Q_PAPER:EXTRACT_CONFIG_PAPER_",
-				new Object[]{paperId},new Object[]{examId, courseCode, groupCode},
+			String groupCode, String paperId) {
+		return ObjectRedisCacheProcessor.get("Q_PAPER:EXTRACT_CONFIG_PAPER_",
+				new Object[]{examId, courseCode, groupCode, paperId},
 				ExtractConfigPaperCacheBean.class, "EC-CORE-QUESTION",
 				"cn.com.qmth.examcloud.core.questions.service.cache.ExtractConfigPaperCache");
 	}
@@ -166,9 +165,9 @@ public class CacheHelper {
 	 * @return
 	 */
 	public static QuestionCacheBean getQuestion(Long examId, String courseCode, String groupCode,
-												String questionId) {
-		return HashRedisCacheProcessor.get("Q_QUESTION:",
-				new Object[]{questionId},new Object[]{examId, courseCode, groupCode}, QuestionCacheBean.class,
+			String questionId) {
+		return ObjectRedisCacheProcessor.get("Q_QUESTION:",
+				new Object[]{examId, courseCode, groupCode, questionId}, QuestionCacheBean.class,
 				"EC-CORE-QUESTION",
 				"cn.com.qmth.examcloud.core.questions.service.cache.QuestionCache");
 	}
@@ -237,7 +236,7 @@ public class CacheHelper {
 	 * @return
 	 */
 	public static ExamStudentPropertyCacheBean getExamStudentProperty(Long examId, Long studentId,
-																	  String key) {
+			String key) {
 		return ObjectRedisCacheProcessor.get("E_EXAM_STUDENT_PROP:",
 				new Object[]{examId, studentId, key}, ExamStudentPropertyCacheBean.class,
 				"EC-CORE-EXAMWORK",

+ 0 - 6
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/BlockType.java

@@ -1,6 +0,0 @@
-package cn.com.qmth.examcloud.support.enums;
-
-public enum BlockType {
-
-    text, image, audio;
-}

+ 0 - 21
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/DataCategory.java

@@ -1,21 +0,0 @@
-package cn.com.qmth.examcloud.support.enums;
-
-
-/**
- * @Description 数据分类
- * @Author lideyin
- * @Date 2020/3/12 16:43
- * @Version 1.0
- */
-public enum DataCategory {
-    /**
-     * 系统数据
-     */
-    SYSTEM,
-
-    /**
-     * 自定义数据
-     */
-    CUSTOM
-
-}

+ 6 - 7
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/enums/ExamProperties.java

@@ -1,7 +1,7 @@
 package cn.com.qmth.examcloud.support.enums;
 
 /**
- *
+ * 
  * @author  	chenken
  * @date    	2018年11月15日 下午5:37:35
  * @company 	QMTH
@@ -49,13 +49,12 @@ public enum ExamProperties {
 	MAX_INTERRUPT_NUM("最大断点续考次数"),
 	IS_STRANGER_ENABLE("是否启用陌生人检测"),
 	LIMITED_IF_NO_SPECIAL_SETTINGS("无特殊设置时禁止考试"),
-	WEIXIN_ANSWER_ENABLED("是否开放微信小程序作答"),
-	APP_EXAM_ENABLED("是否开放app考试");
-
+	WEIXIN_ANSWER_ENABLED("是否开放微信小程序作答");
+	
 	private ExamProperties(String desc){
 		this.desc = desc;
 	}
-
+	
 	private String desc;
 
 	public String getDesc() {
@@ -65,5 +64,5 @@ public enum ExamProperties {
 	public void setDesc(String desc) {
 		this.desc = desc;
 	}
-
-}
+	
+}

+ 0 - 65
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/AudioTextHandler.java

@@ -1,65 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.support.enums.BlockType;
-import cn.com.qmth.examcloud.support.handler.richText.bean.BlockBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
-import com.mysql.cj.util.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @Description 音频处理器类
- * @Author lideyin
- * @Date 2020/5/15 16:29
- * @Version 1.0
- */
-public class AudioTextHandler implements RichTextHandler{
-    private static Log logger = LogFactory.getLog(HtmlTextHandler.class);
-
-    @Override
-    public SectionCollectionBean handle(String richText) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("[HTML-TEXT-HANDLER]--richText: " + richText);
-        }
-
-        if (StringUtils.isNullOrEmpty(richText)) {
-            return new SectionCollectionBean();
-        }
-
-        SectionCollectionBean sectionCollection = new SectionCollectionBean();
-        List<SectionBean> sectionList = new ArrayList<>();
-        SectionBean section = new SectionBean();
-        List<BlockBean> blockList = new ArrayList<>();
-
-        if (validateAudioAnswer(richText)) {
-            BlockBean blockBean = new BlockBean(BlockType.audio.name());
-            blockBean.setValue(richText);
-            blockList.add(blockBean);
-        }
-
-        section.setBlocks(blockList);
-        sectionList.add(section);
-        sectionCollection.setSections(sectionList);
-
-        return sectionCollection;
-    }
-
-    /**
-     * 校验音频答案格式是否正确
-     *
-     * @param studentAnswer
-     * @return
-     */
-    private boolean validateAudioAnswer(String studentAnswer) {
-        if (StringUtils.isNullOrEmpty(studentAnswer)) {
-            return false;
-        }
-
-        String regExp = "^(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(mp3)";
-        return studentAnswer.matches(regExp);
-    }
-}

+ 0 - 145
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/ComplexTextHandler.java

@@ -1,145 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.support.enums.BlockType;
-import cn.com.qmth.examcloud.support.handler.richText.bean.BlockBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
-import com.mysql.cj.util.StringUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @Description 复合文本处理器类
- * @Author lideyin
- * @Date 2020/5/15 16:29
- * @Version 1.0
- */
-public class ComplexTextHandler implements RichTextHandler {
-    private static Log logger = LogFactory.getLog(HtmlTextHandler.class);
-
-    @Override
-    public SectionCollectionBean handle(String richText) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("[HTML-TEXT-HANDLER]--richText: " + richText);
-        }
-
-        if (StringUtils.isNullOrEmpty(richText)) {
-            return new SectionCollectionBean();
-        }
-
-        SectionCollectionBean body = new SectionCollectionBean();
-        List<SectionBean> sections = new ArrayList<>();
-        // 得到小题题干或者答案行数
-        if (org.apache.commons.lang3.StringUtils.isBlank(richText)) {
-            return body;
-        }
-
-        String[] questionRowStrings = richText.split("</p>");
-        for (int i = 0; i < questionRowStrings.length; i++) {
-            List<BlockBean> blocks = disposeQuestionBodyOrOption(questionRowStrings[i]);
-            if (blocks != null && blocks.size() > 0) {
-                SectionBean section = new SectionBean();
-                // 将小题题干拆分为Block集合
-                section.setBlocks(blocks);
-                sections.add(section);
-            }
-        }
-        body.setSections(sections);
-        return body;
-    }
-
-
-    private List<BlockBean> disposeQuestionBodyOrOption(String questionRow) {
-        List<BlockBean> blocks = new ArrayList<>();
-        // 去掉每行里面的<p>,<span>,</span>标签
-        questionRow = questionRow.replaceAll("<p>", "").replaceAll("</p>", "").replaceAll("<span>", "")
-                .replaceAll("</span>", "").replaceAll("</a>", "");
-        String[] questionRowStrings = questionRow.split("<|/>|>");
-        for (int i = 0; i < questionRowStrings.length; i++) {
-            BlockBean block = new BlockBean(BlockType.text.name());
-            String rowStr = questionRowStrings[i];
-            // 判断是否有图片
-            if (rowStr.startsWith("img")) {
-                rowStr = "<" + rowStr + ">";
-                Map<String, Object> param = new HashMap<>();
-                // 需要继续做截取,取到Parma
-                block.setType("image");
-                // 获取图片的路径
-                List<String> strSrcList = getImg(rowStr, "src");
-                if (strSrcList.size() > 0) {
-                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
-                    block.setValue(strSrc);
-                }
-                // 获取图片的高度
-                List<String> strHeightList = getImg(rowStr, "height");
-                if (strHeightList.size() > 0) {
-                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
-                    param.put("height", strHeight);
-                }
-                // 获取图片的宽度
-                List<String> strWidthList = getImg(rowStr, "width");
-                if (strHeightList.size() > 0) {
-                    String strWidth = strWidthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
-                    param.put("width", strWidth);
-                }
-                block.setParam(param);
-                blocks.add(block);
-            } else if (rowStr.startsWith("a") && rowStr.contains("id") && rowStr.contains("name")) { // 处理音频
-                rowStr = "<" + rowStr + ">";
-                block.setPlayTime(1);
-                block.setType("audio");
-                block.setValue(this.getAttrValue(rowStr, "url"));
-                blocks.add(block);
-            } else {
-                block.setType("text");
-                if (org.apache.commons.lang3.StringUtils.isNotBlank(rowStr)) {
-                    block.setValue(StringEscapeUtils.unescapeHtml(rowStr));
-                    blocks.add(block);
-                }
-            }
-        }
-
-        return blocks;
-    }
-
-    /**
-     * 获取图片里面的路径,长度,宽度
-     */
-    private List<String> getImg(String s, String str) {
-        String regex;
-        List<String> list = new ArrayList<>();
-        regex = str + "=\"(.*?)\"";
-        Pattern pa = Pattern.compile(regex, Pattern.DOTALL);
-        Matcher ma = pa.matcher(s);
-        while (ma.find()) {
-            list.add(ma.group());
-        }
-        return list;
-    }
-
-    private String getAttrValue(String questionStr, String attrName) {
-        Pattern aPattern = Pattern.compile("a.*");
-        Matcher aMatcher = aPattern.matcher(questionStr);
-
-        if (aMatcher.find()) {
-            String idRegex = attrName + "=\".*?\"";
-            Pattern idPattern = Pattern.compile(idRegex);
-            Matcher idMatcher = idPattern.matcher(aMatcher.group());
-            if (idMatcher.find()) {
-                return idMatcher.group()
-                        .replaceAll(attrName + "=\"", "")
-                        .replaceAll("\"", "");
-            }
-        }
-
-        return "";
-    }
-}

+ 0 - 193
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/HtmlTextHandler.java

@@ -1,193 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.commons.util.RegExpUtil;
-import cn.com.qmth.examcloud.support.enums.BlockType;
-import cn.com.qmth.examcloud.support.handler.richText.bean.BlockBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
-import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
-import com.mysql.cj.util.StringUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jsoup.Jsoup;
-import org.jsoup.safety.Whitelist;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @Description html类型的文本处理器
- * @Author lideyin
- * @Date 2020/5/15 16:28
- * @Version 1.0
- */
-public class HtmlTextHandler implements RichTextHandler {
-    private static Log logger = LogFactory.getLog(HtmlTextHandler.class);
-
-    private static Map<String, String> tagMap;
-    private static String DEFAULT_RETAIN_TAG = "b,u,i,sup,sub";
-
-    static {
-        tagMap = new HashMap<>();
-        tagMap.put("b", "bold");
-        tagMap.put("u", "underline");
-        tagMap.put("i", "italic");
-        tagMap.put("sup", "sup");
-        tagMap.put("sub", "sub");
-    }
-
-    @Override
-    public SectionCollectionBean handle(String richText) {
-
-        if (logger.isDebugEnabled()) {
-            logger.debug("[HTML-TEXT-HANDLER]--richText: " + richText);
-        }
-
-        if (StringUtils.isNullOrEmpty(richText)) {
-            return new SectionCollectionBean();
-        }
-
-        /*过滤不需要的html标签*/
-        String retainTags = PropertyHolder.getString("cloudMarking.interface.retainTags", DEFAULT_RETAIN_TAG);
-
-//        String[] specialRetainTagArr = (retainTags + ",br").split(",");
-//        richText = Jsoup.clean(richText, new Whitelist().addTags(specialRetainTagArr));
-
-        richText = richText.replace("<div>", "\n")
-                .replace("</div>", "")
-                .replace("<br>", "");
-        richText = richText.replace("<br>", "\n");
-
-        SectionCollectionBean sectionCollection = new SectionCollectionBean();
-        List<SectionBean> sectionList = new ArrayList<>();
-        String[] retainTagArr = retainTags.split(",");
-        //有多少个换行,则生成多少个section
-        String[] paragraphArray = richText.split("\n");
-        for (int i = 0; i < paragraphArray.length; i++) {
-            String p = paragraphArray[i];
-            SectionBean section = new SectionBean();
-
-            List<BlockBean> blockList = new ArrayList<>();
-            blockList = getSplitList(p, blockList, retainTagArr);
-
-            section.setBlocks(blockList);
-            sectionList.add(section);
-        }
-
-        sectionCollection.setSections(sectionList);
-
-        //html实体符号编码解析
-
-        return sectionCollection;
-    }
-
-    private static List<BlockBean> getSplitList(String str, List<BlockBean> resultList, final String[] retainTagArr) {
-        if (StringUtils.isNullOrEmpty(str)) {
-            return null;
-        }
-
-        String regPattern = "";
-        for (int i = 0; i < retainTagArr.length; i++) {
-            String tag = retainTagArr[i];
-            if (i != 0) {
-                regPattern += "|";
-            }
-            regPattern += String.format("<%s>\\S*<\\/%s>", tag, tag);
-        }
-
-
-        //找到第一个匹配项
-        String firstMatch = RegExpUtil.find(str, regPattern);
-
-        //如果未找到任何匹配项,则直接返回原字符串
-        if (StringUtils.isNullOrEmpty(firstMatch)) {
-            resultList.add(buildNormalTextAnswer(str));
-            return resultList;
-        }
-
-        //查找到的结果的索引
-        int matchIndex = str.indexOf(firstMatch);
-
-        //如果字符串以特殊标签开头的场景特殊处理
-        if (matchIndex == 0) {
-            //如果字符串中只有特殊标签,则直接返回处理过的数据
-            if (firstMatch.length() == str.length()) {
-                resultList.add(buildSpecialTextAnswer(Jsoup.clean(firstMatch, Whitelist.none()), getTag(firstMatch)));
-                return resultList;
-            }
-
-            //如果字符串以特殊标签开头,且还有其它内容
-            //首先,将特殊标签加入返回集合
-            resultList.add(buildSpecialTextAnswer(Jsoup.clean(firstMatch, Whitelist.none()), getTag(firstMatch)));
-            //其次,将剩下的字符串递归继续处理
-            str = str.substring(firstMatch.length());
-            getSplitList(str, resultList, retainTagArr);
-
-            return resultList;
-        }
-
-        //如果字符串不以特殊标签开头,且还有其它内容
-        String value = str.substring(0, matchIndex);
-        //首先,将前面的普通文本添加到结果集
-        resultList.add(buildNormalTextAnswer(value));
-        //其次,将特殊结果添加到结果集
-        resultList.add(buildSpecialTextAnswer(Jsoup.clean(firstMatch, Whitelist.none()), getTag(firstMatch)));
-        //剩下部分的字符串,继续递归处理
-        str = str.substring(matchIndex + firstMatch.length());
-        getSplitList(str, resultList, retainTagArr);
-
-        return resultList;
-    }
-
-    //构建普通的文本作答
-    private static BlockBean buildNormalTextAnswer(String value) {
-        BlockBean obb = new BlockBean(BlockType.text.name());
-        obb.setValue(StringEscapeUtils.unescapeHtml(value));
-
-        return obb;
-    }
-
-    //构建带特殊标签的文本作答
-    private static BlockBean buildSpecialTextAnswer(String value, String tag) {
-        BlockBean obb = new BlockBean(BlockType.text.name());
-        obb.setType("text");
-        obb.setValue(StringEscapeUtils.unescapeHtml(value));
-
-        Map<String, Object> paramMap = new HashMap<>();
-        paramMap.put(tag, true);
-        obb.setParam(paramMap);
-
-        return obb;
-    }
-
-    private static String getTag(String target) {
-        if (StringUtils.isNullOrEmpty(target)) {
-            return null;
-        }
-
-        for (String s : tagMap.keySet()) {
-            if (target.indexOf(String.format("<%s>", s)) != -1) {
-                return tagMap.get(s);
-            }
-        }
-
-        return null;
-    }
-
-//    public static void main(String[] args) {
-////        String testStr = "1111111<div>222&lt;div&gt;&lt;/div&gt;21000<sup>2</sup></div><div>3333399<sub>3</sub>5555555</div><div><br></div><div>444444</div>";
-////        String testStr="{\"mainNumber\":2,\"order\":23,\"questionId\":\"5ebdf1cbcad4db1aee85e907\",\"studentAnswer\":\"发发呆<div>ななぅぅぉてふっふてふ</div><div class='photo-answers-block'><a href='https://ecs-test-static.qmth.com.cn/oe-answer-file/21083/19288/23/21083_19288_23_15895106360336244.jpeg' target='_blank' ><img class='photo-answer' src='https://ecs-test-static.qmth.com.cn/oe-answer-file/21083/19288/23/21083_19288_23_15895106360336244.jpeg?x-oss-process=image/resize,m_lfit,h_200,w_200' /></a></div>\",\"answerType\":null,\"answer\":\"<p><span> えいが</span></p>\",\"body\":\"<p>映画</p>\",\"parentBody\":null,\"questionType\":\"ESSAY\"}";
-//            String testStr="{\"mainNumber\":5,\"order\":19,\"questionId\":\"5e942585cad4db278def3df5\",\"studentAnswer\":\"范德萨范德萨飞<sup>电风扇的</sup><div>范德萨范德萨</div><div>范德萨范德萨范<sub>德萨发的</sub></div><div class='photo-answers-block'><a href='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464519267961.jpeg' target='_blank' ><img class='photo-answer' src='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464519267961.jpeg?x-oss-process=image/resize,m_lfit,h_200,w_200' /></a><a href='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464518985666.jpeg' target='_blank' ><img class='photo-answer' src='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464518985666.jpeg?x-oss-process=image/resize,m_lfit,h_200,w_200' /></a><a href='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464519221951.jpeg' target='_blank' ><img class='photo-answer' src='https://ecs-test-static.qmth.com.cn/oe-answer-file/20820/19336/19/20820_19336_19_15899464519221951.jpeg?x-oss-process=image/resize,m_lfit,h_200,w_200' /></a></div>\",\"answerType\":\"DIVERSIFIED_TEXT\",\"answer\":\"<p>1).杆件变形的基本形式有轴向拉伸和压缩,剪切,扭转和弯曲。</p>\\n\\n<p>2).强度&mdash;&mdash;构建抵抗破坏的能力。刚度&mdash;&mdash;构件抵抗变形的能力。</p>\\n\\n<p>3).稳定性&mdash;&mdash;构件保持原型状的能力。</p>\",\"body\":\"<p>杆件变形的<em><strong><u>基本形式</u></strong></em>有哪几种?何谓构件的强度,刚度和稳定性?</p><p><a id=\\\"5eba5fadcad4db05908c8d13\\\" name=\\\"19_1_2.mp3\\\" question-audio url=\\\"https://ecs-test-static.qmth.com.cn/comm-ques-bank/prod/audio/5e942585cad4db278def3df5_514_19_1_2.mp3\\\"></a></p>\",\"parentBody\":null,\"questionType\":\"ESSAY\"}";
-//
-//        HtmlTextHandler o = new HtmlTextHandler();
-//
-//
-//        SectionCollectionBean sfds = o.handle(testStr);
-//
-//        System.out.println(JsonUtil.toJson(sfds));
-//    }
-
-}

+ 0 - 172
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/ImageTextHandler.java

@@ -1,172 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.commons.util.JsonUtil;
-import cn.com.qmth.examcloud.commons.util.RegExpUtil;
-import cn.com.qmth.examcloud.support.enums.BlockType;
-import cn.com.qmth.examcloud.support.handler.richText.bean.BlockBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionBean;
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
-import com.mysql.cj.util.StringUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.safety.Whitelist;
-import org.jsoup.select.Elements;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @Description 图片类型的文本处理器
- * @Author lideyin
- * @Date 2020/5/15 16:28
- * @Version 1.0
- */
-public class ImageTextHandler implements RichTextHandler {
-    private static Log logger = LogFactory.getLog(HtmlTextHandler.class);
-
-    @Override
-    public SectionCollectionBean handle(String richText) {
-        if (logger.isDebugEnabled()) {
-            logger.debug("[HTML-TEXT-HANDLER]--richText: " + richText);
-        }
-
-        if (StringUtils.isNullOrEmpty(richText)) {
-            return new SectionCollectionBean();
-        }
-
-        SectionCollectionBean sectionCollection = new SectionCollectionBean();
-        List<SectionBean> sectionList = new ArrayList<>();
-        SectionBean section = new SectionBean();
-        List<BlockBean> blockList = new ArrayList<>();
-
-        //图片文本部分
-        String txtStr = getImgTxt(richText);
-        if (!StringUtils.isNullOrEmpty(txtStr)) {
-            BlockBean blockBean = new BlockBean(BlockType.text.name());
-            blockBean.setValue(StringEscapeUtils.unescapeHtml(txtStr));
-            blockList.add(blockBean);
-        }
-
-        //图片部分
-        if (validateImgAnswer(richText)) {
-            String imgSrc = getImgSrc(richText);
-            String[] imgAnswers = imgSrc.split("\\|");
-
-            for (int i = 0; i < imgAnswers.length; i++) {
-                BlockBean blockBean = new BlockBean(BlockType.image.name());
-                blockBean.setValue(getPureUrl(imgAnswers[i]));
-
-                //又拍云图片的宽*高
-                String width=RegExpUtil.find(imgAnswers[i], "w_(\\d+)");
-                String height=RegExpUtil.find(imgAnswers[i], "h_(\\d+)");
-                Map<String, Object> paramMap = new HashMap<>();
-                if (!StringUtils.isNullOrEmpty(width) && !StringUtils.isNullOrEmpty(height)) {
-                    paramMap.put("width", Integer.valueOf(width.replaceAll("w_","")));
-                    paramMap.put("height", Integer.valueOf(height.replaceAll("h_","")));
-                    blockBean.setParam(paramMap);
-                }
-
-                blockList.add(blockBean);
-            }
-        }
-
-        section.setBlocks(blockList);
-        sectionList.add(section);
-        sectionCollection.setSections(sectionList);
-
-        return sectionCollection;
-
-    }
-
-    /**
-     * 获取图片作答的文本部分
-     *
-     * @param studentAnswer
-     * @return
-     */
-    private String getImgTxt(String studentAnswer) {
-        if (!StringUtils.isNullOrEmpty(studentAnswer)) {
-            return Jsoup.clean(studentAnswer, Whitelist.none());
-        }
-
-        return null;
-    }
-
-    /**
-     * 校验图片答案格式是否正确
-     *
-     * @param studentAnswer
-     * @return
-     */
-    private boolean validateImgAnswer(String studentAnswer) {
-        if (StringUtils.isNullOrEmpty(studentAnswer)) {
-            return false;
-        }
-
-        String regExp = "[\\s\\S]*(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(png|jpg|gif|jpeg).*[\\s\\S]*";
-        return studentAnswer.matches(regExp);
-    }
-
-    /**
-     * 获取图片作答图片路径
-     *
-     * @param studentAnswer
-     * @return
-     */
-    private String getImgSrc(String studentAnswer) {
-        if (StringUtils.isNullOrEmpty(studentAnswer)) {
-            return studentAnswer;
-        }
-
-        //图片题特殊处理(因为图片作答题中有html标签,只需要取url即可)
-        Document doc = Jsoup.parse(studentAnswer);
-        Elements imgElements = doc.select("img[src]");
-
-        String imgSrc = "";
-
-        for (Element el : imgElements) {
-            String src = el.attr("src");
-            if (!StringUtils.isNullOrEmpty(src)) {
-                imgSrc += src + "|";
-            }
-        }
-        if (!StringUtils.isNullOrEmpty(imgSrc)) {
-            return imgSrc.substring(0, imgSrc.length() - 1);
-        }
-
-        return imgSrc;
-    }
-
-    /**
-     * 获取图片url中不带参数部分,去除地址中的多余后缀
-     *
-     * @param imgUrl 图片地址
-     * @return
-     */
-    private String getPureUrl(String imgUrl) {
-        if (StringUtils.isNullOrEmpty(imgUrl)) {
-            return "";
-        }
-
-        String regExp = "(ftp|https?)\\:\\/\\/([\\w\\_\\-]+)\\.([\\w\\-]+[\\.]?)*[\\w]+\\.[a-zA-Z]{2,10}(.*)\\.(png|jpg|gif|jpeg)";
-        return RegExpUtil.find(imgUrl, regExp);
-    }
-
-//    public static void main(String[] args) {
-////        String testStr = "1111111<div>222&lt;div&gt;&lt;/div&gt;21000<sup>2</sup></div><div>3333399<sub>3</sub>5555555</div><div><br></div><div>444444</div>";
-//        String testStr = "{\"mainNumber\":2,\"order\":23,\"questionId\":\"5ebdf1cbcad4db1aee85e907\",\"studentAnswer\":\"发发呆<div>ななぅぅぉてふっふてふ</div><div class='photo-answers-block'><a href='https://ecs-test-static.qmth.com.cn/oe-answer-file/21083/19288/23/21083_19288_23_15895106360336244.jpeg' target='_blank' ><img class='photo-answer' src='https://ecs-test-static.qmth.com.cn/oe-answer-file/21083/19288/23/21083_19288_23_15895106360336244.jpeg?x-oss-process=image/resize,m_lfit,h_200,w_200' /></a></div>\",\"answerType\":null,\"answer\":\"<p><span> えいが</span></p>\",\"body\":\"<p>映画</p>\",\"parentBody\":null,\"questionType\":\"ESSAY\"}";
-//
-//        ImageTextHandler o = new ImageTextHandler();
-//
-//
-//        SectionCollectionBean sfds = o.handle(testStr);
-//
-//        System.out.println(JsonUtil.toJson(sfds));
-//    }
-}

+ 0 - 13
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/RichTextHandler.java

@@ -1,13 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.support.handler.richText.bean.SectionCollectionBean;
-
-/**
- * @Description 富文本处理器接口
- * @Author lideyin
- * @Date 2020/5/15 17:00
- * @Version 1.0
- */
-public interface RichTextHandler {
-    SectionCollectionBean handle(String richText);
-}

+ 0 - 41
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/RichTextHandlerFactory.java

@@ -1,41 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText;
-
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import com.mysql.cj.util.StringUtils;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @Description 富文本处理器工厂类
- * @Author lideyin
- * @Date 2020/5/15 16:33
- * @Version 1.0
- */
-public class RichTextHandlerFactory {
-    private static final Map<String,RichTextHandler> handlerMap=new HashMap<>();
-
-    static {
-        handlerMap.put("text",new HtmlTextHandler());
-        handlerMap.put("image",new ImageTextHandler());
-        handlerMap.put("audio",new AudioTextHandler());
-        handlerMap.put("complex",new ComplexTextHandler());
-    }
-
-    /**
-     * 根据类型获取实例
-     * @param type 文本类型
-     * @return
-     */
-    public static RichTextHandler getHandler(String type) {
-        if (StringUtils.isNullOrEmpty(type)) {
-            throw new StatusException("900101","参数type不允许为空");
-        }
-
-        if (!handlerMap.containsKey(type)) {
-            throw new StatusException("900102","不支持的文本类型");
-        }
-
-        return handlerMap.get(type);
-    }
-}

+ 0 - 70
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/BlockBean.java

@@ -1,70 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText.bean;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @Description 块
- * @Author lideyin
- * @Date 2020/3/2 18:35
- * @Version 1.0
- */
-public class BlockBean {
-    public BlockBean(String type) {
-        this.type = type;
-        this.param = new HashMap<>();
-        this.value = "";
-    }
-
-    /**
-     * text:文字
-     * image:图片
-     * audio:音频
-     * video:视频
-     */
-    private String type;
-    /**
-     * 资源相对路径
-     */
-    private String value;
-    /**
-     * 播放次数
-     */
-    private Integer playTime;
-
-    private Map<String, Object> param;
-
-    public String getType() {
-        return type;
-    }
-
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    public String getValue() {
-        return value;
-    }
-
-    public void setValue(String value) {
-        this.value = value;
-    }
-
-    public Map<String, Object> getParam() {
-        return param;
-    }
-
-    public void setParam(Map<String, Object> param) {
-        this.param = param;
-    }
-
-    public Integer getPlayTime() {
-        return playTime;
-    }
-
-    public void setPlayTime(Integer playTime) {
-        this.playTime = playTime;
-    }
-
-}
-

+ 0 - 31
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/SectionBean.java

@@ -1,31 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText.bean;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @Description 节点
- * @Author lideyin
- * @Date 2020/3/30 17:00
- * @Version 1.0
- */
-public class SectionBean {
-
-    public SectionBean() {
-        this.blocks=new ArrayList<>();
-    }
-
-    private List<BlockBean> blocks;
-
-    public List<BlockBean> getBlocks() {
-        return blocks;
-    }
-
-    public void setBlocks(List<BlockBean> blocks) {
-        this.blocks = blocks;
-    }
-
-
-
-}
-

+ 0 - 25
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/handler/richText/bean/SectionCollectionBean.java

@@ -1,25 +0,0 @@
-package cn.com.qmth.examcloud.support.handler.richText.bean;
-
-import java.util.List;
-
-/**
- * @Description 节点集合
- * @Author lideyin
- * @Date 2020/3/30 16:59
- * @Version 1.0
- */
-public class SectionCollectionBean {
-
-    private List<SectionBean> sections;
-
-    public List<SectionBean> getSections() {
-        return sections;
-    }
-
-    public void setSections(List<SectionBean> sections) {
-        this.sections = sections;
-    }
-
-
-}
-

+ 0 - 49
examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Block.java

@@ -1,49 +0,0 @@
-package cn.com.qmth.examcloud.support.test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class Block {
-
-    private String type;
-
-    private String value;
-
-    /**
-     * 播放次数
-     */
-    private Integer playTime;
-
-    public Integer getPlayTime() {
-        return playTime;
-    }
-
-    public void setPlayTime(Integer playTime) {
-        this.playTime = playTime;
-    }
-
-    private Map<String, Object> param;
-
-    public Block(BlockType type) {
-        this.type = type.name().toLowerCase();
-        this.param = new HashMap<>();
-        this.value = "";
-    }
-
-    public String getType() {
-        return type;
-    }
-
-    public String getValue() {
-        return value;
-    }
-
-    public void setValue(String value) {
-        this.value = value;
-    }
-
-    public Map<String, Object> getParam() {
-        return param;
-    }
-
-}

+ 0 - 6
examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/BlockType.java

@@ -1,6 +0,0 @@
-package cn.com.qmth.examcloud.support.test;
-
-public enum BlockType {
-
-    TEXT, IMAGE, AUDIO;
-}

+ 0 - 162
examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Context.java

@@ -1,162 +0,0 @@
-package cn.com.qmth.examcloud.support.test;
-
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Element;
-import org.jsoup.nodes.Node;
-import org.jsoup.nodes.TextNode;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class Context {
-
-    private static final Map<String, String> TEXT_PARAM_MAP = new HashMap<>();
-
-    static {
-        TEXT_PARAM_MAP.put("b", "bold");
-        TEXT_PARAM_MAP.put("i", "italic");
-        TEXT_PARAM_MAP.put("strong", "bold");
-        TEXT_PARAM_MAP.put("em", "italic");
-        TEXT_PARAM_MAP.put("u", "underline");
-        TEXT_PARAM_MAP.put("sup", "sup");
-        TEXT_PARAM_MAP.put("sub", "sub");
-    }
-
-    private List<Section> sections;
-
-    private Section currentSection;
-
-    private Map<String, Object> currentTextParam;
-
-    public Context() {
-        this.sections = new ArrayList<>();
-        this.currentTextParam = new HashMap<>();
-    }
-
-    public List<Section> process(String input) {
-        Element body = Jsoup.parseBodyFragment(StringUtils.trimToEmpty(input)).body();
-        switchSection();
-        for (Node child : body.childNodes()) {
-            parseNode(child);
-        }
-        return sections;
-    }
-
-    private void parseNode(Node node) {
-        if (node instanceof TextNode) {
-            TextNode textNode = (TextNode) node;
-            parseText(textNode.text());
-        } else if (node instanceof Element) {
-            Element element = (Element) node;
-            onElementStart(element);
-            for (Node child : element.childNodes()) {
-                parseNode(child);
-            }
-            onElementEnd(element);
-        }
-    }
-
-    private void parseText(String text) {
-        Block block = new Block(BlockType.TEXT);
-        block.setValue(StringEscapeUtils.unescapeHtml(text));
-        block.getParam().putAll(currentTextParam);
-        addBlock(block);
-    }
-
-    private void parseImage(Element element) {
-        Block block = new Block(BlockType.IMAGE);
-
-        String src = element.attr("src");
-        block.setValue(src);
-
-        Map<String, Object> param = new HashMap<>();
-        String height = element.attr("height");
-        String width = element.attr("width");
-        param.put("width", height);
-        param.put("height", width);
-        block.getParam().putAll(param);
-
-        addBlock(block);
-    }
-
-    private void parseAudio(Element element) {
-        //todo 此处为题库特殊处理,待确认
-        String id = element.attr("id");
-        String name = element.attr("name");
-        if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(name)) {
-            Block block = new Block(BlockType.AUDIO);
-            block.setPlayTime(1);
-            block.setValue(element.attr("url"));
-            addBlock(block);
-        }
-    }
-
-    private void onElementStart(Element element) {
-        String name = element.nodeName().toLowerCase();
-        switch (name) {
-            case "div":
-            case "p":
-                switchSection();
-                break;
-            case "br":
-                finishSection();
-                break;
-            case "img":
-                parseImage(element);
-                break;
-            case "audio":// TODO
-            case "a":// TODO
-                parseAudio(element);
-                break;
-            default:
-                String style = TEXT_PARAM_MAP.get(name);
-                if (style != null) {
-                    currentTextParam.put(style, true);
-                }
-        }
-    }
-
-    private void onElementEnd(Element element) {
-        String name = element.nodeName().toLowerCase();
-        switch (name) {
-            case "div":
-            case "p":
-            case "span":
-                finishSection();
-                break;
-            case "img":// TODO
-            case "audio":// TODO
-            case "a":// TODO
-//                finishSection();
-                break;
-            default:
-                String style = TEXT_PARAM_MAP.get(name);
-                if (style != null) {
-                    currentTextParam.remove(style);
-                }
-        }
-    }
-
-    private void addBlock(Block block) {
-        if (currentSection == null) {
-            switchSection();
-        }
-        currentSection.addBlock(block);
-    }
-
-    private void finishSection() {
-        currentSection = null;
-    }
-
-    private void switchSection() {
-        Section section = new Section();
-        sections.add(section);
-        currentSection = section;
-        currentTextParam.clear();
-    }
-
-}

+ 0 - 21
examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Section.java

@@ -1,21 +0,0 @@
-package cn.com.qmth.examcloud.support.test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Section {
-
-    private List<Block> blocks;
-
-    public Section() {
-        this.blocks = new ArrayList<>();
-    }
-
-    public void addBlock(Block block) {
-        this.blocks.add(block);
-    }
-
-    public List<Block> getBlocks() {
-        return blocks;
-    }
-}

+ 0 - 19
examcloud-support/src/test/java/cn/com/qmth/examcloud/support/test/Test.java

@@ -1,19 +0,0 @@
-package cn.com.qmth.examcloud.support.test;
-
-import net.sf.json.JSONArray;
-import org.apache.commons.lang.StringUtils;
-
-public class Test {
-
-    public static void main(String[] args) {
-        String input = "<br>普通文本<br><div>这个被div包裹着</div><p>这个被p包裹 着</p><div><b>加粗<i>加粗且斜体<u>加粗且斜体且有下划线</u><b>加粗且斜体且有重复加粗标签</b></i>100<sup>2</sup></b></div>普通文本log<sub>3</sub>";
-//        String t2="<p><strong><em>杆件变形</em></strong><a id='a' name='1' url='http://1.mp3'></a>的基本形式有哪几种?<img src='http://www.baidu.com'/>何谓构件的强度,刚度和稳定性?</p>";
-//        String t2="<p><strong><em>杆件变形</em></strong>的基本形式有哪几种?何谓构件的强度,刚度和稳定性?</p>";
-        Context context = new Context();
-
-        System.out.println(JSONArray.fromObject(context.process(input)));
-
-//        System.out.println(JSONArray.fromObject(context.process(t2)));
-    }
-
-}

+ 0 - 58
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/CacheCloudServiceProvider.java

@@ -35,8 +35,6 @@ public class CacheCloudServiceProvider implements CloudService {
 			.getLog(CacheCloudServiceProvider.class);
 
 	private static Map<String, ObjectCache<?>> map = Maps.newConcurrentMap();
-	
-	private static Map<String, HashCache<?>> hashCacheMap = Maps.newConcurrentMap();
 
 	@PostMapping("refresh")
 	public String refresh(@RequestBody RefreshCacheReq req) {
@@ -76,61 +74,5 @@ public class CacheCloudServiceProvider implements CloudService {
 		Object object = objectCache.get(expectedKeys);
 		return JsonUtil.toJson(object);
 	}
-	
-	@PostMapping("refreshHash")
-    public String refreshHash(@RequestBody RefreshHashCacheReq req) {
-
-        String className = req.getClassName();
-        String[] keys = req.getKeys();
-        String[] subkeys = req.getSubKeys();
-        BasicDataType[] typeArray = req.getTypeArray();
-        BasicDataType[] subTypeArray = req.getSubTypeArray();
-
-        Object[] expectedKeys = new Object[keys.length];
-
-        for (int i = 0; i < keys.length; i++) {
-            String key = keys[i];
-            BasicDataType type = typeArray[i];
-            if (type.equals(BasicDataType.LONG)) {
-                expectedKeys[i] = Long.parseLong(key);
-            } else if (type.equals(BasicDataType.STRING)) {
-                expectedKeys[i] = key;
-            } else if (type.equals(BasicDataType.INTEGER)) {
-                expectedKeys[i] = Integer.parseInt(key);
-            } else {
-                throw new ExamCloudRuntimeException("key type is not supported");
-            }
-        }
-        
-        Object[] expectedSubKeys = new Object[subkeys.length];
-        for (int i = 0; i < subkeys.length; i++) {
-            String key = subkeys[i];
-            BasicDataType type = subTypeArray[i];
-            if (type.equals(BasicDataType.LONG)) {
-                expectedSubKeys[i] = Long.parseLong(key);
-            } else if (type.equals(BasicDataType.STRING)) {
-                expectedSubKeys[i] = key;
-            } else if (type.equals(BasicDataType.INTEGER)) {
-                expectedSubKeys[i] = Integer.parseInt(key);
-            } else {
-                throw new ExamCloudRuntimeException("subkey type is not supported");
-            }
-        }
-
-        HashCache<?> hashCache = hashCacheMap.get(className);
-        if (null == hashCache) {
-
-            try {
-                Class<?> c = Class.forName(className);
-                hashCache = (HashCache<?>) SpringContextHolder.getBean(c);
-                hashCacheMap.put(className, hashCache);
-            } catch (ClassNotFoundException e) {
-                throw new StatusException("008002", "class not found", e);
-            }
-        }
-        hashCache.refresh(expectedKeys,expectedSubKeys);
-        Object object = hashCache.get(expectedKeys,expectedSubKeys);
-        return JsonUtil.toJson(object);
-    }
 
 }

+ 0 - 41
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashCache.java

@@ -1,41 +0,0 @@
-package cn.com.qmth.examcloud.web.cache;
-
-/**
- * Hash缓存
- *
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- * @param <T>
- */
-public interface HashCache<T> {
-
-	/**
-	 * 从缓存中获取
-	 *
-	 * @param keys
-	 * @return
-	 */
-	T get(Object[] keys,Object[] subkeys);
-
-	/**
-	 * 删除缓存
-	 *
-	 * @param keys 大key
-	 */
-	void remove(Object... keys);
-
-	/**
-	 * 刷新缓存
-	 *
-	 * @param keys
-	 */
-	void refresh(Object[] keys,Object[] subkeys);
-
-	/**
-	 * 从数据源(数据库,配置文件等)加载单个缓存项
-	 *
-	 * @param keys
-	 * @return
-	 */
-	T loadFromResource(Object[] keys,Object[] subkeys);
-
-}

+ 0 - 89
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCache.java

@@ -1,89 +0,0 @@
-package cn.com.qmth.examcloud.web.cache;
-
-import org.apache.commons.lang3.StringUtils;
-import org.assertj.core.util.Arrays;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.web.redis.RedisClient;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
-/**
- * Hash redis缓存
- *
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- * @param <T>
- */
-public abstract class HashRedisCache<T extends RandomCacheBean> implements HashCache<T> {
-
-    private RedisClient redisClient;
-
-    private RedisClient getRedisClient() {
-        if (null == redisClient) {
-            redisClient = SpringContextHolder.getBean(RedisClient.class);
-        }
-        return redisClient;
-    }
-
-    protected abstract String getKeyPrefix();
-
-    protected abstract int getTimeout();
-
-    protected String buildKey(Object... keys) {
-        String key = getKeyPrefix() + StringUtils.join(Arrays.asList(keys), '_');
-        return key;
-    }
-    
-    protected String buildSubKey(Object... keys) {
-        String key = StringUtils.join(Arrays.asList(keys), '_');
-        return key;
-    }
-
-    private T getFromCache(String key, String subkey) {
-        Object object = getRedisClient().get(key,subkey, Object.class);
-        @SuppressWarnings("unchecked")
-        T t = (T) object;
-        return t;
-    }
-    @Override
-    public T get(Object[] keys,Object[] subkeys) {
-        String key = buildKey(keys);
-        String subkey = buildSubKey(subkeys);
-        T t = getFromCache(key,subkey);
-
-        if (null == t) {
-            refresh(keys,subkeys);
-        }
-        t = getFromCache(key,subkey);
-        return t;
-    }
-
-    @Override
-    public void remove(Object... keys) {
-        String key = buildKey(keys);
-        getRedisClient().delete(key);
-    }
-
-    @Override
-    public void refresh(Object[] keys,Object[] subkeys) {
-        String key = buildKey(keys);
-        String subkey = buildSubKey(subkeys);
-        T t = null;
-        try {
-            t = loadFromResource(keys,subkeys);
-        } catch (StatusException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new ExamCloudRuntimeException("fail to load data. key=" + key+" subkey="+subkey, e);
-        }
-        if (null != t) {
-            int timeout = getTimeout();
-            if (timeout < 60) {
-                timeout = 60;
-            }
-            getRedisClient().set(key,subkey, t, timeout);
-        } else {
-            getRedisClient().delete(key,subkey);
-        }
-    }
-}

+ 0 - 134
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCacheProcessor.java

@@ -1,134 +0,0 @@
-package cn.com.qmth.examcloud.web.cache;
-
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.lang3.StringUtils;
-import org.assertj.core.util.Arrays;
-
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import cn.com.qmth.examcloud.commons.util.ThreadLocalUtil;
-import cn.com.qmth.examcloud.commons.util.Util;
-import cn.com.qmth.examcloud.web.redis.RedisClient;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
-/**
- * redis Hash缓存处理器
- *
- * @date 2019年5月10日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class HashRedisCacheProcessor {
-
-	private static RedisClient redisClient;
-
-	private static HashRedisCacheTrigger hashRedisCacheTrigger;
-
-	private static RedisClient getRedisClient() {
-		if (null == redisClient) {
-			redisClient = SpringContextHolder.getBean(RedisClient.class);
-		}
-		return redisClient;
-	}
-
-	private static HashRedisCacheTrigger getHashRedisCacheTrigger() {
-		if (null == hashRedisCacheTrigger) {
-			hashRedisCacheTrigger = SpringContextHolder.getBean(HashRedisCacheTrigger.class);
-		}
-		return hashRedisCacheTrigger;
-	}
-
-	/**
-	 * 获取缓存对象
-	 *
-	 * @author 
-	 * @param keyPrefix
-	 * @param propKeys
-	 * @param c
-	 * @return
-	 */
-	public static <T> T get(String keyPrefix, Object[] propKeys,Object[] subpropKeys, Class<T> c) {
-		String key = keyPrefix + StringUtils.join(Arrays.asList(propKeys), '_');
-		String hashKey=StringUtils.join(Arrays.asList(subpropKeys), '_');
-		T t = getRedisClient().get(key,hashKey, c);
-		return t;
-	}
-
-	/**
-	 * 取缓存对象(不存在时远程或本地加载)<br>
-	 * 缓存失效时,只允许一个线程加载缓存,防止缓存击穿<br>
-	 * 缓存加载时长不得超过10秒,否则所有取缓存线程无等待抛出异常,只到缓存被正确加载<br>
-	 * 
-	 *
-	 * @author 
-	 * @param keyPrefix
-	 * @param propKeys
-	 * @param c
-	 * @param appName
-	 * @param className
-	 * @return
-	 */
-	public static <T> T get(String keyPrefix, Object[] propKeys,Object[] subpropKeys, Class<? extends RandomCacheBean> c,
-			String appName, String className) {
-
-		String key = keyPrefix + StringUtils.join(Arrays.asList(propKeys), '_');
-		String subKey=StringUtils.join(Arrays.asList(subpropKeys), '_');
-
-		RandomCacheBean t = getRedisClient().get(key,subKey, c);
-
-		if (null == t) {
-
-			int count = 0;
-
-			String cacheLock = "$_CACHE_LOCK:" + key+"_"+subKey;
-			String cacheException = "$_CACHE_EXCEPTION:" + key+"_"+subKey;
-
-			while (true) {
-				count++;
-
-				t = getRedisClient().get(key,subKey, c);
-
-				if (null != t) {
-					break;
-				}
-
-				Boolean locked = getRedisClient().setIfAbsent(cacheLock,
-						ThreadLocalUtil.getTraceId(), 30);
-
-				if (locked) {
-					try {
-					    getHashRedisCacheTrigger().fire(appName, className, propKeys,subpropKeys);
-						getRedisClient().delete(cacheException);
-						t = getRedisClient().get(key,subKey, c);
-						break;
-					} catch (Exception e) {
-						getRedisClient().set(cacheException, true, 60);
-						throw e;
-					} finally {
-						getRedisClient().delete(cacheLock);
-					}
-				} else {
-
-					if (null != getRedisClient().get(cacheException, Boolean.class)) {
-						throw new ExamCloudRuntimeException(
-								"exception happened when loading cache. key=" + key+" subKey="+subKey);
-					}
-
-					// 10秒内未加载完缓存,抛出异常
-					if (200 < count) {
-						throw new ExamCloudRuntimeException(
-								"fail to load cache in 10 seconds. key=" + key+" subKey="+subKey);
-					}
-
-					Util.sleep(TimeUnit.MILLISECONDS, 50);
-
-				}
-			}
-
-		}
-
-		@SuppressWarnings("unchecked")
-		T ret = (T) t;
-		return ret;
-	}
-
-}

+ 0 - 109
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/HashRedisCacheTrigger.java

@@ -1,109 +0,0 @@
-package cn.com.qmth.examcloud.web.cache;
-
-import java.util.Map;
-
-import org.springframework.stereotype.Component;
-
-import com.google.common.collect.Maps;
-
-import cn.com.qmth.examcloud.api.commons.enums.BasicDataType;
-import cn.com.qmth.examcloud.commons.exception.ExamCloudRuntimeException;
-import cn.com.qmth.examcloud.web.cloud.CloudClientSupport;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
-/**
- * redis缓存触发器
- *
- * @author 
- * @date 2019年5月9日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-@Component
-public class HashRedisCacheTrigger extends CloudClientSupport {
-
-	private static Map<String, Boolean> hasClassMap = Maps.newConcurrentMap();
-
-	private static Map<String, HashCache<?>> hashCacheMap = Maps.newConcurrentMap();
-
-	/**
-	 * 开火
-	 *
-	 * @author 
-	 * @param appName
-	 * @param keys
-	 * @return
-	 */
-	public void fire(String appName, String className, Object[] keys,Object[] subkeys) {
-
-		Boolean has = hasClassMap.get(className);
-		HashCache<?> hashCache = null;
-
-		if (null != has) {
-			if (has) {
-				hashCache = hashCacheMap.get(className);
-				hashCache.refresh(keys,subkeys);
-				return;
-			}
-		} else {
-			try {
-				Class<?> c = Class.forName(className);
-				hashCache = (HashCache<?>) SpringContextHolder.getBean(c);
-				hashCache.refresh(keys,subkeys);
-				hashCacheMap.put(className, hashCache);
-				hasClassMap.put(className, true);
-				return;
-			} catch (ClassNotFoundException e) {
-				hasClassMap.put(className, false);
-			}
-		}
-
-		String[] keyArray = new String[keys.length];
-		BasicDataType[] typeArray = new BasicDataType[keys.length];
-
-		for (int i = 0; i < keys.length; i++) {
-			keyArray[i] = String.valueOf(keys[i]);
-			Class<? extends Object> c = keys[i].getClass();
-			if (c.equals(Long.class)) {
-				typeArray[i] = BasicDataType.LONG;
-			} else if (c.equals(String.class)) {
-				typeArray[i] = BasicDataType.STRING;
-			} else if (c.equals(Integer.class)) {
-				typeArray[i] = BasicDataType.INTEGER;
-			} else {
-				throw new ExamCloudRuntimeException("key type is not supported");
-			}
-		}
-		
-		String[] subKeyArray = new String[subkeys.length];
-        BasicDataType[] subTypeArray = new BasicDataType[subkeys.length];
-
-        for (int i = 0; i < subkeys.length; i++) {
-            subKeyArray[i] = String.valueOf(subkeys[i]);
-            Class<? extends Object> c = subkeys[i].getClass();
-            if (c.equals(Long.class)) {
-                subTypeArray[i] = BasicDataType.LONG;
-            } else if (c.equals(String.class)) {
-                subTypeArray[i] = BasicDataType.STRING;
-            } else if (c.equals(Integer.class)) {
-                subTypeArray[i] = BasicDataType.INTEGER;
-            } else {
-                throw new ExamCloudRuntimeException("subkey type is not supported");
-            }
-        }
-
-		RefreshHashCacheReq req = new RefreshHashCacheReq();
-		req.setClassName(className);
-		req.setKeys(keyArray);
-		req.setTypeArray(typeArray);
-		req.setSubKeys(subKeyArray);
-		req.setSubTypeArray(subTypeArray);
-		post(appName, "refreshHash", req);
-
-	}
-
-	@Override
-	protected String getRequestMappingPrefix() {
-		return "cache";
-	}
-
-}

+ 0 - 76
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/cache/RefreshHashCacheReq.java

@@ -1,76 +0,0 @@
-package cn.com.qmth.examcloud.web.cache;
-
-import cn.com.qmth.examcloud.api.commons.enums.BasicDataType;
-import cn.com.qmth.examcloud.api.commons.exchange.BaseRequest;
-
-/**
- * 刷新Hash缓存请求
- *
- * @author 
- * @date 2019年5月9日
- * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
- */
-public class RefreshHashCacheReq extends BaseRequest {
-
-
-	/**
-     * 
-     */
-    private static final long serialVersionUID = 3251806982238101789L;
-
-    private String className;
-
-	private String[] keys;
-
-	private BasicDataType[] typeArray;
-	
-	private String[] subKeys;
-
-    private BasicDataType[] subTypeArray;
-
-	public String getClassName() {
-		return className;
-	}
-
-	public void setClassName(String className) {
-		this.className = className;
-	}
-
-	public String[] getKeys() {
-		return keys;
-	}
-
-	public void setKeys(String[] keys) {
-		this.keys = keys;
-	}
-
-	public BasicDataType[] getTypeArray() {
-		return typeArray;
-	}
-
-	public void setTypeArray(BasicDataType[] typeArray) {
-		this.typeArray = typeArray;
-	}
-
-    
-    public String[] getSubKeys() {
-        return subKeys;
-    }
-
-    
-    public void setSubKeys(String[] subKeys) {
-        this.subKeys = subKeys;
-    }
-
-    
-    public BasicDataType[] getSubTypeArray() {
-        return subTypeArray;
-    }
-
-    
-    public void setSubTypeArray(BasicDataType[] subTypeArray) {
-        this.subTypeArray = subTypeArray;
-    }
-
-
-}

+ 0 - 26
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/redis/RedisClient.java

@@ -35,13 +35,6 @@ public interface RedisClient {
 	 * @param value
 	 */
 	public void set(String key, Object value);
-	
-	/**
-	 * @param key
-	 * @param subkey
-	 * @param value
-	 */
-	public void set(String key,String subkey, Object value);
 
 	/**
 	 * 方法注释
@@ -52,14 +45,6 @@ public interface RedisClient {
 	 * @param timeout
 	 */
 	public void set(String key, Object value, int timeout);
-	
-    /**
-     * @param key
-     * @param subkey
-     * @param value
-     * @param timeout
-     */
-    public void set(String key,String subkey, Object value, int timeout);
 
 	/**
 	 * 方法注释
@@ -100,15 +85,6 @@ public interface RedisClient {
 	 * @return
 	 */
 	public <T> T get(String key, Class<T> c);
-	
-	/** hash get
-	 * @param <T>
-	 * @param key
-	 * @param subkey
-	 * @param c
-	 * @return
-	 */
-	public <T> T get(String key, String subkey, Class<T> c);
 
 	/**
 	 * 方法注释
@@ -117,8 +93,6 @@ public interface RedisClient {
 	 * @param key
 	 */
 	public void delete(String key);
-	
-	public void delete(String key,String subkey);
 
 	/**
 	 * 方法注释

+ 3 - 39
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/redis/SimpleRedisClient.java

@@ -54,7 +54,8 @@ public final class SimpleRedisClient implements RedisClient {
 	public void set(String key, Object value, int timeout) {
 		long s = System.currentTimeMillis();
 		beforeMethod();
-		redisTemplate.opsForValue().set(key, value,timeout,TimeUnit.SECONDS);
+		set(key, value);
+		expire(key, timeout);
 		afterMethod("set(String key, Object value, int timeout)", s);
 	}
 
@@ -104,17 +105,6 @@ public final class SimpleRedisClient implements RedisClient {
 		return t;
 	}
 
-
-    @Override
-    public <T> T get(String key,String hashKey, Class<T> c) {
-        long s = System.currentTimeMillis();
-        beforeMethod();
-        Object object = redisTemplate.opsForHash().get(key,hashKey);
-        @SuppressWarnings("unchecked")
-        T t = (T) object;
-        afterMethod("get(String key, Class<T> c)", s);
-        return t;
-    }
 	@Override
 	public void delete(String key) {
 		long s = System.currentTimeMillis();
@@ -156,30 +146,4 @@ public final class SimpleRedisClient implements RedisClient {
 		return redisTemplate.getExpire(key, timeUnit);
 	}
 
-    @Override
-    public void set(String key, String subkey, Object value, int timeout) {
-        long s = System.currentTimeMillis();
-        beforeMethod();
-		expire(key, timeout);
-		set(key,subkey, value);
-        afterMethod("set(String key,String subkey,Object value, int timeout)", s);
-
-    }
-
-    @Override
-    public void delete(String key, String subkey) {
-        long s = System.currentTimeMillis();
-        beforeMethod();
-        redisTemplate.opsForHash().delete(subkey, subkey);
-        afterMethod("delete(String key,String subkey)", s);
-    }
-
-    @Override
-    public void set(String key, String subkey, Object value) {
-        long s = System.currentTimeMillis();
-        beforeMethod();
-        redisTemplate.opsForHash().put(key,subkey, value);
-        afterMethod("set(String key,String subkey, Object value)", s);
-    }
-
-}
+}

+ 314 - 309
examcloud-web/src/main/java/cn/com/qmth/examcloud/web/support/ControllerSupport.java

@@ -1,5 +1,27 @@
 package cn.com.qmth.examcloud.web.support;
 
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import com.google.common.collect.Lists;
+
 import cn.com.qmth.examcloud.api.commons.security.bean.Role;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
@@ -9,342 +31,325 @@ import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
 import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
 import cn.com.qmth.examcloud.commons.util.ObjectUtil;
 import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
-import com.google.common.collect.Lists;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.*;
-import java.lang.reflect.Field;
-import java.net.URLEncoder;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * contorller 基类
- *
+ * 
  * @author wang wei
  * @date 2018年4月4日
  */
 public abstract class ControllerSupport {
 
-    /**
-     * controller 统一业务日志对象
-     */
-    protected ExamCloudLog log = ExamCloudLogFactory.getLog(this.getClass());
-
-    /**
-     * 获取接入用户
-     *
-     * @return
-     */
-    protected User getAccessUser() {
-        User accessUser = (User) ServletUtil.getRequest()
-                .getAttribute(HttpServletRequestAttribute.$_ACCESS_USER.name());
-        if (null == accessUser) {
-            throw new StatusException("252", "请重新登陆");
-        }
-        return accessUser;
-    }
+	/**
+	 * controller 统一业务日志对象
+	 */
+	protected ExamCloudLog log = ExamCloudLogFactory.getLog(this.getClass());
 
-    /**
-     * 设置http响应码总是为200
-     *
-     * @author WANGWEI
-     */
-    protected void setAlwaysOKResponse() {
-        ServletUtil.getRequest().setAttribute(HttpServletRequestAttribute.$_ALWAYS_OK.name(), true);
-    }
+	/**
+	 * 获取接入用户
+	 * 
+	 * @return
+	 */
+	protected User getAccessUser() {
+		User accessUser = (User) ServletUtil.getRequest()
+				.getAttribute(HttpServletRequestAttribute.$_ACCESS_USER.name());
+		if (null == accessUser) {
+			throw new StatusException("252", "请重新登陆");
+		}
+		return accessUser;
+	}
 
-    /**
-     * 获取企业的顶级机构(非session状态)
-     *
-     * @return
-     * @author WANGWEI
-     */
-    protected Long getEnterpriseRootOrgId() {
-        Long rootOrgId = (Long) getRequest()
-                .getAttribute(HttpServletRequestAttribute.$_ENTERPRISE_ROOT_ORG_ID.name());
-        if (null == rootOrgId) {
-            throw new StatusException("280", "安全接入的顶级机构ID为空");
-        }
-        return rootOrgId;
-    }
+	/**
+	 * 设置http响应码总是为200
+	 *
+	 * @author WANGWEI
+	 */
+	protected void setAlwaysOKResponse() {
+		ServletUtil.getRequest().setAttribute(HttpServletRequestAttribute.$_ALWAYS_OK.name(), true);
+	}
 
-    /**
-     * 获取顶级机构(session状态)
-     *
-     * @return
-     * @author WANGWEI
-     */
-    protected Long getRootOrgId() {
-        Long rootOrgId = getAccessUser().getRootOrgId();
-        return rootOrgId;
-    }
+	/**
+	 * 获取企业的顶级机构(非session状态)
+	 *
+	 * @author WANGWEI
+	 * @return
+	 */
+	protected Long getEnterpriseRootOrgId() {
+		Long rootOrgId = (Long) getRequest()
+				.getAttribute(HttpServletRequestAttribute.$_ENTERPRISE_ROOT_ORG_ID.name());
+		if (null == rootOrgId) {
+			throw new StatusException("280", "安全接入的顶级机构ID为空");
+		}
+		return rootOrgId;
+	}
 
-    /**
-     * 判断是否超级管理员
-     *
-     * @return
-     * @author WANGWEI
-     */
-    protected boolean isSuperAdmin() {
-        User accessUser = getAccessUser();
-        List<Role> roleList = accessUser.getRoleList();
-        for (Role role : roleList) {
-            if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-                return true;
-            }
-        }
+	/**
+	 * 获取顶级机构(session状态)
+	 *
+	 * @author WANGWEI
+	 * @return
+	 */
+	protected Long getRootOrgId() {
+		Long rootOrgId = getAccessUser().getRootOrgId();
+		return rootOrgId;
+	}
 
-        return false;
-    }
+	/**
+	 * 判断是否超级管理员
+	 *
+	 * @author WANGWEI
+	 * @return
+	 */
+	protected boolean isSuperAdmin() {
+		User accessUser = getAccessUser();
+		List<Role> roleList = accessUser.getRoleList();
+		for (Role role : roleList) {
+			if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+				return true;
+			}
+		}
 
-    /**
-     * 验证顶级机构隔离
-     *
-     * @param rootOrgId
-     * @author WANGWEI
-     */
-    protected void validateRootOrgIsolation(Long rootOrgId) {
-        if ((!isSuperAdmin()) && (!rootOrgId.equals(getRootOrgId()))) {
-            throw new StatusException("250", "非法请求");
-        }
-    }
+		return false;
+	}
 
-    /**
-     * 获取接入用户的角色ID集合
-     *
-     * @return
-     * @author WANGWEI
-     */
-    protected List<Long> getAccessUserRoleIdList() {
-        List<Role> roleList = getAccessUser().getRoleList();
-        List<Long> roleIdList = Lists.newArrayList();
-        for (Role cur : roleList) {
-            roleIdList.add(cur.getRoleId());
-        }
-        return roleIdList;
-    }
+	/**
+	 * 验证顶级机构隔离
+	 *
+	 * @author WANGWEI
+	 * @param rootOrgId
+	 */
+	protected void validateRootOrgIsolation(Long rootOrgId) {
+		if ((!isSuperAdmin()) && (!rootOrgId.equals(getRootOrgId()))) {
+			throw new StatusException("250", "非法请求");
+		}
+	}
 
-    /**
-     * 判断用户是否拥有指定的角色
-     *
-     * @param role
-     * @return
-     * @author WANGWEI
-     */
-    protected Boolean hasRole(RoleMeta role) {
-        List<Role> roleList = getAccessUser().getRoleList();
-        for (Role cur : roleList) {
-            if (cur.getRoleCode().equals(role.name())) {
-                return true;
-            }
-        }
-        return false;
-    }
+	/**
+	 * 获取接入用户的角色ID集合
+	 *
+	 * @author WANGWEI
+	 * @return
+	 */
+	protected List<Long> getAccessUserRoleIdList() {
+		List<Role> roleList = getAccessUser().getRoleList();
+		List<Long> roleIdList = Lists.newArrayList();
+		for (Role cur : roleList) {
+			roleIdList.add(cur.getRoleId());
+		}
+		return roleIdList;
+	}
 
-    /**
-     * 获取request对象
-     *
-     * @return
-     */
-    protected HttpServletRequest getRequest() {
-        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
-                .getRequestAttributes();
-        HttpServletRequest request = requestAttributes.getRequest();
-        return request;
-    }
+	/**
+	 * 判断用户是否拥有指定的角色
+	 *
+	 * @author WANGWEI
+	 * @param role
+	 * @return
+	 */
+	protected Boolean hasRole(RoleMeta role) {
+		List<Role> roleList = getAccessUser().getRoleList();
+		for (Role cur : roleList) {
+			if (cur.getRoleCode().equals(role.name())) {
+				return true;
+			}
+		}
+		return false;
+	}
 
-    /**
-     * 获取response对象
-     *
-     * @return
-     */
-    protected HttpServletResponse getResponse() {
-        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
-                .getRequestAttributes();
-        HttpServletResponse response = requestAttributes.getResponse();
-        return response;
-    }
+	/**
+	 * 获取request对象
+	 * 
+	 * @return
+	 */
+	protected HttpServletRequest getRequest() {
+		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes();
+		HttpServletRequest request = requestAttributes.getRequest();
+		return request;
+	}
 
-    /**
-     * 文件导出
-     *
-     * @param fileName
-     * @param file
-     * @author WANGWEI
-     */
-    protected void exportFile(String fileName, File file) {
-        OutputStream out = null;
-        InputStream in = null;
-        try {
-            in = new FileInputStream(file);
-            fileName = URLEncoder.encode(fileName, "UTF-8");
-            HttpServletResponse response = getResponse();
-            response.reset();
-            response.setHeader("Content-Disposition", "inline; filename=" + fileName);
-            response.addHeader("Content-Length", "" + file.length());
-            response.setContentType("application/octet-stream;charset=UTF-8");
-            out = new BufferedOutputStream(response.getOutputStream());
-            IOUtils.copy(in, out);
-            out.flush();
-        } catch (IOException e) {
-            throw new ExamCloudRuntimeException(e);
-        } finally {
-            IOUtils.closeQuietly(out);
-            IOUtils.closeQuietly(in);
-        }
-    }
+	/**
+	 * 获取response对象
+	 * 
+	 * @return
+	 */
+	protected HttpServletResponse getResponse() {
+		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+				.getRequestAttributes();
+		HttpServletResponse response = requestAttributes.getResponse();
+		return response;
+	}
 
-    /**
-     * 文件导出
-     *
-     * @param fileName
-     * @param bytes
-     * @author WANGWEI
-     */
-    protected void exportFile(String fileName, byte[] bytes) {
-        OutputStream out = null;
-        try {
-            fileName = URLEncoder.encode(fileName, "UTF-8");
-            HttpServletResponse response = getResponse();
-            response.reset();
-            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
-            response.addHeader("Content-Length", "" + bytes.length);
-            response.setContentType("application/octet-stream;charset=UTF-8");
-            out = new BufferedOutputStream(response.getOutputStream());
-            out.write(bytes);
-            out.flush();
-        } catch (IOException e) {
-            throw new ExamCloudRuntimeException(e);
-        } finally {
-            IOUtils.closeQuietly(out);
-        }
-    }
+	/**
+	 * 文件导出
+	 *
+	 * @author WANGWEI
+	 * @param fileName
+	 * @param file
+	 */
+	protected void exportFile(String fileName, File file) {
+		OutputStream out = null;
+		InputStream in = null;
+		try {
+			in = new FileInputStream(file);
+			fileName = URLEncoder.encode(fileName, "UTF-8");
+			HttpServletResponse response = getResponse();
+			response.reset();
+			response.setHeader("Content-Disposition", "inline; filename=" + fileName);
+			response.addHeader("Content-Length", "" + file.length());
+			response.setContentType("application/octet-stream;charset=UTF-8");
+			out = new BufferedOutputStream(response.getOutputStream());
+			IOUtils.copy(in, out);
+			out.flush();
+		} catch (IOException e) {
+			throw new ExamCloudRuntimeException(e);
+		} finally {
+			IOUtils.closeQuietly(out);
+			IOUtils.closeQuietly(in);
+		}
+	}
 
-    /**
-     * 转换为数据库模糊查询匹配模式
-     */
-    protected String toSqlSearchPattern(String column) {
-        if (StringUtils.isBlank(column)) {
-            return "%";
-        }
-        return "%" + column.trim() + "%";
-    }
+	/**
+	 * 文件导出
+	 *
+	 * @author WANGWEI
+	 * @param fileName
+	 * @param bytes
+	 */
+	protected void exportFile(String fileName, byte[] bytes) {
+		OutputStream out = null;
+		try {
+			fileName = URLEncoder.encode(fileName, "UTF-8");
+			HttpServletResponse response = getResponse();
+			response.reset();
+			response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
+			response.addHeader("Content-Length", "" + bytes.length);
+			response.setContentType("application/octet-stream;charset=UTF-8");
+			out = new BufferedOutputStream(response.getOutputStream());
+			out.write(bytes);
+			out.flush();
+		} catch (IOException e) {
+			throw new ExamCloudRuntimeException(e);
+		} finally {
+			IOUtils.closeQuietly(out);
+		}
+	}
 
-    /**
-     * 转换为数据库模糊查询匹配模式 (左边全匹配、右边模糊匹配)
-     */
-    protected String toSqlRightLike(String column) {
-        if (StringUtils.isBlank(column)) {
-            return "%";
-        }
-        return column.trim() + "%";
-    }
+	/**
+	 * 转换为数据库模糊查询匹配模式
+	 *
+	 * @author WANGWEI
+	 * @param column
+	 * @return
+	 */
+	protected String toSqlSearchPattern(String column) {
+		if (StringUtils.isBlank(column)) {
+			return "%";
+		} else {
+			column = column.trim().replaceAll("\\s", "%");
+			column = "%" + column + "%";
+			return column;
+		}
+	}
 
-    /**
-     * 获取非空参数
-     *
-     * @param paramName
-     * @return
-     * @author WANGWEI
-     */
-    protected String getRequiredStringParam(String paramName) {
-        String value = getRequest().getParameter(paramName);
-        if (StringUtils.isBlank(value)) {
-            throw new StatusException("520", "param is  missing. paramName=" + paramName);
-        } else {
-            return value.trim();
-        }
-    }
+	/**
+	 * 获取非空参数
+	 *
+	 * @author WANGWEI
+	 * @param paramName
+	 * @return
+	 */
+	protected String getRequiredStringParam(String paramName) {
+		String value = getRequest().getParameter(paramName);
+		if (StringUtils.isBlank(value)) {
+			throw new StatusException("520", "param is  missing. paramName=" + paramName);
+		} else {
+			return value.trim();
+		}
+	}
 
-    /**
-     * 获取参数
-     *
-     * @param paramName
-     * @return
-     * @author WANGWEI
-     */
-    protected String getStringParam(String paramName) {
-        String value = getRequest().getParameter(paramName);
-        if (StringUtils.isBlank(value)) {
-            return null;
-        } else {
-            return value.trim();
-        }
-    }
+	/**
+	 * 获取参数
+	 *
+	 * @author WANGWEI
+	 * @param paramName
+	 * @return
+	 */
+	protected String getStringParam(String paramName) {
+		String value = getRequest().getParameter(paramName);
+		if (StringUtils.isBlank(value)) {
+			return null;
+		} else {
+			return value.trim();
+		}
+	}
 
-    /**
-     * 参数trim.<br>
-     * set null if blank.
-     *
-     * @param bean
-     * @author WANGWEI
-     */
-    protected void trim(Object bean) {
-        trim(bean, false);
-    }
+	/**
+	 * 参数trim.<br>
+	 * set null if blank.
+	 *
+	 * @author WANGWEI
+	 * @param bean
+	 */
+	protected void trim(Object bean) {
+		trim(bean, false);
+	}
 
-    /**
-     * 参数trim
-     *
-     * @param bean
-     * @param nullIfBlank
-     * @author WANGWEI
-     */
-    protected void trim(Object bean, boolean nullIfBlank) {
-        if (null == bean) {
-            return;
-        }
-        Class<? extends Object> clazz = bean.getClass();
-        if (clazz.equals(Map.class)) {
-            return;
-        } else if (clazz.equals(List.class)) {
-            return;
-        } else if (clazz.equals(Set.class)) {
-            return;
-        } else if (clazz.isEnum()) {
-            return;
-        } else if (ObjectUtil.isBaseDataType(clazz)) {
-            return;
-        }
+	/**
+	 * 参数trim
+	 *
+	 * @author WANGWEI
+	 * @param bean
+	 * @param nullIfBlank
+	 */
+	protected void trim(Object bean, boolean nullIfBlank) {
+		if (null == bean) {
+			return;
+		}
+		Class<? extends Object> clazz = bean.getClass();
+		if (clazz.equals(Map.class)) {
+			return;
+		} else if (clazz.equals(List.class)) {
+			return;
+		} else if (clazz.equals(Set.class)) {
+			return;
+		} else if (clazz.isEnum()) {
+			return;
+		} else if (ObjectUtil.isBaseDataType(clazz)) {
+			return;
+		}
 
-        Field[] fields = clazz.getDeclaredFields();
-        try {
-            for (int i = 0; i < fields.length; i++) {
-                Field f = fields[i];
-                f.setAccessible(true);
-                Object value = f.get(bean);
-                if (null == value) {
-                    continue;
-                }
-                if (f.getType().equals(String.class)) {
-                    if (null != value) {
-                        String s = (String) value;
-                        s = s.trim();
-                        if (nullIfBlank && StringUtils.isBlank(s)) {
-                            s = null;
-                        }
-                        f.set(bean, s);
-                    }
-                } else if (f.getType().equals(Map.class)) {
-                } else if (f.getType().equals(List.class)) {
-                } else if (f.getType().equals(Set.class)) {
-                } else if (f.getType().isEnum()) {
-                } else if (ObjectUtil.isBaseDataType(f.getType())) {
-                } else {
-                    trim(value);
-                }
+		Field[] fields = clazz.getDeclaredFields();
+		try {
+			for (int i = 0; i < fields.length; i++) {
+				Field f = fields[i];
+				f.setAccessible(true);
+				Object value = f.get(bean);
+				if (null == value) {
+					continue;
+				}
+				if (f.getType().equals(String.class)) {
+					if (null != value) {
+						String s = (String) value;
+						s = s.trim();
+						if (nullIfBlank && StringUtils.isBlank(s)) {
+							s = null;
+						}
+						f.set(bean, s);
+					}
+				} else if (f.getType().equals(Map.class)) {
+				} else if (f.getType().equals(List.class)) {
+				} else if (f.getType().equals(Set.class)) {
+				} else if (f.getType().isEnum()) {
+				} else if (ObjectUtil.isBaseDataType(f.getType())) {
+				} else {
+					trim(value);
+				}
 
-            }
-        } catch (Exception e) {
-            throw new ExamCloudRuntimeException(e);
-        }
-    }
+			}
+		} catch (Exception e) {
+			throw new ExamCloudRuntimeException(e);
+		}
+	}
 
 }