|
@@ -0,0 +1,163 @@
|
|
|
+package cn.com.qmth.examcloud.support.handler.richText;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.commons.util.RegExpUtil;
|
|
|
+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.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 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) {
|
|
|
+ /*过滤不需要的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("<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<>();
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果字符串不以特殊标签开头,且还有其它内容
|
|
|
+ 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();
|
|
|
+ obb.setType("text");
|
|
|
+ obb.setValue(StringEscapeUtils.unescapeHtml(value));
|
|
|
+
|
|
|
+ return obb;
|
|
|
+ }
|
|
|
+
|
|
|
+ //构建带特殊标签的文本作答
|
|
|
+ private static BlockBean buildSpecialTextAnswer(String value, String tag) {
|
|
|
+ BlockBean obb = new BlockBean();
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|