浏览代码

创建后结构化所需的实体对象,修改目录对象

louhr 5 年之前
父节点
当前提交
e3c291e6b7
共有 90 个文件被更改,包括 3084 次插入58 次删除
  1. 51 0
      kernel/src/main/java/com/lantone/qc/kernel/web/controller/MrqcTokenController.java
  2. 50 0
      kernel/src/main/java/com/lantone/qc/kernel/web/controller/QCController.java
  3. 1 0
      kernel/src/main/resources/kernel.properties
  4. 358 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/ParticipleToken.java
  5. 227 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/ParticipleUtil.java
  6. 17 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/cfg/Configuration.java
  7. 197 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/cfg/DefaultConfig.java
  8. 37 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacter.java
  9. 97 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterContext.java
  10. 49 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterFilter.java
  11. 80 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterUtil.java
  12. 80 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/Lexeme.java
  13. 6 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/LexemePath.java
  14. 112 0
      nlp/src/main/java/com/lantone/qc/nlp/participle/word/Segment.java
  15. 58 0
      nlp/src/main/java/com/lantone/qc/nlp/util/CharacterUtil.java
  16. 79 0
      nlp/src/main/java/com/lantone/qc/nlp/util/Constants.java
  17. 189 0
      nlp/src/main/java/com/lantone/qc/nlp/util/NegativeEnum.java
  18. 251 0
      nlp/src/main/java/com/lantone/qc/nlp/util/NlpCache.java
  19. 122 0
      nlp/src/main/java/com/lantone/qc/nlp/util/NlpUtil.java
  20. 159 0
      public/src/main/java/com/lantone/qc/pub/Constants.java
  21. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/BeHospitalizedDoc.java
  22. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ClinicalBloodDoc.java
  23. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ConsultationDoc.java
  24. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DeathCaseDiscussDoc.java
  25. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DeathRecordDoc.java
  26. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DifficultCaseDiscussDoc.java
  27. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DutyShiftSystemDoc.java
  28. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/FirstCourseRecordDoc.java
  29. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/FirstPageRecordDoc.java
  30. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/LeaveHospitalDoc.java
  31. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/NursingSystemDoc.java
  32. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/OperationDiscussionDoc.java
  33. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/PreoperativeDiscussionDoc.java
  34. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ThreeLevelWardDoc.java
  35. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Address.java
  36. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/BodyPart.java
  37. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Cause.java
  38. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Clinical.java
  39. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Consultation.java
  40. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Decorate.java
  41. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Degree.java
  42. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Diag.java
  43. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Dose.java
  44. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Family.java
  45. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Frequency.java
  46. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/General.java
  47. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/GeneralDesc.java
  48. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/IndexValue.java
  49. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Lis.java
  50. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/LisValue.java
  51. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Medicine.java
  52. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Negative.java
  53. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Occupation.java
  54. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Operation.java
  55. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Organism.java
  56. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/PD.java
  57. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Pacs.java
  58. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/PacsValue.java
  59. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Possible.java
  60. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Treat.java
  61. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Trend.java
  62. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Vital.java
  63. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/CaseCharacteristicLabel.java
  64. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/ChiefLabel.java
  65. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/DifferDiagLabel.java
  66. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/FamilyLabel.java
  67. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/InitialDiagLabel.java
  68. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/LisLabel.java
  69. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/MaritalLabel.java
  70. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/MenstrualLabel.java
  71. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PacsLabel.java
  72. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PastLabel.java
  73. 2 2
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PersonalLabel.java
  74. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PresentLabel.java
  75. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/RevisedDiagLabel.java
  76. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/SuppleDiagLabel.java
  77. 1 1
      kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/VatilLabel.java
  78. 194 0
      public/src/main/java/com/lantone/qc/pub/res/Response.java
  79. 131 0
      public/src/main/java/com/lantone/qc/pub/res/Status.java
  80. 15 0
      security/src/main/java/com/lantone/qc/security/aop/Security.java
  81. 44 0
      security/src/main/java/com/lantone/qc/security/aop/SecurityAop.java
  82. 63 0
      security/src/main/java/com/lantone/qc/security/exception/CommonErrorCode.java
  83. 36 0
      security/src/main/java/com/lantone/qc/security/exception/CommonException.java
  84. 81 0
      security/src/main/java/com/lantone/qc/security/exception/CommonExceptionHandler.java
  85. 15 0
      security/src/main/java/com/lantone/qc/security/exception/ErrorCode.java
  86. 49 0
      security/src/main/java/com/lantone/qc/security/exception/ServiceErrorCode.java
  87. 96 0
      security/src/main/java/com/lantone/qc/security/facade/QcRuleFacade.java
  88. 52 0
      security/src/main/java/com/lantone/qc/security/facade/TokenFacade.java
  89. 13 0
      trans/src/main/java/com/lantone/qc/trans/DocTrans.java
  90. 17 0
      trans/src/main/java/com/lantone/qc/trans/taizhou/TaiZhouDocTrans.java

+ 51 - 0
kernel/src/main/java/com/lantone/qc/kernel/web/controller/MrqcTokenController.java

@@ -0,0 +1,51 @@
+package com.lantone.qc.kernel.web.controller;
+
+
+import com.lantone.aop.Security;
+import com.lantone.dto.RespDTO;
+import com.lantone.facade.TokenFacade;
+import com.lantone.vo.LoginKeyVO;
+import com.lantone.vo.TokenVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 病历质控token信息 前端控制器
+ * </p>
+ *
+ * @author zhoutg
+ * @since 2019-12-23
+ */
+@RestController
+@RequestMapping("/token")
+@Api(value = "token相关接口", tags = { "token相关接口" })
+@Slf4j
+public class MrqcTokenController {
+
+    @Autowired
+    TokenFacade tokenFacade;
+
+    @ApiOperation(value = "获取token",
+            notes = "")
+    @PostMapping("/getToken")
+    public RespDTO<String> list(@RequestBody LoginKeyVO loginKeyVO) {
+        String token = tokenFacade.getToken(loginKeyVO);
+        return RespDTO.onSuc(token);
+    }
+
+
+    @ApiOperation(value = "模拟接口测试",
+            notes = "")
+    @PostMapping("/test")
+    @Security
+    public RespDTO<String> test(@RequestBody TokenVO tokenVO) {
+        return RespDTO.onSuc("测试成功了");
+    }
+}

+ 50 - 0
kernel/src/main/java/com/lantone/qc/kernel/web/controller/QCController.java

@@ -0,0 +1,50 @@
+package com.lantone.qc.kernel.web.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.xml.ws.Response;
+import java.util.Map;
+
+/**
+ * @ClassName : QCController
+ * @Description : 质控总入口
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:57
+ */
+@Api(value = "质控服务接口", tags = { "质控服务接口" })
+@RestController
+@RequestMapping(value = "analyse")
+public class QCController {
+    @Autowired
+    private QcRuleFacade qcRuleFacade;
+
+
+    @ApiOperation(value = "质控外部接口,需要token信息", notes = "")
+    @PostMapping("rec")
+    @Security
+    public Response<Map<String, Object>> extract(@RequestBody QueryVo queryVo) {
+
+
+        Rule rules = new Rule();
+        Response response = qcRuleFacade.parseDocu(queryVo, rules);
+
+        return response;
+    }
+
+
+    @ApiOperation(value = "质控内部接口,不需要token信息", notes = "")
+    @PostMapping("recInner")
+    public Response<Map<String, Object>> extractInner(@RequestBody QueryVo queryVo) {
+
+        Rule rules = new Rule();
+        Response response = qcRuleFacade.parseDocu(queryVo, rules);
+
+        return response;
+    }
+}

+ 1 - 0
kernel/src/main/resources/kernel.properties

@@ -0,0 +1 @@
+trans.classname.taizhou = com.lantone.qc.trans.taizhou.TaiZhouDocTrans

+ 358 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/ParticipleToken.java

@@ -0,0 +1,358 @@
+package com.lantone.qc.nlp.participle;
+
+import com.lantone.qc.nlp.participle.word.Lexeme;
+import com.lantone.qc.nlp.participle.word.LexemePath;
+import com.lantone.qc.nlp.participle.word.Segment;
+import com.lantone.qc.nlp.util.CharacterUtil;
+import com.lantone.qc.nlp.util.Constants;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Arrays;
+
+/**
+ * @Auther: fyeman
+ * @Date: 2018.06.08 15:24
+ * @Description: 分词算法 最大长度匹配法
+ */
+public class ParticipleToken {
+    //每次读取最大长度
+    private int BUFFER_SIZE = 4096;
+    //缓冲区耗尽的临界值
+    private int BUFFER_CRITICAL_VALUE = 128;
+    //每次读进预处理数据包
+    private char[] buffer;
+    //最新词开始位置
+    private int offset = 0;
+    //游标
+    private int cursor = 0;
+    //可处理的字符串长度
+    private int available = 0;
+    //读取文本总长豆
+    private int text_size = 0;
+    //分词截止位置
+    private int stop_position = 0;
+    //字符不会被打断  即使词库中未找到对应词
+    private char[] join_symbols = new char[]{'~', '-', '/', '.', '*', '^', '+'};
+    //待分词数据包
+    private Reader reader;
+    //词库二叉树
+    private Segment segment;
+    //词频次
+    private float threshold;
+    //词性
+    private String property;
+    //标准词
+    private String concept;
+    //缺省词性
+    private String DEFAULT_PROPERTY = Constants.word_property_other;
+
+    private String ARABIC_PROPERTY = Constants.word_property_number;
+
+    private LexemePath<Lexeme> lexemePath;
+
+    public ParticipleToken() {
+        //不排序 无法使用search方法
+        Arrays.sort(join_symbols);
+    }
+
+    public void start(Reader reader, Segment segment) throws IOException {
+        this.reader = reader;
+        this.segment = segment;
+        this.buffer = null;
+        this.offset = 0;
+        this.cursor = 0;
+        this.lexemePath = new LexemePath<Lexeme>();
+
+        this.fillBuffer();
+        this.participle();
+    }
+
+    public void participle() throws IOException {
+        while (hasNext()) {
+            this.next();
+            this.property = null;
+        }
+    }
+
+    private void next() throws IOException {
+        if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_CHINESE
+                || CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_USELESS
+                || CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_OTHER_HALF) {
+            this.matchCHN(segment, cursor, 0, false);
+            //最大长度重新计算当前分词是否合理
+            this.validate();
+        } else if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ARABIC) {
+            //先依据词库是否成词判断
+            this.matchCHN(segment, cursor, 0, false);
+            //不成词量词拼接
+            if (cursor - offset <= 1) {
+                this.matchARABIC();
+            } else {
+                this.addLexeme(offset, cursor - offset, this.property, this.concept);
+                this.offset = this.cursor;
+            }
+        } else if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_CHINESE_QUANTIFIER) {
+            //先依据词库是否成词判断
+            this.matchCHN(segment, cursor, 0, false);
+            //不成词量词拼接
+            if (cursor - offset <= 1) {
+                this.matchQUANTIFIER();
+            } else {
+                this.addLexeme(offset, cursor - offset, this.property, this.concept);
+                this.offset = this.cursor;
+            }
+        } else if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ENGLISH) {
+            //先依据词库是否成词判断
+            this.matchCHN(segment, cursor, 0, false);
+            //不成词所有英文字符拼接
+            if (cursor - offset <= 1) {
+                if (this.property == null || ARABIC_PROPERTY.equals(this.property)) {
+                    this.matchENGLISH();
+                } else {
+                    this.addLexeme(offset, cursor - offset, this.property, this.concept);
+                    this.offset = this.cursor;
+                }
+            } else {
+                this.addLexeme(offset, cursor - offset, this.property, this.concept);
+                this.offset = this.cursor;
+            }
+        }
+    }
+
+    private void matchQUANTIFIER() throws IOException {
+        int position;
+        while (cursor < available) {
+            position = Arrays.binarySearch(join_symbols, buffer[cursor]);
+            if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_CHINESE_QUANTIFIER        //中文量词
+                    || position > -1) {
+                cursor++;
+            } else {
+                break;
+            }
+        }
+        this.addLexeme(this.offset, this.cursor - this.offset, "33", "");
+        this.offset = this.cursor;
+    }
+
+    private void matchARABIC() throws IOException {
+        int position;
+        int cur_offset = this.offset;
+        while (cursor < available) {
+            position = Arrays.binarySearch(join_symbols, buffer[cursor]);
+            if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ARABIC        //数字后跟'-'、'/'、'.'作为数字处理
+//                    || CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ENGLISH
+                    || position > -1) {
+//                cursor++;
+                cur_offset++;
+                //先依据词库是否成词判断
+                this.matchCHN(segment, cursor, 0, false);
+                if (cursor - cur_offset > 1) {
+                    this.cursor = cur_offset;
+                    break;
+                }
+            } else if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_CHINESE) {    //数字后跟中文单位
+                break;
+            } else {
+                break;
+            }
+        }
+        this.addLexeme(this.offset, this.cursor - this.offset, this.ARABIC_PROPERTY, "");
+        this.offset = this.cursor;
+    }
+
+    private void matchENGLISH() throws IOException {
+        int position;
+        while (cursor < available) {
+            position = Arrays.binarySearch(join_symbols, buffer[cursor]);
+            if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ENGLISH //英文拼接
+                    || position > -1
+                    || CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_ARABIC) {
+                cursor++;
+            } else if (CharacterUtil.identifyCharType(buffer[cursor]) == CharacterUtil.CHAR_CHINESE) {    //英文后跟中文单位
+                break;
+            } else {
+                break;
+            }
+        }
+        this.addLexeme(this.offset, this.cursor - this.offset, this.ARABIC_PROPERTY, "");
+        this.offset = this.cursor;
+    }
+
+    /**
+     * @param s
+     * @param begin
+     * @param length
+     * @param status 递归标示,部分字打头的词在字典中有可能不存在,此时应认为该字是一个词,offset+1,进入递归方法前将值设置为true
+     */
+    private void matchCHN(Segment s, int begin, int length, boolean status) {
+        //分词停止位置
+        if (begin >= stop_position) {
+            this.cutLexeme(s, begin, length, status);
+            return;
+        }
+        Character character = Character.valueOf(buffer[begin]);
+        Segment character_segment = s.getSegmentMap().get(character);
+        if (character_segment != null) {
+            status = true;
+            matchCHN(character_segment, begin + 1, length + 1, status);
+        } else {
+            this.cutLexeme(s, begin, length, status);
+        }
+    }
+
+    /**
+     * 切词
+     *
+     * @param s
+     * @param begin
+     * @param length
+     * @param status
+     */
+    private void cutLexeme(Segment s, int begin, int length, boolean status) {
+        if (s.isLexeme() == false && length > 1) {//不成词进行回溯  二叉树每条路径节点不一定成词
+            do {
+                s = s.parent();
+                begin--;
+                length--;
+            } while (s != null && s.isLexeme() == false && length > 1);
+        }
+        if (!status) { //字典库不存在该字 且不是unit_segment
+            this.cursor++;
+        } else {
+            this.cursor = begin;
+        }
+        //保存词频数据,便于最大长度相同时 按词频排序
+        this.threshold = s.getThreshold();
+        this.property = s.getProperty();
+        this.concept = s.getConcept();
+    }
+
+    /**
+     * 分词规则:1、最大词长度匹配
+     * 2、相同词长度 按频次优先
+     * 每个词被切出后需要矫正,以便找出最大长度的词
+     */
+    private void validate() throws IOException {
+        int o_offset = this.offset;
+        int o_cursor = this.cursor;         //切出来的词 暂时游标位置
+        float o_threshold = this.threshold;
+
+        int o_begin = o_offset;
+        int o_length = o_cursor - o_offset;
+        //当前词长度
+        int max_length = o_length;
+        int max_begin = o_offset;   //最大长度词默认起始位置为前一个词开始位置
+        //词性会被递归覆盖,需要先保存
+        String property = this.property;
+        String concept = this.concept;
+        while (o_begin < o_cursor - 1) {
+            o_begin++;
+            this.matchCHN(segment, o_begin, 0, false);      //执行后this.cursor会变化
+            if (this.cursor - o_begin > max_length) {
+                max_length = this.cursor - o_begin;
+                max_begin = o_begin;
+                property = this.property;
+                concept = this.concept;
+            } else if (this.cursor - o_begin == max_length) {       //词长度相同 有词性的保留
+                if (this.DEFAULT_PROPERTY.equals(property)
+                        && this.property != null && !this.DEFAULT_PROPERTY.equals(this.property)) {
+//                if (this.threshold > o_threshold) {
+                    max_begin = o_begin;
+                    property = this.property;
+                    concept = this.concept;
+                }
+            }
+        }
+        //还原词性
+        this.property = property;
+        this.concept = concept;
+        if (max_length >= o_length) {    //如果发现有新词比最初切出来的词更长,那么先对新词前面字符进行切词,this.cursor应该被还原为最初的值,并且只能最多切到新词起始位置
+            if (max_begin != o_offset) {
+                this.cursor = this.offset;
+                this.stop_position = max_begin;
+                this.next();
+            } else {
+                this.cursor = o_cursor;
+                this.addLexeme(offset, this.cursor - offset, this.property, this.concept);
+                this.offset = this.cursor;
+                this.stop_position = this.text_size;
+            }
+        }
+    }
+
+    private void addLexeme(int begin, int length) throws IOException {
+        this.addLexeme(begin, length, this.DEFAULT_PROPERTY, "");
+    }
+
+    private void addLexeme(int begin, int length, String property, String concept) throws IOException {
+        if(length > 0){
+            Lexeme lexeme = new Lexeme(begin, length);
+            char[] chars = new char[lexeme.getLength()];
+            System.arraycopy(buffer, lexeme.getOffset(), chars, 0, lexeme.getLength());
+            lexeme.setText(String.valueOf(chars));
+            lexeme.setProperty(property==null?this.DEFAULT_PROPERTY:property);
+            lexeme.setConcept(concept);
+            lexemePath.add(lexeme);
+            //判断是否需要加载文本内容
+            this.fillBuffer();
+        }
+    }
+
+    public boolean hasNext() {
+        return this.available > 0
+                && this.cursor < this.available;
+    }
+
+    /**
+     * 是否读取新缓存判断判断
+     *
+     * @return
+     */
+    private boolean isLoadReader() {
+        return this.available == BUFFER_SIZE
+                && this.cursor < this.available - 1
+                && this.cursor > this.available - BUFFER_CRITICAL_VALUE;
+    }
+
+    private void fillBuffer() throws IOException {
+        if (buffer == null) {
+            buffer = new char[BUFFER_SIZE];
+            available = reader.read(buffer);
+            this.text_size = available;
+        } else {
+            if (isLoadReader()) {
+                int unreader_length = this.available - this.cursor;
+                //将还未进行分词的内容拷贝到数据包最前面
+                System.arraycopy(this.buffer, this.cursor, this.buffer, 0, unreader_length);
+                //最新数据包长度=新读取数据包长度+未解析完长度
+                available = reader.read(this.buffer, unreader_length, BUFFER_SIZE - unreader_length) + unreader_length;
+                //当前读取文本总长度
+                this.text_size = this.cursor + this.available;
+                //重置偏移量
+                this.cursor = 0;
+                this.offset = 0;
+            }
+        }
+        //默认读取到文本尾
+        this.stop_position = this.text_size;
+    }
+
+    public void end() {
+        if (reader != null) {
+            try {
+                reader.close();
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            }
+        }
+    }
+
+    public LexemePath<Lexeme> getLexemePath() {
+        return lexemePath;
+    }
+
+    public void setLexemePath(LexemePath<Lexeme> lexemePath) {
+        this.lexemePath = lexemePath;
+    }
+}

+ 227 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/ParticipleUtil.java

@@ -0,0 +1,227 @@
+package com.lantone.qc.nlp.participle;
+
+import com.lantone.qc.nlp.participle.cfg.Configuration;
+import com.lantone.qc.nlp.participle.cfg.DefaultConfig;
+import com.lantone.qc.nlp.participle.word.Lexeme;
+import com.lantone.qc.nlp.participle.word.LexemePath;
+import com.lantone.qc.nlp.participle.word.Segment;
+import com.lantone.qc.nlp.util.Constants;
+import com.lantone.qc.nlp.util.NlpUtil;
+import com.lantone.qc.nlp.util.NlpCache;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.regex.Pattern;
+
+/**
+ * Created by fyeman on 2018/1/31.
+ */
+public class ParticipleUtil {
+
+    public static LexemePath<Lexeme> participle(String content, boolean isCombineUnit) throws IOException {
+        LexemePath<Lexeme> lexemes = participle(content);
+        if (isCombineUnit) {
+            ParticipleUtil util = new ParticipleUtil();
+            lexemes = util.combine(util, lexemes);
+        }
+        return lexemes;
+    }
+
+    public static LexemePath<Lexeme> participle(String content) throws IOException {
+        if (NlpCache.segment_cache == null) {
+            NlpCache.createSegmentCache();
+        }
+        return participle(content, NlpCache.segment_cache);
+    }
+
+    public static LexemePath<Lexeme> participlePacs(String content) throws IOException {
+        if (NlpCache.segment_cache_pacs == null) {
+            NlpCache.createSegmentCachePacs();
+        }
+        ParticipleToken token = new ParticipleToken();
+        token.start(new StringReader(content), NlpCache.segment_cache_pacs);
+        LexemePath<Lexeme> lexemePath = token.getLexemePath();
+        ParticipleUtil util = new ParticipleUtil();
+        lexemePath = util.combine(util, lexemePath);
+        token.end();
+        return lexemePath;
+    }
+
+    public static LexemePath<Lexeme> participle(String content, String path) throws IOException {
+        Configuration configuration = new DefaultConfig();
+        NlpCache.segment_cache = configuration.loadMainDict(path);
+        return participle(content, NlpCache.segment_cache);
+    }
+
+    public static LexemePath<Lexeme> participle(String content, Segment segment) throws IOException {
+        if (segment == null) return participle(content);
+        ParticipleToken token = new ParticipleToken();
+        NlpCache.segment_cache = segment;
+        token.start(new StringReader(content), NlpCache.segment_cache);
+        LexemePath<Lexeme> lexemePath = token.getLexemePath();
+        token.end();
+
+        return lexemePath;
+    }
+
+    private LexemePath<Lexeme> combine(ParticipleUtil util, LexemePath<Lexeme> lexemes) {
+        lexemes = util.combineValidate(lexemes);
+        lexemes = util.joinTime(lexemes);
+
+        String year_pattern = "([1-2][0-9]{3}|[0-9]{2})";
+        String mouth_day_pattern = "([0-9]{2}|[0-9])";
+        String join_pattern = "([-/.]?)";
+        String pattern_string = year_pattern + join_pattern + mouth_day_pattern + join_pattern + mouth_day_pattern;
+        for (Lexeme l : lexemes) {
+            if (l.getProperty().equals(Constants.word_property_number)) {
+                if (Pattern.matches(pattern_string,l.getText())) {
+                    l.setProperty(Constants.word_property_time);
+                }
+            }
+        }
+        return lexemes;
+    }
+
+    public static String participleAndHighlight(String content) throws IOException {
+        LexemePath<Lexeme> lexemePath = participle(content, false);
+        String separator = "&nbsp;*&nbsp;";
+        StringBuffer sb = new StringBuffer();
+        Lexeme lexeme = null;
+        boolean new_line = true;
+        for (int i = 0; i < lexemePath.size(); i++) {
+            lexeme = lexemePath.get(i);
+            if (lexeme.getOffset() > -1) {
+                if ("\r".equals(lexeme.getText()) || "\n".equals(lexeme.getText())) {
+                    sb.append(lexeme.getText());
+                    new_line = true;
+                } else {
+                    if (!new_line) {
+                        sb.append(separator);
+                    }
+                    if (lexeme.getProperty() != null && !Constants.word_property_other.equals(lexeme.getProperty())) {
+                        sb.append("<font color='blue'>");
+                        sb.append(lexeme.getText());
+                        if (!StringUtils.isEmpty(lexeme.getConcept()) && hasConcept(lexeme)) {
+//                            sb.append("【" + lexeme.getConcept() + "】");
+                        }
+                        sb.append("</font>");
+                    } else {
+                        sb.append(lexeme.getText());
+                    }
+                    new_line = false;
+                }
+            }
+        }
+        String s = sb.toString();
+        s = s.replaceAll("\r\n", "</br>");
+        return s;
+    }
+
+    public static void main(String args[]) {
+        String year_pattern = "([1-2][0-9]{3}|[0-9]{2})";
+        String mouth_day_pattern = "([0-9]{2}|[0-9])";
+        String join_pattern = "([-/.]?)";
+
+        String pattern_string = year_pattern + join_pattern + mouth_day_pattern + join_pattern + mouth_day_pattern;
+
+        System.out.println(Pattern.matches(pattern_string,"12.434"));
+        try {
+            ParticipleUtil util = new ParticipleUtil();
+            String content = "5天2017-01,9毫克7斤重量015年6月23日出现";
+            LexemePath<Lexeme> lexemes = util.participle(content);
+
+            lexemes = util.combineValidate(lexemes);
+
+            lexemes = util.joinTime(lexemes);
+            for (Lexeme l : lexemes) {
+                System.out.println(l.getText() + " | ");
+                if (l.getProperty().equals(Constants.word_property_number)) {
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private LexemePath<Lexeme> combineValidate(LexemePath<Lexeme> lexemes) {
+        Lexeme l = null;
+        LexemePath<Lexeme> results = new LexemePath<>();
+        for (int i = 0, len = lexemes.size(); i < len; i++) {
+            l = lexemes.get(i);
+            if (l.getProperty() != null
+                    && (l.getProperty().equals(Constants.word_property_time) || l.getProperty().equals(Constants.word_property_unit))) {
+                findLast(lexemes, i, l, results);
+            } else {
+                results.add(l);
+            }
+        }
+        return results;
+    }
+
+    private void findLast(LexemePath<Lexeme> lexemes, int index, Lexeme lexeme, LexemePath<Lexeme> results) {
+        Lexeme last_l = null;
+        if (index > 0) {
+            index--;
+            last_l = lexemes.get(index);
+            if (("×".equals(last_l.getText()) || StringUtils.isEmpty(last_l.getText())) && index > 0) {
+                lexeme.setOffset(last_l.getOffset());
+                lexeme.setLength(last_l.getLength() + lexeme.getLength());
+                lexeme.setText(last_l.getText() + lexeme.getText());
+                results.remove(results.size() - 1);
+                index--;
+                last_l = lexemes.get(index);
+            }
+            if (NlpUtil.isNumberString(last_l)) {
+                lexeme.setOffset(last_l.getOffset());
+                lexeme.setLength(last_l.getLength() + lexeme.getLength());
+                lexeme.setText(last_l.getText() + lexeme.getText());
+                results.remove(results.size() - 1);
+            }
+            results.add(lexeme);
+        }
+    }
+
+    private LexemePath<Lexeme> joinTime(LexemePath<Lexeme> lexemes) {
+        Lexeme l = null;
+        Lexeme next_l = null;
+        LexemePath<Lexeme> results = new LexemePath<>();
+        int cursor = 1;
+        for (int i = 0, len = lexemes.size(); i < len; i++) {
+            l = lexemes.get(i);
+            if (l.getProperty() != null
+                    && (l.getProperty().equals(Constants.word_property_time))) {
+                while (i + cursor < len) {
+                    next_l = lexemes.get(i + cursor);
+                    if (next_l.getProperty() != null
+                            && (next_l.getProperty().equals(Constants.word_property_time))) {
+                        l.setText(l.getText() + next_l.getText());
+                        l.setLength(l.getLength() + next_l.getLength());
+                        cursor++;
+                    } else {
+                        break;
+                    }
+                }
+            }
+            if (cursor > 1) {
+                i = i + cursor - 1;
+                cursor = 1;
+            }
+            results.add(l);
+        }
+        return results;
+    }
+
+    public static boolean hasConcept(Lexeme lexeme) {
+        if (lexeme.getText().equals(lexeme.getConcept())) {
+            return false;
+        } else {
+            String[] texts = lexeme.getConcept().split(",");
+            boolean hasConcept = true;
+            for (int i = 0; i < texts.length; i++) {
+                hasConcept = lexeme.getText().equals(texts[i]);
+            }
+            return !hasConcept;
+        }
+    }
+}

+ 17 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/cfg/Configuration.java

@@ -0,0 +1,17 @@
+package com.lantone.qc.nlp.participle.cfg;
+
+import com.lantone.qc.nlp.participle.word.Segment;
+
+import java.util.List;
+import java.util.Map;
+
+public interface Configuration {
+	public Segment loadMainDict(String path);
+	public Segment loadMainDict(List<String> dicts);
+	public Map<String, String> loadMapDict(String path);
+	public List<String> readFileContents(String path);
+	public List<String> readDirectFileContents(String path);
+	public List<String> readTargetFileContents(String path);
+	void writeFileContents(List<String> contents, String path);
+
+}

+ 197 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/cfg/DefaultConfig.java

@@ -0,0 +1,197 @@
+package com.lantone.qc.nlp.participle.cfg;
+
+import com.lantone.qc.nlp.participle.word.Segment;
+import org.diagbot.pub.utils.PropertiesUtil;
+import org.diagbot.pub.utils.security.EncrypDES;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DefaultConfig implements Configuration {
+    Logger logger = LoggerFactory.getLogger(DefaultConfig.class);
+    private static final String DEFAULT_PATH = "tc.dict";
+    private List<Character[]> contents = new ArrayList<Character[]>();
+
+    private Map<Integer, Character> chars = new HashMap<Integer, Character>(100, 0.75f);
+    private Integer charsKey;
+
+    Segment segment;
+
+    private String path_prefix = "";
+
+    public DefaultConfig() {
+        PropertiesUtil propertiesUtil = new PropertiesUtil("nlp.properties");
+        path_prefix = propertiesUtil.getProperty("cache.file.dir");
+    }
+
+    public Segment loadMainDict(String path) {
+        List<String> fileContents = readFileContents(path);
+        logger.info("读取文件" + path + "结果:" + fileContents.size() + "行");
+        return loadMainDict(fileContents);
+    }
+
+    public Segment loadMainDict(List<String> dicts) {
+        int i = 0;
+        int length = dicts.size();
+
+        segment = new Segment(Character.valueOf('0'));
+        try {
+            String[] line_string;
+            char[] chars;
+            for (i = 0; i < length; i++) {
+                String s = dicts.get(i);
+                line_string = org.apache.commons.lang3.StringUtils.split(dicts.get(i), "\\|");
+                chars = line_string[0].toCharArray();
+                if (line_string.length == 4) {
+                    segment.fill(segment, chars, 0, chars.length, Float.parseFloat(line_string[1]), line_string[2], line_string[3]);
+                } else if (line_string.length == 1) {
+                    segment.fill(segment, chars, 0, chars.length);
+                } else {
+                    continue;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return segment;
+    }
+
+    public Map<String, String> loadMapDict(String path) {
+        List<String> fileContents = readFileContents(path);
+        String[] line_string;
+        Map<String, String> map = new HashMap<>(10, 0.8f);
+        try {
+            for (int i = 0; i < fileContents.size(); i++) {
+                line_string = org.apache.commons.lang3.StringUtils.split(fileContents.get(i), "\\|");
+                if (line_string.length == 2) {
+                    if (map.get(line_string[0]) != null) {
+                        map.put(line_string[0], map.get(line_string[0]) + "," + line_string[1]);
+                    } else {
+                        map.put(line_string[0], line_string[1]);
+                    }
+                } else {
+                    continue;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    public List<String> readFileContents(String path) {
+        if (!StringUtils.isEmpty(path_prefix)) {
+            path = path_prefix + path;
+        }
+        return readDirectFileContents(path);
+    }
+
+    public List<String> readDirectFileContents(String path) {
+        InputStream is = null;
+        List<String> fileContents = new ArrayList<String>(10);
+        try {
+            if (StringUtils.isEmpty(path)) {
+                path = DEFAULT_PATH;
+            }
+            //            is = this.getClass().getClassLoader().getResourceAsStream(path);
+            File file = new File(path);
+            //            File file = new File(this.getClass().getResource(path).getFile());
+            is = new FileInputStream(file);
+            if (is == null) {
+                throw new RuntimeException(path + ".......文件未找到!!");
+            }
+
+            addFileContents(is, fileContents);
+        } catch (Exception ioe) {
+            System.err.println("读取文件" + path + "出错.......................");
+            ioe.printStackTrace();
+        } finally {
+            this.close(is);
+        }
+        return fileContents;
+    }
+
+    public List<String> readTargetFileContents(String path) {
+        InputStream is = null;
+        List<String> fileContents = new ArrayList<String>(10);
+        try {
+            if (StringUtils.isEmpty(path)) {
+                path = DEFAULT_PATH;
+            }
+            is = this.getClass().getClassLoader().getResourceAsStream(path);
+            //            File file = new File(path);
+            //            File file = new File(this.getClass().getResource(path).getFile());
+            //            is = new FileInputStream(file);
+            if (is == null) {
+                throw new RuntimeException(path + ".......文件未找到!!");
+            }
+
+            addFileContents(is, fileContents);
+        } catch (Exception ioe) {
+            System.err.println("读取文件" + path + "出错.......................");
+            ioe.printStackTrace();
+        } finally {
+            this.close(is);
+        }
+        return fileContents;
+    }
+
+    public void addFileContents(InputStream is, List<String> fileContents) throws Exception {
+        BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
+
+        EncrypDES encrypDES = new EncrypDES();
+        String theWord = null;
+        int i = 0;
+        do {
+            theWord = br.readLine();
+            if (theWord != null && !"".equals(theWord.trim())) {
+                if (i == 5) {
+                    logger.info("读取文件第六行解密前:" + theWord.trim());
+                    logger.info("读取文件第六行解密后:" + encrypDES.decryptor(theWord.trim()));
+                }
+                fileContents.add(encrypDES.decryptor(theWord.trim()));
+            }
+            i++;
+        } while (theWord != null);
+    }
+
+
+    public void writeFileContents(List<String> contents, String path) {
+        this.writeFileContents(contents, path, "");
+    }
+
+    public void writeFileContents(List<String> contents, String path, String separator) {
+        if (!StringUtils.isEmpty(path_prefix)) {
+            path = path_prefix + path;
+        }
+        try {
+            FileWriter fw = new FileWriter(path);
+            for (String content : contents) {
+                fw.write(content);
+                if (!StringUtils.isEmpty(separator)) {
+                    fw.write(separator);
+                }
+            }
+            fw.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void close(InputStream is) {
+        try {
+            if (is != null) {
+                is.close();
+                is = null;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 37 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacter.java

@@ -0,0 +1,37 @@
+package com.lantone.qc.nlp.participle.word;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by fyeman
+ */
+public class CHNCharacter {
+    private float count = 0f;
+    private Map<Character, Float> left = new HashMap<Character, Float>(18, 0.75f);
+    private Map<Character, Float> right = new HashMap<Character, Float>(18, 0.75f);
+
+    public Map<Character, Float> getLeft() {
+        return left;
+    }
+
+    public void setLeft(Map<Character, Float> left) {
+        this.left = left;
+    }
+
+    public Map<Character, Float> getRight() {
+        return right;
+    }
+
+    public void setRight(Map<Character, Float> right) {
+        this.right = right;
+    }
+
+    public float getCount() {
+        return count;
+    }
+
+    public void setCount(Float count) {
+        this.count = count;
+    }
+}

+ 97 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterContext.java

@@ -0,0 +1,97 @@
+package com.lantone.qc.nlp.participle.word;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 基于语料库,频次抽取常见词元
+ */
+public class CHNCharacterContext {
+    private Map<Character, CHNCharacter> words;
+    private Map<String, Float> ontologyLibraryMap = new HashMap<String, Float>(100, 0.75f);
+
+    private String ontologyLibraryWord;
+
+    private int cursor = 0;
+    private int offset = 1;
+    private int ontology_word_cursor = 0;
+    private int chars_length = 0;
+
+    //计算当前字符前后字词频差
+    private int drop_length = 0;
+    //最大落差 如 于余姚人民医院  于余组合频次是10 余姚组合频次是50 那么认为 于余姚 这三个字组合不是很合理,直接于后面切掉
+    private int max_drop_length = 10;
+
+    private Map<Character, Float> rightCharMap;
+    private Map<Character, Float> leftCharMap;
+
+    private int buffer_size = 50;
+    private Character[] buffer = new Character[buffer_size];
+
+    public CHNCharacterContext(Map<Character, CHNCharacter> words) {
+        this.words = words;
+    }
+
+    private void init() {
+        this.offset = 1;
+        this.ontology_word_cursor = 0;
+        this.clearBuffer();
+    }
+
+    public void start(Character[] chars) {
+        chars_length = chars.length;
+        if (chars_length == 1) return;
+        this.init();
+        this.cursor = 0;
+        buffer[0] = chars[cursor];
+        this.join(chars, chars[cursor], chars[cursor + offset]);
+    }
+
+    private void join(Character[] chars, Character current, Character next) {
+        rightCharMap = words.get(current).getRight();
+        if (rightCharMap.get(next) != null) {
+            buffer[offset] = next;
+            offset++;
+            if (cursor + offset < chars_length) {
+                this.join(chars, next, chars[cursor + offset]);
+            } else {
+                joinOntologyLibrary();
+            }
+        } else {
+            if (offset > 1) {
+                joinOntologyLibrary();
+            }
+            this.init();
+            cursor = cursor + offset;
+            buffer[0] = chars[cursor];
+            if (cursor + offset < chars_length) {
+                this.join(chars, chars[cursor], chars[cursor + offset]);
+            }
+        }
+    }
+
+    private void joinOntologyLibrary() {
+        ontologyLibraryWord = StringUtils.join(buffer, "");
+        if (ontologyLibraryMap.get(ontologyLibraryWord) == null) {
+            ontologyLibraryMap.put(ontologyLibraryWord, 1f);
+        } else {
+            ontologyLibraryMap.put(ontologyLibraryWord, ontologyLibraryMap.get(ontologyLibraryWord) + 1);
+        }
+    }
+
+    private void clearBuffer() {
+        for (ontology_word_cursor = 0; ontology_word_cursor < buffer.length; ontology_word_cursor++) {
+            buffer[ontology_word_cursor] = null;
+        }
+    }
+
+    public Map<String, Float> getOntologyLibraryMap() {
+        return ontologyLibraryMap;
+    }
+
+    public void setOntologyLibraryMap(Map<String, Float> ontologyLibraryMap) {
+        this.ontologyLibraryMap = ontologyLibraryMap;
+    }
+}

+ 49 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterFilter.java

@@ -0,0 +1,49 @@
+package com.lantone.qc.nlp.participle.word;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by fyeman
+ */
+public class CHNCharacterFilter {
+    private ObjectMapper mapper = new ObjectMapper();
+    private double FREQUENCY_THRESHOLD = 0.05;
+    private float COUNT_THRESHOLD = 100000;
+    private float LESS_COUNT = 10f;
+
+    /**
+     * 设定阀值删除低于阀值的左右邻数据
+     *
+     * @param words
+     */
+    public void filter(Map<Character, CHNCharacter> words) {
+        CHNCharacter CHNChar;
+        CHNCharacter rightCHNChar;
+        Map<Character, Float> rightCharMap;
+        Map<Character, Float> rightFilterCharMap;
+        for (Map.Entry<Character, CHNCharacter> entry : words.entrySet()) {
+            CHNChar = entry.getValue();
+            rightCharMap = CHNChar.getRight();
+            rightFilterCharMap = new HashMap<Character, Float>(100, 0.75f);
+            for (Map.Entry<Character, Float> rightEntry : rightCharMap.entrySet()) {
+                rightCHNChar = words.get(rightEntry.getKey());
+                if (rightEntry.getValue() == null || rightCHNChar.getLeft().get(entry.getKey()) == null
+                        || rightEntry.getValue() < LESS_COUNT) {
+                    continue;
+                }
+                if (rightEntry.getValue() / CHNChar.getCount() >= FREQUENCY_THRESHOLD || rightEntry.getValue() >= COUNT_THRESHOLD
+                        || rightCHNChar.getLeft().get(entry.getKey()) / rightCHNChar.getCount() >= FREQUENCY_THRESHOLD
+                        || rightCHNChar.getLeft().get(entry.getKey()) >= COUNT_THRESHOLD
+                        ) {
+                    rightFilterCharMap.put(rightEntry.getKey(), rightEntry.getValue());
+                }
+            }
+            CHNChar.setRight(rightFilterCharMap);
+            entry.setValue(CHNChar);
+        }
+    }
+}
+

+ 80 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/CHNCharacterUtil.java

@@ -0,0 +1,80 @@
+package com.lantone.qc.nlp.participle.word;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by fyeman
+ * 读取语料库,将每个字左右相邻保存,包括频次
+ */
+public class CHNCharacterUtil {
+    private Map<Character, CHNCharacter> words = new HashMap<>(100, 0.75f);
+    private long word_length = 0;
+    private int cursor = 0;
+
+    private Map<Character, Float> leftCharMap;
+    private Map<Character, Float> rightCharMap;
+    private Float leftCharCount;
+    private Float rightCharCount;
+
+    private Character cursorChar;
+    private Character leftChar;
+    private Character rightChar;
+
+    public Map<Character, CHNCharacter> fillCHNCharacter(Character[] chars) {
+        word_length = chars.length;
+        CHNCharacter CHNChar;
+        for (cursor = 0; cursor < word_length; cursor++) {
+            cursorChar = chars[cursor];
+            if (words.get(cursorChar) == null) { //新字符
+                words.put(cursorChar, new CHNCharacter());
+            }
+            CHNChar = words.get(cursorChar);
+            if (cursor == 0 && cursor < word_length - 1) {
+                CHNChar = updateRightChar(chars, CHNChar);
+            } else if (cursor > 0 && cursor == word_length - 1) {
+                CHNChar = updateLeftChar(chars, CHNChar);
+            } else if (cursor > 0 && cursor < word_length - 1) {
+                updateLeftChar(chars, CHNChar);
+                updateRightChar(chars, CHNChar);
+            }
+            CHNChar.setCount(CHNChar.getCount() + 1);
+            words.put(cursorChar, CHNChar);
+        }
+        return words;
+    }
+
+    private CHNCharacter updateLeftChar(Character[] chars, CHNCharacter CHNChar) {
+        leftCharMap = CHNChar.getLeft();
+        leftChar = chars[cursor - 1];
+        leftCharCount = leftCharMap.get(leftChar);
+        if (leftCharCount == null) {
+            leftCharMap.put(leftChar, 1f);
+        } else {
+            leftCharMap.put(leftChar, leftCharCount + 1);
+        }
+        CHNChar.setLeft(leftCharMap);
+        return CHNChar;
+    }
+
+    private CHNCharacter updateRightChar(Character[] chars, CHNCharacter CHNChar) {
+        rightCharMap = CHNChar.getRight();
+        rightChar = chars[cursor + 1];
+        rightCharCount = rightCharMap.get(rightChar);
+        if (rightCharCount == null) {
+            rightCharMap.put(rightChar, 1f);
+        } else {
+            rightCharMap.put(rightChar, rightCharCount + 1);
+        }
+        CHNChar.setRight(rightCharMap);
+        return CHNChar;
+    }
+
+    public Map<Character, CHNCharacter> getWords() {
+        return words;
+    }
+
+    public void setWords(Map<Character, CHNCharacter> words) {
+        this.words = words;
+    }
+}

+ 80 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/Lexeme.java

@@ -0,0 +1,80 @@
+package com.lantone.qc.nlp.participle.word;
+
+/**
+ * 词元定义.
+ */
+public class Lexeme implements Comparable<Lexeme> {
+    private int offset = 0;
+    private int length = 0;
+
+    private String text;
+    private String property;
+    //段落分割 成句 '。',';',';','?' = -1 , ',',',',':',':' = -2
+    private String flag;
+
+    private float threshold;
+
+    private String concept;
+
+    public Lexeme(int offset, int length) {
+        this.offset = offset;
+        this.length = length;
+    }
+    public int getOffset() {
+        return offset;
+    }
+
+    public void setOffset(int offset) {
+        this.offset = offset;
+    }
+
+    public int getLength() {
+        return length;
+    }
+
+    public void setLength(int length) {
+        this.length = length;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public String getProperty() {
+        return property;
+    }
+
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    public float getThreshold() { return threshold; }
+
+    public void setThreshold(float threshold) {
+        this.threshold = threshold;
+    }
+
+    public String getFlag() {
+        return flag;
+    }
+
+    public void setFlag(String flag) {
+        this.flag = flag;
+    }
+
+    public String getConcept() {
+        return concept;
+    }
+
+    public void setConcept(String concept) {
+        this.concept = concept;
+    }
+
+    public int compareTo(Lexeme o) {
+        return  this.offset - o.getOffset();
+    }
+}

+ 6 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/LexemePath.java

@@ -0,0 +1,6 @@
+package com.lantone.qc.nlp.participle.word;
+
+import java.util.ArrayList;
+
+public class LexemePath<T> extends ArrayList<T> {
+}

+ 112 - 0
nlp/src/main/java/com/lantone/qc/nlp/participle/word/Segment.java

@@ -0,0 +1,112 @@
+package com.lantone.qc.nlp.participle.word;
+
+import com.lantone.qc.nlp.util.Constants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 词典树
+ */
+public class Segment {
+
+    private Map<Character, Segment> segment_map = new HashMap<Character, Segment>(10, 0.7f);
+
+    private Character node_char;
+
+    private boolean isLexeme = false;
+    //频次
+    private float threshold = 0f;
+    //词性
+    private String property;
+    //标准词
+    private String concept;
+
+    private Segment parent;
+
+    public Segment(Character node_char) {
+        this.node_char = node_char;
+    }
+
+    public void fill(Segment s, char[] chars, int cursor, int length) {
+        this.fill(s, chars, cursor, length, 0f, "99", "");
+    }
+
+    public void fill(Segment s, char[] chars, int cursor, int length, float threshold, String property, String concept) {
+        Character c_char = Character.valueOf(chars[cursor]);
+        if (Constants.chn_chars_map.get(c_char) == null) {
+            Constants.chn_chars_map.put(c_char, c_char);
+        }
+        c_char = Constants.chn_chars_map.get(c_char);
+
+        Segment segment = lookforSegment(c_char);
+        if (segment != null) {
+            segment.setParent(s);
+            if (length > 1) {
+                segment.fill(segment, chars, cursor + 1, length - 1, threshold, property, concept);
+            } else {
+                segment.isLexeme = true;
+                segment.threshold = threshold;
+                segment.property = property;
+                segment.concept = concept;
+                segment_map.put(c_char, segment);
+            }
+        }
+    }
+
+    private Segment lookforSegment(Character c_char) {
+        Segment segment = segment_map.get(c_char);
+        if (segment == null) {
+            segment = new Segment(c_char);
+            segment_map.put(c_char, segment);
+        }
+        return segment;
+    }
+
+    private Map<Character, Segment> getChildCharsMap() {
+        if (segment_map == null) {
+            segment_map = new HashMap<Character, Segment>(10, 0.7f);
+        }
+        return this.segment_map;
+    }
+
+    public boolean isLexeme() {
+        return this.isLexeme;
+    }
+
+    public void setParent(Segment segment) {
+        this.parent = segment;
+    }
+
+    public Segment parent() {
+        return this.parent;
+    }
+
+    public Map<Character, Segment> getSegmentMap() {
+        return this.segment_map;
+    }
+
+    public float getThreshold() {
+        return threshold;
+    }
+
+    public void setThreshold(float threshold) {
+        this.threshold = threshold;
+    }
+
+    public String getProperty() {
+        return property;
+    }
+
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    public String getConcept() {
+        return concept;
+    }
+
+    public void setConcept(String concept) {
+        this.concept = concept;
+    }
+}

+ 58 - 0
nlp/src/main/java/com/lantone/qc/nlp/util/CharacterUtil.java

@@ -0,0 +1,58 @@
+package com.lantone.qc.nlp.util;
+
+import java.util.Arrays;
+
+public class CharacterUtil {
+
+    public static final String QUANTIFIER = "一二三四五六七八九十壹贰叁肆伍陆柒捌玖拾";
+
+    public static final int CHAR_USELESS = 0;
+
+    public static final int CHAR_ARABIC = 0X00000001;
+
+    public static final int CHAR_ENGLISH = 0X00000002;
+
+    public static final int CHAR_CHINESE = 0X00000004;
+
+    public static final int CHAR_OTHER_HALF = 0X00000008;
+
+    public static final int CHAR_CHINESE_QUANTIFIER = 0X00000016;
+
+    public static char[] cs;
+
+    static {
+        cs = QUANTIFIER.toCharArray();
+        Arrays.sort(cs);
+    }
+
+    public static int identifyCharType(char input) {
+        if (input >= '0' && input <= '9') {
+            return CHAR_ARABIC;
+        } else if ((input >= 'a' && input <= 'z')
+                || (input >= 'A' && input <= 'Z') || input == 'μ') {
+            return CHAR_ENGLISH;
+        }  else if (isQuantifier(input)) {
+            return CHAR_CHINESE_QUANTIFIER;
+        } else {
+            Character.UnicodeBlock ub = Character.UnicodeBlock.of(input);
+            if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
+                    || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
+                    || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A) {
+                //目前已知的中文字符UTF-8集合
+                return CHAR_CHINESE;
+            } else if (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {    //全角数字字符和日韩字符
+                return CHAR_OTHER_HALF;
+            }
+        }
+        //其他的不做处理的字符
+        return CHAR_USELESS;
+    }
+
+    public static boolean isQuantifier(char input) {
+        int searched_position = Arrays.binarySearch(cs, input);
+        if (searched_position > -1) {
+            return true;
+        }
+        return  false;
+    }
+}

+ 79 - 0
nlp/src/main/java/com/lantone/qc/nlp/util/Constants.java

@@ -0,0 +1,79 @@
+package com.lantone.qc.nlp.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Constants {
+    public static Map<Character, Character> chn_chars_map = new HashMap<Character, Character>(100, 0.75f);
+
+    public final static String default_negative = "有";
+
+    public final static String feature_type_symptom  = "1"; //症状
+    public final static String feature_type_diag  = "2";    //诊断
+    public final static String feature_type_vital  = "3";   //体征
+    public final static String feature_type_lis = "4";      //化验
+    public final static String feature_type_pacs = "5";     //检查
+    public final static String feature_type_treat = "6";       //治疗
+    public final static String feature_type_history = "7";       //历史
+    public final static String feature_type_feature = "9"; //症状描述中的特征信息 如部位、性质等
+    public final static String feature_type_time = "10";    //提取时间
+    public final static String feature_type_vital_index = "42"; //体征指标
+    public final static String feature_type_default = "-1"; //默认返回类型
+
+    public static NegativeEnum[] symptom_type = new NegativeEnum[]{NegativeEnum.SYMPTOM, NegativeEnum.SYMPTOM_INDEX, NegativeEnum.SYMPTOM_PERFORMANCE};
+    public static NegativeEnum[] unit_time_type = new NegativeEnum[]{NegativeEnum.EVENT_TIME, NegativeEnum.UNIT};
+    public static NegativeEnum[] event_time_desc_type = new NegativeEnum[]{NegativeEnum.EVENT_TIME_DESC};
+    public static NegativeEnum[] vital_type = new NegativeEnum[]{NegativeEnum.VITAL_INDEX, NegativeEnum.VITAL_RESULT, NegativeEnum.BODY_PART};
+    public static NegativeEnum[] vital_index_type = new NegativeEnum[]{NegativeEnum.VITAL_INDEX};
+    public static NegativeEnum[] vital_result_type = new NegativeEnum[]{NegativeEnum.VITAL_RESULT};
+    public static NegativeEnum[] vital_value_type = new NegativeEnum[]{NegativeEnum.VITAL_INDEX_VALUE};
+    public static NegativeEnum[] body_part_type = new NegativeEnum[]{NegativeEnum.BODY_PART};
+    public static NegativeEnum[] position_type = new NegativeEnum[]{NegativeEnum.POSITION};
+    public static NegativeEnum[] property_type = new NegativeEnum[]{NegativeEnum.PROPERTY};
+    public static NegativeEnum[] degree_type = new NegativeEnum[]{NegativeEnum.DEEP};
+    public static NegativeEnum[] cause_type = new NegativeEnum[]{NegativeEnum.CAUSE};
+    public static NegativeEnum[] negative_type = new NegativeEnum[]{NegativeEnum.FEMININE};
+    public static NegativeEnum[] lis_name_type = new NegativeEnum[]{NegativeEnum.LIS_NAME};
+    public static NegativeEnum[] lis_result_type = new NegativeEnum[]{NegativeEnum.LIS_RESULT};
+    public static NegativeEnum[] pacs_name_type = new NegativeEnum[]{NegativeEnum.PACS_NAME};
+    public static NegativeEnum[] pacs_result_type = new NegativeEnum[]{NegativeEnum.PACS_RESULT};
+    public static NegativeEnum[] treatment_type = new NegativeEnum[]{NegativeEnum.TREATMENT};
+    public static NegativeEnum[] medicine_type = new NegativeEnum[]{NegativeEnum.MEDICINE};
+
+    public static String[] negative_words = new String[]{"无", "未", "未及", "无殊", "否认", "未见", "不", "未闻", "未闻及", "欠", "非", "无明显", "不伴", "不伴有", "不规则"};
+
+    public final static String word_property_time = "2";
+    public final static String word_property_unit = "9";
+    public final static String word_property_number = "28";
+
+    public static String[] vital_filter_data = new String[] {
+            "神清","神志清","睡眠可","精神可","精神佳","二便无殊","体重无明显减轻","睡眠一般","小便无殊","大便无殊","胃纳可","食欲可", "大小便正常"
+    };
+
+    public final static String word_property_timestamp = "40";
+    public final static String word_property_symptom = "1";
+    public final static String word_property_bodypart = "3";
+    public final static String word_property_prop = "4";
+    public final static String word_property_cause = "5";
+    public final static String word_property_degree = "6";
+    public final static String word_property_neg = "7";
+    public final static String word_property_med = "53";
+    public final static String word_property_med_com = "54";
+    public final static String word_property_treat = "11";
+    public final static String word_property_LIS = "12";
+    public final static String word_property_LIS_Detail = "13";
+    public final static String word_property_LIS_Result = "14";
+    public final static String word_property_PACS = "15";
+    public final static String word_property_PACS_Detail = "16";
+    public final static String word_property_PACS_Result = "17";
+    public final static String word_property_diagnose = "18";
+    public final static String word_property_direction = "20";
+    public final static String word_property_freq = "27";
+    public final static String word_property_vital_idx = "33";
+    public final static String word_property_vital_value = "34";
+    public final static String word_property_vital_result = "35";
+    public final static String word_property_degree_quan = "43";
+    public final static String word_property_other = "44";
+
+    public final static String app_rule_type_id = "6";
+}

+ 189 - 0
nlp/src/main/java/com/lantone/qc/nlp/util/NegativeEnum.java

@@ -0,0 +1,189 @@
+package com.lantone.qc.nlp.util;
+
+/**
+ * Created by Administrator on 2017/11/8.
+ */
+public enum NegativeEnum {
+    NUMBER("0"), SYMPTOM("1"), SYMPTOM_INDEX("41"), EVENT_TIME("2"), EVENT_TIME_DESC("40"), BODY_PART("3"), PROPERTY("4"), CAUSE("5"), DEEP("6"), DEEP_QUANTIFIER("43"), FEMININE("7"), POSITIVE("8"),
+    UNIT("9"), MEDICINE("10"), TREATMENT("11"),
+    LIS_TYPE("12"), LIS_NAME("13"), LIS_RESULT("14"), WAY("15"),
+    PACS_NAME("16"), PACS_RESULT("17"),
+    DISEASE("18"), JOIN("19"), POSITION("20"), FAMILY("21"), FOOD("23"), PAST("24"), OPERATION("25"),
+    SYMPTOM_PERFORMANCE("26"), NUMBER_QUANTIFIER("27"), DIGITS("28"),
+    OTHER("44"),
+    VITAL_INDEX("33"), VITAL_INDEX_VALUE("34"), VITAL_RESULT("35"),
+    ADDRESS("36"), PERSON("38"), PERSON_FEATURE_DESC("39"), PUB_NAME("46"), MEDICINE_NAME("53"),MEDICINE_PRD("54"),PAST_DESC("55"),ALLERGY("65"),
+    MARRIED_DESC("62"), RETURN_VISIT("68"), DIAG_STAND("70"), BLOOD("58"), BAD_HABBIT("60"), FAMILY_HISTORY("64"), VACCINATION("71");
+    private String value;
+
+    NegativeEnum(String value) {
+        this.value = value;
+    }
+
+    public String toString() {
+        return value;
+    }
+
+    public static com.lantone.qc.nlp.util.NegativeEnum parseOfValue(String value) {
+        if (value == null) {
+            return com.lantone.qc.nlp.util.NegativeEnum.OTHER;
+        }
+        com.lantone.qc.nlp.util.NegativeEnum negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.OTHER;
+        switch (value) {
+            case "0":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.NUMBER;
+                break;
+            case "1":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.SYMPTOM;
+                break;
+            case "2":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.EVENT_TIME;
+                break;
+            case "3":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.BODY_PART;
+                break;
+            case "4":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.PROPERTY;
+                break;
+            case "5":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.CAUSE;
+                break;
+            case "6":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.DEEP;
+                break;
+            case "7":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.FEMININE;
+                break;
+            case "8":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.POSITIVE;
+                break;
+            case "9":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.UNIT;
+                break;
+            case "10":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.MEDICINE;
+                break;
+            case "11":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.TREATMENT;
+                break;
+            case "12":
+                negativeEnum = NegativeEnum.LIS_TYPE;
+                break;
+            case "13":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.LIS_NAME;
+                break;
+            case "14":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.LIS_RESULT;
+                break;
+            case "15":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.WAY;
+                break;
+            case "16":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.PACS_NAME;
+                break;
+            case "17":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.PACS_RESULT;
+                break;
+            case "18":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.DISEASE;
+                break;
+            case "19":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.JOIN;
+                break;
+            case "20":
+                negativeEnum = NegativeEnum.POSITION;
+                break;
+            case "21":
+                negativeEnum = NegativeEnum.FAMILY;
+                break;
+            case "23":
+                negativeEnum = NegativeEnum.FOOD;
+                break;
+            case "24":
+                negativeEnum = NegativeEnum.PAST;
+                break;
+            case "25":
+                negativeEnum = NegativeEnum.OPERATION;
+                break;
+            case "26":
+                negativeEnum = NegativeEnum.SYMPTOM_PERFORMANCE;
+                break;
+            case "27":
+                negativeEnum = NegativeEnum.NUMBER_QUANTIFIER;
+                break;
+            case "28":
+                negativeEnum = NegativeEnum.DIGITS;
+                break;
+            //            case "44":
+            //                negativeEnum = NegativeEnum.SCALE;
+            //                break;
+            case "33":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.VITAL_INDEX;
+                break;
+            case "34":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.VITAL_INDEX_VALUE;
+                break;
+            case "35":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.VITAL_RESULT;
+                break;
+            case "36":
+                negativeEnum = NegativeEnum.ADDRESS;
+                break;
+            case "38":
+                negativeEnum = NegativeEnum.PERSON;
+                break;
+            case "39":
+                negativeEnum = NegativeEnum.PERSON_FEATURE_DESC;
+                break;
+            case "40":
+                negativeEnum = NegativeEnum.EVENT_TIME_DESC;
+                break;
+            case "41":
+                negativeEnum = NegativeEnum.SYMPTOM_INDEX;
+                break;
+            case "43":
+                negativeEnum = NegativeEnum.DEEP_QUANTIFIER;
+                break;
+            case "44":
+                negativeEnum = com.lantone.qc.nlp.util.NegativeEnum.OTHER;
+                break;
+            case "46":
+                negativeEnum = NegativeEnum.PUB_NAME;
+                break;
+            case "53":
+                negativeEnum = NegativeEnum.MEDICINE_NAME;
+                break;
+            case "54":
+                negativeEnum = NegativeEnum.MEDICINE_PRD;
+                break;
+            case "55":
+                negativeEnum = NegativeEnum.PAST_DESC;
+                break;
+            case "58":
+                negativeEnum = NegativeEnum.BLOOD;
+                break;
+            case "60":
+                negativeEnum = NegativeEnum.BAD_HABBIT;
+                break;
+            case "62":
+                negativeEnum = NegativeEnum.MARRIED_DESC;
+                break;
+            case "64":
+                negativeEnum = NegativeEnum.FAMILY_HISTORY;
+                break;
+            case "65":
+                negativeEnum = NegativeEnum.ALLERGY;
+                break;
+            case "68":
+                negativeEnum = NegativeEnum.RETURN_VISIT;
+                break;
+            case "70":
+                negativeEnum = NegativeEnum.DIAG_STAND;
+                break;
+            case "71":
+                negativeEnum = NegativeEnum.VACCINATION;
+                break;
+        }
+        return negativeEnum;
+    }
+}

+ 251 - 0
nlp/src/main/java/com/lantone/qc/nlp/util/NlpCache.java

@@ -0,0 +1,251 @@
+package com.lantone.qc.nlp.util;
+
+import com.lantone.qc.nlp.participle.cfg.Configuration;
+import com.lantone.qc.nlp.participle.cfg.DefaultConfig;
+import com.lantone.qc.nlp.participle.word.Segment;
+
+import java.util.*;
+
+/**
+ * @ClassName com.lantone.qc.nlp.util.NlpCache
+ * @Description 词典库 同义词 大小类缓存
+ * @Author fyeman
+ * @Date 2019/1/11/011 14:04
+ * @Version 1.0
+ **/
+public class NlpCache {
+    //词典库
+    public static Segment segment_cache = null;
+    //词典库
+    public static Segment segment_cache_pacs = null;
+    //推送字典
+    public static Map<String, String> standard_info_push_map = null;
+    //词库同义词定义
+    public static Map<String, Map<String, String>> standard_info_synonym_map = null;
+    //词库大小类定义
+    public static Map<String, String> standard_info_classify_map = null;
+    //慢病推送
+    public static Map<String, String> standard_info_chronic_map = null;
+    //树形结构存储大小类
+    public static Map<String, Node> standard_info_type_tree_map = null;
+    //后结构化 有可能作为训练样本词性匹配对
+    public static Map<String, List<String>> extract_relation_property_pair_map = null;
+
+    public static void createSegmentCache() {
+        Configuration configuration = new DefaultConfig();
+        segment_cache = configuration.loadMainDict( "tc.dict");
+    }
+
+    public static void createSegmentCachePacs() {
+        Configuration configuration = new DefaultConfig();
+        segment_cache_pacs = configuration.loadMainDict("pacs-tc.dict");
+    }
+
+    public static void createPushCache() {
+        Configuration configuration = new DefaultConfig();
+        standard_info_push_map = configuration.loadMapDict( "push-tc.dict");
+    }
+
+    public static void createSynonymCache() {
+        Configuration configuration = new DefaultConfig();
+        List<String> lines = configuration.readFileContents("synonym.dict");
+
+        String[] line_arr;
+        Map<String, String> map = null;
+        standard_info_synonym_map = new HashMap<>();
+        for (String line : lines) {
+            line_arr = org.apache.commons.lang3.StringUtils.split(line, "\\|");
+            if (line_arr.length > 2) {
+                map = standard_info_synonym_map.get(line_arr[2]);
+                if (map == null) {
+                    map = new HashMap<>();
+                }
+                map.put(line_arr[0], line_arr[1]);
+                standard_info_synonym_map.put(line_arr[2], map);
+            }
+        }
+    }
+
+    public static void createClassifyCache() {
+        Configuration configuration = new DefaultConfig();
+
+        standard_info_classify_map = configuration.loadMapDict("classify.dict");
+    }
+
+    public static void createChronicCache() {
+        Configuration configuration = new DefaultConfig();
+        standard_info_chronic_map = configuration.loadMapDict("chronic.dict");
+    }
+
+    public static void createClassifyTreeCache() {
+        Configuration configuration = new DefaultConfig();
+        standard_info_classify_map = configuration.loadMapDict("classify.dict");
+    }
+
+    public static void createPropertyPairCache() {
+        Configuration configuration = new DefaultConfig();
+        List<String> lines = configuration.readFileContents("relation.dict");
+
+        extract_relation_property_pair_map = new HashMap<>();
+        List<String> list = null;
+        for (String line : lines) {
+            String[] prop = line.split("\\|");
+            if(prop.length != 2) {
+                continue;
+            }
+            String prop1_id = prop[0];
+            String prop2_id = prop[1];
+
+            list = extract_relation_property_pair_map.get(prop1_id);
+            if (list == null) {
+                list = new ArrayList<>();
+                list.add(prop2_id);
+                extract_relation_property_pair_map.put(prop1_id, list);
+            } else {
+                if (!list.contains(prop2_id)) {
+                    list.add(prop2_id);
+                    extract_relation_property_pair_map.put(prop1_id, list);
+                }
+            }
+
+            list = extract_relation_property_pair_map.get(prop2_id);
+            if (list == null) {
+                list = new ArrayList<>();
+                list.add(prop1_id);
+                extract_relation_property_pair_map.put(prop2_id, list);
+            } else {
+                if (!list.contains(prop1_id)) {
+                    list.add(prop1_id);
+                    extract_relation_property_pair_map.put(prop2_id, list);
+                }
+            }
+        }
+    }
+
+    public static Segment getSegment_cache() {
+        if (segment_cache == null) {
+            createSegmentCache();
+        }
+        return segment_cache;
+    }
+
+    public static Segment getSegment_cache_pacs() {
+        if (segment_cache_pacs == null) {
+            createSegmentCachePacs();
+        }
+        return segment_cache_pacs;
+    }
+
+    public static Map<String, String> getStandard_info_push_map() {
+        if (standard_info_push_map == null) {
+            createPushCache();
+        }
+        return standard_info_push_map;
+    }
+
+    public static Map<String, Map<String, String>> getStandard_info_synonym_map() {
+        if (standard_info_synonym_map == null) {
+            createSynonymCache();
+        }
+        return standard_info_synonym_map;
+    }
+
+    public static Map<String, String> getStandard_info_classify_map() {
+        if (standard_info_classify_map == null) {
+            createClassifyCache();
+        }
+        return standard_info_classify_map;
+    }
+
+    public static Map<String, String> getStandard_info_chronic_map() {
+        if (standard_info_chronic_map == null) {
+            createChronicCache();
+        }
+        return standard_info_chronic_map;
+    }
+
+    public static Map<String, List<String>> getExtract_relation_property_pair_map() {
+        if (extract_relation_property_pair_map == null) {
+            createPropertyPairCache();
+        }
+        return extract_relation_property_pair_map;
+    }
+
+
+    public static Map<String, Node> getStandard_info_type_tree_map() {
+        if (standard_info_type_tree_map == null) {
+            standard_info_type_tree_map = new HashMap<>();
+            for (Map.Entry<String, String> entry : getStandard_info_classify_map().entrySet()) {
+                Node parent_node = standard_info_type_tree_map.get(entry.getValue());
+                if (parent_node == null) {
+                    parent_node = new Node();
+                    parent_node.setName(entry.getValue());
+                }
+                Node child_node = standard_info_type_tree_map.get(entry.getKey());
+                if (child_node == null) {
+                    child_node = new Node();
+                    child_node.setName(entry.getKey());
+                }
+                parent_node.add(parent_node, child_node);
+                standard_info_type_tree_map.put(entry.getValue(), parent_node);
+                standard_info_type_tree_map.put(entry.getKey(), child_node);
+            }
+        }
+        return standard_info_type_tree_map;
+    }
+
+    private void addChilds(Node root, Map<String, String> standardInfoTypeMap, List<String> hasAddList) {
+        for (Node node : root.getChilds()) {
+            for (Map.Entry<String, String> entry : standardInfoTypeMap.entrySet()) {
+                if (node.getName().equals(entry.getValue())) {
+                    node.add(node, entry.getKey());
+                    hasAddList.add(entry.getKey());
+                }
+            }
+        }
+    }
+
+    public static class Node {
+        private String name;
+        private Node parent;
+        private Set<Node> childs = new HashSet<>();
+
+        public Node add(Node parent, String name) {
+            Node node = new Node();
+            node.setName(name);
+            node.setParent(parent);
+            parent.getChilds().add(node);
+            return parent;
+        }
+
+        public Node add(Node parent, Node node) {
+            node.setParent(parent);
+            parent.getChilds().add(node);
+            return parent;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public Set<Node> getChilds() {
+            return childs;
+        }
+
+        public void setChilds(Set<Node> childs) {
+            this.childs = childs;
+        }
+
+        public Node getParent() {
+            return parent;
+        }
+
+        public void setParent(Node parent) {
+            this.parent = parent;
+        }
+    }
+}

+ 122 - 0
nlp/src/main/java/com/lantone/qc/nlp/util/NlpUtil.java

@@ -0,0 +1,122 @@
+package com.lantone.qc.nlp.util;
+
+import org.apache.commons.lang3.StringUtils;
+import com.lantone.qc.nlp.participle.word.Lexeme;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * @Auther: fyeman
+ * @Date: 2018/12/24/024 16:04
+ * @Description:
+ */
+public class NlpUtil {
+
+    private static List numtextList = new ArrayList(Arrays.asList("数", "多", "半", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"));
+    private static  Map<String, String> numtextMap = new HashMap<String, String>(){{
+        put("一","1");
+        put("二","2");
+        put("三","3");
+        put("四","4");
+        put("五","5");
+        put("六","6");
+        put("七","7");
+        put("八","8");
+        put("九","9");
+        put("十","10");
+    }};
+
+    public static String[] extendsSymbol(String[] origin, String[] extend_symbols) {
+        String[] symbols = new String[origin.length + extend_symbols.length];
+        System.arraycopy(origin, 0, symbols, 0, origin.length);
+        System.arraycopy(extend_symbols, 0, symbols, origin.length, extend_symbols.length);
+
+        Arrays.sort(symbols);
+        return symbols;
+    }
+
+    public static boolean isNumberString(Lexeme l) {
+        if (l == null) return false;
+        if (NlpUtil.isFeature(l.getProperty(), new NegativeEnum[]{NegativeEnum.NUMBER_QUANTIFIER})) {
+            return true;
+        }
+        return Pattern.matches("^[-\\+]?\\d+(\\.\\d+)?",l.getText());
+    }
+
+    public static boolean isNumberString(String s) {
+        if (StringUtils.isEmpty(s)) return false;
+        return Pattern.matches("^[-\\+]?\\d+(\\.\\d+)?",s);
+    }
+
+    public static double numberText2value(Lexeme l) {
+        double value = 0.0;
+        if (numtextList.contains(l.getText())) {
+            if ("数".equals(l.getText()) || "多".equals(l.getText())) {     //数年直接按5年处理
+                value = 5;
+            } else if ("半".equals(l.getText())) {
+                value = 0.5;
+            } else {
+                value = Double.valueOf(numtextMap.get(l.getText()));
+            }
+        } else {
+            try {
+                value = Double.valueOf(l.getText());
+            } catch (Exception nfe) {
+                if (l.getText().indexOf("-") > -1) {
+                    try {
+                        value = Double.valueOf(l.getText().split("-")[0]);
+                    } catch (Exception e) {
+                    }
+                }
+            }
+        }
+        return value;
+    }
+
+    public static boolean isFeature(String property, NegativeEnum[] features) {
+        if (property == null) {
+            return false;
+        }
+        if (features == null || features.length == 0) {
+            return true;
+        }
+        if (property.indexOf(",") > 0) {
+            String[] properties = property.split(",");
+            for (int i = 0; i < properties.length; i++) {
+                for (NegativeEnum nenum : features) {
+                    if (NegativeEnum.parseOfValue(properties[i]) == nenum) {
+                        return true;
+                    }
+                }
+            }
+        } else {
+            for (NegativeEnum nenum : features) {
+                if (NegativeEnum.parseOfValue(property) == nenum) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 返回对应词性的标准术语
+     * @param lexeme
+     * @param feature
+     * @return
+     */
+    public static String concept(Lexeme lexeme, NegativeEnum feature) {
+        if (lexeme.getProperty() == null) {
+            return lexeme.getText();
+        }
+        String[] properties = lexeme.getProperty().split(",");
+        String[] concepts = lexeme.getConcept().split(",");
+        for (int i = 0; i < properties.length; i++) {
+            if (NegativeEnum.parseOfValue(properties[i]) == feature) {
+                return concepts[i];
+            }
+        }
+        return lexeme.getText();
+    }
+}

+ 159 - 0
public/src/main/java/com/lantone/qc/pub/Constants.java

@@ -0,0 +1,159 @@
+/**   
+* @Company: 杭州朗通信息技术有限公司 
+* @Department: 系统软件部 
+* @Description: 朗通智能辅助诊疗系统 
+* @Address: 浙江省杭州市西湖区西斗门路3号 天堂软件园D-7B 
+*/
+package com.lantone.qc.pub;
+
+/**
+* @Title: Constants.java 
+* @Package org.diagbot.public 
+* @Description: 通用常数接口定义  
+* @author 楼辉荣(Fyeman)   
+* @date 2015年4月23日 下午11:25:37 
+* @version V1.0
+ */
+public interface Constants {
+    /**
+     * 操作名称
+     */
+    String OP_NAME = "op";
+    /**
+     * 消息key
+     */
+    String MESSAGE = "message";
+    /**
+     * 错误key
+     */
+    String ERROR = "error";
+    /**
+     * 上个页面地址
+     */
+    String BACK_URL = "BackURL";
+    String IGNORE_BACK_URL = "ignoreBackURL";
+    /**
+     * 当前请求的地址 带参数
+     */
+    String CURRENT_URL = "currentURL";
+    /**
+     * 当前请求的地址 不带参数
+     */
+    String NO_QUERYSTRING_CURRENT_URL = "noQueryStringCurrentURL";
+    /**
+     * 上下文
+     */
+    String CONTEXT_PATH = "ctx";
+    /**
+     * 当前登录的用户
+     */
+    String CURRENT_APPLICATION = "c_app";
+    String CURRENT_USER = "c_user";
+    String CURRENT_USERNAME = "username";
+    String USER_MENUS = "menus";
+    
+    /**
+     * 管理控制台应用ID=0
+     */
+    long ADMIN_APPLICATION = 0;
+    /**
+     * 一级菜单grade标识
+     */
+    int FIRST_MENU = 1;
+    /**
+     * 二级菜单grade标识
+     */
+    int SECOND_MENU = 2;
+    /**
+     * 操作按钮等级标识
+     */
+    int MENU_GRADE = 3;
+    /**
+     * 最高级资源grade标识
+     */
+    int TOP_REC = 0;
+    /**
+     * 编码方式
+     */
+    String ENCODING = "UTF-8";
+    /**
+     * 系统用户状态--启用
+     */
+    int USER_STATUS_UNLOCK = 1;
+    /**
+     * 系统用户状态--禁用
+     */
+    int USER_STATUS_LOCK = 0;
+    /**
+     * 通用值0
+     */
+    int COMMON_INT_0 = 0;
+    /**
+     * 通用值1
+     */
+    int COMMON_INT_1 = 1;
+    /**
+     * 通用值-1
+     */
+    int COMMON_INT_NEG_1 = -1;
+    /**
+     * 通用值0
+     */
+    long COMMON_LONG_0 = 0L;
+    /**
+     * 通用值1
+     */
+    long COMMON_LONG_1 = 1L;
+    /**
+     * 通用值-1
+     */
+    long COMMON_LONG_NEG_1 = -1L;
+    /**
+     * 通用值"0"
+     */
+    String COMMON_STRING_0 = "0";
+    /**
+     * 通用值"1"
+     */
+    String COMMON_STRING_1 = "1";
+    /**
+     * 通用值"-1"
+     */
+    String COMMON_STRING_NEG_1 = "-1";
+    
+    /**
+     * 通用值"-1"
+     */
+    String COMMON_STRING_99 = "99";
+    /**
+     * 登录页面
+     */
+    String LOGIN_URL = "/login";
+    /**
+     * 上传文件夹
+     */
+    String UPLOAD_FOLDER_NAME = "upload";
+    /**
+     * 临时文件夹
+     */
+    String TEMP_FOLDER_NAME = "temp";
+    /**
+     * 地域标示
+     */
+    public static final String DEFAULT_LOCALE = "zh_CN";
+    /**
+     * 缺省字符集
+     */
+    public static final String DEFAULT_ENCODE = "UTF-8";
+    /**
+     * 以下为接口返回公共属性定义常量
+     */
+    public static final String MSG_SUCCESS = "操作成功";	//操作成功
+    public static final String MSG_FALURE = "操作失败";	//操作失败
+    
+    public static final long INVALIDATE_VALUE = -1;		//起止时间定义
+    public static final int RET_SUCCESS = 0; 			//成功
+	public static final int RET_FAIL = 1; 				//失败
+	public static final int RET_ERROR_PARAM = -1; 		//参数校验失败
+	public static final int RET_NO_TOKEN = -2; 	//用户token丢失
+}

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/BeHospitalizedDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : InHospitalDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ClinicalBloodDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : ClinicalBloodDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ConsultationDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : ConsultationDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DeathCaseDiscussDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : DeathCaseDiscussionDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DeathRecordDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : DeathRecordDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DifficultCaseDiscussDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : DifficultCaseDiscussDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/DutyShiftSystemDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : DutyShiftSystemDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/FirstCourseRecordDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : FirstCourseRecordDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/FirstPageRecordDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : FirstPageRecordDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/LeaveHospitalDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : LeaveHospitalDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/NursingSystemDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : NursingSystemDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/OperationDiscussionDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : Operation

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/PreoperativeDiscussionDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : PreoperativeDiscussionDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/doc/ThreeLevelWardDoc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.doc;
+package com.lantone.qc.pub.model.doc;
 
 /**
  * @ClassName : ThreeLevelWardDoc

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Address.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/BodyPart.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Cause.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Clinical.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Consultation.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Decorate.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Degree.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Diag.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Dose.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Family.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Frequency.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/General.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/GeneralDesc.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/IndexValue.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Lis.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/LisValue.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Medicine.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 /**
  * @ClassName : Medicine

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Negative.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Occupation.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Operation.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Organism.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/PD.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Pacs.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/PacsValue.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Possible.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 /**
  * @ClassName : Possible

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Treat.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Trend.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 /**
  * @ClassName : Trend

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/entity/Vital.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.entity;
+package com.lantone.qc.pub.model.entity;
 
 import lombok.Getter;
 import lombok.Setter;

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/CaseCharacteristicLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : CaseCharacteristicLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/ChiefLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : Chief

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/DifferDiagLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : DifferDiagLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/FamilyLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : FamilyLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/InitialDiagLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : InitialDiagLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/LisLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : LisLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/MaritalLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : MaritalLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/MenstrualLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : MenstrualLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PacsLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : PacsLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PastLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : PastLabel

+ 2 - 2
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PersonalLabel.java

@@ -1,6 +1,6 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
-import com.lantone.qc.kernel.structure.bean.entity.General;
+import com.lantone.qc.pub.model.entity.General;
 import lombok.Getter;
 import lombok.Setter;
 

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/PresentLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : PresentLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/RevisedDiagLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : RevisedDiagLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/SuppleDiagLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : FinalDiagLabel

+ 1 - 1
kernel/src/main/java/com/lantone/qc/kernel/structure/bean/label/VatilLabel.java

@@ -1,4 +1,4 @@
-package com.lantone.qc.kernel.structure.bean.label;
+package com.lantone.qc.pub.model.label;
 
 /**
  * @ClassName : VatilLabel

+ 194 - 0
public/src/main/java/com/lantone/qc/pub/res/Response.java

@@ -0,0 +1,194 @@
+package com.lantone.qc.pub.res;
+
+//import com.lantone.pub.Constants;
+
+import com.lantone.qc.pub.Constants;
+
+/**
+ * 
+ * ClassName: org.diagbot.pub.api.Response 
+ * Function: API接口提供标准返回数据包, 数据包格式如下:
+ * 			{
+ * 				status:"OK",
+ * 				startTime:8206448610408,
+ * 				endTime:8206448610418,
+ * 				version:"1.0",
+ * 				msg:"操作成功",
+ * 				ret:"0",
+ *				timeConsum:10,
+ *				data:{
+ *					..。		
+ *				}
+ * 			}
+ * date: 2015年7月6日 下午1:36:58  
+ * 
+ * @author 楼辉荣(Fyeman) 
+ * @version 1.0 
+ * @since JDK 1.7
+ */
+public class Response<T> implements java.io.Serializable {
+	private static final long serialVersionUID = 8206448610408409499L;
+	private Status status =  Status.PENDING;  //状态
+    private long startTime = Constants.INVALIDATE_VALUE;                                  //起始时间
+    private long endTime = Constants.INVALIDATE_VALUE;                                    //结束时间
+    private String version="1.0";
+    private String msg = Constants.MSG_SUCCESS;                                  //消息
+    private T data = null;                                                                //序列化后的结果数据
+    // 返回结果标志,默认成功0,失败 1 参数错误 -1 token丢失-2
+    private int ret = Constants.RET_SUCCESS;
+    
+    private String token;
+    //耗时
+ 	private long timeConsum;
+ 	
+    public int getRet() {
+		return ret;
+	}
+
+	public void setRet(int ret) {
+		this.ret = ret;
+	}
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public long getTimeConsum() {
+		return timeConsum;
+	}
+
+	public void setTimeConsum(long timeConsum) {
+		this.timeConsum = timeConsum;
+	}
+
+	public Response(){
+        super();
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    /**
+     * 在调用end()方法时,会自动设置状态,因此,如果调用了end()方法,就不要调用这个方法
+     * @param status
+     */
+    public Response<T> setStatus(Status status) {
+        this.status = status;
+        return this;
+    }
+
+ 
+	public String getVersion() {
+		return version;
+	}
+
+	public void setVersion(String version) {
+		this.version = version;
+	}
+
+	public long getStartTime() {
+        return startTime;
+    }
+
+    public Response<T> setStartTime(long startTime) {
+        this.startTime = startTime;
+        return this;
+    }
+
+    public long getEndTime() {
+        return endTime;
+    }
+
+    public Response<T> setEndTime(long endTime) {
+        this.endTime = endTime;
+        return this;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public String getToken() {
+		return token;
+	}
+
+	public void setToken(String token) {
+		this.token = token;
+	}
+
+	/**
+     * 设置状态和起始时间,表示操作正在进行
+     */
+    public Response<T> start(){
+        this.setStatus(Status.RUNNING);
+        this.setStartTime(System.currentTimeMillis());
+        return this;
+    }
+
+    /**
+     * 设置状态和时间,表示操作结束,没有失败
+     */
+    public Response<T> end(){
+        this.setEndTime(System.currentTimeMillis());
+        this.setTimeConsum(this.endTime-this.startTime);
+		this.setStatus(Status.OK);
+        return this;
+    }
+
+    /**
+     * 设置状态和时间,表示操作结束,并且失败
+     */
+    public Response<T> endAndFailed(){
+        this.setStatus(Status.FAIL);
+        this.setEndTime(System.currentTimeMillis());
+        return this;
+    }
+    
+    /**
+     * 非参数错误通用失败信息
+     */
+    public Response<T> failure(String msg) {
+    	this.msg = msg;
+    	this.ret = Constants.RET_FAIL;
+    	this.end();
+    	return this;
+    }
+    
+    /**
+     * 参数错误信息
+     */
+    public Response<T> paramFailure(String msg) {
+    	this.msg = msg;
+    	this.ret = Constants.RET_ERROR_PARAM;
+    	this.end();
+    	return this;
+    }
+    
+    /**
+     * 用户信息丢失
+     */
+    public Response<T> tokenFailure(String msg) {
+    	this.msg = msg;
+    	this.ret = Constants.RET_NO_TOKEN;
+    	this.end();
+    	return this;
+    }
+    
+    /**
+     * 通用成功
+     */
+    public Response<T> success() {
+    	this.end();
+    	return this;
+    }
+
+}

+ 131 - 0
public/src/main/java/com/lantone/qc/pub/res/Status.java

@@ -0,0 +1,131 @@
+package com.lantone.qc.pub.res;
+
+public enum Status {
+	/**
+	 * <code>PENDING = 1;</code>
+	 *
+	 * <pre>
+	 * 操作尚未开始
+	 * </pre>
+	 */
+	PENDING(1),
+	/**
+	 * <code>RUNNING = 2;</code>
+	 *
+	 * <pre>
+	 * 操作开始
+	 * </pre>
+	 */
+	RUNNING(2),
+	/**
+	 * <code>OK = 3;</code>
+	 *
+	 * <pre>
+	 * 操作正常结束
+	 * </pre>
+	 */
+	OK(3),
+	/**
+	 * <code>WARN = 4;</code>
+	 *
+	 * <pre>
+	 * 有警告,但是正常结束
+	 * </pre>
+	 */
+	WARN(4),
+	/**
+	 * <code>ERROR = 5;</code>
+	 *
+	 * <pre>
+	 * 有错误,但是完整结束
+	 * </pre>
+	 */
+	ERROR(5),
+	/**
+	 * <code>FAIL = 6;</code>
+	 *
+	 * <pre>
+	 * 操作失败
+	 * </pre>
+	 */
+	FAIL(6), ;
+
+	/**
+	 * <code>PENDING = 1;</code>
+	 *
+	 * <pre>
+	 * 操作尚未开始
+	 * </pre>
+	 */
+	public static final int PENDING_VALUE = 1;
+	/**
+	 * <code>RUNNING = 2;</code>
+	 *
+	 * <pre>
+	 * 操作开始
+	 * </pre>
+	 */
+	public static final int RUNNING_VALUE = 2;
+	/**
+	 * <code>OK = 3;</code>
+	 *
+	 * <pre>
+	 * 操作正常结束
+	 * </pre>
+	 */
+	public static final int OK_VALUE = 3;
+	/**
+	 * <code>WARN = 4;</code>
+	 *
+	 * <pre>
+	 * 有警告,但是正常结束
+	 * </pre>
+	 */
+	public static final int WARN_VALUE = 4;
+	/**
+	 * <code>ERROR = 5;</code>
+	 *
+	 * <pre>
+	 * 有错误,但是完整结束
+	 * </pre>
+	 */
+	public static final int ERROR_VALUE = 5;
+	/**
+	 * <code>FAIL = 6;</code>
+	 *
+	 * <pre>
+	 * 操作失败
+	 * </pre>
+	 */
+	public static final int FAIL_VALUE = 6;
+
+	public final int getNumber() {
+		return value;
+	}
+
+	public static Status valueOf(int value) {
+		switch (value) {
+		case 1:
+			return PENDING;
+		case 2:
+			return RUNNING;
+		case 3:
+			return OK;
+		case 4:
+			return WARN;
+		case 5:
+			return ERROR;
+		case 6:
+			return FAIL;
+		default:
+			return null;
+		}
+	}
+
+	private final int value;
+
+	private Status(int value) {
+		this.value = value;
+	}
+
+}

+ 15 - 0
security/src/main/java/com/lantone/qc/security/aop/Security.java

@@ -0,0 +1,15 @@
+package com.lantone.qc.security.aop;
+
+import java.lang.annotation.*;
+
+/**
+ * @Description: 安全校验注解
+ * @author: gaodm
+ * @time: 2018/8/1 14:54
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Security {
+    String value() default "";
+}

+ 44 - 0
security/src/main/java/com/lantone/qc/security/aop/SecurityAop.java

@@ -0,0 +1,44 @@
+package com.lantone.qc.security.aop;
+
+import com.lantone.exception.CommonErrorCode;
+import com.lantone.exception.CommonException;
+import com.lantone.util.TokenUtil;
+import com.lantone.vo.TokenVO;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Description: 安全验证切面
+ * @author: gaodm
+ * @time: 2019/12/24 10:23
+ */
+@Aspect
+@Component
+@Slf4j
+@ConditionalOnProperty(prefix = "mysecurity", value = { "enable" }, havingValue = "true")
+public class SecurityAop {
+
+    @Pointcut("@annotation(com.lantone.aop.Security)")
+    public void securityPointCut() {
+
+    }
+
+    @Before("securityPointCut()")
+    public void SecurityCheck(JoinPoint joinPoint) {
+        Object[] args = joinPoint.getArgs();
+        TokenVO tokenVO = null;
+        for (Object obj : args) {
+            // 获取token参数
+            tokenVO = (TokenVO)obj;
+        }
+        boolean pass = TokenUtil.verifyToken(tokenVO);
+        if (!pass) {
+            throw new CommonException(CommonErrorCode.SERVER_IS_ERROR, "接口校验未通过,请联系朗通!");
+        }
+    }
+}

+ 63 - 0
security/src/main/java/com/lantone/qc/security/exception/CommonErrorCode.java

@@ -0,0 +1,63 @@
+package com.lantone.qc.security.exception;
+
+/**
+ * @Description: 通用错误码
+ * 系统码(3位) + 等级码(1位) + 4位顺序号
+ * 系统码 通用码 000;用户中心 100; 管理中心 200;
+ * @author: gaodm
+ * @time: 2018/8/1 14:56
+ */
+public enum CommonErrorCode implements ErrorCode {
+
+    OK("0", "操作成功"),
+    FAIL("00000001", "操作失败"),
+    RPC_ERROR("00000002", "远程调度失败"),
+    PARAM_ERROR("00029999", "%s"), //参数错误
+    NOT_EXISTS("00020001", "该数据不存在!"),
+    INSERT_DATA_FAILED("00020002", "数据库写入失败!"),
+    UPDATE_INFO_FAIL("00020003", "更新数据失败!"),
+    PARAM_IS_NULL("00020004", "传入的参数为空!"),
+    PARAM_IS_ERROR("00020005", "传入的参数为错误!"),
+    STATUS_IS_ERROR("00020006", "参数状态错误!"),
+    SERVER_IS_ERROR("00020007", "各自业务错误!"),
+    NO_PERMISSION("00020008", "无权访问!"),
+    IS_EXISTS("00020009", "已存在!"),
+    ANALYZER_TOKEN_FAIL("10020010", "解析token失败"),
+    TOKEN_PAST("10020011", "token已失效,请重新登录"),
+
+    SECURITYCODE_ERROR("20020001", "防伪码错误"),
+    APPKEY_ERROR("20020002", "appkey或secret错误"),
+    PRODUCT_STOP_ERROR("20020003", "该产品已停用"),
+    OVERDUE_ERROR("20020004", "访问权限已过期"),
+    NOPERMISSION_ERROR("20020005", "无权限访问"),
+    SERVICE_STOP_ERROR("20020006", "当前服务已停用"),
+    NOTVALID_ERROR("20020007", "该产品未在有效服务期内,无法使用"),
+    EXPIRE_ERROR("20020008", "该产品已超出有效服务期,无法使用");
+
+    private String code;
+    private String msg;
+
+
+    CommonErrorCode(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public static CommonErrorCode codeOf(String code) {
+        for (CommonErrorCode state : values()) {
+            if (state.getCode() == code) {
+                return state;
+            }
+        }
+        return null;
+    }
+}

+ 36 - 0
security/src/main/java/com/lantone/qc/security/exception/CommonException.java

@@ -0,0 +1,36 @@
+package com.lantone.qc.security.exception;
+
+
+/**
+ * @Description: 通用错误封装
+ * @author: gaodm
+ * @time: 2018/8/1 14:56
+ */
+public class CommonException extends RuntimeException {
+
+    private ErrorCode errorCode;
+
+    public CommonException(ErrorCode errorCode) {
+        super(errorCode.getMsg());
+        this.errorCode = errorCode;
+    }
+
+    public CommonException(ErrorCode errorCode, String msg) {
+        super(msg);
+        this.errorCode = errorCode;
+    }
+
+    public ErrorCode getErrorCode() {
+        return errorCode;
+    }
+
+
+    public String getCode() {
+        return errorCode.getCode();
+    }
+
+    public String getMsg() {
+        return errorCode.getMsg();
+    }
+
+}

+ 81 - 0
security/src/main/java/com/lantone/qc/security/exception/CommonExceptionHandler.java

@@ -0,0 +1,81 @@
+package com.lantone.qc.security.exception;
+
+import com.lantone.dto.RespDTO;
+import com.lantone.util.GsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @Description: 错误通用处理
+ * @author: gaodm
+ * @time: 2018/8/2 14:22
+ */
+@ControllerAdvice
+@ResponseBody
+@Slf4j
+public class CommonExceptionHandler {
+
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<RespDTO> handleException(Exception e) {
+        RespDTO resp = new RespDTO();
+        if (e instanceof BindException) {
+            BindException ex = (BindException) e;
+            Map<String, String> stringMap = new HashMap<>();
+            for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
+                stringMap.put(fieldError.getField(), fieldError.getDefaultMessage());
+            }
+            String msg = GsonUtil.toJson(stringMap);
+            log.warn("【参数异常】:{}", msg);
+            resp.code = CommonErrorCode.PARAM_ERROR.getCode();
+            resp.msg = msg;
+            return new ResponseEntity(resp, HttpStatus.OK);
+        }
+        if (e instanceof MethodArgumentNotValidException) {
+            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
+            Map<String, String> stringMap = new HashMap<>();
+            for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
+                stringMap.put(fieldError.getField(), fieldError.getDefaultMessage());
+            }
+            String msg = GsonUtil.toJson(stringMap);
+            log.warn("【参数异常】:{}", msg);
+            resp.code = CommonErrorCode.PARAM_ERROR.getCode();
+            resp.msg = msg;
+            return new ResponseEntity(resp, HttpStatus.OK);
+        }
+        if (e instanceof MissingServletRequestParameterException) {
+            MissingServletRequestParameterException ex = (MissingServletRequestParameterException) e;
+            Map<String, String> stringMap = new HashMap<>();
+            stringMap.put(ex.getParameterName(), "不能为null");
+            String msg = GsonUtil.toJson(stringMap);
+            log.warn("【参数异常】:{}", msg);
+            resp.code = CommonErrorCode.PARAM_ERROR.getCode();
+            resp.msg = msg;
+            return new ResponseEntity(resp, HttpStatus.OK);
+        }
+        if (e instanceof CommonException) {
+            CommonException taiChiException = (CommonException) e;
+            resp.code = taiChiException.getCode();
+            resp.msg = e.getMessage();
+            log.error("【业务异常】:{}", e.getMessage());
+            return new ResponseEntity(resp, HttpStatus.OK);
+        }
+        resp.code = CommonErrorCode.FAIL.getCode();
+        resp.msg = e.getMessage();
+        log.error("【系统异常】:{}", e.getMessage());
+        e.printStackTrace();
+        return new ResponseEntity(resp, HttpStatus.OK);
+    }
+
+}

+ 15 - 0
security/src/main/java/com/lantone/qc/security/exception/ErrorCode.java

@@ -0,0 +1,15 @@
+package com.lantone.qc.security.exception;
+
+import java.io.Serializable;
+
+/**
+ * @Description: 错误基础接口
+ * @author: gaodm
+ * @time: 2018/9/10 11:01
+ */
+public interface ErrorCode extends Serializable {
+
+    String getCode();
+
+    String getMsg();
+}

+ 49 - 0
security/src/main/java/com/lantone/qc/security/exception/ServiceErrorCode.java

@@ -0,0 +1,49 @@
+package com.lantone.qc.security.exception;
+
+/**
+ * @Description: 本服务错误码
+ * 系统码(3位) + 等级码(1位) + 4位顺序号
+ * 系统码 通用码 000;用户中心 100; 管理中心 200;
+ * @author: gaodm
+ * @time: 2018/9/10 11:11
+ */
+public enum ServiceErrorCode implements ErrorCode {
+    USER_NOT_FOUND("10020000", "该手机号暂未注册"),
+    USER_PASSWORD_ERROR("10020001", "手机号或密码不正确"),
+    GET_TOKEN_FAIL("10020002", "获取token失败"),
+    TOKEN_IS_NOT_MATCH_USER("10020003", "请使用自己的token进行接口请求"),
+
+    SMS_SEND_ERROR("10020004", "短信发送错误"),
+    USER_BIND_ERROR("10020005", "用户手机号已经绑定无需再次验证"),
+    USER_UN_BIND_ERROR("10020006", "用户手机号未绑定无需解绑"),
+    VERIFYCODE_ERROR("10020007", "图片验证码生成错误"),
+    USER_EXIST("10020008", "该手机已注册"),
+    EMAIL_IS_NULL("10020009", "请输入邮箱");
+
+    private String code;
+    private String msg;
+
+
+    ServiceErrorCode(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public static ServiceErrorCode codeOf(String code) {
+        for (ServiceErrorCode state : values()) {
+            if (state.getCode() == code) {
+                return state;
+            }
+        }
+        return null;
+    }
+}

+ 96 - 0
security/src/main/java/com/lantone/qc/security/facade/QcRuleFacade.java

@@ -0,0 +1,96 @@
+package com.lantone.qc.security.facade;
+
+
+import com.lantone.analysis.Content;
+import com.lantone.analysis.StructureAnalyze;
+import com.lantone.client.CRFServiceClient;
+import com.lantone.client.GDBServiceClient;
+import com.lantone.pub.Response;
+import com.lantone.qcrule.Rule;
+import com.lantone.qcrule.RuleInfo;
+import com.lantone.util.DictUtil;
+import com.lantone.vo.MedrecVo;
+import com.lantone.vo.QueryVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+//import com.lantone.service.impl.QcRuleServiceImpl;
+
+
+@Component
+public class QcRuleFacade /*extends QcRuleServiceImpl*/ {
+
+    @Autowired
+    GDBServiceClient gdbServiceClient;
+
+    @Autowired
+    CRFServiceClient crfServiceClient;
+
+
+
+    public QcRuleFacade() {
+        DictUtil.LoadDict();
+    }
+
+    public Response<Map<String, Object>> parseDocu(QueryVo queryVo, Rule rules) {
+
+        Response response = new Response();
+        int cid = queryVo.getCid();
+
+        StructureAnalyze structureAnalyze = new StructureAnalyze(gdbServiceClient, crfServiceClient);
+        rules.setGDBSvc(gdbServiceClient);
+
+        List<MedrecVo> medrecVos = preprocess(queryVo.getMedrec(), queryVo.getCid());
+        structureAnalyze.parseContent(cid, medrecVos, rules);
+
+
+        Map<String, Object> res = new HashMap<>();
+
+        res.put(Rule.warntitle, rules.getRules());
+        // 针对ICSS提供的告警信息
+        if (queryVo.getCid()==0) {
+            List<String> warning = new ArrayList<>();
+            Map<String, List<String>> warns = rules.getRules().get(Content.docname[1]);
+            if (null != warns) {
+                for (String key : warns.keySet()) {
+                    if (key.equals(RuleInfo.pre_diag)) {
+                        warning.add(RuleInfo.diag + ": " + String.join(",", warns.get(key)));
+                    } else {
+                        warning.add(key + ": " + String.join(", ", warns.get(key)));
+                    }
+                }
+                res.put(Rule.warntitle, warning);
+            }
+        }
+        // 诊断其它系统的告警信息
+        else {
+            res.put(Rule.warntitle, rules.getRules());
+        }
+
+        res.put(Content.title, rules.getContent());
+
+        response.setData(res);
+
+        return response;
+    }
+
+    private List<MedrecVo> preprocess(List<MedrecVo> medrecVos, int cid) {
+        if (cid==0) {
+            MedrecVo medrecVo = medrecVos.get(0);
+            List<String> lbl = medrecVo.getLabel();
+            String content = medrecVo.getContent().get(Content.label).toString();
+
+            if (lbl.indexOf(RuleInfo.diag)>=0) {
+                content = content.replace(RuleInfo.diag, RuleInfo.pre_diag);
+                medrecVo.getContent().put(Content.label, content);
+                lbl.set(lbl.indexOf(RuleInfo.diag), RuleInfo.pre_diag);
+            }
+        }
+        return medrecVos;
+    }
+}

+ 52 - 0
security/src/main/java/com/lantone/qc/security/facade/TokenFacade.java

@@ -0,0 +1,52 @@
+package com.lantone.qc.security.facade;
+
+import com.lantone.exception.CommonErrorCode;
+import com.lantone.exception.CommonException;
+import com.lantone.util.RSAEncrypt;
+import com.lantone.util.StringUtil;
+import com.lantone.util.TokenUtil;
+import com.lantone.vo.LoginKeyVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class TokenFacade {
+
+    /**
+     * 获取token
+     *
+     * @param loginKeyVO
+     * @return 返回token信息
+     */
+    public String getToken(LoginKeyVO loginKeyVO) {
+        Map<String, String> tokenMap = TokenUtil.tokenMap;
+        // 记录信息
+        log.info(tokenMap.get("server.provider") + "——" + tokenMap.get("server.hospital") + "登录了!");
+
+        if (StringUtil.isEmpty(loginKeyVO.getLoginKey())) {
+            throw new CommonException(CommonErrorCode.SERVER_IS_ERROR, "loginKey为空");
+        }
+        try {
+            // 获取文件中的loginKey,已解密
+            String loginKey = tokenMap.get("server.key");
+            if (!loginKey.equals(loginKeyVO.getLoginKey())) {
+                throw new CommonException(CommonErrorCode.SERVER_IS_ERROR, "loginKey不匹配");
+            }
+            // 生成token,格式如下:server.remainday=xx$$server.validtime=xx
+            StringBuffer sb = new StringBuffer();
+            sb.append("server.remainday=" + tokenMap.get("server.remainday"));
+            sb.append("$$");
+            // 分钟数 * 60 * 1000,转换成毫秒
+            Long date = new Date().getTime() + Integer.parseInt(tokenMap.get("server.validtime")) * 60 * 1000;
+            sb.append("server.validtime=" + date);
+            return RSAEncrypt.encrypt(sb.toString());
+        } catch (Exception e) {
+            throw new CommonException(CommonErrorCode.SERVER_IS_ERROR, "获取token失败");
+        }
+    }
+
+}

+ 13 - 0
trans/src/main/java/com/lantone/qc/trans/DocTrans.java

@@ -0,0 +1,13 @@
+package com.lantone.qc.trans;
+
+import java.util.Map;
+
+/**
+ * @ClassName : DocTrans
+ * @Description :
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:47
+ */
+public abstract class DocTrans {
+    protected abstract Map<String, String> extract(String classify);
+}

+ 17 - 0
trans/src/main/java/com/lantone/qc/trans/taizhou/TaiZhouDocTrans.java

@@ -0,0 +1,17 @@
+package com.lantone.qc.trans.taizhou;
+
+import com.lantone.qc.trans.DocTrans;
+
+import java.util.Map;
+
+/**
+ * @ClassName : TaiZhouDocTrans
+ * @Description :
+ * @Author : 楼辉荣
+ * @Date: 2020-03-03 19:47
+ */
+public class TaiZhouDocTrans extends DocTrans {
+    public Map<String, String> extract(String classify) {
+        return null;
+    }
+}