Explorar el Código

增加树状视图

guochao hace 6 años
padre
commit
a77ee17def
Se han modificado 100 ficheros con 8211 adiciones y 5747 borrados
  1. 28 28
      .gitignore
  2. 12 12
      .idea/compiler.xml
  3. 5 5
      .idea/encodings.xml
  4. 14 14
      .idea/inspectionProfiles/Project_Default.xml
  5. 16 16
      .idea/misc.xml
  6. 123 123
      .idea/uiDesigner.xml
  7. 0 396
      .idea/workspace.xml
  8. 7 7
      Dockerfile
  9. 8 8
      build-run.sh
  10. 0 2
      crowd_review.iml
  11. 4 4
      deploy.sh
  12. 167 158
      pom.xml
  13. 24 24
      src/main/java/com/mooctest/CrowdReviewApplication.java
  14. 18 18
      src/main/java/com/mooctest/annotation/AutoValue.java
  15. 317 317
      src/main/java/com/mooctest/cluster/Cluster.java
  16. 110 110
      src/main/java/com/mooctest/cluster/ClusterAnalyzer.java
  17. 13 13
      src/main/java/com/mooctest/cluster/Doc.java
  18. 114 114
      src/main/java/com/mooctest/cluster/Document.java
  19. 15 15
      src/main/java/com/mooctest/cluster/Group.java
  20. 338 338
      src/main/java/com/mooctest/cluster/MyClusterAnalyzer.java
  21. 191 191
      src/main/java/com/mooctest/cluster/SparseVector.java
  22. 46 46
      src/main/java/com/mooctest/config/MongoOneConfig.java
  23. 47 47
      src/main/java/com/mooctest/config/MongoTwoConfig.java
  24. 55 55
      src/main/java/com/mooctest/config/ThymeleafViewResolverConfig.java
  25. 17 17
      src/main/java/com/mooctest/config/WebMvcConfiguration.java
  26. 75 75
      src/main/java/com/mooctest/controller/AggController.java
  27. 241 0
      src/main/java/com/mooctest/controller/AnalyzeController.java
  28. 20 20
      src/main/java/com/mooctest/controller/BugReviewController.java
  29. 91 91
      src/main/java/com/mooctest/controller/FinalReportController.java
  30. 113 113
      src/main/java/com/mooctest/controller/GraphController.java
  31. 117 117
      src/main/java/com/mooctest/controller/HelloController.java
  32. 215 0
      src/main/java/com/mooctest/controller/HistoryController.java
  33. 228 0
      src/main/java/com/mooctest/controller/RecommendController.java
  34. 185 185
      src/main/java/com/mooctest/controller/ReportController.java
  35. 73 73
      src/main/java/com/mooctest/controller/TaskController.java
  36. 116 116
      src/main/java/com/mooctest/controller/TestController.java
  37. 12 12
      src/main/java/com/mooctest/dao/AggTaskStatusDao.java
  38. 117 0
      src/main/java/com/mooctest/dao/BugExtDao.java
  39. 94 0
      src/main/java/com/mooctest/dao/BugHistoryDao.java
  40. 189 0
      src/main/java/com/mooctest/dao/BugMirrorDao.java
  41. 69 0
      src/main/java/com/mooctest/dao/BugPageDao.java
  42. 41 0
      src/main/java/com/mooctest/dao/BugScoreDao.java
  43. 88 0
      src/main/java/com/mooctest/dao/CTBDao.java
  44. 14 14
      src/main/java/com/mooctest/dao/FinalReportDao.java
  45. 41 0
      src/main/java/com/mooctest/dao/KWDao.java
  46. 27 27
      src/main/java/com/mooctest/dao/MasterReportDao.java
  47. 37 0
      src/main/java/com/mooctest/dao/StuInfoDao.java
  48. 19 19
      src/main/java/com/mooctest/dao/SupplementDao.java
  49. 10 10
      src/main/java/com/mooctest/dao2/BugDao.java
  50. 29 29
      src/main/java/com/mooctest/data/BugDTO.java
  51. 16 16
      src/main/java/com/mooctest/data/BugHistoryDTO.java
  52. 15 15
      src/main/java/com/mooctest/data/DiffImg.java
  53. 16 16
      src/main/java/com/mooctest/data/DiffText.java
  54. 33 33
      src/main/java/com/mooctest/data/FinalReportDTO.java
  55. 13 13
      src/main/java/com/mooctest/data/ImgDTO.java
  56. 19 19
      src/main/java/com/mooctest/data/ReportDTO.java
  57. 14 14
      src/main/java/com/mooctest/data/SentenceDTO.java
  58. 20 20
      src/main/java/com/mooctest/data/SupplementDTO.java
  59. 21 21
      src/main/java/com/mooctest/data/TaskDTO.java
  60. 7 7
      src/main/java/com/mooctest/event/Event.java
  61. 42 42
      src/main/java/com/mooctest/event/EventUtil.java
  62. 18 18
      src/main/java/com/mooctest/event/TaskEndEvent.java
  63. 22 22
      src/main/java/com/mooctest/event/TaskEndListener.java
  64. 18 18
      src/main/java/com/mooctest/event/TaskStartEvent.java
  65. 36 36
      src/main/java/com/mooctest/event/TaskStartListener.java
  66. 285 285
      src/main/java/com/mooctest/image/FingerPrint.java
  67. 90 90
      src/main/java/com/mooctest/image/ImageDownload.java
  68. 198 198
      src/main/java/com/mooctest/image/ImagePHash.java
  69. 68 68
      src/main/java/com/mooctest/listener/SaveEventListener.java
  70. 31 31
      src/main/java/com/mooctest/model/AggTaskStatus.java
  71. 49 47
      src/main/java/com/mooctest/model/Bug.java
  72. 64 0
      src/main/java/com/mooctest/model/BugHistory.java
  73. 177 0
      src/main/java/com/mooctest/model/BugMirror.java
  74. 80 0
      src/main/java/com/mooctest/model/BugPage.java
  75. 51 0
      src/main/java/com/mooctest/model/BugScore.java
  76. 65 0
      src/main/java/com/mooctest/model/CaseToBug.java
  77. 52 52
      src/main/java/com/mooctest/model/FinalReport.java
  78. 52 0
      src/main/java/com/mooctest/model/KeyWords.java
  79. 34 34
      src/main/java/com/mooctest/model/MasterReport.java
  80. 20 20
      src/main/java/com/mooctest/model/SequenceId.java
  81. 53 0
      src/main/java/com/mooctest/model/StuInfo.java
  82. 34 34
      src/main/java/com/mooctest/model/SupplementItem.java
  83. 20 20
      src/main/java/com/mooctest/model/Task.java
  84. 104 104
      src/main/java/com/mooctest/nlp/DistanceMatrix.java
  85. 57 57
      src/main/java/com/mooctest/service/AggTaskStatusService.java
  86. 179 179
      src/main/java/com/mooctest/service/AggregationService.java
  87. 326 0
      src/main/java/com/mooctest/service/AnalyzeService.java
  88. 10 10
      src/main/java/com/mooctest/service/BugHistoryService.java
  89. 17 17
      src/main/java/com/mooctest/service/BugReportService.java
  90. 38 38
      src/main/java/com/mooctest/service/BugReviewService.java
  91. 124 124
      src/main/java/com/mooctest/service/DiffImgService.java
  92. 146 146
      src/main/java/com/mooctest/service/DiffTextService.java
  93. 152 152
      src/main/java/com/mooctest/service/FinalReportService.java
  94. 167 167
      src/main/java/com/mooctest/service/GraphService.java
  95. 189 0
      src/main/java/com/mooctest/service/HistoryService.java
  96. 129 129
      src/main/java/com/mooctest/service/MasterReportService.java
  97. 434 0
      src/main/java/com/mooctest/service/RecommendService.java
  98. 308 308
      src/main/java/com/mooctest/service/SupplementService.java
  99. 103 103
      src/main/java/com/mooctest/service/TaskService.java
  100. 45 45
      src/main/java/com/mooctest/service/impl/BugHistoryServiceImpl.java

+ 28 - 28
.gitignore

@@ -1,28 +1,28 @@
-*.class
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.ear
-
-#Gradle temporary files
-target/
-
-#Eclipse files
-**/.project
-**/.classpath
-**/.settings/
-blog/bin/
-**/.tern-project
-
-#IntelliJ files
-**/*.iml
-**/.idea
-**/.gradle
-
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+#Gradle temporary files
+target/
+
+#Eclipse files
+**/.project
+**/.classpath
+**/.settings/
+blog/bin/
+**/.tern-project
+
+#IntelliJ files
+**/*.iml
+**/.idea
+**/.gradle
+
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*

+ 12 - 12
.idea/compiler.xml

@@ -1,13 +1,13 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <annotationProcessing>
-      <profile name="Maven default annotation processors profile" enabled="true">
-        <sourceOutputDir name="target/generated-sources/annotations" />
-        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
-        <outputRelativeToContentRoot value="true" />
-        <module name="crowd_review" />
-      </profile>
-    </annotationProcessing>
-  </component>
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="crowd_review" />
+      </profile>
+    </annotationProcessing>
+  </component>
 </project>

+ 5 - 5
.idea/encodings.xml

@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="Encoding">
-    <file url="file://$PROJECT_DIR$" charset="UTF-8" />
-  </component>
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$" charset="UTF-8" />
+  </component>
 </project>

+ 14 - 14
.idea/inspectionProfiles/Project_Default.xml

@@ -1,15 +1,15 @@
-<component name="InspectionProjectProfileManager">
-  <profile version="1.0">
-    <option name="myName" value="Project Default" />
-    <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
-      <option name="myValues">
-        <value>
-          <list size="1">
-            <item index="0" class="java.lang.String" itemvalue="th:text" />
-          </list>
-        </value>
-      </option>
-      <option name="myCustomValuesEnabled" value="true" />
-    </inspection_tool>
-  </profile>
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="myValues">
+        <value>
+          <list size="1">
+            <item index="0" class="java.lang.String" itemvalue="th:text" />
+          </list>
+        </value>
+      </option>
+      <option name="myCustomValuesEnabled" value="true" />
+    </inspection_tool>
+  </profile>
 </component>

+ 16 - 16
.idea/misc.xml

@@ -1,17 +1,17 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ExternalStorageConfigurationManager" enabled="true" />
-  <component name="JavaScriptSettings">
-    <option name="languageLevel" value="ES6" />
-  </component>
-  <component name="MavenProjectsManager">
-    <option name="originalFiles">
-      <list>
-        <option value="$PROJECT_DIR$/pom.xml" />
-      </list>
-    </option>
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_3" project-jdk-name="1.8" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
-  </component>
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="ES6" />
+  </component>
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
 </project>

+ 123 - 123
.idea/uiDesigner.xml

@@ -1,124 +1,124 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="Palette2">
-    <group name="Swing">
-      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
-      </item>
-      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
-      </item>
-      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
-      </item>
-      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
-        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
-      </item>
-      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
-        <initial-values>
-          <property name="text" value="Button" />
-        </initial-values>
-      </item>
-      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
-        <initial-values>
-          <property name="text" value="RadioButton" />
-        </initial-values>
-      </item>
-      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
-        <initial-values>
-          <property name="text" value="CheckBox" />
-        </initial-values>
-      </item>
-      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
-        <initial-values>
-          <property name="text" value="Label" />
-        </initial-values>
-      </item>
-      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
-          <preferred-size width="150" height="-1" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
-          <preferred-size width="150" height="-1" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
-          <preferred-size width="150" height="-1" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
-      </item>
-      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
-          <preferred-size width="150" height="50" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
-          <preferred-size width="200" height="200" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
-          <preferred-size width="200" height="200" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
-      </item>
-      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
-      </item>
-      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
-      </item>
-      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
-      </item>
-      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
-          <preferred-size width="-1" height="20" />
-        </default-constraints>
-      </item>
-      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
-        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
-      </item>
-      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
-        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
-      </item>
-    </group>
-  </component>
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
 </project>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 396
.idea/workspace.xml


+ 7 - 7
Dockerfile

@@ -1,7 +1,7 @@
-FROM openjdk:8-jdk-alpine
-ADD ./deploy.sh /project/
-RUN chmod 777 /project/deploy.sh
-RUN wget -c -P /project/ http://third-part-tool.oss-cn-shanghai.aliyuncs.com/sgns.wiki.word.zip
-ADD ./target/crowd_review-1.0-SNAPSHOT.jar /project/crowd_review.jar
-EXPOSE 8090
-ENTRYPOINT ["/project/deploy.sh"]
+FROM openjdk:8-jdk-alpine
+ADD ./deploy.sh /project/
+RUN chmod 777 /project/deploy.sh
+RUN wget -c -P /project/ http://third-part-tool.oss-cn-shanghai.aliyuncs.com/sgns.wiki.word.zip
+ADD ./target/crowd_review-1.0-SNAPSHOT.jar /project/crowd_review.jar
+EXPOSE 8090
+ENTRYPOINT ["/project/deploy.sh"]

+ 8 - 8
build-run.sh

@@ -1,9 +1,9 @@
-#!/bin/sh
-mvn clean package
-
-docker build -t crowd_review:0.2 .
-
-docker run --name crowd_review --rm -it -v /Users/major/development/crowd_review/deploy.sh:/project/deploy.sh -p 8090:8090 -e MONGODB_REVIEW_DB=crowd_review -e MONGODB_REVIEW_HOST=host.docker.internal -e MONGODB_REVIEW_PORT=27017 -e MONGODB_REPORT_DB=co-report -e MONGODB_REPORT_HOST=host.docker.internal -e MONGODB_REPORT_PORT=27017 -e EXPORT_ADDR=http://182.254.197.194:9002/generateReport crowd_review:0.2 /bin/sh
-
-
+#!/bin/sh
+mvn clean package
+
+docker build -t crowd_review:0.2 .
+
+docker run --name crowd_review --rm -it -v /Users/major/development/crowd_review/deploy.sh:/project/deploy.sh -p 8090:8090 -e MONGODB_REVIEW_DB=crowd_review -e MONGODB_REVIEW_HOST=host.docker.internal -e MONGODB_REVIEW_PORT=27017 -e MONGODB_REPORT_DB=co-report -e MONGODB_REPORT_HOST=host.docker.internal -e MONGODB_REPORT_PORT=27017 -e EXPORT_ADDR=http://182.254.197.194:9002/generateReport crowd_review:0.2 /bin/sh
+
+
 docker run --name crowd_review --rm -it -v /root/moooc_review/deploy.sh:/project/deploy.sh -p 80:8090 -e MONGODB_REVIEW_DB=crowd_review -e MONGODB_REVIEW_HOST=10.81.65.118 -e MONGODB_REVIEW_PORT=29019 -e MONGODB_REPORT_DB=co-report -e MONGODB_REPORT_HOST=10.81.65.118 -e MONGODB_REPORT_PORT=29019 -e EXPORT_ADDR=http://47.99.140.117:9002/generateReport -e TASK_ADDR=http://47.99.140.117:9001/Bug/api/extra/getExamList crowd_review:0.2 /bin/sh

+ 0 - 2
crowd_review.iml

@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4" />

+ 4 - 4
deploy.sh

@@ -1,4 +1,4 @@
-#!/bin/sh
-unzip -o /project/sgns.wiki.word.zip -d /project/
-
-java -Djava.security.egd=file:/dev/./urandom -Xms800m -Xmx1g -jar -Dspring.profiles.active=test /project/crowd_review.jar
+#!/bin/sh
+unzip -o /project/sgns.wiki.word.zip -d /project/
+
+java -Djava.security.egd=file:/dev/./urandom -Xms800m -Xmx1g -jar -Dspring.profiles.active=test /project/crowd_review.jar

+ 167 - 158
pom.xml

@@ -1,159 +1,168 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>1.5.7.RELEASE</version>
-    </parent>
-
-    <groupId>com.mooctest</groupId>
-    <artifactId>crowd_review</artifactId>
-    <version>1.0-SNAPSHOT</version>
-
-    <properties>
-        <jackson.version>2.9.5</jackson.version>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
-        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.build.locales>zh_CN</project.build.locales>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-thymeleaf</artifactId>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.github.haifengl</groupId>
-            <artifactId>smile-core</artifactId>
-            <version>1.5.2</version>
-        </dependency>
-        <dependency>
-            <groupId>com.github.haifengl</groupId>
-            <artifactId>smile-netlib</artifactId>
-            <version>1.5.2</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-            <version>1.2.47</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-configuration-processor</artifactId>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <version>1.18.6</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.fasterxml.jackson.dataformat</groupId>
-            <artifactId>jackson-dataformat-yaml</artifactId>
-            <version>2.6.3</version>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.jgrapht/jgrapht-core -->
-        <dependency>
-            <groupId>org.jgrapht</groupId>
-            <artifactId>jgrapht-core</artifactId>
-            <version>1.3.0</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.hankcs</groupId>
-            <artifactId>hanlp</artifactId>
-            <version>portable-1.7.0</version>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/com.github.zengde/lire -->
-        <dependency>
-            <groupId>com.github.zengde</groupId>
-            <artifactId>lire</artifactId>
-            <version>1.0b2</version>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-collections4</artifactId>
-            <version>4.2</version>
-        </dependency>
-
-
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-thymeleaf</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-configuration-processor</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-            <version>19.0</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-mongodb</artifactId>
-        </dependency>
-
-
-
-    </dependencies>
-
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>1.8</source>
-                    <target>1.8</target>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-deploy-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-
-            </plugin>
-        </plugins>
-    </build>
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>1.5.7.RELEASE</version>
+    </parent>
+
+    <groupId>com.mooctest</groupId>
+    <artifactId>crowd_review</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <jackson.version>2.9.5</jackson.version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.build.locales>zh_CN</project.build.locales>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20180130</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.haifengl</groupId>
+            <artifactId>smile-core</artifactId>
+            <version>1.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.haifengl</groupId>
+            <artifactId>smile-netlib</artifactId>
+            <version>1.5.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.47</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.6</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
+            <version>2.6.3</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.jgrapht/jgrapht-core -->
+        <dependency>
+            <groupId>org.jgrapht</groupId>
+            <artifactId>jgrapht-core</artifactId>
+            <version>1.3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.hankcs</groupId>
+            <artifactId>hanlp</artifactId>
+            <version>portable-1.7.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.ansj</groupId>
+            <artifactId>ansj_seg</artifactId>
+            <version>5.1.1</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.github.zengde/lire -->
+        <dependency>
+            <groupId>com.github.zengde</groupId>
+            <artifactId>lire</artifactId>
+            <version>1.0b2</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.2</version>
+        </dependency>
+
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>19.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
+
+
+    </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+
+            </plugin>
+        </plugins>
+    </build>
 </project>

+ 24 - 24
src/main/java/com/mooctest/CrowdReviewApplication.java

@@ -1,24 +1,24 @@
-package com.mooctest;
-
-import com.mooctest.util.Doc2VecUtil;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.boot.web.support.SpringBootServletInitializer;
-import org.springframework.scheduling.annotation.EnableAsync;
-
-@SpringBootApplication
-@ServletComponentScan
-@EnableAsync
-public class CrowdReviewApplication extends SpringBootServletInitializer {
-    public static void main(String[] args) {
-        SpringApplication.run(CrowdReviewApplication.class, args);
-        Doc2VecUtil.loadModel();
-    }
-
-    @Override
-    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
-        return application.sources(CrowdReviewApplication.class);
-    }
-}
+package com.mooctest;
+
+import com.mooctest.util.Doc2VecUtil;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@SpringBootApplication
+@ServletComponentScan
+@EnableAsync
+public class CrowdReviewApplication extends SpringBootServletInitializer {
+    public static void main(String[] args) {
+        SpringApplication.run(CrowdReviewApplication.class, args);
+        Doc2VecUtil.loadModel();
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(CrowdReviewApplication.class);
+    }
+}

+ 18 - 18
src/main/java/com/mooctest/annotation/AutoValue.java

@@ -1,18 +1,18 @@
-package com.mooctest.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 自定义自增长ID注解
- *
- * @author xq
- *
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.FIELD })
-public @interface AutoValue {
-
-}
+package com.mooctest.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义自增长ID注解
+ *
+ * @author xq
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD })
+public @interface AutoValue {
+
+}

+ 317 - 317
src/main/java/com/mooctest/cluster/Cluster.java

@@ -1,317 +1,317 @@
-package com.mooctest.cluster;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Random;
-
-public class Cluster<K> implements Comparable< Cluster<K>>
-{
-    List<Document<K>> documents_;          ///< documents
-    SparseVector composite_;                           ///< a composite SparseVector
-    SparseVector centroid_;                            ///< a centroid SparseVector
-    List< Cluster<K>> sectioned_clusters_;  ///< sectioned clusters
-    double sectioned_gain_;                      ///< a sectioned gain
-    Random random;
-
-    public Cluster()
-    {
-        this(new ArrayList<Document<K>>());
-    }
-
-    public Cluster(List<Document<K>> documents)
-    {
-        this.documents_ = documents;
-        composite_ = new SparseVector();
-        random = new Random();
-    }
-
-    /**
-     * Add the vectors of all documents to a composite vector.
-     */
-    void set_composite_vector()
-    {
-        composite_.clear();
-        for (Document<K> document : documents_)
-        {
-            composite_.add_vector(document.feature());
-        }
-    }
-
-    /**
-     * Clear status.
-     */
-    void clear()
-    {
-        documents_.clear();
-        composite_.clear();
-        if (centroid_ != null)
-            centroid_.clear();
-        if (sectioned_clusters_ != null)
-            sectioned_clusters_.clear();
-        sectioned_gain_ = 0.0;
-    }
-
-
-    /**
-     * Get the size.
-     *
-     * @return the size of this cluster
-     */
-    int size()
-    {
-        return documents_.size();
-    }
-
-    /**
-     * Get the pointer of a centroid vector.
-     *
-     * @return the pointer of a centroid vector
-     */
-    SparseVector centroid_vector()
-    {
-        if (documents_.size() > 0 && composite_.size() == 0)
-            set_composite_vector();
-        centroid_ = (SparseVector) composite_vector().clone();
-        centroid_.normalize();
-        return centroid_;
-    }
-
-    /**
-     * Get the pointer of a composite vector.
-     *
-     * @return the pointer of a composite vector
-     */
-    SparseVector composite_vector()
-    {
-        return composite_;
-    }
-
-    /**
-     * Get documents in this cluster.
-     *
-     * @return documents in this cluster
-     */
-    List<Document<K>> documents()
-    {
-        return documents_;
-    }
-
-    /**
-     * Add a document.
-     *
-     * @param doc the pointer of a document object
-     */
-    void add_document(Document doc)
-    {
-        doc.feature().normalize();
-        documents_.add(doc);
-        composite_.add_vector(doc.feature());
-    }
-
-    /**
-     * Remove a document from this cluster.
-     *
-     * @param index the index of vector container of documents
-     */
-    void remove_document(int index)
-    {
-        ListIterator<Document<K>> listIterator = documents_.listIterator(index);
-        Document<K> document = listIterator.next();
-        listIterator.set(null);
-        composite_.sub_vector(document.feature());
-    }
-
-    /**
-     * Remove a document from this cluster.
-     *
-     * @param doc the pointer of a document object
-     */
-    void remove_document(Document doc)
-    {
-        for (Document<K> document : documents_)
-        {
-            if (document.equals(doc))
-            {
-                remove_document(doc);
-                return;
-            }
-        }
-    }
-
-
-    /**
-     * Delete removed documents from the internal container.
-     */
-    void refresh()
-    {
-        ListIterator<Document<K>> listIterator = documents_.listIterator();
-        while (listIterator.hasNext())
-        {
-            if (listIterator.next() == null)
-                listIterator.remove();
-        }
-    }
-
-    /**
-     * Get a gain when this cluster sectioned.
-     *
-     * @return a gain
-     */
-    double sectioned_gain()
-    {
-        return sectioned_gain_;
-    }
-
-    /**
-     * Set a gain when the cluster sectioned.
-     */
-    void set_sectioned_gain()
-    {
-        double gain = 0.0f;
-        if (sectioned_gain_ == 0 && sectioned_clusters_.size() > 1)
-        {
-            for ( Cluster<K> cluster : sectioned_clusters_)
-            {
-                gain += cluster.composite_vector().norm();
-            }
-            gain -= composite_.norm();
-        }
-        sectioned_gain_ = gain;
-    }
-
-    /**
-     * Get sectioned clusters.
-     *
-     * @return sectioned clusters
-     */
-    List< Cluster<K>> sectioned_clusters()
-    {
-        return sectioned_clusters_;
-    }
-
-//    /**
-//     * Choose documents randomly.
-//     */
-//    void choose_randomly(int ndocs, List<Document > docs)
-//{
-//    HashMap<int, bool>.type choosed;
-//    int siz = size();
-//    init_hash_map(siz, choosed, ndocs);
-//    if (siz < ndocs)
-//        ndocs = siz;
-//    int count = 0;
-//    while (count < ndocs)
-//    {
-//        int index = myrand(seed_) % siz;
-//        if (choosed.find(index) == choosed.end())
-//        {
-//            choosed.insert(std.pair<int, bool>(index, true));
-//            docs.push_back(documents_[index]);
-//            ++count;
-//        }
-//    }
-//}
-
-    /**
-     * 选取初始质心
-     *
-     * @param ndocs 质心数量
-     * @param docs  输出到该列表中
-     */
-    void choose_smartly(int ndocs, List<Document> docs)
-    {
-        int siz = size();
-        double[] closest = new double[siz];
-        if (siz < ndocs)
-            ndocs = siz;
-        int index, count = 0;
-
-        index = random.nextInt(siz);  // initial center
-        docs.add(documents_.get(index));
-        ++count;
-        double potential = 0.0;
-        for (int i = 0; i < documents_.size(); i++)
-        {
-            double dist = 1.0 - SparseVector.inner_product(documents_.get(i).feature(), documents_.get(index).feature());
-            potential += dist;
-            closest[i] = dist;
-        }
-
-        // choose each center
-        while (count < ndocs)
-        {
-            double randval = random.nextDouble() * potential;
-
-            for (index = 0; index < documents_.size(); index++)
-            {
-                double dist = closest[index];
-                if (randval <= dist)
-                    break;
-                randval -= dist;
-            }
-            if (index == documents_.size())
-                index--;
-            docs.add(documents_.get(index));
-            ++count;
-
-            double new_potential = 0.0;
-            for (int i = 0; i < documents_.size(); i++)
-            {
-                double dist = 1.0 - SparseVector.inner_product(documents_.get(i).feature(), documents_.get(index).feature());
-                double min = closest[i];
-                if (dist < min)
-                {
-                    closest[i] = dist;
-                    min = dist;
-                }
-                new_potential += min;
-            }
-            potential = new_potential;
-        }
-    }
-
-    /**
-     * 将本簇划分为nclusters个簇
-     *
-     * @param nclusters
-     */
-    void section(int nclusters)
-    {
-        if (size() < nclusters)
-            return;
-
-        sectioned_clusters_ = new ArrayList< Cluster<K>>(nclusters);
-        List<Document> centroids = new ArrayList<Document>(nclusters);
-        // choose_randomly(nclusters, centroids);
-        choose_smartly(nclusters, centroids);
-        for (int i = 0; i < centroids.size(); i++)
-        {
-             Cluster<K> cluster = new  Cluster<K>();
-            sectioned_clusters_.add(cluster);
-        }
-
-        for (Document<K> d : documents_)
-        {
-            double max_similarity = -1.0;
-            int max_index = 0;
-            for (int j = 0; j < centroids.size(); j++)
-            {
-                double similarity = SparseVector.inner_product(d.feature(), centroids.get(j).feature());
-                if (max_similarity < similarity)
-                {
-                    max_similarity = similarity;
-                    max_index = j;
-                }
-            }
-            sectioned_clusters_.get(max_index).add_document(d);
-        }
-    }
-
-    @Override
-    public int compareTo( Cluster<K> o)
-    {
-        return Double.compare(o.sectioned_gain(), sectioned_gain());
-    }
-}
-
+package com.mooctest.cluster;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Random;
+
+public class Cluster<K> implements Comparable< Cluster<K>>
+{
+    List<Document<K>> documents_;          ///< documents
+    SparseVector composite_;                           ///< a composite SparseVector
+    SparseVector centroid_;                            ///< a centroid SparseVector
+    List< Cluster<K>> sectioned_clusters_;  ///< sectioned clusters
+    double sectioned_gain_;                      ///< a sectioned gain
+    Random random;
+
+    public Cluster()
+    {
+        this(new ArrayList<Document<K>>());
+    }
+
+    public Cluster(List<Document<K>> documents)
+    {
+        this.documents_ = documents;
+        composite_ = new SparseVector();
+        random = new Random();
+    }
+
+    /**
+     * Add the vectors of all documents to a composite vector.
+     */
+    void set_composite_vector()
+    {
+        composite_.clear();
+        for (Document<K> document : documents_)
+        {
+            composite_.add_vector(document.feature());
+        }
+    }
+
+    /**
+     * Clear status.
+     */
+    void clear()
+    {
+        documents_.clear();
+        composite_.clear();
+        if (centroid_ != null)
+            centroid_.clear();
+        if (sectioned_clusters_ != null)
+            sectioned_clusters_.clear();
+        sectioned_gain_ = 0.0;
+    }
+
+
+    /**
+     * Get the size.
+     *
+     * @return the size of this cluster
+     */
+    int size()
+    {
+        return documents_.size();
+    }
+
+    /**
+     * Get the pointer of a centroid vector.
+     *
+     * @return the pointer of a centroid vector
+     */
+    SparseVector centroid_vector()
+    {
+        if (documents_.size() > 0 && composite_.size() == 0)
+            set_composite_vector();
+        centroid_ = (SparseVector) composite_vector().clone();
+        centroid_.normalize();
+        return centroid_;
+    }
+
+    /**
+     * Get the pointer of a composite vector.
+     *
+     * @return the pointer of a composite vector
+     */
+    SparseVector composite_vector()
+    {
+        return composite_;
+    }
+
+    /**
+     * Get documents in this cluster.
+     *
+     * @return documents in this cluster
+     */
+    List<Document<K>> documents()
+    {
+        return documents_;
+    }
+
+    /**
+     * Add a document.
+     *
+     * @param doc the pointer of a document object
+     */
+    void add_document(Document doc)
+    {
+        doc.feature().normalize();
+        documents_.add(doc);
+        composite_.add_vector(doc.feature());
+    }
+
+    /**
+     * Remove a document from this cluster.
+     *
+     * @param index the index of vector container of documents
+     */
+    void remove_document(int index)
+    {
+        ListIterator<Document<K>> listIterator = documents_.listIterator(index);
+        Document<K> document = listIterator.next();
+        listIterator.set(null);
+        composite_.sub_vector(document.feature());
+    }
+
+    /**
+     * Remove a document from this cluster.
+     *
+     * @param doc the pointer of a document object
+     */
+    void remove_document(Document doc)
+    {
+        for (Document<K> document : documents_)
+        {
+            if (document.equals(doc))
+            {
+                remove_document(doc);
+                return;
+            }
+        }
+    }
+
+
+    /**
+     * Delete removed documents from the internal container.
+     */
+    void refresh()
+    {
+        ListIterator<Document<K>> listIterator = documents_.listIterator();
+        while (listIterator.hasNext())
+        {
+            if (listIterator.next() == null)
+                listIterator.remove();
+        }
+    }
+
+    /**
+     * Get a gain when this cluster sectioned.
+     *
+     * @return a gain
+     */
+    double sectioned_gain()
+    {
+        return sectioned_gain_;
+    }
+
+    /**
+     * Set a gain when the cluster sectioned.
+     */
+    void set_sectioned_gain()
+    {
+        double gain = 0.0f;
+        if (sectioned_gain_ == 0 && sectioned_clusters_.size() > 1)
+        {
+            for ( Cluster<K> cluster : sectioned_clusters_)
+            {
+                gain += cluster.composite_vector().norm();
+            }
+            gain -= composite_.norm();
+        }
+        sectioned_gain_ = gain;
+    }
+
+    /**
+     * Get sectioned clusters.
+     *
+     * @return sectioned clusters
+     */
+    List< Cluster<K>> sectioned_clusters()
+    {
+        return sectioned_clusters_;
+    }
+
+//    /**
+//     * Choose documents randomly.
+//     */
+//    void choose_randomly(int ndocs, List<Document > docs)
+//{
+//    HashMap<int, bool>.type choosed;
+//    int siz = size();
+//    init_hash_map(siz, choosed, ndocs);
+//    if (siz < ndocs)
+//        ndocs = siz;
+//    int count = 0;
+//    while (count < ndocs)
+//    {
+//        int index = myrand(seed_) % siz;
+//        if (choosed.find(index) == choosed.end())
+//        {
+//            choosed.insert(std.pair<int, bool>(index, true));
+//            docs.push_back(documents_[index]);
+//            ++count;
+//        }
+//    }
+//}
+
+    /**
+     * 选取初始质心
+     *
+     * @param ndocs 质心数量
+     * @param docs  输出到该列表中
+     */
+    void choose_smartly(int ndocs, List<Document> docs)
+    {
+        int siz = size();
+        double[] closest = new double[siz];
+        if (siz < ndocs)
+            ndocs = siz;
+        int index, count = 0;
+
+        index = random.nextInt(siz);  // initial center
+        docs.add(documents_.get(index));
+        ++count;
+        double potential = 0.0;
+        for (int i = 0; i < documents_.size(); i++)
+        {
+            double dist = 1.0 - SparseVector.inner_product(documents_.get(i).feature(), documents_.get(index).feature());
+            potential += dist;
+            closest[i] = dist;
+        }
+
+        // choose each center
+        while (count < ndocs)
+        {
+            double randval = random.nextDouble() * potential;
+
+            for (index = 0; index < documents_.size(); index++)
+            {
+                double dist = closest[index];
+                if (randval <= dist)
+                    break;
+                randval -= dist;
+            }
+            if (index == documents_.size())
+                index--;
+            docs.add(documents_.get(index));
+            ++count;
+
+            double new_potential = 0.0;
+            for (int i = 0; i < documents_.size(); i++)
+            {
+                double dist = 1.0 - SparseVector.inner_product(documents_.get(i).feature(), documents_.get(index).feature());
+                double min = closest[i];
+                if (dist < min)
+                {
+                    closest[i] = dist;
+                    min = dist;
+                }
+                new_potential += min;
+            }
+            potential = new_potential;
+        }
+    }
+
+    /**
+     * 将本簇划分为nclusters个簇
+     *
+     * @param nclusters
+     */
+    void section(int nclusters)
+    {
+        if (size() < nclusters)
+            return;
+
+        sectioned_clusters_ = new ArrayList< Cluster<K>>(nclusters);
+        List<Document> centroids = new ArrayList<Document>(nclusters);
+        // choose_randomly(nclusters, centroids);
+        choose_smartly(nclusters, centroids);
+        for (int i = 0; i < centroids.size(); i++)
+        {
+             Cluster<K> cluster = new  Cluster<K>();
+            sectioned_clusters_.add(cluster);
+        }
+
+        for (Document<K> d : documents_)
+        {
+            double max_similarity = -1.0;
+            int max_index = 0;
+            for (int j = 0; j < centroids.size(); j++)
+            {
+                double similarity = SparseVector.inner_product(d.feature(), centroids.get(j).feature());
+                if (max_similarity < similarity)
+                {
+                    max_similarity = similarity;
+                    max_index = j;
+                }
+            }
+            sectioned_clusters_.get(max_index).add_document(d);
+        }
+    }
+
+    @Override
+    public int compareTo( Cluster<K> o)
+    {
+        return Double.compare(o.sectioned_gain(), sectioned_gain());
+    }
+}
+

+ 110 - 110
src/main/java/com/mooctest/cluster/ClusterAnalyzer.java

@@ -1,110 +1,110 @@
-package com.mooctest.cluster;
-
-import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
-import com.hankcs.hanlp.mining.word2vec.WordVectorModel;
-import com.mooctest.data.BugDTO;
-import lombok.Getter;
-import smile.clustering.GMeans;
-import smile.clustering.HierarchicalClustering;
-import smile.clustering.MEC;
-import smile.clustering.SIB;
-import smile.clustering.linkage.WardLinkage;
-import smile.math.distance.EuclideanDistance;
-
-import java.io.IOException;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Getter
-public class ClusterAnalyzer<K> {
-
-    protected Map<K, Doc<K>> documents;
-    protected List<K> idList;
-
-    public ClusterAnalyzer() {
-        documents = new HashMap<>();
-        idList = new ArrayList<>();
-    }
-    public List<Set<K>> HAC(double[][] distMatrix, List<K> ids, double h) {
-        idList = ids;
-        HierarchicalClustering hc = new HierarchicalClustering(new WardLinkage(distMatrix));
-        int[] labels = hc.partition(h);
-        return genClusters(labels);
-    }
-
-    public List<Set<K>> gmeans(List<BugDTO> bugs) throws IOException {
-        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
-        double[][] data = new double[bugs.size()][];
-        for (int i = 0; i < bugs.size(); i++) {
-            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
-            data[i] = convertFloatsToDoubles(vec);
-        }
-
-        GMeans gMeans = new GMeans(data, bugs.size() / 2);
-        int[] labels = gMeans.getClusterLabel();
-        return genClusters(labels);
-    }
-
-    public List<Set<K>> sib(List<BugDTO> bugs) throws IOException {
-        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
-        double[][] data = new double[bugs.size()][];
-        for (int i = 0; i < bugs.size(); i++) {
-            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
-            data[i] = convertFloatsToDoubles(vec);
-        }
-
-        SIB sib = new SIB(data, 65);
-        int[] labels = sib.getClusterLabel();
-        return genClusters(labels);
-    }
-
-    public List<Set<K>> mec(List<BugDTO> bugs) throws IOException {
-        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
-        double[][] data = new double[bugs.size()][];
-        for (int i = 0; i < bugs.size(); i++) {
-            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
-            data[i] = convertFloatsToDoubles(vec);
-        }
-
-        MEC mec = new MEC(data, new EuclideanDistance(),65, 1.0);
-        int[] labels = mec.getClusterLabel();
-        return genClusters(labels);
-    }
-
-    public static double[] convertFloatsToDoubles(float[] input)
-    {
-        if (input == null)
-        {
-            return null; // Or throw an exception - your choice
-        }
-        double[] output = new double[input.length];
-        for (int i = 0; i < input.length; i++)
-        {
-            output[i] = input[i];
-        }
-        return output;
-    }
-
-    private List<Set<K>> genClusters(int[] labels) {
-        Map<Integer, Set<K>> groupSet = new HashMap<>();
-        for (int i = 0; i < labels.length; i++) {
-            int clusterId = labels[i];
-            if (groupSet.get(clusterId) == null) {
-                Set<K> cluster = new HashSet<>();
-                cluster.add(idList.get(i));
-                groupSet.put(clusterId, cluster);
-            } else {
-                groupSet.get(clusterId).add(idList.get(i));
-            }
-        }
-        return groupSet.entrySet().stream()
-                .map(entry -> entry.getValue())
-                .collect(Collectors.toList());
-    }
-
-    public void addDocument(K id, String document) {
-        Doc<K> doc= new Doc<>(id, document);
-        documents.put(id, doc);
-        idList.add(id);
-    }
-}
+package com.mooctest.cluster;
+
+import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
+import com.hankcs.hanlp.mining.word2vec.WordVectorModel;
+import com.mooctest.data.BugDTO;
+import lombok.Getter;
+import smile.clustering.GMeans;
+import smile.clustering.HierarchicalClustering;
+import smile.clustering.MEC;
+import smile.clustering.SIB;
+import smile.clustering.linkage.WardLinkage;
+import smile.math.distance.EuclideanDistance;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Getter
+public class ClusterAnalyzer<K> {
+
+    protected Map<K, Doc<K>> documents;
+    protected List<K> idList;
+
+    public ClusterAnalyzer() {
+        documents = new HashMap<>();
+        idList = new ArrayList<>();
+    }
+    public List<Set<K>> HAC(double[][] distMatrix, List<K> ids, double h) {
+        idList = ids;
+        HierarchicalClustering hc = new HierarchicalClustering(new WardLinkage(distMatrix));
+        int[] labels = hc.partition(h);
+        return genClusters(labels);
+    }
+
+    public List<Set<K>> gmeans(List<BugDTO> bugs) throws IOException {
+        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
+        double[][] data = new double[bugs.size()][];
+        for (int i = 0; i < bugs.size(); i++) {
+            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
+            data[i] = convertFloatsToDoubles(vec);
+        }
+
+        GMeans gMeans = new GMeans(data, bugs.size() / 2);
+        int[] labels = gMeans.getClusterLabel();
+        return genClusters(labels);
+    }
+
+    public List<Set<K>> sib(List<BugDTO> bugs) throws IOException {
+        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
+        double[][] data = new double[bugs.size()][];
+        for (int i = 0; i < bugs.size(); i++) {
+            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
+            data[i] = convertFloatsToDoubles(vec);
+        }
+
+        SIB sib = new SIB(data, 65);
+        int[] labels = sib.getClusterLabel();
+        return genClusters(labels);
+    }
+
+    public List<Set<K>> mec(List<BugDTO> bugs) throws IOException {
+        DocVectorModel docVectorModel2 = new DocVectorModel(new WordVectorModel("/Users/major/Downloads/sgns.wiki.word"));
+        double[][] data = new double[bugs.size()][];
+        for (int i = 0; i < bugs.size(); i++) {
+            float[] vec = docVectorModel2.query(bugs.get(i).getDescription()).getElementArray();
+            data[i] = convertFloatsToDoubles(vec);
+        }
+
+        MEC mec = new MEC(data, new EuclideanDistance(),65, 1.0);
+        int[] labels = mec.getClusterLabel();
+        return genClusters(labels);
+    }
+
+    public static double[] convertFloatsToDoubles(float[] input)
+    {
+        if (input == null)
+        {
+            return null; // Or throw an exception - your choice
+        }
+        double[] output = new double[input.length];
+        for (int i = 0; i < input.length; i++)
+        {
+            output[i] = input[i];
+        }
+        return output;
+    }
+
+    private List<Set<K>> genClusters(int[] labels) {
+        Map<Integer, Set<K>> groupSet = new HashMap<>();
+        for (int i = 0; i < labels.length; i++) {
+            int clusterId = labels[i];
+            if (groupSet.get(clusterId) == null) {
+                Set<K> cluster = new HashSet<>();
+                cluster.add(idList.get(i));
+                groupSet.put(clusterId, cluster);
+            } else {
+                groupSet.get(clusterId).add(idList.get(i));
+            }
+        }
+        return groupSet.entrySet().stream()
+                .map(entry -> entry.getValue())
+                .collect(Collectors.toList());
+    }
+
+    public void addDocument(K id, String document) {
+        Doc<K> doc= new Doc<>(id, document);
+        documents.put(id, doc);
+        idList.add(id);
+    }
+}

+ 13 - 13
src/main/java/com/mooctest/cluster/Doc.java

@@ -1,13 +1,13 @@
-package com.mooctest.cluster;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class Doc<K> {
-    private K id;
-    private String text;
-}
+package com.mooctest.cluster;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Doc<K> {
+    private K id;
+    private String text;
+}

+ 114 - 114
src/main/java/com/mooctest/cluster/Document.java

@@ -1,114 +1,114 @@
-package com.mooctest.cluster;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class Document<K>
-{
-    K id_;    /// the identifier of a document
-
-    SparseVector feature;  /// feature vector of a document
-
-    public K getId_() {
-        return id_;
-    }
-
-    public SparseVector getFeature() {
-        return feature;
-    }
-
-    public Document(K id_, SparseVector feature_)
-    {
-        this.id_ = id_;
-        this.feature = feature_;
-    }
-
-    public Document(K id_)
-    {
-        this(id_, new SparseVector());
-    }
-
-    /**
-     * Get an identifier.
-     *
-     * @return an identifier
-     */
-    K id()
-    {
-        return id_;
-    }
-
-    /**
-     * Get the pointer of a feature vector
-     *
-     * @return the pointer of a feature vector
-     */
-    SparseVector feature()
-    {
-        return feature;
-    }
-
-
-    /**
-     * Add a feature.
-     *
-     * @param key   the key of a feature
-     * @param value the value of a feature
-     */
-    void add_feature(int key, double value)
-    {
-        feature.put(key, value);
-    }
-
-    /**
-     * Set features.
-     *
-     * @param feature a feature vector
-     */
-    void set_features(SparseVector feature)
-    {
-        this.feature = feature;
-    }
-
-    /**
-     * Clear features.
-     */
-    void clear()
-    {
-        feature.clear();
-    }
-
-    /**
-     * Apply IDF(inverse document frequency) weighting.
-     *
-     * @param df    document frequencies
-     * @param ndocs the number of documents
-     */
-    void idf(HashMap<Integer, Integer> df, int ndocs)
-    {
-        for (Map.Entry<Integer, Double> entry : feature.entrySet())
-        {
-            Integer denom = df.get(entry.getKey());
-            if (denom == null) denom = 1;
-            entry.setValue((double) (entry.getValue() * Math.log(ndocs / denom)));
-        }
-    }
-
-    @Override
-    public boolean equals(Object o)
-    {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Document<?> document = (Document<?>) o;
-
-        return id_ != null ? id_.equals(document.id_) : document.id_ == null;
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return id_ != null ? id_.hashCode() : 0;
-    }
-}
-
+package com.mooctest.cluster;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Document<K>
+{
+    K id_;    /// the identifier of a document
+
+    SparseVector feature;  /// feature vector of a document
+
+    public K getId_() {
+        return id_;
+    }
+
+    public SparseVector getFeature() {
+        return feature;
+    }
+
+    public Document(K id_, SparseVector feature_)
+    {
+        this.id_ = id_;
+        this.feature = feature_;
+    }
+
+    public Document(K id_)
+    {
+        this(id_, new SparseVector());
+    }
+
+    /**
+     * Get an identifier.
+     *
+     * @return an identifier
+     */
+    K id()
+    {
+        return id_;
+    }
+
+    /**
+     * Get the pointer of a feature vector
+     *
+     * @return the pointer of a feature vector
+     */
+    SparseVector feature()
+    {
+        return feature;
+    }
+
+
+    /**
+     * Add a feature.
+     *
+     * @param key   the key of a feature
+     * @param value the value of a feature
+     */
+    void add_feature(int key, double value)
+    {
+        feature.put(key, value);
+    }
+
+    /**
+     * Set features.
+     *
+     * @param feature a feature vector
+     */
+    void set_features(SparseVector feature)
+    {
+        this.feature = feature;
+    }
+
+    /**
+     * Clear features.
+     */
+    void clear()
+    {
+        feature.clear();
+    }
+
+    /**
+     * Apply IDF(inverse document frequency) weighting.
+     *
+     * @param df    document frequencies
+     * @param ndocs the number of documents
+     */
+    void idf(HashMap<Integer, Integer> df, int ndocs)
+    {
+        for (Map.Entry<Integer, Double> entry : feature.entrySet())
+        {
+            Integer denom = df.get(entry.getKey());
+            if (denom == null) denom = 1;
+            entry.setValue((double) (entry.getValue() * Math.log(ndocs / denom)));
+        }
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Document<?> document = (Document<?>) o;
+
+        return id_ != null ? id_.equals(document.id_) : document.id_ == null;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return id_ != null ? id_.hashCode() : 0;
+    }
+}
+

+ 15 - 15
src/main/java/com/mooctest/cluster/Group.java

@@ -1,15 +1,15 @@
-package com.mooctest.cluster;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.Set;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class Group<K, V> {
-    private K id;
-    private Set<V> cluster;
-}
+package com.mooctest.cluster;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Set;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Group<K, V> {
+    private K id;
+    private Set<V> cluster;
+}

+ 338 - 338
src/main/java/com/mooctest/cluster/MyClusterAnalyzer.java

@@ -1,338 +1,338 @@
-package com.mooctest.cluster;
-
-import com.hankcs.hanlp.HanLP;
-import com.hankcs.hanlp.collection.trie.datrie.MutableDoubleArrayTrieInteger;
-import com.hankcs.hanlp.dictionary.stopword.CoreStopWordDictionary;
-import com.hankcs.hanlp.seg.Segment;
-import com.hankcs.hanlp.seg.common.Term;
-
-import java.util.*;
-
-public class MyClusterAnalyzer<K> {
-
-    protected HashMap<K, Document<K>> documents_;
-    protected Segment segment;
-    protected MutableDoubleArrayTrieInteger vocabulary;
-    static final int NUM_REFINE_LOOP = 30;
-
-    public MyClusterAnalyzer()
-    {
-        documents_ = new HashMap<K, Document<K>>();
-        segment = HanLP.newSegment();
-        vocabulary = new MutableDoubleArrayTrieInteger();
-    }
-
-    protected int id(String word)
-    {
-        int id = vocabulary.get(word);
-        if (id == -1)
-        {
-            id = vocabulary.size();
-            vocabulary.put(word, id);
-        }
-        return id;
-    }
-
-    /**
-     * 重载此方法实现自己的预处理逻辑(预处理、分词、去除停用词)
-     *
-     * @param document 文档
-     * @return 单词列表
-     */
-    protected List<String> preprocess(String document)
-    {
-        List<Term> termList = segment.seg(document);
-        ListIterator<Term> listIterator = termList.listIterator();
-        while (listIterator.hasNext())
-        {
-            Term term = listIterator.next();
-            if (CoreStopWordDictionary.contains(term.word) ||
-                    term.nature.startsWith("w")
-                    )
-            {
-                listIterator.remove();
-            }
-        }
-        List<String> wordList = new ArrayList<String>(termList.size());
-        for (Term term : termList)
-        {
-            wordList.add(term.word);
-        }
-        return wordList;
-    }
-
-    protected SparseVector toVector(List<String> wordList)
-    {
-        SparseVector vector = new SparseVector();
-        for (String word : wordList)
-        {
-            int id = id(word);
-            Double f = vector.get(id);
-            if (f == null)
-            {
-                f = 1.;
-                vector.put(id, f);
-            }
-            else
-            {
-                vector.put(id, ++f);
-            }
-        }
-        return vector;
-    }
-
-    /**
-     * 添加文档
-     *
-     * @param id       文档id
-     * @param document 文档内容
-     * @return 文档对象
-     */
-    public Document<K> addDocument(K id, String document)
-    {
-        return addDocument(id, preprocess(document));
-    }
-
-    /**
-     * 添加文档
-     *
-     * @param id       文档id
-     * @param document 文档内容
-     * @return 文档对象
-     */
-    public Document<K> addDocument(K id, List<String> document)
-    {
-        SparseVector vector = toVector(document);
-        Document<K> d = new Document<K>(id, vector);
-        return documents_.put(id, d);
-    }
-
-    /**
-     * k-means聚类
-     *
-     * @param nclusters 簇的数量
-     * @return 指定数量的簇(Set)构成的集合
-     */
-    public List<Set<K>> kmeans(int nclusters)
-    {
-        Cluster<K> cluster = new Cluster<K>();
-        for (Document<K> document : documents_.values())
-        {
-            cluster.add_document(document);
-        }
-        cluster.section(nclusters);
-        refine_clusters(cluster.sectioned_clusters());
-        List<Cluster<K>> clusters_ = new ArrayList<Cluster<K>>(nclusters);
-        for (Cluster<K> s : cluster.sectioned_clusters())
-        {
-            s.refresh();
-            clusters_.add(s);
-        }
-        return toResult(clusters_);
-    }
-
-    private List<Set<K>> toResult(List<Cluster<K>> clusters_)
-    {
-        List<Set<K>> result = new ArrayList<Set<K>>(clusters_.size());
-        for (Cluster<K> c : clusters_)
-        {
-            Set<K> s = new HashSet<K>();
-            for (Document<K> d : c.documents_)
-            {
-                s.add(d.id_);
-            }
-            result.add(s);
-        }
-        return result;
-    }
-
-    /**
-     * repeated bisection 聚类
-     *
-     * @param nclusters 簇的数量
-     * @return 指定数量的簇(Set)构成的集合
-     */
-    public List<Set<K>> repeatedBisection(int nclusters)
-    {
-        return repeatedBisection(nclusters, 0);
-    }
-
-    /**
-     * repeated bisection 聚类
-     *
-     * @param limit_eval 准则函数增幅阈值
-     * @return 指定数量的簇(Set)构成的集合
-     */
-    public List<Set<K>> repeatedBisection(double limit_eval)
-    {
-        return repeatedBisection(0, limit_eval);
-    }
-
-    /**
-     * repeated bisection 聚类
-     *
-     * @param nclusters  簇的数量
-     * @param limit_eval 准则函数增幅阈值
-     * @return 指定数量的簇(Set)构成的集合
-     */
-    public List<Set<K>> repeatedBisection(int nclusters, double limit_eval)
-    {
-        Cluster<K> cluster = new Cluster<K>();
-        List<Cluster<K>> clusters_ = new ArrayList<Cluster<K>>(nclusters > 0 ? nclusters : 16);
-        for (Document<K> document : documents_.values())
-        {
-            cluster.add_document(document);
-        }
-
-        PriorityQueue<Cluster<K>> que = new PriorityQueue<Cluster<K>>();
-        cluster.section(2);
-        refine_clusters(cluster.sectioned_clusters());
-        cluster.set_sectioned_gain();
-        cluster.composite_vector().clear();
-        que.add(cluster);
-
-        while (!que.isEmpty())
-        {
-            if (nclusters > 0 && que.size() >= nclusters)
-                break;
-            cluster = que.peek();
-            if (cluster.sectioned_clusters().size() < 1)
-                break;
-            if (limit_eval > 0 && cluster.sectioned_gain() < limit_eval)
-                break;
-            que.poll();
-            List<Cluster<K>> sectioned = cluster.sectioned_clusters();
-
-            for (Cluster<K> c : sectioned)
-            {
-                c.section(2);
-                refine_clusters(c.sectioned_clusters());
-                c.set_sectioned_gain();
-                if (c.sectioned_gain() < limit_eval)
-                {
-                    for (Cluster<K> sub : c.sectioned_clusters())
-                    {
-                        sub.clear();
-                    }
-                }
-                c.composite_vector().clear();
-                que.add(c);
-            }
-        }
-        while (!que.isEmpty())
-        {
-            clusters_.add(0, que.poll());
-        }
-        return toResult(clusters_);
-    }
-
-    /**
-     * 根据k-means算法迭代优化聚类
-     *
-     * @param clusters 簇
-     * @return 准则函数的值
-     */
-    double refine_clusters(List<Cluster<K>> clusters)
-    {
-        double[] norms = new double[clusters.size()];
-        int offset = 0;
-        for (Cluster cluster : clusters)
-        {
-            norms[offset++] = cluster.composite_vector().norm();
-        }
-
-        double eval_cluster = 0.0;
-        int loop_count = 0;
-        while (loop_count++ < NUM_REFINE_LOOP)
-        {
-            List<int[]> items = new ArrayList<int[]>(documents_.size());
-            for (int i = 0; i < clusters.size(); i++)
-            {
-                for (int j = 0; j < clusters.get(i).documents().size(); j++)
-                {
-                    items.add(new int[]{i, j});
-                }
-            }
-            Collections.shuffle(items);
-
-            boolean changed = false;
-            for (int[] item : items)
-            {
-                int cluster_id = item[0];
-                int item_id = item[1];
-                Cluster<K> cluster = clusters.get(cluster_id);
-                Document<K> doc = cluster.documents().get(item_id);
-                double value_base = refined_vector_value(cluster.composite_vector(), doc.feature(), -1);
-                double norm_base_moved = Math.pow(norms[cluster_id], 2) + value_base;
-                norm_base_moved = norm_base_moved > 0 ? Math.sqrt(norm_base_moved) : 0.0;
-
-                double eval_max = -1.0;
-                double norm_max = 0.0;
-                int max_index = 0;
-                for (int j = 0; j < clusters.size(); j++)
-                {
-                    if (cluster_id == j)
-                        continue;
-                    Cluster<K> other = clusters.get(j);
-                    double value_target = refined_vector_value(other.composite_vector(), doc.feature(), 1);
-                    double norm_target_moved = Math.pow(norms[j], 2) + value_target;
-                    norm_target_moved = norm_target_moved > 0 ? Math.sqrt(norm_target_moved) : 0.0;
-                    double eval_moved = norm_base_moved + norm_target_moved - norms[cluster_id] - norms[j];
-                    if (eval_max < eval_moved)
-                    {
-                        eval_max = eval_moved;
-                        norm_max = norm_target_moved;
-                        max_index = j;
-                    }
-                }
-                if (eval_max > 0)
-                {
-                    eval_cluster += eval_max;
-                    clusters.get(max_index).add_document(doc);
-                    clusters.get(cluster_id).remove_document(item_id);
-                    norms[cluster_id] = norm_base_moved;
-                    norms[max_index] = norm_max;
-                    changed = true;
-                }
-            }
-            if (!changed)
-                break;
-            for (Cluster<K> cluster : clusters)
-            {
-                cluster.refresh();
-            }
-        }
-        return eval_cluster;
-    }
-
-    /**
-     * c^2 - 2c(a + c) + d^2 - 2d(b + d)
-     *
-     * @param composite (a+c,b+d)
-     * @param vec       (c,d)
-     * @param sign
-     * @return
-     */
-    double refined_vector_value(SparseVector composite, SparseVector vec, int sign)
-    {
-        double sum = 0.0;
-        for (Map.Entry<Integer, Double> entry : vec.entrySet())
-        {
-            sum += Math.pow(entry.getValue(), 2) + sign * 2 * composite.get(entry.getKey()) * entry.getValue();
-        }
-        return sum;
-    }
-
-    public HashMap<K, Document<K>> getDocuments() {
-        return this.documents_;
-    }
-
-    public void clear() {
-        this.documents_.clear();
-        this.vocabulary.clear();
-    }
-    public void clearDocs() {
-        this.documents_.clear();
-    }
-
-}
+package com.mooctest.cluster;
+
+import com.hankcs.hanlp.HanLP;
+import com.hankcs.hanlp.collection.trie.datrie.MutableDoubleArrayTrieInteger;
+import com.hankcs.hanlp.dictionary.stopword.CoreStopWordDictionary;
+import com.hankcs.hanlp.seg.Segment;
+import com.hankcs.hanlp.seg.common.Term;
+
+import java.util.*;
+
+public class MyClusterAnalyzer<K> {
+
+    protected HashMap<K, Document<K>> documents_;
+    protected Segment segment;
+    protected MutableDoubleArrayTrieInteger vocabulary;
+    static final int NUM_REFINE_LOOP = 30;
+
+    public MyClusterAnalyzer()
+    {
+        documents_ = new HashMap<K, Document<K>>();
+        segment = HanLP.newSegment();
+        vocabulary = new MutableDoubleArrayTrieInteger();
+    }
+
+    protected int id(String word)
+    {
+        int id = vocabulary.get(word);
+        if (id == -1)
+        {
+            id = vocabulary.size();
+            vocabulary.put(word, id);
+        }
+        return id;
+    }
+
+    /**
+     * 重载此方法实现自己的预处理逻辑(预处理、分词、去除停用词)
+     *
+     * @param document 文档
+     * @return 单词列表
+     */
+    protected List<String> preprocess(String document)
+    {
+        List<Term> termList = segment.seg(document);
+        ListIterator<Term> listIterator = termList.listIterator();
+        while (listIterator.hasNext())
+        {
+            Term term = listIterator.next();
+            if (CoreStopWordDictionary.contains(term.word) ||
+                    term.nature.startsWith("w")
+                    )
+            {
+                listIterator.remove();
+            }
+        }
+        List<String> wordList = new ArrayList<String>(termList.size());
+        for (Term term : termList)
+        {
+            wordList.add(term.word);
+        }
+        return wordList;
+    }
+
+    protected SparseVector toVector(List<String> wordList)
+    {
+        SparseVector vector = new SparseVector();
+        for (String word : wordList)
+        {
+            int id = id(word);
+            Double f = vector.get(id);
+            if (f == null)
+            {
+                f = 1.;
+                vector.put(id, f);
+            }
+            else
+            {
+                vector.put(id, ++f);
+            }
+        }
+        return vector;
+    }
+
+    /**
+     * 添加文档
+     *
+     * @param id       文档id
+     * @param document 文档内容
+     * @return 文档对象
+     */
+    public Document<K> addDocument(K id, String document)
+    {
+        return addDocument(id, preprocess(document));
+    }
+
+    /**
+     * 添加文档
+     *
+     * @param id       文档id
+     * @param document 文档内容
+     * @return 文档对象
+     */
+    public Document<K> addDocument(K id, List<String> document)
+    {
+        SparseVector vector = toVector(document);
+        Document<K> d = new Document<K>(id, vector);
+        return documents_.put(id, d);
+    }
+
+    /**
+     * k-means聚类
+     *
+     * @param nclusters 簇的数量
+     * @return 指定数量的簇(Set)构成的集合
+     */
+    public List<Set<K>> kmeans(int nclusters)
+    {
+        Cluster<K> cluster = new Cluster<K>();
+        for (Document<K> document : documents_.values())
+        {
+            cluster.add_document(document);
+        }
+        cluster.section(nclusters);
+        refine_clusters(cluster.sectioned_clusters());
+        List<Cluster<K>> clusters_ = new ArrayList<Cluster<K>>(nclusters);
+        for (Cluster<K> s : cluster.sectioned_clusters())
+        {
+            s.refresh();
+            clusters_.add(s);
+        }
+        return toResult(clusters_);
+    }
+
+    private List<Set<K>> toResult(List<Cluster<K>> clusters_)
+    {
+        List<Set<K>> result = new ArrayList<Set<K>>(clusters_.size());
+        for (Cluster<K> c : clusters_)
+        {
+            Set<K> s = new HashSet<K>();
+            for (Document<K> d : c.documents_)
+            {
+                s.add(d.id_);
+            }
+            result.add(s);
+        }
+        return result;
+    }
+
+    /**
+     * repeated bisection 聚类
+     *
+     * @param nclusters 簇的数量
+     * @return 指定数量的簇(Set)构成的集合
+     */
+    public List<Set<K>> repeatedBisection(int nclusters)
+    {
+        return repeatedBisection(nclusters, 0);
+    }
+
+    /**
+     * repeated bisection 聚类
+     *
+     * @param limit_eval 准则函数增幅阈值
+     * @return 指定数量的簇(Set)构成的集合
+     */
+    public List<Set<K>> repeatedBisection(double limit_eval)
+    {
+        return repeatedBisection(0, limit_eval);
+    }
+
+    /**
+     * repeated bisection 聚类
+     *
+     * @param nclusters  簇的数量
+     * @param limit_eval 准则函数增幅阈值
+     * @return 指定数量的簇(Set)构成的集合
+     */
+    public List<Set<K>> repeatedBisection(int nclusters, double limit_eval)
+    {
+        Cluster<K> cluster = new Cluster<K>();
+        List<Cluster<K>> clusters_ = new ArrayList<Cluster<K>>(nclusters > 0 ? nclusters : 16);
+        for (Document<K> document : documents_.values())
+        {
+            cluster.add_document(document);
+        }
+
+        PriorityQueue<Cluster<K>> que = new PriorityQueue<Cluster<K>>();
+        cluster.section(2);
+        refine_clusters(cluster.sectioned_clusters());
+        cluster.set_sectioned_gain();
+        cluster.composite_vector().clear();
+        que.add(cluster);
+
+        while (!que.isEmpty())
+        {
+            if (nclusters > 0 && que.size() >= nclusters)
+                break;
+            cluster = que.peek();
+            if (cluster.sectioned_clusters().size() < 1)
+                break;
+            if (limit_eval > 0 && cluster.sectioned_gain() < limit_eval)
+                break;
+            que.poll();
+            List<Cluster<K>> sectioned = cluster.sectioned_clusters();
+
+            for (Cluster<K> c : sectioned)
+            {
+                c.section(2);
+                refine_clusters(c.sectioned_clusters());
+                c.set_sectioned_gain();
+                if (c.sectioned_gain() < limit_eval)
+                {
+                    for (Cluster<K> sub : c.sectioned_clusters())
+                    {
+                        sub.clear();
+                    }
+                }
+                c.composite_vector().clear();
+                que.add(c);
+            }
+        }
+        while (!que.isEmpty())
+        {
+            clusters_.add(0, que.poll());
+        }
+        return toResult(clusters_);
+    }
+
+    /**
+     * 根据k-means算法迭代优化聚类
+     *
+     * @param clusters 簇
+     * @return 准则函数的值
+     */
+    double refine_clusters(List<Cluster<K>> clusters)
+    {
+        double[] norms = new double[clusters.size()];
+        int offset = 0;
+        for (Cluster cluster : clusters)
+        {
+            norms[offset++] = cluster.composite_vector().norm();
+        }
+
+        double eval_cluster = 0.0;
+        int loop_count = 0;
+        while (loop_count++ < NUM_REFINE_LOOP)
+        {
+            List<int[]> items = new ArrayList<int[]>(documents_.size());
+            for (int i = 0; i < clusters.size(); i++)
+            {
+                for (int j = 0; j < clusters.get(i).documents().size(); j++)
+                {
+                    items.add(new int[]{i, j});
+                }
+            }
+            Collections.shuffle(items);
+
+            boolean changed = false;
+            for (int[] item : items)
+            {
+                int cluster_id = item[0];
+                int item_id = item[1];
+                Cluster<K> cluster = clusters.get(cluster_id);
+                Document<K> doc = cluster.documents().get(item_id);
+                double value_base = refined_vector_value(cluster.composite_vector(), doc.feature(), -1);
+                double norm_base_moved = Math.pow(norms[cluster_id], 2) + value_base;
+                norm_base_moved = norm_base_moved > 0 ? Math.sqrt(norm_base_moved) : 0.0;
+
+                double eval_max = -1.0;
+                double norm_max = 0.0;
+                int max_index = 0;
+                for (int j = 0; j < clusters.size(); j++)
+                {
+                    if (cluster_id == j)
+                        continue;
+                    Cluster<K> other = clusters.get(j);
+                    double value_target = refined_vector_value(other.composite_vector(), doc.feature(), 1);
+                    double norm_target_moved = Math.pow(norms[j], 2) + value_target;
+                    norm_target_moved = norm_target_moved > 0 ? Math.sqrt(norm_target_moved) : 0.0;
+                    double eval_moved = norm_base_moved + norm_target_moved - norms[cluster_id] - norms[j];
+                    if (eval_max < eval_moved)
+                    {
+                        eval_max = eval_moved;
+                        norm_max = norm_target_moved;
+                        max_index = j;
+                    }
+                }
+                if (eval_max > 0)
+                {
+                    eval_cluster += eval_max;
+                    clusters.get(max_index).add_document(doc);
+                    clusters.get(cluster_id).remove_document(item_id);
+                    norms[cluster_id] = norm_base_moved;
+                    norms[max_index] = norm_max;
+                    changed = true;
+                }
+            }
+            if (!changed)
+                break;
+            for (Cluster<K> cluster : clusters)
+            {
+                cluster.refresh();
+            }
+        }
+        return eval_cluster;
+    }
+
+    /**
+     * c^2 - 2c(a + c) + d^2 - 2d(b + d)
+     *
+     * @param composite (a+c,b+d)
+     * @param vec       (c,d)
+     * @param sign
+     * @return
+     */
+    double refined_vector_value(SparseVector composite, SparseVector vec, int sign)
+    {
+        double sum = 0.0;
+        for (Map.Entry<Integer, Double> entry : vec.entrySet())
+        {
+            sum += Math.pow(entry.getValue(), 2) + sign * 2 * composite.get(entry.getKey()) * entry.getValue();
+        }
+        return sum;
+    }
+
+    public HashMap<K, Document<K>> getDocuments() {
+        return this.documents_;
+    }
+
+    public void clear() {
+        this.documents_.clear();
+        this.vocabulary.clear();
+    }
+    public void clearDocs() {
+        this.documents_.clear();
+    }
+
+}

+ 191 - 191
src/main/java/com/mooctest/cluster/SparseVector.java

@@ -1,191 +1,191 @@
-package com.mooctest.cluster;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class SparseVector extends TreeMap<Integer, Double>
-    {
-        @Override
-        public Double get(Object key)
-        {
-            Double v = super.get(key);
-            if (v == null) return 0.;
-            return v;
-        }
-
-        /**
-         * Normalize a vector.
-         */
-        void normalize()
-        {
-            double nrm = norm();
-            for (Map.Entry<Integer, Double> d : entrySet())
-            {
-                d.setValue(d.getValue() / nrm);
-            }
-        }
-
-        /**
-         * Calculate a squared norm.
-         */
-        double norm_squared()
-        {
-            double sum = 0;
-            for (Double point : values())
-            {
-                sum += point * point;
-            }
-            return sum;
-        }
-
-        /**
-         * Calculate a norm.
-         */
-        double norm()
-        {
-            return (double) Math.sqrt(norm_squared());
-        }
-
-        /**
-         * Multiply each value of  avector by a constant value.
-         */
-        void multiply_constant(double x)
-        {
-            for (Map.Entry<Integer, Double> entry : entrySet())
-            {
-                entry.setValue(entry.getValue() * x);
-            }
-        }
-
-        /**
-         * Add other vector.
-         */
-        void add_vector( SparseVector vec)
-        {
-
-            for (Map.Entry<Integer, Double> entry : vec.entrySet())
-            {
-                Double v = get(entry.getKey());
-                if (v == null)
-                    v = 0.;
-                put(entry.getKey(), v + entry.getValue());
-            }
-        }
-
-        /**
-         * Subtract other vector.
-         */
-        void sub_vector( SparseVector vec)
-        {
-
-            for (Map.Entry<Integer, Double> entry : vec.entrySet())
-            {
-                Double v = get(entry.getKey());
-                if (v == null)
-                    v = 0.;
-                put(entry.getKey(), v - entry.getValue());
-            }
-        }
-
-//    /**
-//     * Calculate the squared euclid distance between vectors.
-//     */
-//    double euclid_distance_squared(const Vector &vec1, const Vector &vec2)
-//{
-//    HashMap<VecKey, bool>::type done;
-//    init_hash_map(VECTOR_EMPTY_KEY, done, vec1.size());
-//    VecHashMap::const_iterator it1, it2;
-//    double dist = 0;
-//    for (it1 = vec1.hash_map()->begin(); it1 != vec1.hash_map()->end(); ++it1)
-//    {
-//        double val = vec2.get(it1->first);
-//        dist += (it1->second - val) * (it1->second - val);
-//        done[it1->first] = true;
-//    }
-//    for (it2 = vec2.hash_map()->begin(); it2 != vec2.hash_map()->end(); ++it2)
-//    {
-//        if (done.find(it2->first) == done.end())
-//        {
-//            double val = vec1.get(it2->first);
-//            dist += (it2->second - val) * (it2->second - val);
-//        }
-//    }
-//    return dist;
-//}
-//
-//    /**
-//     * Calculate the euclid distance between vectors.
-//     */
-//    double euclid_distance(const Vector &vec1, const Vector &vec2)
-//{
-//    return sqrt(euclid_distance_squared(vec1, vec2));
-//}
-
-        /**
-         * Calculate the inner product value between vectors.
-         */
-        public static double inner_product(SparseVector vec1,  SparseVector vec2)
-        {
-            Iterator<Map.Entry<Integer, Double>> it;
-             SparseVector other;
-            if (vec1.size() < vec2.size())
-            {
-                it = vec1.entrySet().iterator();
-                other = vec2;
-            }
-            else
-            {
-                it = vec2.entrySet().iterator();
-                other = vec1;
-            }
-            double prod = 0;
-            while (it.hasNext())
-            {
-                Map.Entry<Integer, Double> entry = it.next();
-                prod += entry.getValue() * other.get(entry.getKey());
-            }
-            return prod;
-        }
-
-        /**
-         * Calculate the cosine value between vectors.
-         */
-        double cosine(SparseVector vec1, SparseVector vec2)
-        {
-            double norm1 = vec1.norm();
-            double norm2 = vec2.norm();
-            double result = 0.0f;
-            if (norm1 == 0 && norm2 == 0)
-            {
-                return result;
-            }
-            else
-            {
-                double prod = inner_product(vec1, vec2);
-                result = prod / (norm1 * norm2);
-                return Double.isNaN(result) ? 0.0f : result;
-            }
-        }
-
-//    /**
-//     * Calculate the Jaccard coefficient value between vectors.
-//     */
-//    double jaccard(const Vector &vec1, const Vector &vec2)
-//{
-//    double norm1 = vec1.norm();
-//    double norm2 = vec2.norm();
-//    double prod = inner_product(vec1, vec2);
-//    double denom = norm1 + norm2 - prod;
-//    double result = 0.0;
-//    if (!denom)
-//    {
-//        return result;
-//    }
-//    else
-//    {
-//        result = prod / denom;
-//        return isnan(result) ? 0.0 : result;
-//    }
-//}
-}
+package com.mooctest.cluster;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class SparseVector extends TreeMap<Integer, Double>
+    {
+        @Override
+        public Double get(Object key)
+        {
+            Double v = super.get(key);
+            if (v == null) return 0.;
+            return v;
+        }
+
+        /**
+         * Normalize a vector.
+         */
+        void normalize()
+        {
+            double nrm = norm();
+            for (Map.Entry<Integer, Double> d : entrySet())
+            {
+                d.setValue(d.getValue() / nrm);
+            }
+        }
+
+        /**
+         * Calculate a squared norm.
+         */
+        double norm_squared()
+        {
+            double sum = 0;
+            for (Double point : values())
+            {
+                sum += point * point;
+            }
+            return sum;
+        }
+
+        /**
+         * Calculate a norm.
+         */
+        double norm()
+        {
+            return (double) Math.sqrt(norm_squared());
+        }
+
+        /**
+         * Multiply each value of  avector by a constant value.
+         */
+        void multiply_constant(double x)
+        {
+            for (Map.Entry<Integer, Double> entry : entrySet())
+            {
+                entry.setValue(entry.getValue() * x);
+            }
+        }
+
+        /**
+         * Add other vector.
+         */
+        void add_vector( SparseVector vec)
+        {
+
+            for (Map.Entry<Integer, Double> entry : vec.entrySet())
+            {
+                Double v = get(entry.getKey());
+                if (v == null)
+                    v = 0.;
+                put(entry.getKey(), v + entry.getValue());
+            }
+        }
+
+        /**
+         * Subtract other vector.
+         */
+        void sub_vector( SparseVector vec)
+        {
+
+            for (Map.Entry<Integer, Double> entry : vec.entrySet())
+            {
+                Double v = get(entry.getKey());
+                if (v == null)
+                    v = 0.;
+                put(entry.getKey(), v - entry.getValue());
+            }
+        }
+
+//    /**
+//     * Calculate the squared euclid distance between vectors.
+//     */
+//    double euclid_distance_squared(const Vector &vec1, const Vector &vec2)
+//{
+//    HashMap<VecKey, bool>::type done;
+//    init_hash_map(VECTOR_EMPTY_KEY, done, vec1.size());
+//    VecHashMap::const_iterator it1, it2;
+//    double dist = 0;
+//    for (it1 = vec1.hash_map()->begin(); it1 != vec1.hash_map()->end(); ++it1)
+//    {
+//        double val = vec2.get(it1->first);
+//        dist += (it1->second - val) * (it1->second - val);
+//        done[it1->first] = true;
+//    }
+//    for (it2 = vec2.hash_map()->begin(); it2 != vec2.hash_map()->end(); ++it2)
+//    {
+//        if (done.find(it2->first) == done.end())
+//        {
+//            double val = vec1.get(it2->first);
+//            dist += (it2->second - val) * (it2->second - val);
+//        }
+//    }
+//    return dist;
+//}
+//
+//    /**
+//     * Calculate the euclid distance between vectors.
+//     */
+//    double euclid_distance(const Vector &vec1, const Vector &vec2)
+//{
+//    return sqrt(euclid_distance_squared(vec1, vec2));
+//}
+
+        /**
+         * Calculate the inner product value between vectors.
+         */
+        public static double inner_product(SparseVector vec1,  SparseVector vec2)
+        {
+            Iterator<Map.Entry<Integer, Double>> it;
+             SparseVector other;
+            if (vec1.size() < vec2.size())
+            {
+                it = vec1.entrySet().iterator();
+                other = vec2;
+            }
+            else
+            {
+                it = vec2.entrySet().iterator();
+                other = vec1;
+            }
+            double prod = 0;
+            while (it.hasNext())
+            {
+                Map.Entry<Integer, Double> entry = it.next();
+                prod += entry.getValue() * other.get(entry.getKey());
+            }
+            return prod;
+        }
+
+        /**
+         * Calculate the cosine value between vectors.
+         */
+        double cosine(SparseVector vec1, SparseVector vec2)
+        {
+            double norm1 = vec1.norm();
+            double norm2 = vec2.norm();
+            double result = 0.0f;
+            if (norm1 == 0 && norm2 == 0)
+            {
+                return result;
+            }
+            else
+            {
+                double prod = inner_product(vec1, vec2);
+                result = prod / (norm1 * norm2);
+                return Double.isNaN(result) ? 0.0f : result;
+            }
+        }
+
+//    /**
+//     * Calculate the Jaccard coefficient value between vectors.
+//     */
+//    double jaccard(const Vector &vec1, const Vector &vec2)
+//{
+//    double norm1 = vec1.norm();
+//    double norm2 = vec2.norm();
+//    double prod = inner_product(vec1, vec2);
+//    double denom = norm1 + norm2 - prod;
+//    double result = 0.0;
+//    if (!denom)
+//    {
+//        return result;
+//    }
+//    else
+//    {
+//        result = prod / denom;
+//        return isnan(result) ? 0.0 : result;
+//    }
+//}
+}

+ 46 - 46
src/main/java/com/mooctest/config/MongoOneConfig.java

@@ -1,46 +1,46 @@
-package com.mooctest.config;
-
-import com.mongodb.MongoClientOptions;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.autoconfigure.mongo.MongoProperties;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import org.springframework.data.mongodb.MongoDbFactory;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
-import org.springframework.core.env.Environment;
-
-@Configuration
-@EnableMongoRepositories(
-        basePackages = "com.mooctest.dao",
-        mongoTemplateRef = "mongoTemplate1")
-public class MongoOneConfig {
-    @Autowired
-    private Environment environment;
-
-
-    @Primary
-    @Bean(name = "mongoTemplate1")
-    public MongoTemplate mongoTemplate(@Qualifier("mongoFactory1") MongoDbFactory mongoFactory) throws Exception {
-        return new MongoTemplate(mongoFactory);
-    }
-
-    @Primary
-    @Bean("mongoFactory1")
-    public MongoDbFactory mongoFactory(@Qualifier("mongoProperties1") MongoProperties mongoProperties) throws Exception {
-        return new SimpleMongoDbFactory(
-                mongoProperties.createMongoClient(MongoClientOptions.builder().build(), environment),
-                mongoProperties.getDatabase());
-    }
-
-    @Bean(name = "mongoProperties1")
-    @ConfigurationProperties(prefix = "mongodb1")
-    @Primary
-    public MongoProperties properties() throws Exception {
-        return new MongoProperties();
-    }
-}
+package com.mooctest.config;
+
+import com.mongodb.MongoClientOptions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.mongo.MongoProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.mongodb.MongoDbFactory;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+import org.springframework.core.env.Environment;
+
+@Configuration
+@EnableMongoRepositories(
+        basePackages = "com.mooctest.dao",
+        mongoTemplateRef = "mongoTemplate1")
+public class MongoOneConfig {
+    @Autowired
+    private Environment environment;
+
+
+    @Primary
+    @Bean(name = "mongoTemplate1")
+    public MongoTemplate mongoTemplate(@Qualifier("mongoFactory1") MongoDbFactory mongoFactory) throws Exception {
+        return new MongoTemplate(mongoFactory);
+    }
+
+    @Primary
+    @Bean("mongoFactory1")
+    public MongoDbFactory mongoFactory(@Qualifier("mongoProperties1") MongoProperties mongoProperties) throws Exception {
+        return new SimpleMongoDbFactory(
+                mongoProperties.createMongoClient(MongoClientOptions.builder().build(), environment),
+                mongoProperties.getDatabase());
+    }
+
+    @Bean(name = "mongoProperties1")
+    @ConfigurationProperties(prefix = "mongodb1")
+    @Primary
+    public MongoProperties properties() throws Exception {
+        return new MongoProperties();
+    }
+}

+ 47 - 47
src/main/java/com/mooctest/config/MongoTwoConfig.java

@@ -1,47 +1,47 @@
-package com.mooctest.config;
-
-import com.mongodb.MongoClientOptions;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.autoconfigure.mongo.MongoProperties;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-import org.springframework.data.mongodb.MongoDbFactory;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
-import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
-
-
-@Configuration
-@EnableMongoRepositories(
-        basePackages = "com.mooctest.dao2",
-        mongoTemplateRef = "mongoTemplate2")
-public class MongoTwoConfig {
-
-    @Autowired
-    private Environment environment;
-
-
-    @Bean(name = "mongoTemplate2")
-    public MongoTemplate mongoTemplate(@Qualifier("mongoFactory2") MongoDbFactory mongoFactory) throws Exception {
-        return new MongoTemplate(mongoFactory);
-    }
-
-    @Bean("mongoFactory2")
-    public MongoDbFactory mongoFactory(
-            @Qualifier("mongoProperties2") MongoProperties mongoProperties) throws Exception {
-        return new SimpleMongoDbFactory(
-                mongoProperties.createMongoClient(MongoClientOptions.builder().build(), environment),
-                mongoProperties.getDatabase());
-    }
-
-    @Bean(name = "mongoProperties2")
-    @ConfigurationProperties(prefix = "mongodb2")
-    public MongoProperties properties() {
-        return new MongoProperties();
-    }
-
-}
-
+package com.mooctest.config;
+
+import com.mongodb.MongoClientOptions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.mongo.MongoProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.data.mongodb.MongoDbFactory;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+
+@Configuration
+@EnableMongoRepositories(
+        basePackages = "com.mooctest.dao2",
+        mongoTemplateRef = "mongoTemplate2")
+public class MongoTwoConfig {
+
+    @Autowired
+    private Environment environment;
+
+
+    @Bean(name = "mongoTemplate2")
+    public MongoTemplate mongoTemplate(@Qualifier("mongoFactory2") MongoDbFactory mongoFactory) throws Exception {
+        return new MongoTemplate(mongoFactory);
+    }
+
+    @Bean("mongoFactory2")
+    public MongoDbFactory mongoFactory(
+            @Qualifier("mongoProperties2") MongoProperties mongoProperties) throws Exception {
+        return new SimpleMongoDbFactory(
+                mongoProperties.createMongoClient(MongoClientOptions.builder().build(), environment),
+                mongoProperties.getDatabase());
+    }
+
+    @Bean(name = "mongoProperties2")
+    @ConfigurationProperties(prefix = "mongodb2")
+    public MongoProperties properties() {
+        return new MongoProperties();
+    }
+
+}
+

+ 55 - 55
src/main/java/com/mooctest/config/ThymeleafViewResolverConfig.java

@@ -1,55 +1,55 @@
-package com.mooctest.config;
-
-import nz.net.ultraq.thymeleaf.LayoutDialect;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.ViewResolver;
-import org.thymeleaf.spring4.SpringTemplateEngine;
-import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
-import org.thymeleaf.spring4.view.ThymeleafViewResolver;
-import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
-import org.thymeleaf.templateresolver.ITemplateResolver;
-
-@Configuration
-public class ThymeleafViewResolverConfig {
-    @Bean
-    public ViewResolver thymeleafViewResolver() {
-
-        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
-
-        viewResolver.setTemplateEngine(thymeleafTemplateEngine());
-        viewResolver.setCharacterEncoding("UTF-8");
-
-        return viewResolver;
-    }
-
-    // Thymeleaf template engine with Spring integration
-    @Bean
-    public SpringTemplateEngine thymeleafTemplateEngine() {
-
-        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
-        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
-        templateEngine.addDialect(new LayoutDialect());
-        return templateEngine;
-    }
-
-    @Bean
-    public SpringResourceTemplateResolver springResourceTemplateResolver() {
-        return new SpringResourceTemplateResolver();
-    }
-
-    // Thymeleaf template resolver serving HTML 5
-    @Bean
-    public ITemplateResolver thymeleafTemplateResolver() {
-
-        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
-
-        templateResolver.setPrefix("templates/");
-        templateResolver.setCacheable(false);
-        templateResolver.setSuffix(".html");
-        templateResolver.setTemplateMode("HTML5");
-        templateResolver.setCharacterEncoding("UTF-8");
-
-        return templateResolver;
-    }
-}
+package com.mooctest.config;
+
+import nz.net.ultraq.thymeleaf.LayoutDialect;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.ViewResolver;
+import org.thymeleaf.spring4.SpringTemplateEngine;
+import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
+import org.thymeleaf.spring4.view.ThymeleafViewResolver;
+import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
+import org.thymeleaf.templateresolver.ITemplateResolver;
+
+@Configuration
+public class ThymeleafViewResolverConfig {
+    @Bean
+    public ViewResolver thymeleafViewResolver() {
+
+        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
+
+        viewResolver.setTemplateEngine(thymeleafTemplateEngine());
+        viewResolver.setCharacterEncoding("UTF-8");
+
+        return viewResolver;
+    }
+
+    // Thymeleaf template engine with Spring integration
+    @Bean
+    public SpringTemplateEngine thymeleafTemplateEngine() {
+
+        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
+        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
+        templateEngine.addDialect(new LayoutDialect());
+        return templateEngine;
+    }
+
+    @Bean
+    public SpringResourceTemplateResolver springResourceTemplateResolver() {
+        return new SpringResourceTemplateResolver();
+    }
+
+    // Thymeleaf template resolver serving HTML 5
+    @Bean
+    public ITemplateResolver thymeleafTemplateResolver() {
+
+        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
+
+        templateResolver.setPrefix("templates/");
+        templateResolver.setCacheable(false);
+        templateResolver.setSuffix(".html");
+        templateResolver.setTemplateMode("HTML5");
+        templateResolver.setCharacterEncoding("UTF-8");
+
+        return templateResolver;
+    }
+}

+ 17 - 17
src/main/java/com/mooctest/config/WebMvcConfiguration.java

@@ -1,17 +1,17 @@
-package com.mooctest.config;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
-
-@Configuration
-public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
-
-    @Override
-    public void addResourceHandlers(ResourceHandlerRegistry registry) {
-        //加上之后spring才会扫描static下子目录的路径
-        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
-    }
-
-
-}
+package com.mooctest.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        //加上之后spring才会扫描static下子目录的路径
+        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
+    }
+
+
+}

+ 75 - 75
src/main/java/com/mooctest/controller/AggController.java

@@ -1,75 +1,75 @@
-package com.mooctest.controller;
-
-import com.mooctest.cluster.ClusterAnalyzer;
-import com.mooctest.cluster.Group;
-import com.mooctest.event.EventUtil;
-import com.mooctest.event.TaskStartEvent;
-import com.mooctest.image.ImageDownload;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffImg;
-import com.mooctest.data.DiffText;
-import com.mooctest.data.ReportDTO;
-import com.mooctest.model.AggTaskStatus;
-import com.mooctest.model.MasterReport;
-import com.mooctest.nlp.DistanceMatrix;
-import com.mooctest.service.*;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.toMap;
-
-@RestController
-public class AggController {
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-
-    @Autowired
-    AggTaskStatusService aggTaskStatusService;
-
-    @Autowired
-    EventUtil eventUtil;
-    @GetMapping("/aggregate_info")
-    public MasterReport getAggInfo(@RequestParam("bugId") String bugId) {
-        return masterReportService.getByBugId(bugId);
-    }
-
-    @GetMapping("/aggregate")
-    public String aggregate(@RequestParam("examId") long examId,
-                            @RequestParam("caseId") long caseId) throws IOException {
-        TaskStartEvent e = new TaskStartEvent(examId, caseId);
-        eventUtil.post(e);
-
-        return "ok";
-    }
-
-    @GetMapping("/agg_task_status")
-    public int getAggStatus(@RequestParam("examId") long examId,
-                            @RequestParam("caseId") long caseId) {
-        AggTaskStatus status = aggTaskStatusService.getByTaskId(examId, caseId);
-        if (status == null) {
-            return 0;
-        }
-        return status.getStatus();
-    }
-
-
-
-
-
-
-}
+package com.mooctest.controller;
+
+import com.mooctest.cluster.ClusterAnalyzer;
+import com.mooctest.cluster.Group;
+import com.mooctest.event.EventUtil;
+import com.mooctest.event.TaskStartEvent;
+import com.mooctest.image.ImageDownload;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffImg;
+import com.mooctest.data.DiffText;
+import com.mooctest.data.ReportDTO;
+import com.mooctest.model.AggTaskStatus;
+import com.mooctest.model.MasterReport;
+import com.mooctest.nlp.DistanceMatrix;
+import com.mooctest.service.*;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.toMap;
+
+@RestController
+public class AggController {
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+
+    @Autowired
+    AggTaskStatusService aggTaskStatusService;
+
+    @Autowired
+    EventUtil eventUtil;
+    @GetMapping("/aggregate_info")
+    public MasterReport getAggInfo(@RequestParam("bugId") String bugId) {
+        return masterReportService.getByBugId(bugId);
+    }
+
+    @GetMapping("/aggregate")
+    public String aggregate(@RequestParam("examId") long examId,
+                            @RequestParam("caseId") long caseId) throws IOException {
+        TaskStartEvent e = new TaskStartEvent(examId, caseId);
+        eventUtil.post(e);
+
+        return "ok";
+    }
+
+    @GetMapping("/agg_task_status")
+    public int getAggStatus(@RequestParam("examId") long examId,
+                            @RequestParam("caseId") long caseId) {
+        AggTaskStatus status = aggTaskStatusService.getByTaskId(examId, caseId);
+        if (status == null) {
+            return 0;
+        }
+        return status.getStatus();
+    }
+
+
+
+
+
+
+}

+ 241 - 0
src/main/java/com/mooctest/controller/AnalyzeController.java

@@ -0,0 +1,241 @@
+package com.mooctest.controller;
+
+import com.mooctest.service.AnalyzeService;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+//import com.mooctest.service.ReportService;
+
+@Controller
+@RequestMapping(value = "/analyze")
+@CrossOrigin(origins = "*", maxAge = 3600, allowCredentials = "true")
+public class AnalyzeController {
+	
+	@Autowired
+	AnalyzeService aservice;
+	
+//	@Autowired
+//	ReportService rservice;
+	
+	//根据用例获取所有有效bug
+	@RequestMapping(value = "/valid")
+	@ResponseBody
+	public void getValid(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			List<String> list = aservice.getValid(case_take_id);
+			result.put("Count", list.size());
+			result.put("Detail", new JSONArray(list));
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取所有有点赞记录的bug
+	@RequestMapping(value = "/thums")
+	@ResponseBody
+	public void getThums(String case_take_id, HttpServletResponse response) {
+		try {
+			JSONObject result = new JSONObject();
+			PrintWriter out = response.getWriter();
+			Map<String, String> map = aservice.getThums(case_take_id);
+			result.put("Count", map.size());
+			result.put("Detail", new JSONObject(map));
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 47.99.140.117:9001/Bug/api/analyze/scores
+	 *
+	 * @param case_take_id
+	 *            caseId - taskId,示例1632-2927
+	 * @return [{"名字":"庄坤涛","report_id":"10010000035757","报告得分":28,"审查得分":4,"worker_id":"39669"}]
+	 */
+	@RequestMapping(value = "/scores")
+	@ResponseBody
+	public void getScores(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			out.print(aservice.getScores(case_take_id));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 47.99.140.117:9001/Bug/api/analyze/newScores
+	 *
+	 * @param case_take_id
+	 *            caseId - taskId,示例1632-2927
+	 * @return [{"名字":"庄坤涛","report_id":"10010000035757","报告得分":28,"审查得分":4,"worker_id":"39669"}]
+	 */
+	@RequestMapping(value = "/newScores")
+	@ResponseBody
+	public void getNewScores(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			out.print(aservice.getNewScores(aservice.getScores(case_take_id)));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取所有的参与用户
+	@RequestMapping(value = "/users")
+	@ResponseBody
+	public void getUsers(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			out.print(new JSONArray(aservice.getReports(case_take_id)));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取指定bug的打分等级
+	@RequestMapping(value = "/grade/{id}")
+	@ResponseBody
+	public String getGrade(@PathVariable String id) {
+		JSONObject result = new JSONObject();
+		try {
+			result.put("grade", aservice.getGrade(id));
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return result.toString();
+	}
+	
+	//存储单个bug的打分等级
+	@RequestMapping(value = "/save")
+	@ResponseBody
+	public void saveGrade(String id, String grade, HttpServletResponse response) {
+		try {
+			JSONObject result = new JSONObject();
+			if(aservice.saveGrade(id, Integer.parseInt(grade))) {result.put("status", "200");}
+			else {result.put("status", "500");}
+			PrintWriter out = response.getWriter();
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取页面和种类的分布情况
+	@RequestMapping(value = "/bugDetail")
+	@ResponseBody
+	public void getDetail(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			out.print(aservice.getCaseDetail(case_take_id));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取所有打分等级
+	@RequestMapping(value = "/allGrades")
+	@ResponseBody
+	public void getAllGrades(String case_take_id, HttpServletResponse response) {
+		try {
+			JSONObject result = new JSONObject();
+			Map<String, Integer> map = aservice.getAllGrades(case_take_id);
+			result.put("Count", map.size());
+			result.put("Detail", new JSONObject(map));
+			PrintWriter out = response.getWriter();
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//判断哪些还没有打分,split后面是用例表中不存在的bug
+	@RequestMapping(value = "/diff")
+	@ResponseBody
+	public void getDiff(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			List<String> list = aservice.getDiff(case_take_id);
+			result.put("Count", list.size());
+			result.put("Detail", new JSONArray(list));
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//获取路径信息
+//	@RequestMapping(value = "/path")
+//	@ResponseBody
+//	public void getUserPath(String case_take_id, String report_id, HttpServletResponse response) {
+//		try {
+//			PrintWriter out = response.getWriter();
+//			JSONObject result = new JSONObject();
+//			result.put("all", filter(aservice.getBugDetail(case_take_id)));
+//			result.put("self", filter(rservice.getUserPath(report_id, case_take_id)));
+//			out.print(result);
+//			out.flush();
+//			out.close();
+//		} catch (Exception e) {
+//			// TODO Auto-generated catch block
+//			e.printStackTrace();
+//		}
+//	}
+	
+	private Map<String, Integer> filter(Map<String, Integer> maps) {
+		Map<String, Integer> result = new HashMap<String, Integer>();
+		for(Map.Entry<String, Integer> entry : maps.entrySet()) {
+			String[] pages = entry.getKey().split("-");
+			if(pages.length > 0) {
+				String key = pages[pages.length - 1];
+				result.put(key, result.getOrDefault(key, 0) + entry.getValue());
+			}
+		}
+		return result;
+	}
+}

+ 20 - 20
src/main/java/com/mooctest/controller/BugReviewController.java

@@ -1,20 +1,20 @@
-package com.mooctest.controller;
-
-import com.mooctest.service.BugReviewService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-public class BugReviewController {
-
-    @Autowired
-    BugReviewService bugReviewService;
-
-    @PutMapping("/bug_review")
-    public void queryReportReviewStatus(@RequestParam("masterId") String masterId) {
-        bugReviewService.aggReportReview(masterId);
-    }
-
-}
+package com.mooctest.controller;
+
+import com.mooctest.service.BugReviewService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class BugReviewController {
+
+    @Autowired
+    BugReviewService bugReviewService;
+
+    @PutMapping("/bug_review")
+    public void queryReportReviewStatus(@RequestParam("masterId") String masterId) {
+        bugReviewService.aggReportReview(masterId);
+    }
+
+}

+ 91 - 91
src/main/java/com/mooctest/controller/FinalReportController.java

@@ -1,91 +1,91 @@
-package com.mooctest.controller;
-
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.FinalReportDTO;
-import com.mooctest.data.TaskDTO;
-import com.mooctest.service.BugReportService;
-import com.mooctest.service.FinalReportService;
-import com.mooctest.service.TaskService;
-import com.mooctest.util.ReportUtil;
-import org.apache.tomcat.util.http.fileupload.IOUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.client.ClientHttpRequest;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.client.RestTemplate;
-
-import javax.servlet.http.HttpServletResponse;
-import java.util.List;
-
-@Controller
-public class FinalReportController {
-    @Autowired
-    FinalReportService finalReportService;
-
-    @Autowired
-    TaskService taskService;
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @PostMapping("final_report")
-    @ResponseBody
-    public FinalReportDTO createReport(@RequestBody FinalReportDTO dto) {
-
-        return finalReportService.save(dto);
-    }
-
-    @GetMapping("final_reports")
-    public String getByExamIdAndCaseId(@RequestParam("examId") long examId,
-                                       @RequestParam("caseId") long caseId,
-                                       Model model) {
-
-        List<FinalReportDTO> finalReports = finalReportService.getByExamIdAndCaseId(examId, caseId);
-        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
-        model.addAttribute("finalReports", finalReports);
-        model.addAttribute("severity2String", ReportUtil.severity2String);
-        model.addAttribute("category2String", ReportUtil.category2String);
-        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
-        model.addAttribute("examId", examId);
-        model.addAttribute("caseId", caseId);
-        model.addAttribute("task", task);
-        return "final_report_list";
-    }
-
-    @DeleteMapping("final_report/{reportId}")
-    @ResponseBody
-    public long deleteReport(@PathVariable long reportId) {
-        finalReportService.delete(reportId);
-        return reportId;
-    }
-
-    @PutMapping("final_report/{reportId}")
-    @ResponseBody
-    public FinalReportDTO updateReport(@PathVariable long reportId,
-                             @RequestBody FinalReportDTO dto) {
-        return finalReportService.update(reportId, dto);
-    }
-
-    @GetMapping("final_report/export")
-    @ResponseBody
-    public String export(@RequestParam("examId") long examId,
-                         @RequestParam("caseId") long caseId) {
-
-        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
-
-        return finalReportService.getExportReportAddr(task);
-    }
-
-    @RequestMapping(value = "/appendBugToFinalReport")
-    @ResponseBody
-    public void processRequest(
-            @RequestParam("examId") long examId,
-            @RequestParam("caseId") long caseId) {
-        List<BugDTO> allBugs = bugReportService.getAllBugs(examId, caseId);
-
-        finalReportService.transAllBug2FinalReport(allBugs, examId, caseId);
-    }
-}
+package com.mooctest.controller;
+
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.FinalReportDTO;
+import com.mooctest.data.TaskDTO;
+import com.mooctest.service.BugReportService;
+import com.mooctest.service.FinalReportService;
+import com.mooctest.service.TaskService;
+import com.mooctest.util.ReportUtil;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.ClientHttpRequest;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.client.RestTemplate;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+@Controller
+public class FinalReportController {
+    @Autowired
+    FinalReportService finalReportService;
+
+    @Autowired
+    TaskService taskService;
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @PostMapping("final_report")
+    @ResponseBody
+    public FinalReportDTO createReport(@RequestBody FinalReportDTO dto) {
+
+        return finalReportService.save(dto);
+    }
+
+    @GetMapping("final_reports")
+    public String getByExamIdAndCaseId(@RequestParam("examId") long examId,
+                                       @RequestParam("caseId") long caseId,
+                                       Model model) {
+
+        List<FinalReportDTO> finalReports = finalReportService.getByExamIdAndCaseId(examId, caseId);
+        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+        model.addAttribute("finalReports", finalReports);
+        model.addAttribute("severity2String", ReportUtil.severity2String);
+        model.addAttribute("category2String", ReportUtil.category2String);
+        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
+        model.addAttribute("examId", examId);
+        model.addAttribute("caseId", caseId);
+        model.addAttribute("task", task);
+        return "final_report_list";
+    }
+
+    @DeleteMapping("final_report/{reportId}")
+    @ResponseBody
+    public long deleteReport(@PathVariable long reportId) {
+        finalReportService.delete(reportId);
+        return reportId;
+    }
+
+    @PutMapping("final_report/{reportId}")
+    @ResponseBody
+    public FinalReportDTO updateReport(@PathVariable long reportId,
+                             @RequestBody FinalReportDTO dto) {
+        return finalReportService.update(reportId, dto);
+    }
+
+    @GetMapping("final_report/export")
+    @ResponseBody
+    public String export(@RequestParam("examId") long examId,
+                         @RequestParam("caseId") long caseId) {
+
+        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+
+        return finalReportService.getExportReportAddr(task);
+    }
+
+    @RequestMapping(value = "/appendBugToFinalReport")
+    @ResponseBody
+    public void processRequest(
+            @RequestParam("examId") long examId,
+            @RequestParam("caseId") long caseId) {
+        List<BugDTO> allBugs = bugReportService.getAllBugs(examId, caseId);
+
+        finalReportService.transAllBug2FinalReport(allBugs, examId, caseId);
+    }
+}

+ 113 - 113
src/main/java/com/mooctest/controller/GraphController.java

@@ -1,113 +1,113 @@
-package com.mooctest.controller;
-
-import com.alibaba.fastjson.JSONObject;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.SupplementDTO;
-import com.mooctest.model.MasterReport;
-import com.mooctest.service.BugReportService;
-import com.mooctest.service.GraphService;
-import com.mooctest.service.MasterReportService;
-import com.mooctest.service.SupplementService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.View;
-import org.springframework.web.servlet.ViewResolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-@RestController
-public class GraphController {
-    @Autowired
-    GraphService graphService;
-
-    @Autowired
-    ViewResolver viewResolver;
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    SupplementService supplementService;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    @GetMapping(value = "/graph")
-    public JSONObject getGraphData(@RequestParam("masterId") String masterId) {
-
-        return graphService.buildAggReportGraph(masterId);
-    }
-    @GetMapping(value = "/tree")
-    public JSONObject getTreeData(@RequestParam("masterId") String masterId) {
-
-        return graphService.buildAggReportTree(masterId);
-    }
-
-    @GetMapping(value = "/graphDetail/rawReport")
-    public void renderRawReport(@RequestParam("bugId") String bugId,
-                                  @RequestParam("masterId") String masterId,
-                                  @RequestParam(value = "isMaster", required = false, defaultValue = "false") boolean isMaster,
-                                  Model model,
-                                  HttpServletRequest req,
-                                  HttpServletResponse resp) throws Exception {
-
-        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
-        long examId = ids[0];
-        long caseId = ids[1];
-        BugDTO bug = bugReportService.getBugById(bugId, examId, caseId);
-        model.addAttribute("bugReport", bug);
-        model.addAttribute("isMaster", isMaster);
-
-        View rawReportView = viewResolver.resolveViewName("thumbnail/raw_report", Locale.CHINESE);
-
-        rawReportView.render(model.asMap(), req, resp);
-
-    }
-
-    @GetMapping(value = "/graphDetail/supReport")
-    public void renderSupReport(@RequestParam("masterId") String masterId,
-                                @RequestParam("supId") String supId,
-                                HttpServletRequest req,
-                                HttpServletResponse resp,
-                                Model model) throws Exception {
-
-        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
-        long examId = ids[0];
-        long caseId = ids[1];
-        Map<String, BugDTO> bugMap = bugReportService.getAllBugsMap(examId, caseId);
-        SupplementDTO supplementDTO = supplementService.findBySupId(supId, bugMap);
-        model.addAttribute("supId", supplementDTO.getSupplementId());
-        model.addAttribute("supplement", supplementDTO);
-
-        View rawReportView = viewResolver.resolveViewName("thumbnail/sup_report", Locale.CHINESE);
-
-        rawReportView.render(model.asMap(), req, resp);
-    }
-
-    @GetMapping(value = "/graphDetail/aggReport")
-    public void renderAggReport(@RequestParam("masterId") String masterId,
-                                HttpServletRequest req,
-                                HttpServletResponse resp,
-                                Model model) throws Exception {
-
-        List<SupplementDTO> supplements = supplementService.getSupplementTopInfoByMasterId(masterId);
-        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
-        long examId = ids[0];
-        long caseId = ids[1];
-
-        BugDTO masterReport = bugReportService.getBugById(masterId, examId, caseId);
-        model.addAttribute("aggReportId", "ML-AG-" + masterId.substring(10));
-        model.addAttribute("supplements", supplements);
-        model.addAttribute("masterReport", masterReport);
-
-        View rawReportView = viewResolver.resolveViewName("thumbnail/agg_report", Locale.CHINESE);
-        rawReportView.render(model.asMap(), req, resp);
-    }
-}
+package com.mooctest.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.SupplementDTO;
+import com.mooctest.model.MasterReport;
+import com.mooctest.service.BugReportService;
+import com.mooctest.service.GraphService;
+import com.mooctest.service.MasterReportService;
+import com.mooctest.service.SupplementService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.ViewResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+@RestController
+public class GraphController {
+    @Autowired
+    GraphService graphService;
+
+    @Autowired
+    ViewResolver viewResolver;
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    SupplementService supplementService;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    @GetMapping(value = "/graph")
+    public JSONObject getGraphData(@RequestParam("masterId") String masterId) {
+
+        return graphService.buildAggReportGraph(masterId);
+    }
+    @GetMapping(value = "/tree")
+    public JSONObject getTreeData(@RequestParam("masterId") String masterId) {
+
+        return graphService.buildAggReportTree(masterId);
+    }
+
+    @GetMapping(value = "/graphDetail/rawReport")
+    public void renderRawReport(@RequestParam("bugId") String bugId,
+                                  @RequestParam("masterId") String masterId,
+                                  @RequestParam(value = "isMaster", required = false, defaultValue = "false") boolean isMaster,
+                                  Model model,
+                                  HttpServletRequest req,
+                                  HttpServletResponse resp) throws Exception {
+
+        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
+        long examId = ids[0];
+        long caseId = ids[1];
+        BugDTO bug = bugReportService.getBugById(bugId, examId, caseId);
+        model.addAttribute("bugReport", bug);
+        model.addAttribute("isMaster", isMaster);
+
+        View rawReportView = viewResolver.resolveViewName("thumbnail/raw_report", Locale.CHINESE);
+
+        rawReportView.render(model.asMap(), req, resp);
+
+    }
+
+    @GetMapping(value = "/graphDetail/supReport")
+    public void renderSupReport(@RequestParam("masterId") String masterId,
+                                @RequestParam("supId") String supId,
+                                HttpServletRequest req,
+                                HttpServletResponse resp,
+                                Model model) throws Exception {
+
+        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
+        long examId = ids[0];
+        long caseId = ids[1];
+        Map<String, BugDTO> bugMap = bugReportService.getAllBugsMap(examId, caseId);
+        SupplementDTO supplementDTO = supplementService.findBySupId(supId, bugMap);
+        model.addAttribute("supId", supplementDTO.getSupplementId());
+        model.addAttribute("supplement", supplementDTO);
+
+        View rawReportView = viewResolver.resolveViewName("thumbnail/sup_report", Locale.CHINESE);
+
+        rawReportView.render(model.asMap(), req, resp);
+    }
+
+    @GetMapping(value = "/graphDetail/aggReport")
+    public void renderAggReport(@RequestParam("masterId") String masterId,
+                                HttpServletRequest req,
+                                HttpServletResponse resp,
+                                Model model) throws Exception {
+
+        List<SupplementDTO> supplements = supplementService.getSupplementTopInfoByMasterId(masterId);
+        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
+        long examId = ids[0];
+        long caseId = ids[1];
+
+        BugDTO masterReport = bugReportService.getBugById(masterId, examId, caseId);
+        model.addAttribute("aggReportId", "ML-AG-" + masterId.substring(10));
+        model.addAttribute("supplements", supplements);
+        model.addAttribute("masterReport", masterReport);
+
+        View rawReportView = viewResolver.resolveViewName("thumbnail/agg_report", Locale.CHINESE);
+        rawReportView.render(model.asMap(), req, resp);
+    }
+}

+ 117 - 117
src/main/java/com/mooctest/controller/HelloController.java

@@ -1,117 +1,117 @@
-package com.mooctest.controller;
-
-import com.hankcs.hanlp.mining.cluster.ClusterAnalyzer;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.BugHistoryDTO;
-import com.mooctest.data.ReportDTO;
-import com.mooctest.service.BugHistoryService;
-import com.mooctest.service.BugReportService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-@RestController
-public class HelloController {
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    BugHistoryService bugHistoryService;
-
-    @RequestMapping("/hello")
-    public List<Double> hello(@RequestParam String algorithm) {
-
-        List<BugDTO> bugs = bugReportService.getAllBugs(2613, 1489);
-
-        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<String>();
-        bugs.forEach(bugDTO -> analyzer.addDocument(bugDTO.getId(), bugDTO.getDescription()));
-
-        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
-        List<BugHistoryDTO> his = bugHistoryService.getBugHistory(bugIds);
-//        System.out.println("kmeans:");
-//        showClusterResult(analyzer.kmeans(25), bugs);
-
-//        System.out.println("bisection:");
-//        showClusterResult(analyzer.repeatedBisection(10), bugs);
-//
-//        System.out.println("bisection-auto:");
-//        showClusterResult(analyzer.repeatedBisection(1.0), bugs);
-
-        List<Set<String>> clusters = null;
-        if (algorithm.equals("bi-auto")) {
-
-            clusters = analyzer.repeatedBisection(1.0);
-        } else if (algorithm.equals("kmeans")) {
-            clusters = analyzer.kmeans(30);
-        }
-        List<Double> scores = evaluateCluster(clusters, his, bugs);
-        return scores;
-    }
-
-
-    public void showClusterResult(List<Set<String>> results, List<BugDTO> bugs) {
-        System.out.println("size: " + results.size());
-        results.forEach(cluster -> {
-            System.out.println("[");
-            cluster.forEach(bugId -> {
-                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
-                System.out.println(result.get(0).getDescription());
-            });
-            System.out.println("]");
-        });
-    }
-
-    public List<Double> evaluateCluster(List<Set<String>> clusters, List<BugHistoryDTO> his, List<BugDTO> bugs) {
-
-        Map<String, Long> treeSize = his.stream().collect(Collectors.groupingBy(BugHistoryDTO::getRoot, Collectors.counting()));
-
-        Map<String, String> treeRootMap = his.stream().collect(Collectors.toMap(BugHistoryDTO::getId, BugHistoryDTO::getRoot));
-        return clusters.stream().map(cluster -> {
-
-            System.out.println("[");
-
-            cluster.forEach(bugId -> {
-                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
-                System.out.println(bugId + " " + result.get(0).getDescription());
-            });
-            System.out.println();
-
-            Set<String> roots = cluster.stream()
-                    .filter(bugId -> treeRootMap.get(bugId) != null)
-                    .map(bugId -> treeRootMap.get(bugId))
-                    .filter(rootId -> treeSize.get(rootId) > 1)
-                    .collect(Collectors.toSet());
-
-            roots.forEach(bugId -> {
-                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
-                System.out.println(bugId + " " + result.get(0).getDescription());
-            });
-
-            long totalTreeBugs = roots.stream()
-                    .mapToLong(rootBugId -> treeSize.get(rootBugId))
-                    .sum();
-            if (totalTreeBugs == 0) {
-                return 0.0;
-            }
-            long bugOfTreeCounts = cluster.stream()
-                    .filter(bugId -> treeRootMap.get(bugId) != null)
-                    .map(bugId -> treeRootMap.get(bugId))
-                    .filter(rootId -> treeSize.get(rootId) > 1)
-                    .count();
-
-            System.out.println("result" + ((bugOfTreeCounts * 1.0) / totalTreeBugs));
-            System.out.println("]");
-            return (bugOfTreeCounts * 1.0) / totalTreeBugs;
-        })
-                .sorted((d1, d2) -> Double.compare(d2, d1))
-                .collect(Collectors.toList());
-    }
-
-}
+package com.mooctest.controller;
+
+import com.hankcs.hanlp.mining.cluster.ClusterAnalyzer;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.BugHistoryDTO;
+import com.mooctest.data.ReportDTO;
+import com.mooctest.service.BugHistoryService;
+import com.mooctest.service.BugReportService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RestController
+public class HelloController {
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    BugHistoryService bugHistoryService;
+
+    @RequestMapping("/hello")
+    public List<Double> hello(@RequestParam String algorithm) {
+
+        List<BugDTO> bugs = bugReportService.getAllBugs(2613, 1489);
+
+        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<String>();
+        bugs.forEach(bugDTO -> analyzer.addDocument(bugDTO.getId(), bugDTO.getDescription()));
+
+        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
+        List<BugHistoryDTO> his = bugHistoryService.getBugHistory(bugIds);
+//        System.out.println("kmeans:");
+//        showClusterResult(analyzer.kmeans(25), bugs);
+
+//        System.out.println("bisection:");
+//        showClusterResult(analyzer.repeatedBisection(10), bugs);
+//
+//        System.out.println("bisection-auto:");
+//        showClusterResult(analyzer.repeatedBisection(1.0), bugs);
+
+        List<Set<String>> clusters = null;
+        if (algorithm.equals("bi-auto")) {
+
+            clusters = analyzer.repeatedBisection(1.0);
+        } else if (algorithm.equals("kmeans")) {
+            clusters = analyzer.kmeans(30);
+        }
+        List<Double> scores = evaluateCluster(clusters, his, bugs);
+        return scores;
+    }
+
+
+    public void showClusterResult(List<Set<String>> results, List<BugDTO> bugs) {
+        System.out.println("size: " + results.size());
+        results.forEach(cluster -> {
+            System.out.println("[");
+            cluster.forEach(bugId -> {
+                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
+                System.out.println(result.get(0).getDescription());
+            });
+            System.out.println("]");
+        });
+    }
+
+    public List<Double> evaluateCluster(List<Set<String>> clusters, List<BugHistoryDTO> his, List<BugDTO> bugs) {
+
+        Map<String, Long> treeSize = his.stream().collect(Collectors.groupingBy(BugHistoryDTO::getRoot, Collectors.counting()));
+
+        Map<String, String> treeRootMap = his.stream().collect(Collectors.toMap(BugHistoryDTO::getId, BugHistoryDTO::getRoot));
+        return clusters.stream().map(cluster -> {
+
+            System.out.println("[");
+
+            cluster.forEach(bugId -> {
+                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
+                System.out.println(bugId + " " + result.get(0).getDescription());
+            });
+            System.out.println();
+
+            Set<String> roots = cluster.stream()
+                    .filter(bugId -> treeRootMap.get(bugId) != null)
+                    .map(bugId -> treeRootMap.get(bugId))
+                    .filter(rootId -> treeSize.get(rootId) > 1)
+                    .collect(Collectors.toSet());
+
+            roots.forEach(bugId -> {
+                List<BugDTO> result = bugs.stream().filter(b -> b.getId().equals(bugId)).collect(Collectors.toList());
+                System.out.println(bugId + " " + result.get(0).getDescription());
+            });
+
+            long totalTreeBugs = roots.stream()
+                    .mapToLong(rootBugId -> treeSize.get(rootBugId))
+                    .sum();
+            if (totalTreeBugs == 0) {
+                return 0.0;
+            }
+            long bugOfTreeCounts = cluster.stream()
+                    .filter(bugId -> treeRootMap.get(bugId) != null)
+                    .map(bugId -> treeRootMap.get(bugId))
+                    .filter(rootId -> treeSize.get(rootId) > 1)
+                    .count();
+
+            System.out.println("result" + ((bugOfTreeCounts * 1.0) / totalTreeBugs));
+            System.out.println("]");
+            return (bugOfTreeCounts * 1.0) / totalTreeBugs;
+        })
+                .sorted((d1, d2) -> Double.compare(d2, d1))
+                .collect(Collectors.toList());
+    }
+
+}

+ 215 - 0
src/main/java/com/mooctest/controller/HistoryController.java

@@ -0,0 +1,215 @@
+package com.mooctest.controller;
+
+import com.mooctest.data.TaskDTO;
+import com.mooctest.service.AnalyzeService;
+import com.mooctest.service.HistoryService;
+import com.mooctest.service.RecommendService;
+import com.mooctest.service.TaskService;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+@Controller
+@RequestMapping(value = "/history")
+@CrossOrigin(origins = "*", maxAge = 3600, allowCredentials = "true")
+public class HistoryController {
+	
+	@Autowired
+	HistoryService hisservice;
+
+	@Autowired
+    TaskService taskService;
+
+	@Autowired
+	AnalyzeService aservice;
+	
+	@Autowired
+	RecommendService recservice;
+
+	//获取指定节点的历史信息
+//	@RequestMapping(value = "/getHistory")
+//	@ResponseBody
+//	public void getHistory(String id, HttpServletResponse response) {
+//		try {
+//			PrintWriter out = response.getWriter();
+//			out.print(new JSONObject(hisservice.getHistory(id)));
+//			out.flush();
+//			out.close();
+//		} catch (IOException e) {
+//			e.printStackTrace();
+//		} catch (JSONException e) {
+//			e.printStackTrace();
+//		}
+//	}
+	
+	//获取所有根节点
+	@RequestMapping(value = "/getRoots")
+	@ResponseBody
+	public void getRoots(String case_take_id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			List<String> list = hisservice.getRoots(case_take_id);
+			result.put("Count", list.size());
+			result.put("TreeRoot", new JSONArray(list));
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+	}
+
+    @RequestMapping(value = "/getTrees2")
+    public String getTrees2(@RequestParam("case_take_id") String case_take_id) {
+	    return "managerCheck";
+    }
+
+
+	//获取所有形成树状结构的bug根节点
+//	case_take_id=1281-2724&start=0&count=10&page=null&identity=0&report_id=5cbc1a9f825a8960cdc7bd4f&worker_id=22383
+	@RequestMapping(value = "/getTrees")
+	public String getTrees(@RequestParam("case_take_id") String case_take_id, @RequestParam("start") String start,
+						   @RequestParam("count") String count, @RequestParam("page") String page,
+						   @RequestParam("identity") String identity, @RequestParam("report_id") String report_id,
+						   @RequestParam("worker_id") String worker_id,Model model) {
+		System.out.println("case_take_id = " + case_take_id);
+		String[] split = case_take_id.split("-");
+		long caseId =  Long.parseLong(split[0]);
+		long examId =  Long.parseLong(split[1]);
+		try {
+			JSONObject result = new JSONObject();
+
+			List<String> all = hisservice.getTreeRoots(case_take_id);
+			System.out.println("all.toString(): " + all.toString());
+			hisservice.pageFilter(all, page);
+			List<String> ids = all.subList(Integer.parseInt(start), Math.min(all.size(), Integer.parseInt(start) + Integer.parseInt(count)));
+			List<List<String>> list = new ArrayList<List<String>>();
+			System.out.println(ids.toString());
+			for(String id: ids) {
+				list.add(hisservice.getDetail(id));
+			}
+			TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+			result.put("Count", all.size());
+			result.put("TreeRoot", new JSONArray(list));
+//			System.out.println("list = " + list);
+			System.out.println("/getTrees result = " + result);
+			model.addAttribute("examId", examId);
+			model.addAttribute("caseId", caseId);
+			model.addAttribute("task", task);
+			model.addAttribute("Count", all.size());
+			model.addAttribute("TreeRoot", list);
+			model.addAttribute("identity", identity);
+			model.addAttribute("report_id", report_id);
+			model.addAttribute("worker_id", worker_id);
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+		return "managerCheck";
+	}
+
+	//获取所有形成树状结构的bug根节点
+	@RequestMapping(value = "/getTreesList/{case_take_id}/{start}/{count}/{page}")
+	@ResponseBody
+	public String getTreesList(@PathVariable String case_take_id, @PathVariable String start,
+							   @PathVariable String count, @PathVariable String page) {
+		System.out.println("case_take_id = " + case_take_id);
+		JSONObject result = new JSONObject();
+		String[] split = case_take_id.split("-");
+		long caseId =  Long.parseLong(split[0]);
+		long examId =  Long.parseLong(split[1]);
+		List<String> all = hisservice.getTreeRoots(case_take_id);
+		hisservice.pageFilter(all, page);
+		List<String> ids = all.subList(Integer.parseInt(start), Math.min(all.size(), Integer.parseInt(start) + Integer.parseInt(count)));
+		List<List<String>> list = new ArrayList<List<String>>();
+		for(String id: ids) {
+			list.add(hisservice.getDetail(id));
+		}
+		TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+		try {
+			result.put("Count", all.size());
+			result.put("TreeRoot", new JSONArray(list));
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+		return result.toString();
+	}
+	
+	//获取所有单个节点的数据
+	@RequestMapping(value = "/getSingle/{case_take_id}/{start}/{count}/{page}")
+	@ResponseBody
+	public String getSingle(@PathVariable String case_take_id, @PathVariable String start,
+						  @PathVariable String count, @PathVariable String page) {
+		JSONObject result = new JSONObject();
+		try {
+			List<String> all = new ArrayList<String>();
+			for(String id : hisservice.getRoots(case_take_id)) {
+				if(hisservice.getHistory(id).getChildren().size() == 0) {all.add(id);}
+			}
+			hisservice.pageFilter(all, page);
+			List<String> ids = all.subList(Integer.parseInt(start), Math.min(all.size(), Integer.parseInt(start) + Integer.parseInt(count)));
+			List<String> invalid = hisservice.getInvalid(ids);
+			for(String id: invalid) {
+				if(ids.contains(id)) {ids.remove(id);}
+			}
+			
+			List<List<String>> list = new ArrayList<List<String>>();
+			for(String id : ids) {
+				List<String> temp = new ArrayList<String>();
+				temp.add(id);
+				int score = aservice.getGrade(id);
+				if(score != -1) {temp.add("true");}
+				else {temp.add("false");}
+				temp.add(recservice.getTitle(id));
+				list.add(temp);
+			}
+			result.put("Count", all.size());
+			result.put("TreeRoot", new JSONArray(list));
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+		return result.toString();
+	}
+	
+	//获取指定bug的所有路径
+	@RequestMapping(value = "/getPath/{id}")
+	@ResponseBody
+	public String getPath(@PathVariable String id) {
+		JSONObject result = new JSONObject();
+		try {
+			List<List<String>> lists = hisservice.getDepth(id);
+			Set<String> filter = hisservice.filter(lists);
+			result.put("path", new JSONArray(lists));
+			result.put("invalid", new JSONArray(hisservice.getInvalid(filter)));
+			List<String> ids = new ArrayList<String>(filter);
+			result.put("score", new JSONArray(aservice.getScores(ids)));
+			System.out.println("/getPath path = " + result);
+			System.out.println("result.toString() = " + result.toString());
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+		return result.toString();
+	}
+	
+	@RequestMapping(value = "/fresh")
+	@ResponseBody
+	public void fresh(HttpSession session, HttpServletResponse response) {
+		if(session.getAttribute("trees") != null) {session.removeAttribute("trees");}
+		if(session.getAttribute("single") != null) {session.removeAttribute("single");}
+	}
+}

+ 228 - 0
src/main/java/com/mooctest/controller/RecommendController.java

@@ -0,0 +1,228 @@
+package com.mooctest.controller;
+
+import com.mooctest.model.Bug;
+import com.mooctest.model.BugMirror;
+import com.mooctest.service.HistoryService;
+import com.mooctest.service.RecommendService;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+@Controller
+@RequestMapping(value = "/rec")
+@CrossOrigin(origins = "*", maxAge = 3600, allowCredentials = "true")
+public class RecommendController {
+	
+	@Autowired
+	RecommendService recservice;
+	
+	@Autowired
+	HistoryService historyservice;
+	
+//	@Autowired
+//	UserBasedService ubservice;
+//
+//	@Autowired
+//	DivRecService divservice;
+
+	/**
+	 * 每次刷新或进入填写页面,都应该调用一次该方法,因为其中包含了一些初始化操作
+	 * @param case_take_id
+	 * @return 该题目下排完序的BugMirror类的列表
+	 */
+	@RequestMapping(value = "/getList")
+	@ResponseBody
+	public void getList(String case_take_id, String report_id, HttpSession session, HttpServletResponse response) {
+		try {
+			if(session.getAttribute("rec") != null) {
+				session.removeAttribute("rec");
+			}
+			if(session.getAttribute("page") != null) {
+				session.removeAttribute("page");
+			}
+			if(session.getAttribute("path") != null) {
+				session.removeAttribute("path");
+			}
+			if(session.getAttribute("title") != null) {
+				session.removeAttribute("title");
+			}
+			if(session.getAttribute("des") != null) {
+				session.removeAttribute("des");
+			}
+			session.setAttribute("case", case_take_id);
+			session.setAttribute("report", report_id);
+			PrintWriter out = response.getWriter();
+			List<BugMirror> mirrors = recservice.getList(case_take_id, report_id);
+			filter(historyservice.getNew(case_take_id, report_id), mirrors);
+			out.print(new JSONArray(mirrors));
+			out.flush();
+			out.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 用户点击查看一个Bug的详细信息
+	 * @param id
+	 * @return Bug类
+	 */
+	@RequestMapping(value = "/getDetail/{id}")
+	@ResponseBody
+	public String getDetail(@PathVariable  String id) {
+		JSONObject result = new JSONObject();
+		try {
+			Bug bug = recservice.getDetail(id);
+			JSONObject result1 = new JSONObject();
+			if(bug != null) {
+				result.put("detail", new JSONObject(bug));
+				result.put("history", new JSONObject(historyservice.getHistory(id)));
+				result.put("mirror", new JSONObject(recservice.getMirror(id)));
+			}
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+		System.out.println("/getDetail result = " + result);
+		return result.toString();
+	}
+	
+	/**
+	 * 用户点击六个类别之后,都使用该接口
+	 * @param type("category", "severity", "recurrent", "page1", "page2", "page3"), content
+	 * @return List<BugMirror>
+	 */
+	@RequestMapping(value = "/recommend")
+	@ResponseBody
+	public void recommend(String case_take_id, String type, String content, HttpSession session, HttpServletResponse response) {
+		try {
+			JSONObject result = new JSONObject();
+			PrintWriter out = response.getWriter();
+			List<BugMirror> mirror1 = new ArrayList<BugMirror>();
+			List<Float> scores = new ArrayList<Float>();
+			Set<BugMirror> mirror2 = new HashSet<BugMirror>();
+			Map<BugMirror, Float> map;
+			if(type.equals("title") || type.equals("description")) {
+				if(type.equals("title")) {map = recservice.recommandByTitle(content, session);}
+				else {map = recservice.recommandByDes(content, session);}
+				if(mirror1 != null) {
+					mirror1.addAll(map.keySet());
+					scores.addAll(map.values());
+				}
+			} else {
+				if(type.contains("page")) {map = recservice.recommndByPage(case_take_id, type, content, true, session);}
+				else {map = recservice.recommend(case_take_id, type, content, true, session);}
+				List<String> reports = new ArrayList<String>();
+				reports.add((String)session.getAttribute("report"));
+				if(mirror1 != null) {
+					mirror1.addAll(map.keySet());
+					scores.addAll(map.values());
+				}
+//				for(int i = 1; i <= mirror1.size(); i ++) {
+//					String temp = recservice.getReport(mirror1.get(i - 1).getId());
+//					if(!reports.contains(temp)) {reports.add(temp);}
+//				}
+//				mirror2.addAll(ubservice.UserBased(reports.toArray(new String[reports.size()])));
+			}
+//			mirror2.addAll(historyservice.getNew(case_take_id, (String)session.getAttribute("report")));
+//			filter(mirror2, mirror1);
+			try {
+				result.put("same", new JSONArray(mirror1));
+				result.put("scores", new JSONArray(scores));
+				result.put("new", new JSONArray(mirror2));
+			} catch (JSONException e) {
+				e.printStackTrace();
+			}
+
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+//	@RequestMapping(value = "/diversity")
+//	@ResponseBody
+//	public void diversityRec(String case_take_id, String report_id, HttpServletResponse response) {
+//		try {
+//			PrintWriter out = response.getWriter();
+//			out.println(new JSONArray(divservice.diverseRec(report_id, case_take_id)));
+//			out.flush();
+//			out.close();
+//		} catch (Exception e) {
+//			e.printStackTrace();
+//		}
+//	}
+	
+	//获取标题
+	@RequestMapping(value = "/title")
+	@ResponseBody
+	public void getTitle(String id, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			out.print(recservice.getTitle(id));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	//fork时,传回所有的选择参数
+	@RequestMapping(value = "/fork")
+	@ResponseBody
+	public void fork(String page1, String page2, String page3, String bug_category, String severity, String recurrent, HttpSession session, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			Map<String, String> map = new LinkedHashMap<String, String>();
+			if(!page1.equals("null")) {map.put("page1", page1);}
+			if(!page2.equals("null")) {map.put("page2", page2);}
+			if(!page3.equals("null")) {map.put("page3", page3);}
+			map.put("bug_category", bug_category);
+			map.put("severity", severity);
+			map.put("recurrent", recurrent);
+			session.setAttribute("path", map);
+			result.put("status", 200);
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	public static void filter(List<BugMirror> a, List<BugMirror> b) {
+		if(a == null) {return;}
+		for(BugMirror a1: a) {
+			boolean flag = true;
+			for(BugMirror b1 : b) {
+				if(a1.getId().equals(b1.getId())) {flag = false;}
+			}
+			if(flag) {b.add(a1);}
+		}
+	}
+	
+	public static void filter(Set<BugMirror> a, List<BugMirror> b) {
+		if(a == null || b == null) {return;}
+		for(BugMirror mirror : b) {
+			if(a.contains(mirror)) {a.remove(mirror);}
+		}
+	}
+}

+ 185 - 185
src/main/java/com/mooctest/controller/ReportController.java

@@ -1,185 +1,185 @@
-package com.mooctest.controller;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.hankcs.hanlp.seg.Segment;
-import com.hankcs.hanlp.seg.common.Term;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.FinalReportDTO;
-import com.mooctest.data.SupplementDTO;
-import com.mooctest.data.TaskDTO;
-import com.mooctest.model.MasterReport;
-import com.mooctest.service.*;
-import com.mooctest.util.NLPUtil;
-import com.mooctest.util.ReportUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.util.ResourceUtils;
-import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletRequest;
-import java.io.*;
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.toMap;
-
-@Controller
-public class ReportController {
-
-    @Autowired
-    SupplementService supplementService;
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    @Autowired
-    FinalReportService finalReportService;
-
-    @Autowired
-    BugReviewService bugReviewService;
-
-    @Autowired
-    TaskService taskService;
-
-    @GetMapping(value = "/index")
-    public String hello(HttpServletRequest request, @RequestParam(value = "name", required = false, defaultValue = "springboot-thymeleaf") String name) {
-        request.setAttribute("name", name);
-        return "index";
-    }
-
-
-
-    @GetMapping(value = "/report")
-    public String showAggrReport(@RequestParam("masterId") String masterId,
-                                 @RequestParam("examId") long examId,
-                                 @RequestParam("caseId") long caseId,
-                                 @RequestParam(value = "finalReportId", required = false) Long finalReportId,
-                                 Model model) {
-        Map<String, BugDTO> bugMap = bugReportService.getAllBugsMap(examId, caseId);
-        BugDTO masterReport = bugMap.get(masterId);
-
-        List<SupplementDTO> supplements = supplementService.getSupplementByMasterId(masterId, bugMap);
-
-        List<BugDTO> bugs = new LinkedList<>();
-        supplements.forEach(supplementDTO -> bugs.addAll(supplementDTO.getBugs()));
-        List<BugDTO> sourceReports = bugs.stream().distinct().collect(Collectors.toList());
-        Map<String, Long> categoryCounts = sourceReports.stream().collect(Collectors.groupingBy(BugDTO::getBugCategory, Collectors.counting()));
-        Map<String, Long> severityCounts = sourceReports.stream()
-                .map(BugDTO::getSeverity)
-                .map((severityNum) -> ReportUtil.severity2String.get(severityNum))
-                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
-
-        List<FinalReportDTO> finalReports = finalReportService.getBySourceId(masterId);
-
-        model.addAttribute("wordList", getWordCloudList(sourceReports));
-        model.addAttribute("categoryCounts", categoryCounts);
-        model.addAttribute("severityCounts", severityCounts);
-        model.addAttribute("aggReportId", "ML-AG-" + masterId.substring(10));
-        model.addAttribute("masterReport", masterReport);
-        model.addAttribute("createTime", new Date(Long.parseLong(masterReport.getCreateTimeMillis())));
-        model.addAttribute("supplements", supplements);
-        model.addAttribute("finalReports", finalReports);
-        model.addAttribute("category2String", ReportUtil.category2String);
-        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
-        model.addAttribute("severity2String", ReportUtil.severity2String);
-        model.addAttribute("examId", examId);
-        model.addAttribute("caseId", caseId);
-
-        boolean bugReviewed = bugReviewService.isBugReviewed(masterId);
-        model.addAttribute("reviewed", bugReviewed);
-        if (finalReportId != null) {
-            Optional<FinalReportDTO> finalReportDTO = finalReports.stream().filter(finalReport -> finalReport.getId()==finalReportId).findFirst();
-            model.addAttribute("finalReportId", finalReportId);
-            model.addAttribute("editReport", finalReportDTO.get());
-
-        }
-        return "agg_report_new";
-    }
-
-    private String getWordCloudList(List<BugDTO> sourceReports) {
-        Map<String, Integer> wordCount = new HashMap<>();
-        Set<String> stopWords = new HashSet<>();
-        try {
-            File file = ResourceUtils.getFile("classpath:stopwords.txt");
-            BufferedReader reader = new BufferedReader(new FileReader(file));
-            String line;
-            while ((line = reader.readLine()) != null) {
-                stopWords.add(line.trim());
-            }
-        } catch (FileNotFoundException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        sourceReports.forEach((bug) -> {
-            Segment seg = NLPUtil.getDefaultSegment();
-            List<Term> terms = seg.seg(bug.getDescription());
-            for (Term term : terms) {
-                if (stopWords.contains(term.word)) {
-                    continue;
-                }
-                if (wordCount.get(term.word) == null) {
-                    wordCount.put(term.word, 1);
-                    continue;
-                }
-                int count = wordCount.get(term.word);
-                wordCount.put(term.word, ++count);
-            }
-        });
-        JSONArray wordList = new JSONArray();
-        wordCount.forEach((word, count) -> {
-
-            if (word.length() > 1) {
-
-                JSONObject wordObj = new JSONObject();
-                wordObj.fluentPut("text", word)
-                        .fluentPut("weight", count * 10);
-                wordList.add(wordObj);
-            }
-
-        });
-
-        return wordList.toJSONString();
-    }
-
-    @GetMapping(value = "agg_report_list")
-    public String showAggReportList(@RequestParam("examId") long examId,
-                                    @RequestParam("caseId") long caseId,
-                                    @RequestParam(value = "status", required = false, defaultValue = "-1") int status,
-                                    Model model) {
-        List<String> masterIds = masterReportService.getAllMasterIdByExamIdAndCaseId(examId, caseId);
-        List<MasterReport> mrs = masterReportService.getByBugIds(masterIds);
-        Map<String, MasterReport> mrMap = mrs.stream().collect(toMap(MasterReport::getBugId, Function.identity()));
-        if (status >= 0) {
-            masterIds = masterIds.stream().filter(masterId -> mrMap.get(masterId).getStatus() == status).collect(Collectors.toList());
-        }
-
-//        Map<String, List<String>> master2BugIdsMap = supplementService.getMaster2BugIdsMap(masterIds);
-        Map<String, List<String>> master2BugIdsMap = masterReportService.getMaster2BugIdsMap(masterIds);
-        Map<String, BugDTO> bugsMap = bugReportService.getAllBugsMap(examId, caseId);
-
-//        Map<String, List<BugDTO>> masterBugMap = bugReportService.getMasterBugMap(master2BugIdsMap, bugsMap);
-        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
-
-
-        masterIds.forEach(masterId -> {
-
-            bugsMap.get(masterId).setStatus(mrMap.get(masterId).getStatus());
-        });
-
-
-        model.addAttribute("master2BugIdsMap", master2BugIdsMap);
-        model.addAttribute("bugMap", bugsMap);
-        model.addAttribute("examId", examId);
-        model.addAttribute("caseId", caseId);
-        model.addAttribute("task", task);
-        model.addAttribute("aggNum", masterReportService.getAggNum(examId, caseId));
-        return "agg_report_list";
-    }
-}
+package com.mooctest.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.hankcs.hanlp.seg.Segment;
+import com.hankcs.hanlp.seg.common.Term;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.FinalReportDTO;
+import com.mooctest.data.SupplementDTO;
+import com.mooctest.data.TaskDTO;
+import com.mooctest.model.MasterReport;
+import com.mooctest.service.*;
+import com.mooctest.util.NLPUtil;
+import com.mooctest.util.ReportUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.toMap;
+
+@Controller
+public class ReportController {
+
+    @Autowired
+    SupplementService supplementService;
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    @Autowired
+    FinalReportService finalReportService;
+
+    @Autowired
+    BugReviewService bugReviewService;
+
+    @Autowired
+    TaskService taskService;
+
+    @GetMapping(value = "/index")
+    public String hello(HttpServletRequest request, @RequestParam(value = "name", required = false, defaultValue = "springboot-thymeleaf") String name) {
+        request.setAttribute("name", name);
+        return "index";
+    }
+
+
+
+    @GetMapping(value = "/report")
+    public String showAggrReport(@RequestParam("masterId") String masterId,
+                                 @RequestParam("examId") long examId,
+                                 @RequestParam("caseId") long caseId,
+                                 @RequestParam(value = "finalReportId", required = false) Long finalReportId,
+                                 Model model) {
+        Map<String, BugDTO> bugMap = bugReportService.getAllBugsMap(examId, caseId);
+        BugDTO masterReport = bugMap.get(masterId);
+
+        List<SupplementDTO> supplements = supplementService.getSupplementByMasterId(masterId, bugMap);
+
+        List<BugDTO> bugs = new LinkedList<>();
+        supplements.forEach(supplementDTO -> bugs.addAll(supplementDTO.getBugs()));
+        List<BugDTO> sourceReports = bugs.stream().distinct().collect(Collectors.toList());
+        Map<String, Long> categoryCounts = sourceReports.stream().collect(Collectors.groupingBy(BugDTO::getBugCategory, Collectors.counting()));
+        Map<String, Long> severityCounts = sourceReports.stream()
+                .map(BugDTO::getSeverity)
+                .map((severityNum) -> ReportUtil.severity2String.get(severityNum))
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+
+        List<FinalReportDTO> finalReports = finalReportService.getBySourceId(masterId);
+
+        model.addAttribute("wordList", getWordCloudList(sourceReports));
+        model.addAttribute("categoryCounts", categoryCounts);
+        model.addAttribute("severityCounts", severityCounts);
+        model.addAttribute("aggReportId", "ML-AG-" + masterId.substring(10));
+        model.addAttribute("masterReport", masterReport);
+        model.addAttribute("createTime", new Date(Long.parseLong(masterReport.getCreateTimeMillis())));
+        model.addAttribute("supplements", supplements);
+        model.addAttribute("finalReports", finalReports);
+        model.addAttribute("category2String", ReportUtil.category2String);
+        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
+        model.addAttribute("severity2String", ReportUtil.severity2String);
+        model.addAttribute("examId", examId);
+        model.addAttribute("caseId", caseId);
+
+        boolean bugReviewed = bugReviewService.isBugReviewed(masterId);
+        model.addAttribute("reviewed", bugReviewed);
+        if (finalReportId != null) {
+            Optional<FinalReportDTO> finalReportDTO = finalReports.stream().filter(finalReport -> finalReport.getId()==finalReportId).findFirst();
+            model.addAttribute("finalReportId", finalReportId);
+            model.addAttribute("editReport", finalReportDTO.get());
+
+        }
+        return "agg_report_new";
+    }
+
+    private String getWordCloudList(List<BugDTO> sourceReports) {
+        Map<String, Integer> wordCount = new HashMap<>();
+        Set<String> stopWords = new HashSet<>();
+        try {
+            File file = ResourceUtils.getFile("classpath:stopwords.txt");
+            BufferedReader reader = new BufferedReader(new FileReader(file));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                stopWords.add(line.trim());
+            }
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        sourceReports.forEach((bug) -> {
+            Segment seg = NLPUtil.getDefaultSegment();
+            List<Term> terms = seg.seg(bug.getDescription());
+            for (Term term : terms) {
+                if (stopWords.contains(term.word)) {
+                    continue;
+                }
+                if (wordCount.get(term.word) == null) {
+                    wordCount.put(term.word, 1);
+                    continue;
+                }
+                int count = wordCount.get(term.word);
+                wordCount.put(term.word, ++count);
+            }
+        });
+        JSONArray wordList = new JSONArray();
+        wordCount.forEach((word, count) -> {
+
+            if (word.length() > 1) {
+
+                JSONObject wordObj = new JSONObject();
+                wordObj.fluentPut("text", word)
+                        .fluentPut("weight", count * 10);
+                wordList.add(wordObj);
+            }
+
+        });
+
+        return wordList.toJSONString();
+    }
+
+    @GetMapping(value = "agg_report_list")
+    public String showAggReportList(@RequestParam("examId") long examId,
+                                    @RequestParam("caseId") long caseId,
+                                    @RequestParam(value = "status", required = false, defaultValue = "-1") int status,
+                                    Model model) {
+        List<String> masterIds = masterReportService.getAllMasterIdByExamIdAndCaseId(examId, caseId);
+        List<MasterReport> mrs = masterReportService.getByBugIds(masterIds);
+        Map<String, MasterReport> mrMap = mrs.stream().collect(toMap(MasterReport::getBugId, Function.identity()));
+        if (status >= 0) {
+            masterIds = masterIds.stream().filter(masterId -> mrMap.get(masterId).getStatus() == status).collect(Collectors.toList());
+        }
+
+//        Map<String, List<String>> master2BugIdsMap = supplementService.getMaster2BugIdsMap(masterIds);
+        Map<String, List<String>> master2BugIdsMap = masterReportService.getMaster2BugIdsMap(masterIds);
+        Map<String, BugDTO> bugsMap = bugReportService.getAllBugsMap(examId, caseId);
+
+//        Map<String, List<BugDTO>> masterBugMap = bugReportService.getMasterBugMap(master2BugIdsMap, bugsMap);
+        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+
+
+        masterIds.forEach(masterId -> {
+
+            bugsMap.get(masterId).setStatus(mrMap.get(masterId).getStatus());
+        });
+
+
+        model.addAttribute("master2BugIdsMap", master2BugIdsMap);
+        model.addAttribute("bugMap", bugsMap);
+        model.addAttribute("examId", examId);
+        model.addAttribute("caseId", caseId);
+        model.addAttribute("task", task);
+        model.addAttribute("aggNum", masterReportService.getAggNum(examId, caseId));
+        return "agg_report_list";
+    }
+}

+ 73 - 73
src/main/java/com/mooctest/controller/TaskController.java

@@ -1,73 +1,73 @@
-package com.mooctest.controller;
-
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.TaskDTO;
-import com.mooctest.model.MasterReport;
-import com.mooctest.service.BugReportService;
-import com.mooctest.service.MasterReportService;
-import com.mooctest.service.TaskService;
-import com.mooctest.util.ReportUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.toMap;
-
-@Controller
-public class TaskController {
-
-    @Autowired
-    TaskService taskService;
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    MasterReportService masterReportService;
-    @GetMapping("/home")
-    public String home(Model model) {
-
-        List<TaskDTO> tasks = taskService.getAllTasks();
-        model.addAttribute("tasks", tasks);
-        return "task_list";
-    }
-
-    @GetMapping("/task_detail")
-    public String taskDetail(@RequestParam("examId") long examId,
-                             @RequestParam("caseId") long caseId,
-                             Model model) {
-
-        boolean aggregated = masterReportService.isAggregated(examId, caseId);
-        List<BugDTO> allReports = bugReportService.getAllBugs(examId, caseId);
-        if (aggregated) {
-
-            List<String> bugIds = allReports.stream().map(BugDTO::getId).collect(Collectors.toList());
-            List<MasterReport> mrs = masterReportService.getByBugIds(bugIds);
-            Map<String, MasterReport> mrMap = mrs.stream().collect(toMap(MasterReport::getBugId, Function.identity()));
-            allReports.forEach(bug -> {
-                MasterReport mr = mrMap.get(bug.getId());
-                bug.setStatus(mr.getStatus());
-                bug.setReviewerId(mr.getReviewerId());
-                bug.setMasterId(mr.getMasterId());
-            });
-        }
-
-        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
-        model.addAttribute("aggregated", aggregated);
-        model.addAttribute("allReports", allReports);
-        model.addAttribute("severity2String", ReportUtil.severity2String);
-        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
-        model.addAttribute("task", task);
-        model.addAttribute("reviewMap", ReportUtil.reviewerMap);
-        model.addAttribute("examId", examId);
-        model.addAttribute("caseId", caseId);
-        return "task_detail";
-    }
-}
+package com.mooctest.controller;
+
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.TaskDTO;
+import com.mooctest.model.MasterReport;
+import com.mooctest.service.BugReportService;
+import com.mooctest.service.MasterReportService;
+import com.mooctest.service.TaskService;
+import com.mooctest.util.ReportUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.toMap;
+
+@Controller
+public class TaskController {
+
+    @Autowired
+    TaskService taskService;
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    MasterReportService masterReportService;
+    @GetMapping("/home")
+    public String home(Model model) {
+
+        List<TaskDTO> tasks = taskService.getAllTasks();
+        model.addAttribute("tasks", tasks);
+        return "task_list";
+    }
+
+    @GetMapping("/task_detail")
+    public String taskDetail(@RequestParam("examId") long examId,
+                             @RequestParam("caseId") long caseId,
+                             Model model) {
+
+        boolean aggregated = masterReportService.isAggregated(examId, caseId);
+        List<BugDTO> allReports = bugReportService.getAllBugs(examId, caseId);
+        if (aggregated) {
+
+            List<String> bugIds = allReports.stream().map(BugDTO::getId).collect(Collectors.toList());
+            List<MasterReport> mrs = masterReportService.getByBugIds(bugIds);
+            Map<String, MasterReport> mrMap = mrs.stream().collect(toMap(MasterReport::getBugId, Function.identity()));
+            allReports.forEach(bug -> {
+                MasterReport mr = mrMap.get(bug.getId());
+                bug.setStatus(mr.getStatus());
+                bug.setReviewerId(mr.getReviewerId());
+                bug.setMasterId(mr.getMasterId());
+            });
+        }
+
+        TaskDTO task = taskService.getByExamIdAndCaseId(examId, caseId);
+        model.addAttribute("aggregated", aggregated);
+        model.addAttribute("allReports", allReports);
+        model.addAttribute("severity2String", ReportUtil.severity2String);
+        model.addAttribute("recurrent2String", ReportUtil.recurrent2String);
+        model.addAttribute("task", task);
+        model.addAttribute("reviewMap", ReportUtil.reviewerMap);
+        model.addAttribute("examId", examId);
+        model.addAttribute("caseId", caseId);
+        return "task_detail";
+    }
+}

+ 116 - 116
src/main/java/com/mooctest/controller/TestController.java

@@ -1,116 +1,116 @@
-package com.mooctest.controller;
-
-import com.mooctest.cluster.MyClusterAnalyzer;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffText;
-import com.mooctest.data.ReportDTO;
-import com.mooctest.service.BugReportService;
-import com.mooctest.service.DiffTextService;
-import com.mooctest.service.MasterReportService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.*;
-import java.util.function.Function;
-
-import static java.util.stream.Collectors.toMap;
-
-@RestController
-public class TestController {
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    @Autowired
-    DiffTextService diffTextService;
-
-    @GetMapping("/test")
-    public String test() {
-
-        List<BugDTO> bugs = bugReportService.getAllBugs(2613, 1489);
-
-        MyClusterAnalyzer<String> analyzer = new MyClusterAnalyzer<String>();
-        bugs.forEach(bugDTO -> analyzer.addDocument(bugDTO.getId(), bugDTO.getDescription()));
-
-        Map<String, BugDTO> bugMap = bugs.stream().collect(toMap(BugDTO::getId, Function.identity()));
-        bugs = null;
-
-        List<Set<String>> clusters = analyzer.repeatedBisection(1.0);
-
-//        Map<String, Set<String>> masterClusterMap = new HashMap<>();
-//        for (Set<String> cluster : clusters) {
-//            String masterReport = masterReportService.findMasterReport(cluster, analyzer.getDocuments());
-//            masterClusterMap.put(masterReport, cluster);
-//        }
-//        clusters = null;
-//
-//        //showClusterResult(masterClusterMap, bugMap);
-//
-//
-//        Map<String, List<DiffText>> masterDiffTextMap = new HashMap<>();
-//        masterClusterMap.forEach((masterId, cluster) -> {
-//
-//            List<DiffText> diffTexts = diffTextService.genDiffText(masterId, cluster, bugMap);
-//            masterDiffTextMap.put(masterId, diffTexts);
-//        });
-//        showDiffResult(masterDiffTextMap, bugMap);
-//
-//        MyClusterAnalyzer<String> diffTextAnalyzer = new MyClusterAnalyzer<String>();
-//
-//
-//        masterDiffTextMap.forEach((masterId, diffTexts) -> {
-//            Map<String, DiffText> diffTextMap = diffTexts.stream()
-//                    .collect(toMap(diffText -> diffText.getBugId() + "_" + diffText.getIndex(), Function.identity()));
-//
-//            diffTexts.forEach(diffText ->
-//                    diffTextAnalyzer.addDocument(diffText.getBugId() + "_" + diffText.getIndex(), diffText.getSentence()));
-//            List<Set<String>> diffTextClusters = diffTextAnalyzer.repeatedBisection(1.0);
-//            List<Set<DiffText>> diffTextSets = new LinkedList<>();
-//            diffTextClusters.forEach(cluster -> {
-//                Set<DiffText> diffTextSet = cluster.stream()
-//                        .map(sentenceId -> diffTextMap.get(sentenceId))
-//                        .collect(Collectors.toSet());
-//                diffTextSets.add(diffTextSet);
-//            });
-//            diffTextAnalyzer.clearDocs();
-//        });
-        return "ok";
-    }
-
-
-
-    public void showClusterResult(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
-        masterClusterMap.entrySet().forEach(entry -> {
-            System.out.println("[");
-            System.out.println("master:");
-            System.out.println(bugMap.get(entry.getKey()).getDescription());
-            System.out.println();
-
-            entry.getValue().forEach(bugId -> {
-                System.out.println(bugMap.get(bugId).getDescription());
-            });
-            System.out.println("]");
-        });
-
-    }
-
-
-    public void showDiffResult(Map<String, List<DiffText>> masterDiffTextMap, Map<String, BugDTO> bugMap) {
-        masterDiffTextMap.entrySet().forEach(entry -> {
-            System.out.println("[");
-            System.out.println("master:");
-            System.out.println(bugMap.get(entry.getKey()).getDescription());
-            System.out.println();
-
-            entry.getValue().forEach(diffText -> {
-                System.out.println(diffText.getSentence());
-            });
-            System.out.println("]");
-        });
-
-    }
-
-}
+package com.mooctest.controller;
+
+import com.mooctest.cluster.MyClusterAnalyzer;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffText;
+import com.mooctest.data.ReportDTO;
+import com.mooctest.service.BugReportService;
+import com.mooctest.service.DiffTextService;
+import com.mooctest.service.MasterReportService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.function.Function;
+
+import static java.util.stream.Collectors.toMap;
+
+@RestController
+public class TestController {
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    @Autowired
+    DiffTextService diffTextService;
+
+    @GetMapping("/test")
+    public String test() {
+
+        List<BugDTO> bugs = bugReportService.getAllBugs(2613, 1489);
+
+        MyClusterAnalyzer<String> analyzer = new MyClusterAnalyzer<String>();
+        bugs.forEach(bugDTO -> analyzer.addDocument(bugDTO.getId(), bugDTO.getDescription()));
+
+        Map<String, BugDTO> bugMap = bugs.stream().collect(toMap(BugDTO::getId, Function.identity()));
+        bugs = null;
+
+        List<Set<String>> clusters = analyzer.repeatedBisection(1.0);
+
+//        Map<String, Set<String>> masterClusterMap = new HashMap<>();
+//        for (Set<String> cluster : clusters) {
+//            String masterReport = masterReportService.findMasterReport(cluster, analyzer.getDocuments());
+//            masterClusterMap.put(masterReport, cluster);
+//        }
+//        clusters = null;
+//
+//        //showClusterResult(masterClusterMap, bugMap);
+//
+//
+//        Map<String, List<DiffText>> masterDiffTextMap = new HashMap<>();
+//        masterClusterMap.forEach((masterId, cluster) -> {
+//
+//            List<DiffText> diffTexts = diffTextService.genDiffText(masterId, cluster, bugMap);
+//            masterDiffTextMap.put(masterId, diffTexts);
+//        });
+//        showDiffResult(masterDiffTextMap, bugMap);
+//
+//        MyClusterAnalyzer<String> diffTextAnalyzer = new MyClusterAnalyzer<String>();
+//
+//
+//        masterDiffTextMap.forEach((masterId, diffTexts) -> {
+//            Map<String, DiffText> diffTextMap = diffTexts.stream()
+//                    .collect(toMap(diffText -> diffText.getBugId() + "_" + diffText.getIndex(), Function.identity()));
+//
+//            diffTexts.forEach(diffText ->
+//                    diffTextAnalyzer.addDocument(diffText.getBugId() + "_" + diffText.getIndex(), diffText.getSentence()));
+//            List<Set<String>> diffTextClusters = diffTextAnalyzer.repeatedBisection(1.0);
+//            List<Set<DiffText>> diffTextSets = new LinkedList<>();
+//            diffTextClusters.forEach(cluster -> {
+//                Set<DiffText> diffTextSet = cluster.stream()
+//                        .map(sentenceId -> diffTextMap.get(sentenceId))
+//                        .collect(Collectors.toSet());
+//                diffTextSets.add(diffTextSet);
+//            });
+//            diffTextAnalyzer.clearDocs();
+//        });
+        return "ok";
+    }
+
+
+
+    public void showClusterResult(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
+        masterClusterMap.entrySet().forEach(entry -> {
+            System.out.println("[");
+            System.out.println("master:");
+            System.out.println(bugMap.get(entry.getKey()).getDescription());
+            System.out.println();
+
+            entry.getValue().forEach(bugId -> {
+                System.out.println(bugMap.get(bugId).getDescription());
+            });
+            System.out.println("]");
+        });
+
+    }
+
+
+    public void showDiffResult(Map<String, List<DiffText>> masterDiffTextMap, Map<String, BugDTO> bugMap) {
+        masterDiffTextMap.entrySet().forEach(entry -> {
+            System.out.println("[");
+            System.out.println("master:");
+            System.out.println(bugMap.get(entry.getKey()).getDescription());
+            System.out.println();
+
+            entry.getValue().forEach(diffText -> {
+                System.out.println(diffText.getSentence());
+            });
+            System.out.println("]");
+        });
+
+    }
+
+}

+ 12 - 12
src/main/java/com/mooctest/dao/AggTaskStatusDao.java

@@ -1,12 +1,12 @@
-package com.mooctest.dao;
-
-import com.mooctest.model.AggTaskStatus;
-import org.springframework.data.mongodb.repository.MongoRepository;
-
-import java.util.Date;
-import java.util.List;
-
-public interface AggTaskStatusDao extends MongoRepository<AggTaskStatus, Long> {
-    List<AggTaskStatus> findByTaskIdOrderByStartTimeDesc(String taskId);
-    AggTaskStatus findByTaskIdAndStartTime(String taskId, Date startTime);
-}
+package com.mooctest.dao;
+
+import com.mooctest.model.AggTaskStatus;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Date;
+import java.util.List;
+
+public interface AggTaskStatusDao extends MongoRepository<AggTaskStatus, Long> {
+    List<AggTaskStatus> findByTaskIdOrderByStartTimeDesc(String taskId);
+    AggTaskStatus findByTaskIdAndStartTime(String taskId, Date startTime);
+}

+ 117 - 0
src/main/java/com/mooctest/dao/BugExtDao.java

@@ -0,0 +1,117 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.Bug;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Repository
+public class BugExtDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	//save存在则更新,不存在则插入
+	public String save(Bug bug) {
+		mongoOperations.save(bug);
+		return bug.getId();
+	}
+	
+	//insert存在则不做处理,不存在则插入
+	public void insert(Bug bug){
+	    mongoOperations.insert(bug);
+	}
+	
+	//根据id删除文档
+	public void remove(String id){
+	    Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    mongoOperations.remove(query);
+	}
+	
+	//根据ids删除文档
+	public void remove(List<String> ids){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		mongoOperations.remove(query, Bug.class);
+	}
+	
+	//根据report_id查找所有的Bug
+	public List<String> findByReport(String report_id) {
+		List<String> result = new ArrayList<String>();
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("report_id").is(report_id));
+	    List<Bug> lists = mongoOperations.find(query, Bug.class);
+	    for(Bug list : lists) {
+	    	result.add(list.getId());
+	    }
+	    return result;
+	}
+	
+	public List<Bug> findByReport(String report_id, String case_take_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("report_id").is(report_id).and("case_take_id").is(case_take_id));
+		return mongoOperations.find(query, Bug.class);
+	}
+	
+	//根据id更新文档
+//	public int update(Bug bug){
+//	    Query query = new Query();
+//	    query.addCriteria(Criteria.where("_id").is(bug.getId()));
+//	    Update update = new Update();
+//	    update.set("bug_category",bug.getBug_category());
+//	    return mongoOperations.updateFirst(query,update,Bug.class).getN();
+//	}
+
+	//id查询,find查询所有
+	public Bug findByid(String id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		List<Bug> list = mongoOperations.find(query, Bug.class);
+		if(list.size() == 0 || list == null) {return null;}
+		return list.get(0);
+	}
+	
+	//case条件查询,find查询所有
+	public List<Bug> findByCaseid(String case_take_id) {
+	    Query query = new Query();
+	    query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+	    return mongoOperations.find(query, Bug.class);
+	}
+	
+	public List<String> findByCase(String case_take_id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+	    List<String> result = new ArrayList<String>();
+	    List<Bug> bugs = mongoOperations.find(query, Bug.class);
+	    if(bugs != null) { for(Bug bug : bugs) { result.add(bug.getId()); } }
+	    return result;
+	}
+	
+	public void update_case_take(String report_id, String case_take_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("report_id").is(report_id));
+		List<Bug> list = mongoOperations.find(query, Bug.class);
+		for(Bug mirror : list) {
+			mirror.setCaseTakeId(case_take_id);
+			mongoOperations.save(mirror);
+		}
+	}
+
+	public Set<String> findAllids() {
+		Set<String> result = new HashSet<>();
+		List<Bug> list = mongoOperations.findAll(Bug.class);
+		for(Bug bug: list) {
+			String id = bug.getCaseTakeId();
+			if(id != null && id.length() > 0) { result.add(id); }
+		}
+		return result;
+	}
+}

+ 94 - 0
src/main/java/com/mooctest/dao/BugHistoryDao.java

@@ -0,0 +1,94 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.BugHistory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Repository
+public class BugHistoryDao {
+	
+	@Autowired
+    MongoOperations mongoOps;
+	
+	//save存在则更新,不存在则插入
+	public void save(BugHistory history){
+		mongoOps.save(history);
+	}
+	
+	//id查询,find查询所有
+	public BugHistory findByid(String id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		List<BugHistory> history = mongoOps.find(query,BugHistory.class);
+		if(history != null && history.size() != 0) { return history.get(0); }
+		else { return null; }
+	}
+	
+	//查找所有指定的根
+	public List<String> findRoots(List<String> lists) {
+		System.out.println("lists.toString()"+lists.toString());
+		if(lists == null || lists.size() == 0) {return new ArrayList<String>();}
+		System.out.println("roots: ");
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(lists).and("parent").is("null"));
+		List<BugHistory> roots = mongoOps.find(query,BugHistory.class);
+
+		List<String> ids = new ArrayList<String>();
+		for(BugHistory root: roots) {
+			ids.add(root.getRoot());
+		}
+		return ids;
+	}
+	
+	//查找所有的BugRoot
+	public List<String> findRoots() {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("parent").is("null"));
+		List<BugHistory> roots = mongoOps.find(query,BugHistory.class);
+		List<String> ids = new ArrayList<String>();
+		for(BugHistory root : roots) {
+			ids.add(root.getId());
+		}
+		return ids;
+	}
+	
+	//根据id删除文档
+	public void remove(String id){
+	    Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    mongoOps.remove(query,BugHistory.class);
+	}
+	
+	//根据ids删除文档
+	public void remove(List<String> ids){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		mongoOps.remove(query,BugHistory.class);
+	}
+	
+	//根据id查找
+	public BugHistory findParent(String id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		return mongoOps.find(query, BugHistory.class).get(0);
+	}
+	
+	//增加child
+	public void addChild(String id, String child) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		BugHistory temp_hisroty = (BugHistory) mongoOps.find(query, BugHistory.class).get(0);
+		Update update = new Update();
+		List<String> children = temp_hisroty.getChildren();
+		if(!children.contains(child)) {children.add(child);}
+		update.set("children", children);
+		mongoOps.updateFirst(query,update,BugHistory.class);
+	}
+}

+ 189 - 0
src/main/java/com/mooctest/dao/BugMirrorDao.java

@@ -0,0 +1,189 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.BugMirror;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+@Repository
+public class BugMirrorDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	//save存在则更新,不存在则插入
+	public void save(BugMirror mirror){
+	    mongoOperations.save(mirror);
+	}
+	
+	//根据id删除文档
+	public void remove(String id){
+	    Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    mongoOperations.remove(query);
+	}
+	
+	//根据ids删除文档
+	public void remove(List<String> ids){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		mongoOperations.remove(query,BugMirror.class);
+	}
+	
+	public List<BugMirror> findValid(String case_take_id) {
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("flag").is(true));
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<String> findIdsByReport(String report_id, String case_take_id) {
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("report_id").is(report_id).and("flag").is(true));
+		query.addCriteria(Criteria.where("report_id").is(report_id).and("case_take_id").is(case_take_id));
+		List<BugMirror> lists = mongoOperations.find(query, BugMirror.class);
+		List<String> result = new ArrayList<String>();
+		for(BugMirror mirror : lists) {
+			result.add(mirror.getId());
+		}
+		return result;
+	}
+	
+	public List<BugMirror> findByReport(String report_id, String case_take_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("report_id").is(report_id).and("case_take_id").is(case_take_id));
+		List<BugMirror> lists = mongoOperations.find(query, BugMirror.class);
+		return lists;
+	}
+	
+	public List<BugMirror> findByCase(String case_take_id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findByCase(String case_take_id, String report_id){
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("report_id").nin(report_id));
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findByCategory(String case_take_id, String bug_category, String report_id){
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("bug_category").is(bug_category).and("report_id").nin(report_id));
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("bug_category").is(bug_category));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findBySeverity(String case_take_id, int severity, String report_id){
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("severity").is(severity).and("report_id").nin(report_id));
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("severity").is(severity));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findByRecurrent(String case_take_id, int recurrent, String report_id){
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("recurrent").is(recurrent).and("report_id").nin(report_id));
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("recurrent").is(recurrent));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findByIds(List<String> ids){
+		if(ids == null || ids.size() == 0) {return new ArrayList<BugMirror>();}
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+	public List<BugMirror> findByIds(List<String> ids, String report_id){
+		if(ids == null || ids.size() == 0) {return new ArrayList<BugMirror>();}
+		Query query = new Query();
+//		query.addCriteria(Criteria.where("_id").in(ids).and("report_id").nin(report_id));
+		query.addCriteria(Criteria.where("_id").in(ids));
+		return mongoOperations.find(query, BugMirror.class);
+	}
+	
+//	public BugMirror findById(String id){
+//		Query query = new Query();
+//		query.addCriteria(Criteria.where("_id").is(id));
+//		return mongoOperations.find(query, BugMirror.class).get(0);
+//	}
+	
+	public BugMirror findById(String id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		List<BugMirror> mirror = mongoOperations.find(query, BugMirror.class);
+		if(mirror != null && mirror.size() > 0) { return mirror.get(0); }
+		else { return null; }
+	}
+	
+	public boolean haveJudged(String id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		BugMirror mirror = mongoOperations.find(query, BugMirror.class).get(0);
+		if(mirror.getGood().contains(report_id) || mirror.getBad().contains(report_id)) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+	
+	public void good(String id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		Update update = new Update();
+		Set<String> good = mongoOperations.find(query, BugMirror.class).get(0).getGood();
+		good.add(report_id);
+		update.set("good", good);
+		mongoOperations.updateFirst(query,update,BugMirror.class);
+	}
+	
+	public void cancelGood(String id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		Update update = new Update();
+		Set<String> good = mongoOperations.find(query, BugMirror.class).get(0).getGood();
+		if(good.contains(report_id)) { good.remove(report_id); }
+		update.set("good", good);
+		mongoOperations.updateFirst(query,update,BugMirror.class);
+	}
+	
+	public void bad(String id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		Update update = new Update();
+		Set<String> bad = mongoOperations.find(query, BugMirror.class).get(0).getBad();
+		bad.add(report_id);
+		update.set("bad", bad);
+		mongoOperations.updateFirst(query,update,BugMirror.class);
+	}
+	
+	public void canelBad(String id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		Update update = new Update();
+		Set<String> bad = mongoOperations.find(query, BugMirror.class).get(0).getBad();
+		if(bad.contains(report_id)) { bad.remove(report_id); }
+		update.set("bad", bad);
+		mongoOperations.updateFirst(query,update,BugMirror.class);
+	}
+	
+	public void update_case_take(String report_id, String case_take_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("report_id").is(report_id));
+		List<BugMirror> list = mongoOperations.find(query, BugMirror.class);
+		for(BugMirror mirror : list) {
+			mirror.setCase_take_id(case_take_id);
+			mongoOperations.save(mirror);
+		}
+	}
+}

+ 69 - 0
src/main/java/com/mooctest/dao/BugPageDao.java

@@ -0,0 +1,69 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.BugPage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Repository
+public class BugPageDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	//save存在则更新,不存在则插入
+	public void save(BugPage page){
+	    mongoOperations.save(page);
+	}
+	
+	//根据id删除文档
+	public void remove(String id){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		mongoOperations.remove(query,BugPage.class);
+	}
+	
+	//根据ids删除文档
+	public void remove(List<String> ids){
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		mongoOperations.remove(query,BugPage.class);
+	}
+	
+	public BugPage findByid(String id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		return mongoOperations.find(query,BugPage.class).get(0);
+	}
+	
+	public List<BugPage> findByIds(List<String> ids) {
+		if(ids == null || ids.size() == 0) {return new ArrayList<BugPage>();}
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(ids));
+		return mongoOperations.find(query, BugPage.class);
+	}
+	
+	public List<BugPage> findByPage1(String case_take_id, String page1) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("page1").is(page1));
+		return mongoOperations.find(query,BugPage.class);
+	}
+	
+	public List<BugPage> findByPage2(String case_take_id, String page2) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("page2").is(page2));
+		return mongoOperations.find(query,BugPage.class);
+	}
+	
+	public List<BugPage> findByPage3(String case_take_id, String page3) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id).and("page3").is(page3));
+		return mongoOperations.find(query,BugPage.class);
+	}
+	
+}

+ 41 - 0
src/main/java/com/mooctest/dao/BugScoreDao.java

@@ -0,0 +1,41 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.BugScore;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class BugScoreDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	public void save(BugScore score) {
+		mongoOperations.save(score);
+	}
+	
+	public BugScore findById(String id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    List<BugScore> list = mongoOperations.find(query, BugScore.class);
+	    if(list != null && list.size() != 0) {return list.get(0);}
+	    return null;
+	}
+	
+	public List<BugScore> findByIds(List<String> list) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").in(list));
+	    return mongoOperations.find(query, BugScore.class);
+	}
+	
+	public void remove(List<String> ids) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").in(ids));
+	    mongoOperations.remove(query, BugScore.class);
+	}
+}

+ 88 - 0
src/main/java/com/mooctest/dao/CTBDao.java

@@ -0,0 +1,88 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.CaseToBug;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Repository
+public class CTBDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	public void save(CaseToBug ctb) {
+		mongoOperations.save(ctb);
+	}
+	
+	public void save(String useCase, String bug_id, String case_take_id, String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(useCase));
+		List<CaseToBug> result = mongoOperations.find(query, CaseToBug.class);
+		if(result.size() != 0) {
+			CaseToBug ctb = result.get(0);
+			if(!ctb.getBug_id().contains(bug_id)) {
+				ctb.getBug_id().add(bug_id);
+				mongoOperations.save(ctb);
+			}
+		} else {
+			List<String> list = new ArrayList<String>();
+			list.add(bug_id);
+			CaseToBug ctb = new CaseToBug(useCase, list, case_take_id, report_id);
+			mongoOperations.save(ctb);
+		}
+		
+	}
+	
+	public CaseToBug find(String id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		return mongoOperations.find(query, CaseToBug.class).get(0);
+	}
+	
+	public List<String> findById(String id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    List<CaseToBug> result = mongoOperations.find(query, CaseToBug.class);
+	    if(result.size() == 0 || result == null) {return new ArrayList<String>();}
+	    return result.get(0).getBug_id();
+	    
+	}
+	
+	public List<CaseToBug> findByCase(String case_take_id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+	    return mongoOperations.find(query, CaseToBug.class);
+	}
+	
+	public List<CaseToBug> findByReport(String report_id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("report_id").is(report_id));
+	    return mongoOperations.find(query, CaseToBug.class);
+	}
+	
+	public void remove(String useCase, String bug_id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(useCase));
+	    CaseToBug result = mongoOperations.find(query, CaseToBug.class).get(0);
+	    result.getBug_id().remove(bug_id);
+	    mongoOperations.save(result);
+	}
+	
+	public void removeAll(String case_take_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("case_take_id").is(case_take_id));
+		mongoOperations.remove(query, CaseToBug.class);
+	}
+	
+	public void remove(String useCase) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(useCase));
+		mongoOperations.remove(query, CaseToBug.class);
+	}
+}

+ 14 - 14
src/main/java/com/mooctest/dao/FinalReportDao.java

@@ -1,14 +1,14 @@
-package com.mooctest.dao;
-
-import com.mooctest.model.FinalReport;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-@Transactional
-public interface FinalReportDao extends MongoRepository<FinalReport, Long> {
-
-    List<FinalReport> findByExamIdAndCaseId(long examId, long caseId);
-    List<FinalReport> findBySourceId(String sourceId);
-}
+package com.mooctest.dao;
+
+import com.mooctest.model.FinalReport;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Transactional
+public interface FinalReportDao extends MongoRepository<FinalReport, Long> {
+
+    List<FinalReport> findByExamIdAndCaseId(long examId, long caseId);
+    List<FinalReport> findBySourceId(String sourceId);
+}

+ 41 - 0
src/main/java/com/mooctest/dao/KWDao.java

@@ -0,0 +1,41 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.KeyWords;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class KWDao {
+
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	public void save(KeyWords kws) {
+		mongoOperations.save(kws);
+	}
+	
+	public KeyWords findById(String id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(id));
+		List<KeyWords> keywords = mongoOperations.find(query, KeyWords.class);
+		if(keywords != null && keywords.size() != 0) { return keywords.get(0); }
+		else { return null; }
+	}
+	
+	public void remove(String id){
+	    Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(id));
+	    mongoOperations.remove(query, KeyWords.class);
+	}
+	
+	public void remove(List<String> ids) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").in(ids));
+	    mongoOperations.remove(query, KeyWords.class);
+	}
+}

+ 27 - 27
src/main/java/com/mooctest/dao/MasterReportDao.java

@@ -1,27 +1,27 @@
-package com.mooctest.dao;
-
-import com.mooctest.model.MasterReport;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-@Transactional
-public interface MasterReportDao extends MongoRepository<MasterReport, Long> {
-
-    List<MasterReport> findByMasterId(String masterId);
-
-    List<MasterReport> findByMasterIdIn(List<String> masterIds);
-
-    List<MasterReport> findByExamIdAndCaseId(long examId, long caseId);
-
-    List<MasterReport> findByBugIdIn(List<String> bugIds);
-
-    MasterReport findByBugId(String bugId);
-
-    long countByExamIdAndCaseId(long examId, long caseId);
-
-    long countByExamIdAndCaseIdAndStatus(long examId, long caseId, int status);
-
-    void deleteByExamIdAndCaseId(long examId, long caseId);
-}
+package com.mooctest.dao;
+
+import com.mooctest.model.MasterReport;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Transactional
+public interface MasterReportDao extends MongoRepository<MasterReport, Long> {
+
+    List<MasterReport> findByMasterId(String masterId);
+
+    List<MasterReport> findByMasterIdIn(List<String> masterIds);
+
+    List<MasterReport> findByExamIdAndCaseId(long examId, long caseId);
+
+    List<MasterReport> findByBugIdIn(List<String> bugIds);
+
+    MasterReport findByBugId(String bugId);
+
+    long countByExamIdAndCaseId(long examId, long caseId);
+
+    long countByExamIdAndCaseIdAndStatus(long examId, long caseId, int status);
+
+    void deleteByExamIdAndCaseId(long examId, long caseId);
+}

+ 37 - 0
src/main/java/com/mooctest/dao/StuInfoDao.java

@@ -0,0 +1,37 @@
+package com.mooctest.dao;
+
+import com.mooctest.model.StuInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public class StuInfoDao {
+	
+	@Autowired
+	private MongoOperations mongoOperations;
+	
+	public void save(String report_id, String stu_id, String name) {
+		mongoOperations.save(new StuInfo(report_id, stu_id, name));
+	}
+	
+	public String findById(String report_id) {
+		Query query = new Query();
+	    query.addCriteria(Criteria.where("_id").is(report_id));
+	    List<StuInfo> stu_info = mongoOperations.find(query, StuInfo.class);
+	    if(stu_info == null || stu_info.size() == 0) { return "null"; }
+	    else { return stu_info.get(0).getName(); }
+	}
+
+	public String findWorkerId(String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(report_id));
+		List<StuInfo> stu_info = mongoOperations.find(query, StuInfo.class);
+		if(stu_info == null || stu_info.size() == 0) { return "null"; }
+		else { return stu_info.get(0).getWorker_id(); }
+	}
+}

+ 19 - 19
src/main/java/com/mooctest/dao/SupplementDao.java

@@ -1,19 +1,19 @@
-package com.mooctest.dao;
-
-import com.mooctest.model.SupplementItem;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-@Transactional
-public interface SupplementDao extends MongoRepository<SupplementItem, Long> {
-
-    List<SupplementItem> findByMasterId(String masterId);
-
-    List<SupplementItem> findBySupplementId(String supId);
-
-    List<SupplementItem> findByMasterIdIn(List<String> masterIds);
-
-    void deleteByMasterIdIn(List<String> masterIds);
-}
+package com.mooctest.dao;
+
+import com.mooctest.model.SupplementItem;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Transactional
+public interface SupplementDao extends MongoRepository<SupplementItem, Long> {
+
+    List<SupplementItem> findByMasterId(String masterId);
+
+    List<SupplementItem> findBySupplementId(String supId);
+
+    List<SupplementItem> findByMasterIdIn(List<String> masterIds);
+
+    void deleteByMasterIdIn(List<String> masterIds);
+}

+ 10 - 10
src/main/java/com/mooctest/dao2/BugDao.java

@@ -1,10 +1,10 @@
-package com.mooctest.dao2;
-
-import com.mooctest.model.Bug;
-import org.springframework.data.mongodb.repository.MongoRepository;
-
-import java.util.List;
-
-public interface BugDao extends MongoRepository<Bug, String> {
-    List<Bug> findByCaseTakeId(String caseTakeId);
-}
+package com.mooctest.dao2;
+
+import com.mooctest.model.Bug;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.List;
+
+public interface BugDao extends MongoRepository<Bug, String> {
+    List<Bug> findByCaseTakeId(String caseTakeId);
+}

+ 29 - 29
src/main/java/com/mooctest/data/BugDTO.java

@@ -1,29 +1,29 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.List;
-
-@Builder(toBuilder = true)
-@AllArgsConstructor
-@NoArgsConstructor
-@Data
-public class BugDTO{
-    private String id;
-    private String caseTakeId;
-    private String bugCategory;
-    private String description;
-    private short severity = 3;
-    private short recurrent = 3;
-    private List<String> path;
-    private String[] imgUrls;
-    private String createTimeMillis;
-    private List<SentenceDTO> taggedSentences;
-    private List<ImgDTO> taggedImgs;
-    private int status = 0;
-    private Long reviewerId;
-    private String masterId;
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Builder(toBuilder = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class BugDTO{
+    private String id;
+    private String caseTakeId;
+    private String bugCategory;
+    private String description;
+    private short severity = 3;
+    private short recurrent = 3;
+    private List<String> path;
+    private String[] imgUrls;
+    private String createTimeMillis;
+    private List<SentenceDTO> taggedSentences;
+    private List<ImgDTO> taggedImgs;
+    private int status = 0;
+    private Long reviewerId;
+    private String masterId;
+}

+ 16 - 16
src/main/java/com/mooctest/data/BugHistoryDTO.java

@@ -1,16 +1,16 @@
-package com.mooctest.data;
-
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class BugHistoryDTO {
-    private String id;
-
-    private String parent;
-
-    private List<String> children;
-
-    private String root;
-}
+package com.mooctest.data;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class BugHistoryDTO {
+    private String id;
+
+    private String parent;
+
+    private List<String> children;
+
+    private String root;
+}

+ 15 - 15
src/main/java/com/mooctest/data/DiffImg.java

@@ -1,15 +1,15 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class DiffImg {
-    private String masterId;
-    private String bugId;
-    private String imgUrl;
-    private int index;
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DiffImg {
+    private String masterId;
+    private String bugId;
+    private String imgUrl;
+    private int index;
+}

+ 16 - 16
src/main/java/com/mooctest/data/DiffText.java

@@ -1,16 +1,16 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class DiffText {
-    private String masterId;
-    private String bugId;
-    private String sentence;
-    private int index;
-
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DiffText {
+    private String masterId;
+    private String bugId;
+    private String sentence;
+    private int index;
+
+}

+ 33 - 33
src/main/java/com/mooctest/data/FinalReportDTO.java

@@ -1,33 +1,33 @@
-package com.mooctest.data;
-
-import lombok.Data;
-
-import java.sql.Timestamp;
-import java.util.Date;
-import java.util.List;
-
-@Data
-public class FinalReportDTO {
-    private long id;
-
-
-    private String description;
-
-    private String[] imgUrls;
-
-    private short severity;
-
-    private short recurrent;
-
-    private int category;
-
-    private long writerId;
-
-    private String sourceId;
-
-    private Date createTime;
-
-    private long examId;
-
-    private long caseId;
-}
+package com.mooctest.data;
+
+import lombok.Data;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class FinalReportDTO {
+    private long id;
+
+
+    private String description;
+
+    private String[] imgUrls;
+
+    private short severity;
+
+    private short recurrent;
+
+    private int category;
+
+    private long writerId;
+
+    private String sourceId;
+
+    private Date createTime;
+
+    private long examId;
+
+    private long caseId;
+}

+ 13 - 13
src/main/java/com/mooctest/data/ImgDTO.java

@@ -1,13 +1,13 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class ImgDTO {
-    private String imgUrl;
-    private boolean isDiff;
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ImgDTO {
+    private String imgUrl;
+    private boolean isDiff;
+}

+ 19 - 19
src/main/java/com/mooctest/data/ReportDTO.java

@@ -1,19 +1,19 @@
-package com.mooctest.data;
-
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class ReportDTO {
-
-    private Long stuId;
-    private Long examId;
-    private Long caseId;
-    private Long caseTakeId;
-    private String deviceBrand;
-    private String deviceModel;
-    private String deviceOs;
-
-    private List<BugDTO> bugVOS;
-}
+package com.mooctest.data;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ReportDTO {
+
+    private Long stuId;
+    private Long examId;
+    private Long caseId;
+    private Long caseTakeId;
+    private String deviceBrand;
+    private String deviceModel;
+    private String deviceOs;
+
+    private List<BugDTO> bugVOS;
+}

+ 14 - 14
src/main/java/com/mooctest/data/SentenceDTO.java

@@ -1,14 +1,14 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class SentenceDTO {
-    private String sentence;
-    private boolean isDiff;
-
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SentenceDTO {
+    private String sentence;
+    private boolean isDiff;
+
+}

+ 20 - 20
src/main/java/com/mooctest/data/SupplementDTO.java

@@ -1,20 +1,20 @@
-package com.mooctest.data;
-
-import com.mooctest.model.SupplementItem;
-import lombok.Builder;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-@Builder
-public class SupplementDTO {
-
-    private String supplementId;
-    private List<SupplementItem> items;
-    private List<BugDTO> bugs;
-    private boolean hasTxt;
-    private String topTxt;
-    private List<String> top3Img;
-
-}
+package com.mooctest.data;
+
+import com.mooctest.model.SupplementItem;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class SupplementDTO {
+
+    private String supplementId;
+    private List<SupplementItem> items;
+    private List<BugDTO> bugs;
+    private boolean hasTxt;
+    private String topTxt;
+    private List<String> top3Img;
+
+}

+ 21 - 21
src/main/java/com/mooctest/data/TaskDTO.java

@@ -1,21 +1,21 @@
-package com.mooctest.data;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class TaskDTO {
-    private long examId;
-    private long caseId;
-    private String name;
-    private String icon;
-    private String version;
-    private int status;
-    private String startTime;
-    private String endTime;
-    private long numOfTotalBug;
-    private long numOfUndeal;
-}
+package com.mooctest.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TaskDTO {
+    private long examId;
+    private long caseId;
+    private String name;
+    private String icon;
+    private String version;
+    private int status;
+    private String startTime;
+    private String endTime;
+    private long numOfTotalBug;
+    private long numOfUndeal;
+}

+ 7 - 7
src/main/java/com/mooctest/event/Event.java

@@ -1,7 +1,7 @@
-package com.mooctest.event;
-
-public interface Event {
-
-    String getDescription();
-
-}
+package com.mooctest.event;
+
+public interface Event {
+
+    String getDescription();
+
+}

+ 42 - 42
src/main/java/com/mooctest/event/EventUtil.java

@@ -1,42 +1,42 @@
-package com.mooctest.event;
-
-import com.google.common.eventbus.AsyncEventBus;
-import com.google.common.eventbus.EventBus;
-import com.google.common.eventbus.Subscribe;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-
-import java.util.concurrent.Executors;
-
-@Component
-public class EventUtil {
-
-    private static Logger logger = LoggerFactory.getLogger(EventUtil.class);
-    private EventBus eventBus;
-
-    public EventUtil() {
-        eventBus = new AsyncEventBus(Executors.newCachedThreadPool());
-        eventBus.register(this);
-    }
-
-    public void register(Object listener) {
-        eventBus.register(listener);
-    }
-
-    public void unregister(Object listener) {
-        eventBus.unregister(listener);
-    }
-
-    public void post(Event event) {
-        logger.info("event fired: {}", event.getDescription());
-        eventBus.post(event);
-    }
-
-    @Subscribe
-    public void logDeadEvent(Event deadEvent) {
-        logger.info("dead event captured: {}", deadEvent.getDescription());
-    }
-
-}
-
+package com.mooctest.event;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.Executors;
+
+@Component
+public class EventUtil {
+
+    private static Logger logger = LoggerFactory.getLogger(EventUtil.class);
+    private EventBus eventBus;
+
+    public EventUtil() {
+        eventBus = new AsyncEventBus(Executors.newCachedThreadPool());
+        eventBus.register(this);
+    }
+
+    public void register(Object listener) {
+        eventBus.register(listener);
+    }
+
+    public void unregister(Object listener) {
+        eventBus.unregister(listener);
+    }
+
+    public void post(Event event) {
+        logger.info("event fired: {}", event.getDescription());
+        eventBus.post(event);
+    }
+
+    @Subscribe
+    public void logDeadEvent(Event deadEvent) {
+        logger.info("dead event captured: {}", deadEvent.getDescription());
+    }
+
+}
+

+ 18 - 18
src/main/java/com/mooctest/event/TaskEndEvent.java

@@ -1,18 +1,18 @@
-package com.mooctest.event;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-
-@Getter
-@Builder
-@AllArgsConstructor
-public class TaskEndEvent implements Event {
-    long examId;
-    long caseId;
-
-    @Override
-    public String getDescription() {
-        return String.format("bug report aggregate end, exam id: %d, case id: %d", examId, caseId);
-    }
-}
+package com.mooctest.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+@AllArgsConstructor
+public class TaskEndEvent implements Event {
+    long examId;
+    long caseId;
+
+    @Override
+    public String getDescription() {
+        return String.format("bug report aggregate end, exam id: %d, case id: %d", examId, caseId);
+    }
+}

+ 22 - 22
src/main/java/com/mooctest/event/TaskEndListener.java

@@ -1,22 +1,22 @@
-package com.mooctest.event;
-
-import com.google.common.eventbus.Subscribe;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-@Component
-public class TaskEndListener implements InitializingBean {
-    @Autowired
-    private EventUtil eventUtil;
-
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        eventUtil.register(this);
-    }
-
-    @Subscribe
-    public void updateTaskStatus(TaskEndEvent event) {
-
-    }
-}
+package com.mooctest.event;
+
+import com.google.common.eventbus.Subscribe;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TaskEndListener implements InitializingBean {
+    @Autowired
+    private EventUtil eventUtil;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        eventUtil.register(this);
+    }
+
+    @Subscribe
+    public void updateTaskStatus(TaskEndEvent event) {
+
+    }
+}

+ 18 - 18
src/main/java/com/mooctest/event/TaskStartEvent.java

@@ -1,18 +1,18 @@
-package com.mooctest.event;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-
-@Getter
-@Builder
-@AllArgsConstructor
-public class TaskStartEvent implements Event {
-    private long examId;
-    private long caseId;
-
-    @Override
-    public String getDescription() {
-        return String.format("bug report aggregate start, exam id: %d, case id: %d", examId, caseId);
-    }
-}
+package com.mooctest.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+@AllArgsConstructor
+public class TaskStartEvent implements Event {
+    private long examId;
+    private long caseId;
+
+    @Override
+    public String getDescription() {
+        return String.format("bug report aggregate start, exam id: %d, case id: %d", examId, caseId);
+    }
+}

+ 36 - 36
src/main/java/com/mooctest/event/TaskStartListener.java

@@ -1,36 +1,36 @@
-package com.mooctest.event;
-
-import com.google.common.eventbus.Subscribe;
-import com.mooctest.model.AggTaskStatus;
-import com.mooctest.service.AggTaskStatusService;
-import com.mooctest.service.AggregationService;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-@Component
-public class TaskStartListener implements InitializingBean {
-
-    @Autowired
-    private EventUtil eventUtil;
-
-    @Autowired
-    private AggregationService aggregationService;
-
-    @Autowired
-    private AggTaskStatusService aggTaskStatusService;
-
-    @Override
-    public void afterPropertiesSet() throws Exception {
-        eventUtil.register(this);
-    }
-
-    @Subscribe
-    public void aggretate(TaskStartEvent event) {
-
-        AggTaskStatus aggTaskStatus = aggTaskStatusService.create(event.getExamId(), event.getCaseId());
-        aggregationService.aggregate(event.getExamId(), event.getCaseId());
-        AggTaskStatus result = aggTaskStatusService.updateStatus(aggTaskStatus.getTaskId(), aggTaskStatus.getStartTime());
-
-    }
-}
+package com.mooctest.event;
+
+import com.google.common.eventbus.Subscribe;
+import com.mooctest.model.AggTaskStatus;
+import com.mooctest.service.AggTaskStatusService;
+import com.mooctest.service.AggregationService;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TaskStartListener implements InitializingBean {
+
+    @Autowired
+    private EventUtil eventUtil;
+
+    @Autowired
+    private AggregationService aggregationService;
+
+    @Autowired
+    private AggTaskStatusService aggTaskStatusService;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        eventUtil.register(this);
+    }
+
+    @Subscribe
+    public void aggretate(TaskStartEvent event) {
+
+        AggTaskStatus aggTaskStatus = aggTaskStatusService.create(event.getExamId(), event.getCaseId());
+        aggregationService.aggregate(event.getExamId(), event.getCaseId());
+        AggTaskStatus result = aggTaskStatusService.updateStatus(aggTaskStatus.getTaskId(), aggTaskStatus.getStartTime());
+
+    }
+}

+ 285 - 285
src/main/java/com/mooctest/image/FingerPrint.java

@@ -1,285 +1,285 @@
-package com.mooctest.image;
-
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorConvertOp;
-import java.util.Arrays;
-
-/**
- * 均值哈希实现图像指纹比较
- * @author guyadong
- *
- */
-public final class FingerPrint {
-    /**
-     * 图像指纹的尺寸,将图像resize到指定的尺寸,来计算哈希数组
-     */
-    private static final int HASH_SIZE=16;
-
-    public byte[] getBinaryzationMatrix() {
-        return binaryzationMatrix;
-    }
-
-    /**
-     * 保存图像指纹的二值化矩阵
-     */
-    private final byte[] binaryzationMatrix;
-    public FingerPrint(byte[] hashValue) {
-        if(hashValue.length!=HASH_SIZE*HASH_SIZE)
-            throw new IllegalArgumentException(String.format("length of hashValue must be %d",HASH_SIZE*HASH_SIZE ));
-        this.binaryzationMatrix=hashValue;
-    }
-    public FingerPrint(String hashValue) {
-        this(toBytes(hashValue));
-    }
-    public FingerPrint (BufferedImage src){
-        this(hashValue(src));
-    }
-    private static byte[] hashValue(BufferedImage src){
-        BufferedImage hashImage = resize(src,HASH_SIZE,HASH_SIZE);
-        byte[] matrixGray = (byte[]) toGray(hashImage).getData().getDataElements(0, 0, HASH_SIZE, HASH_SIZE, null);
-        return  binaryzation(matrixGray);
-    }
-    /**
-     * 从压缩格式指纹创建{@link FingerPrint}对象
-     * @param compactValue
-     * @return
-     */
-    public static FingerPrint createFromCompact(byte[] compactValue){
-        return new FingerPrint(uncompact(compactValue));
-    }
-
-    public static boolean validHashValue(byte[] hashValue){
-        if(hashValue.length!=HASH_SIZE)
-            return false;
-        for(byte b:hashValue){
-            if(0!=b&&1!=b)return false;
-        }
-        return true;
-    }
-    public static boolean validHashValue(String hashValue){
-        if(hashValue.length()!=HASH_SIZE)
-            return false;
-        for(int i=0;i<hashValue.length();++i){
-            if('0'!=hashValue.charAt(i)&&'1'!=hashValue.charAt(i))return false;
-        }
-        return true;
-    }
-    public byte[] compact(){
-        return compact(binaryzationMatrix);
-    }
-
-    /**
-     * 指纹数据按位压缩
-     * @param hashValue
-     * @return
-     */
-    private static byte[] compact(byte[] hashValue){
-        byte[] result=new byte[(hashValue.length+7)>>3];
-        byte b=0;
-        for(int i=0;i<hashValue.length;++i){
-            if(0==(i&7)){
-                b=0;
-            }
-            if(1==hashValue[i]){
-                b|=1<<(i&7);
-            }else if(hashValue[i]!=0)
-                throw new IllegalArgumentException("invalid hashValue,every element must be 0 or 1");
-            if(7==(i&7)||i==hashValue.length-1){
-                result[i>>3]=b;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * 压缩格式的指纹解压缩
-     * @param compactValue
-     * @return
-     */
-    private static byte[] uncompact(byte[] compactValue){
-        byte[] result=new byte[compactValue.length<<3];
-        for(int i=0;i<result.length;++i){
-            if((compactValue[i>>3]&(1<<(i&7)))==0)
-                result[i]=0;
-            else
-                result[i]=1;
-        }
-        return result;
-    }
-    /**
-     * 字符串类型的指纹数据转为字节数组
-     * @param hashValue
-     * @return
-     */
-    private static byte[] toBytes(String hashValue){
-        hashValue=hashValue.replaceAll("\\s", "");
-        byte[] result=new byte[hashValue.length()];
-        for(int i=0;i<result.length;++i){
-            char c = hashValue.charAt(i);
-            if('0'==c)
-                result[i]=0;
-            else if('1'==c)
-                result[i]=1;
-            else
-                throw new IllegalArgumentException("invalid hashValue String");
-        }
-        return result;
-    }
-    /**
-     * 缩放图像到指定尺寸
-     * @param src
-     * @param width
-     * @param height
-     * @return
-     */
-    private static BufferedImage resize(Image src,int width,int height){
-        BufferedImage result = new BufferedImage(width, height,
-                BufferedImage.TYPE_3BYTE_BGR);
-        Graphics g = result.getGraphics();
-        try{
-            g.drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
-        }finally{
-            g.dispose();
-        }
-        return result;
-    }
-    /**
-     * 计算均值
-     * @param src
-     * @return
-     */
-    private static  int mean(byte[] src){
-        long sum=0;
-        // 将数组元素转为无符号整数
-        for(byte b:src)sum+=(long)b&0xff;
-        return (int) (Math.round((float)sum/src.length));
-    }
-    /**
-     * 二值化处理
-     * @param src
-     * @return
-     */
-    private static byte[] binaryzation(byte[]src){
-        byte[] dst = src.clone();
-        int mean=mean(src);
-        for(int i=0;i<dst.length;++i){
-            // 将数组元素转为无符号整数再比较
-            dst[i]=(byte) (((int)dst[i]&0xff)>=mean?1:0);
-        }
-        return dst;
-
-    }
-    /**
-     * 转灰度图像
-     * @param src
-     * @return
-     */
-    private static BufferedImage toGray(BufferedImage src){
-        if(src.getType()==BufferedImage.TYPE_BYTE_GRAY){
-            return src;
-        }else{
-            // 图像转灰
-            BufferedImage grayImage = new BufferedImage(src.getWidth(), src.getHeight(),
-                    BufferedImage.TYPE_BYTE_GRAY);
-            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(src, grayImage);
-            return grayImage;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return toString(true);
-    }
-    /**
-     * @param multiLine 是否分行
-     * @return
-     */
-    public String toString(boolean multiLine) {
-        StringBuffer buffer=new StringBuffer();
-        int count=0;
-        for(byte b:this.binaryzationMatrix){
-            buffer.append(0==b?'0':'1');
-            if(multiLine&&++count%HASH_SIZE==0)
-                buffer.append('\n');
-        }
-        return buffer.toString();
-    }
-    @Override
-    public boolean equals(Object obj) {
-        if(obj instanceof FingerPrint){
-            return Arrays.equals(this.binaryzationMatrix,((FingerPrint)obj).binaryzationMatrix);
-        }else
-            return super.equals(obj);
-    }
-
-    /**
-     * 与指定的压缩格式指纹比较相似度
-     * @param compactValue
-     * @return
-     * @see #compare(FingerPrint)
-     */
-    public float compareCompact(byte[] compactValue){
-        return compare(createFromCompact(compactValue));
-    }
-    /**
-     * @param hashValue
-     * @return
-     * @see #compare(FingerPrint)
-     */
-    public float compare(String hashValue){
-        return compare(new FingerPrint(hashValue));
-    }
-    /**
-     * 与指定的指纹比较相似度
-     * @param hashValue
-     * @return
-     * @see #compare(FingerPrint)
-     */
-    public float compare(byte[] hashValue){
-        return compare(new FingerPrint(hashValue));
-    }
-    /**
-     * 与指定图像比较相似度
-     * @param image2
-     * @return
-     * @see #compare(FingerPrint)
-     */
-    public float compare(BufferedImage image2){
-        return compare(new FingerPrint(image2));
-    }
-    /**
-     * 比较指纹相似度
-     * @param src
-     * @return
-     * @see #compare(byte[], byte[])
-     */
-    public float compare(FingerPrint src){
-        if(src.binaryzationMatrix.length!=this.binaryzationMatrix.length)
-            throw new IllegalArgumentException("length of hashValue is mismatch");
-        return compare(binaryzationMatrix,src.binaryzationMatrix);
-    }
-    /**
-     * 判断两个数组相似度,数组长度必须一致否则抛出异常
-     * @param f1
-     * @param f2
-     * @return 返回相似度(0.0~1.0)
-     */
-    private static float compare(byte[] f1,byte[] f2){
-        if(f1.length!=f2.length)
-            throw new IllegalArgumentException("mismatch FingerPrint length");
-        int sameCount=0;
-        for(int i=0;i<f1.length;++i){
-            if(f1[i]==f2[i])++sameCount;
-        }
-        return (float)sameCount/f1.length;
-    }
-    public static float compareCompact(byte[] f1,byte[] f2){
-        return compare(uncompact(f1),uncompact(f2));
-    }
-    public static float compare(BufferedImage image1,BufferedImage image2){
-        return new FingerPrint(image1).compare(new FingerPrint(image2));
-    }
-}
+package com.mooctest.image;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.util.Arrays;
+
+/**
+ * 均值哈希实现图像指纹比较
+ * @author guyadong
+ *
+ */
+public final class FingerPrint {
+    /**
+     * 图像指纹的尺寸,将图像resize到指定的尺寸,来计算哈希数组
+     */
+    private static final int HASH_SIZE=16;
+
+    public byte[] getBinaryzationMatrix() {
+        return binaryzationMatrix;
+    }
+
+    /**
+     * 保存图像指纹的二值化矩阵
+     */
+    private final byte[] binaryzationMatrix;
+    public FingerPrint(byte[] hashValue) {
+        if(hashValue.length!=HASH_SIZE*HASH_SIZE)
+            throw new IllegalArgumentException(String.format("length of hashValue must be %d",HASH_SIZE*HASH_SIZE ));
+        this.binaryzationMatrix=hashValue;
+    }
+    public FingerPrint(String hashValue) {
+        this(toBytes(hashValue));
+    }
+    public FingerPrint (BufferedImage src){
+        this(hashValue(src));
+    }
+    private static byte[] hashValue(BufferedImage src){
+        BufferedImage hashImage = resize(src,HASH_SIZE,HASH_SIZE);
+        byte[] matrixGray = (byte[]) toGray(hashImage).getData().getDataElements(0, 0, HASH_SIZE, HASH_SIZE, null);
+        return  binaryzation(matrixGray);
+    }
+    /**
+     * 从压缩格式指纹创建{@link FingerPrint}对象
+     * @param compactValue
+     * @return
+     */
+    public static FingerPrint createFromCompact(byte[] compactValue){
+        return new FingerPrint(uncompact(compactValue));
+    }
+
+    public static boolean validHashValue(byte[] hashValue){
+        if(hashValue.length!=HASH_SIZE)
+            return false;
+        for(byte b:hashValue){
+            if(0!=b&&1!=b)return false;
+        }
+        return true;
+    }
+    public static boolean validHashValue(String hashValue){
+        if(hashValue.length()!=HASH_SIZE)
+            return false;
+        for(int i=0;i<hashValue.length();++i){
+            if('0'!=hashValue.charAt(i)&&'1'!=hashValue.charAt(i))return false;
+        }
+        return true;
+    }
+    public byte[] compact(){
+        return compact(binaryzationMatrix);
+    }
+
+    /**
+     * 指纹数据按位压缩
+     * @param hashValue
+     * @return
+     */
+    private static byte[] compact(byte[] hashValue){
+        byte[] result=new byte[(hashValue.length+7)>>3];
+        byte b=0;
+        for(int i=0;i<hashValue.length;++i){
+            if(0==(i&7)){
+                b=0;
+            }
+            if(1==hashValue[i]){
+                b|=1<<(i&7);
+            }else if(hashValue[i]!=0)
+                throw new IllegalArgumentException("invalid hashValue,every element must be 0 or 1");
+            if(7==(i&7)||i==hashValue.length-1){
+                result[i>>3]=b;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 压缩格式的指纹解压缩
+     * @param compactValue
+     * @return
+     */
+    private static byte[] uncompact(byte[] compactValue){
+        byte[] result=new byte[compactValue.length<<3];
+        for(int i=0;i<result.length;++i){
+            if((compactValue[i>>3]&(1<<(i&7)))==0)
+                result[i]=0;
+            else
+                result[i]=1;
+        }
+        return result;
+    }
+    /**
+     * 字符串类型的指纹数据转为字节数组
+     * @param hashValue
+     * @return
+     */
+    private static byte[] toBytes(String hashValue){
+        hashValue=hashValue.replaceAll("\\s", "");
+        byte[] result=new byte[hashValue.length()];
+        for(int i=0;i<result.length;++i){
+            char c = hashValue.charAt(i);
+            if('0'==c)
+                result[i]=0;
+            else if('1'==c)
+                result[i]=1;
+            else
+                throw new IllegalArgumentException("invalid hashValue String");
+        }
+        return result;
+    }
+    /**
+     * 缩放图像到指定尺寸
+     * @param src
+     * @param width
+     * @param height
+     * @return
+     */
+    private static BufferedImage resize(Image src,int width,int height){
+        BufferedImage result = new BufferedImage(width, height,
+                BufferedImage.TYPE_3BYTE_BGR);
+        Graphics g = result.getGraphics();
+        try{
+            g.drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
+        }finally{
+            g.dispose();
+        }
+        return result;
+    }
+    /**
+     * 计算均值
+     * @param src
+     * @return
+     */
+    private static  int mean(byte[] src){
+        long sum=0;
+        // 将数组元素转为无符号整数
+        for(byte b:src)sum+=(long)b&0xff;
+        return (int) (Math.round((float)sum/src.length));
+    }
+    /**
+     * 二值化处理
+     * @param src
+     * @return
+     */
+    private static byte[] binaryzation(byte[]src){
+        byte[] dst = src.clone();
+        int mean=mean(src);
+        for(int i=0;i<dst.length;++i){
+            // 将数组元素转为无符号整数再比较
+            dst[i]=(byte) (((int)dst[i]&0xff)>=mean?1:0);
+        }
+        return dst;
+
+    }
+    /**
+     * 转灰度图像
+     * @param src
+     * @return
+     */
+    private static BufferedImage toGray(BufferedImage src){
+        if(src.getType()==BufferedImage.TYPE_BYTE_GRAY){
+            return src;
+        }else{
+            // 图像转灰
+            BufferedImage grayImage = new BufferedImage(src.getWidth(), src.getHeight(),
+                    BufferedImage.TYPE_BYTE_GRAY);
+            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(src, grayImage);
+            return grayImage;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return toString(true);
+    }
+    /**
+     * @param multiLine 是否分行
+     * @return
+     */
+    public String toString(boolean multiLine) {
+        StringBuffer buffer=new StringBuffer();
+        int count=0;
+        for(byte b:this.binaryzationMatrix){
+            buffer.append(0==b?'0':'1');
+            if(multiLine&&++count%HASH_SIZE==0)
+                buffer.append('\n');
+        }
+        return buffer.toString();
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if(obj instanceof FingerPrint){
+            return Arrays.equals(this.binaryzationMatrix,((FingerPrint)obj).binaryzationMatrix);
+        }else
+            return super.equals(obj);
+    }
+
+    /**
+     * 与指定的压缩格式指纹比较相似度
+     * @param compactValue
+     * @return
+     * @see #compare(FingerPrint)
+     */
+    public float compareCompact(byte[] compactValue){
+        return compare(createFromCompact(compactValue));
+    }
+    /**
+     * @param hashValue
+     * @return
+     * @see #compare(FingerPrint)
+     */
+    public float compare(String hashValue){
+        return compare(new FingerPrint(hashValue));
+    }
+    /**
+     * 与指定的指纹比较相似度
+     * @param hashValue
+     * @return
+     * @see #compare(FingerPrint)
+     */
+    public float compare(byte[] hashValue){
+        return compare(new FingerPrint(hashValue));
+    }
+    /**
+     * 与指定图像比较相似度
+     * @param image2
+     * @return
+     * @see #compare(FingerPrint)
+     */
+    public float compare(BufferedImage image2){
+        return compare(new FingerPrint(image2));
+    }
+    /**
+     * 比较指纹相似度
+     * @param src
+     * @return
+     * @see #compare(byte[], byte[])
+     */
+    public float compare(FingerPrint src){
+        if(src.binaryzationMatrix.length!=this.binaryzationMatrix.length)
+            throw new IllegalArgumentException("length of hashValue is mismatch");
+        return compare(binaryzationMatrix,src.binaryzationMatrix);
+    }
+    /**
+     * 判断两个数组相似度,数组长度必须一致否则抛出异常
+     * @param f1
+     * @param f2
+     * @return 返回相似度(0.0~1.0)
+     */
+    private static float compare(byte[] f1,byte[] f2){
+        if(f1.length!=f2.length)
+            throw new IllegalArgumentException("mismatch FingerPrint length");
+        int sameCount=0;
+        for(int i=0;i<f1.length;++i){
+            if(f1[i]==f2[i])++sameCount;
+        }
+        return (float)sameCount/f1.length;
+    }
+    public static float compareCompact(byte[] f1,byte[] f2){
+        return compare(uncompact(f1),uncompact(f2));
+    }
+    public static float compare(BufferedImage image1,BufferedImage image2){
+        return new FingerPrint(image1).compare(new FingerPrint(image2));
+    }
+}

+ 90 - 90
src/main/java/com/mooctest/image/ImageDownload.java

@@ -1,90 +1,90 @@
-package com.mooctest.image;
-
-import com.mooctest.util.ImageUtil;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class ImageDownload {
-
-    public static void createImage(String imgurl, String taskId, String filePath) throws Exception {
-
-        String path = ImageUtil.IMAGE_PATH + taskId + "/" + filePath;
-
-        File imageFile = new File(path);
-        if (checkExist(imageFile)) {
-            System.out.println("数据已存在");
-            return;
-        }
-
-        URL url = new URL(encode(imgurl, "utf-8"));
-        BufferedImage image = null;
-        int retryTimes = 3;
-        for (int i = 0; i < retryTimes; i++) {
-            try {
-                image = ImageIO.read(url);
-                break;
-            } catch (IOException e) {
-                System.out.println("image download fail " + filePath + " download times: " + (i + 1));
-                if (i+1 == retryTimes)
-                    throw e;
-            }
-        }
-//        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-//        InputStream inputStream = conn.getInputStream(); // 通过输入流获得图片数据
-//        byte[] getData = readInputStream(inputStream); // 获得图片的二进制数据
-
-        FingerPrint fp = new FingerPrint(image);
-
-
-        FileOutputStream fos = new FileOutputStream(imageFile);
-        fos.write(fp.getBinaryzationMatrix());
-        fos.close();
-    }
-
-    public static byte[] readInputStream(InputStream inputStream) throws IOException {
-        byte[] buffer = new byte[1024];
-        int len = 0;
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        while ((len = inputStream.read(buffer)) != -1) {
-            bos.write(buffer, 0, len);
-        }
-        bos.close();
-        return bos.toByteArray();
-
-    }
-
-    public static boolean checkExist(File file) throws Exception {
-        File file2 = new File(file.getParent());
-        if (!file2.isDirectory()) {// 判断文件目录是否存在
-            file2.mkdirs();
-        }
-        if (!file.exists()) {//判断文件是否存在
-            file.createNewFile();// 创建文件
-        } else {
-            return true;
-        }
-        return false;
-    }
-
-    private static String zhPattern = "[\\u4e00-\\u9fa5]+";
-
-    public static String encode(String str, String charset)
-            throws UnsupportedEncodingException {
-        str = str.replaceAll(" ", "+");// 对空字符串进行处理
-        Pattern p = Pattern.compile(zhPattern);
-        Matcher m = p.matcher(str);
-        StringBuffer b = new StringBuffer();
-        while (m.find()) {
-            m.appendReplacement(b, URLEncoder.encode(m.group(0), charset));
-        }
-        m.appendTail(b);
-        return b.toString();
-    }
-
-}
+package com.mooctest.image;
+
+import com.mooctest.util.ImageUtil;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ImageDownload {
+
+    public static void createImage(String imgurl, String taskId, String filePath) throws Exception {
+
+        String path = ImageUtil.IMAGE_PATH + taskId + "/" + filePath;
+
+        File imageFile = new File(path);
+        if (checkExist(imageFile)) {
+            System.out.println("数据已存在");
+            return;
+        }
+
+        URL url = new URL(encode(imgurl, "utf-8"));
+        BufferedImage image = null;
+        int retryTimes = 3;
+        for (int i = 0; i < retryTimes; i++) {
+            try {
+                image = ImageIO.read(url);
+                break;
+            } catch (IOException e) {
+                System.out.println("image download fail " + filePath + " download times: " + (i + 1));
+                if (i+1 == retryTimes)
+                    throw e;
+            }
+        }
+//        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+//        InputStream inputStream = conn.getInputStream(); // 通过输入流获得图片数据
+//        byte[] getData = readInputStream(inputStream); // 获得图片的二进制数据
+
+        FingerPrint fp = new FingerPrint(image);
+
+
+        FileOutputStream fos = new FileOutputStream(imageFile);
+        fos.write(fp.getBinaryzationMatrix());
+        fos.close();
+    }
+
+    public static byte[] readInputStream(InputStream inputStream) throws IOException {
+        byte[] buffer = new byte[1024];
+        int len = 0;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        while ((len = inputStream.read(buffer)) != -1) {
+            bos.write(buffer, 0, len);
+        }
+        bos.close();
+        return bos.toByteArray();
+
+    }
+
+    public static boolean checkExist(File file) throws Exception {
+        File file2 = new File(file.getParent());
+        if (!file2.isDirectory()) {// 判断文件目录是否存在
+            file2.mkdirs();
+        }
+        if (!file.exists()) {//判断文件是否存在
+            file.createNewFile();// 创建文件
+        } else {
+            return true;
+        }
+        return false;
+    }
+
+    private static String zhPattern = "[\\u4e00-\\u9fa5]+";
+
+    public static String encode(String str, String charset)
+            throws UnsupportedEncodingException {
+        str = str.replaceAll(" ", "+");// 对空字符串进行处理
+        Pattern p = Pattern.compile(zhPattern);
+        Matcher m = p.matcher(str);
+        StringBuffer b = new StringBuffer();
+        while (m.find()) {
+            m.appendReplacement(b, URLEncoder.encode(m.group(0), charset));
+        }
+        m.appendTail(b);
+        return b.toString();
+    }
+
+}

+ 198 - 198
src/main/java/com/mooctest/image/ImagePHash.java

@@ -1,198 +1,198 @@
-package com.mooctest.image;
-
-import java.awt.Graphics2D;
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorConvertOp;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.imageio.ImageIO;
-
-/*
- * pHash-like image hash.
- * Author: Elliot Shepherd (elliot@jarofworms.com
- * Based On: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
- */
-public class ImagePHash {
-
-    private int size = 32;
-    private int smallerSize = 8;
-    private double[] c;
-
-    public ImagePHash() {
-        initCoefficients();
-    }
-
-    public ImagePHash(int size, int smallerSize) {
-        this.size = size;
-        this.smallerSize = smallerSize;
-        initCoefficients();
-    }
-
-    private void initCoefficients() {
-        c = new double[size];
-        for (int i = 1; i < size; i++) {
-            c[i] = 1;
-        }
-        c[0] = 1 / Math.sqrt(2.0);
-    }
-
-
-    private int distance(String s1, String s2) {
-        int counter = 0;
-        for (int k = 0; k < s1.length(); k++) {
-            if (s1.charAt(k) != s2.charAt(k)) {
-                counter++;
-            }
-        }
-        return counter;
-    }
-
-    // Returns a 'binary string' (like. 001010111011100010) which is easy to do
-    // a hamming distance on.
-    private String getHash(InputStream is) throws Exception {
-        BufferedImage img = ImageIO.read(is);
-
-        /*
-         * 1. Reduce size. Like Average Hash, pHash starts with a small image.
-         * However, the image is larger than 8x8; 32x32 is a good size. This is
-         * really done to simplify the DCT computation and not because it is
-         * needed to reduce the high frequencies.
-         */
-        img = resize(img, size, size);
-
-        /*
-         * 2. Reduce color. The image is reduced to a grayscale just to further
-         * simplify the number of computations.
-         */
-        img = grayscale(img);
-
-        double[][] vals = new double[size][size];
-
-        for (int x = 0; x < img.getWidth(); x++) {
-            for (int y = 0; y < img.getHeight(); y++) {
-                vals[x][y] = getBlue(img, x, y);
-            }
-        }
-
-        /*
-         * 3. Compute the DCT. The DCT separates the image into a collection of
-         * frequencies and scalars. While JPEG uses an 8x8 DCT, this algorithm
-         * uses a 32x32 DCT.
-         */
-        double[][] dctVals = applyDCT(vals);
-
-        /*
-         * 4. Reduce the DCT. This is the magic step. While the DCT is 32x32,
-         * just keep the top-left 8x8. Those represent the lowest frequencies in
-         * the picture.
-         */
-        /*
-         * 5. Compute the average value. Like the Average Hash, compute the mean
-         * DCT value (using only the 8x8 DCT low-frequency values and excluding
-         * the first term since the DC coefficient can be significantly
-         * different from the other values and will throw off the average).
-         */
-        double total = 0;
-
-        for (int x = 0; x < smallerSize; x++) {
-            for (int y = 0; y < smallerSize; y++) {
-                total += dctVals[x][y];
-            }
-        }
-        total -= dctVals[0][0];
-
-        double avg = total / (double) ((smallerSize * smallerSize) - 1);
-
-        /*
-         * 6. Further reduce the DCT. This is the magic step. Set the 64 hash
-         * bits to 0 or 1 depending on whether each of the 64 DCT values is
-         * above or below the average value. The result doesn't tell us the
-         * actual low frequencies; it just tells us the very-rough relative
-         * scale of the frequencies to the mean. The result will not vary as
-         * long as the overall structure of the image remains the same; this can
-         * survive gamma and color histogram adjustments without a problem.
-         */
-        String hash = "";
-
-        for (int x = 0; x < smallerSize; x++) {
-            for (int y = 0; y < smallerSize; y++) {
-                if (x != 0 && y != 0) {
-                    hash += (dctVals[x][y] > avg ? "1" : "0");
-                }
-            }
-        }
-
-        return hash;
-    }
-
-    private BufferedImage resize(BufferedImage image, int width, int height) {
-        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        Graphics2D g = resizedImage.createGraphics();
-        g.drawImage(image, 0, 0, width, height, null);
-        g.dispose();
-        return resizedImage;
-    }
-
-    private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
-
-    private BufferedImage grayscale(BufferedImage img) {
-        colorConvert.filter(img, img);
-        return img;
-    }
-
-    private static int getBlue(BufferedImage img, int x, int y) {
-        return (img.getRGB(x, y)) & 0xff;
-    }
-
-    // DCT function stolen from
-    // http://stackoverflow.com/questions/4240490/problems-with-dct-and-idct-algorithm-in-java
-    private double[][] applyDCT(double[][] f) {
-        int N = size;
-
-        double[][] F = new double[N][N];
-        for (int u = 0; u < N; u++) {
-            for (int v = 0; v < N; v++) {
-                double sum = 0.0;
-                for (int i = 0; i < N; i++) {
-                    for (int j = 0; j < N; j++) {
-                        sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)
-                                * Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);
-                    }
-                }
-                sum *= ((c[u] * c[v]) / 4.0);
-                F[u][v] = sum;
-            }
-        }
-        return F;
-    }
-
-    /**
-     * @param srcUrl
-     * @param canUrl
-     * @return 	值越小相识度越高,10之内可以简单判断这两张图片内容一致
-     * @throws Exception
-     * @throws
-     */
-    public int distance(URL srcUrl, URL canUrl) throws Exception {
-        String imgStr = this.getHash(srcUrl.openStream());
-        String canStr = this.getHash(canUrl.openStream());
-        return this.distance(imgStr, canStr);
-    }
-
-    /**
-     * @param srcFile
-     * @param canFile
-     * @return 值越小相识度越高,10之内可以简单判断这两张图片内容一致
-     * @throws Exception
-     */
-    public int distance(File srcFile, File canFile) throws Exception {
-        String imageSrcFile = this.getHash(new FileInputStream(srcFile));
-        String imageCanFile = this.getHash(new FileInputStream(canFile));
-        return this.distance(imageSrcFile, imageCanFile);
-    }
-
-}
+package com.mooctest.image;
+
+import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.imageio.ImageIO;
+
+/*
+ * pHash-like image hash.
+ * Author: Elliot Shepherd (elliot@jarofworms.com
+ * Based On: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
+ */
+public class ImagePHash {
+
+    private int size = 32;
+    private int smallerSize = 8;
+    private double[] c;
+
+    public ImagePHash() {
+        initCoefficients();
+    }
+
+    public ImagePHash(int size, int smallerSize) {
+        this.size = size;
+        this.smallerSize = smallerSize;
+        initCoefficients();
+    }
+
+    private void initCoefficients() {
+        c = new double[size];
+        for (int i = 1; i < size; i++) {
+            c[i] = 1;
+        }
+        c[0] = 1 / Math.sqrt(2.0);
+    }
+
+
+    private int distance(String s1, String s2) {
+        int counter = 0;
+        for (int k = 0; k < s1.length(); k++) {
+            if (s1.charAt(k) != s2.charAt(k)) {
+                counter++;
+            }
+        }
+        return counter;
+    }
+
+    // Returns a 'binary string' (like. 001010111011100010) which is easy to do
+    // a hamming distance on.
+    private String getHash(InputStream is) throws Exception {
+        BufferedImage img = ImageIO.read(is);
+
+        /*
+         * 1. Reduce size. Like Average Hash, pHash starts with a small image.
+         * However, the image is larger than 8x8; 32x32 is a good size. This is
+         * really done to simplify the DCT computation and not because it is
+         * needed to reduce the high frequencies.
+         */
+        img = resize(img, size, size);
+
+        /*
+         * 2. Reduce color. The image is reduced to a grayscale just to further
+         * simplify the number of computations.
+         */
+        img = grayscale(img);
+
+        double[][] vals = new double[size][size];
+
+        for (int x = 0; x < img.getWidth(); x++) {
+            for (int y = 0; y < img.getHeight(); y++) {
+                vals[x][y] = getBlue(img, x, y);
+            }
+        }
+
+        /*
+         * 3. Compute the DCT. The DCT separates the image into a collection of
+         * frequencies and scalars. While JPEG uses an 8x8 DCT, this algorithm
+         * uses a 32x32 DCT.
+         */
+        double[][] dctVals = applyDCT(vals);
+
+        /*
+         * 4. Reduce the DCT. This is the magic step. While the DCT is 32x32,
+         * just keep the top-left 8x8. Those represent the lowest frequencies in
+         * the picture.
+         */
+        /*
+         * 5. Compute the average value. Like the Average Hash, compute the mean
+         * DCT value (using only the 8x8 DCT low-frequency values and excluding
+         * the first term since the DC coefficient can be significantly
+         * different from the other values and will throw off the average).
+         */
+        double total = 0;
+
+        for (int x = 0; x < smallerSize; x++) {
+            for (int y = 0; y < smallerSize; y++) {
+                total += dctVals[x][y];
+            }
+        }
+        total -= dctVals[0][0];
+
+        double avg = total / (double) ((smallerSize * smallerSize) - 1);
+
+        /*
+         * 6. Further reduce the DCT. This is the magic step. Set the 64 hash
+         * bits to 0 or 1 depending on whether each of the 64 DCT values is
+         * above or below the average value. The result doesn't tell us the
+         * actual low frequencies; it just tells us the very-rough relative
+         * scale of the frequencies to the mean. The result will not vary as
+         * long as the overall structure of the image remains the same; this can
+         * survive gamma and color histogram adjustments without a problem.
+         */
+        String hash = "";
+
+        for (int x = 0; x < smallerSize; x++) {
+            for (int y = 0; y < smallerSize; y++) {
+                if (x != 0 && y != 0) {
+                    hash += (dctVals[x][y] > avg ? "1" : "0");
+                }
+            }
+        }
+
+        return hash;
+    }
+
+    private BufferedImage resize(BufferedImage image, int width, int height) {
+        BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g = resizedImage.createGraphics();
+        g.drawImage(image, 0, 0, width, height, null);
+        g.dispose();
+        return resizedImage;
+    }
+
+    private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+
+    private BufferedImage grayscale(BufferedImage img) {
+        colorConvert.filter(img, img);
+        return img;
+    }
+
+    private static int getBlue(BufferedImage img, int x, int y) {
+        return (img.getRGB(x, y)) & 0xff;
+    }
+
+    // DCT function stolen from
+    // http://stackoverflow.com/questions/4240490/problems-with-dct-and-idct-algorithm-in-java
+    private double[][] applyDCT(double[][] f) {
+        int N = size;
+
+        double[][] F = new double[N][N];
+        for (int u = 0; u < N; u++) {
+            for (int v = 0; v < N; v++) {
+                double sum = 0.0;
+                for (int i = 0; i < N; i++) {
+                    for (int j = 0; j < N; j++) {
+                        sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)
+                                * Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);
+                    }
+                }
+                sum *= ((c[u] * c[v]) / 4.0);
+                F[u][v] = sum;
+            }
+        }
+        return F;
+    }
+
+    /**
+     * @param srcUrl
+     * @param canUrl
+     * @return 	值越小相识度越高,10之内可以简单判断这两张图片内容一致
+     * @throws Exception
+     * @throws
+     */
+    public int distance(URL srcUrl, URL canUrl) throws Exception {
+        String imgStr = this.getHash(srcUrl.openStream());
+        String canStr = this.getHash(canUrl.openStream());
+        return this.distance(imgStr, canStr);
+    }
+
+    /**
+     * @param srcFile
+     * @param canFile
+     * @return 值越小相识度越高,10之内可以简单判断这两张图片内容一致
+     * @throws Exception
+     */
+    public int distance(File srcFile, File canFile) throws Exception {
+        String imageSrcFile = this.getHash(new FileInputStream(srcFile));
+        String imageCanFile = this.getHash(new FileInputStream(canFile));
+        return this.distance(imageSrcFile, imageCanFile);
+    }
+
+}

+ 68 - 68
src/main/java/com/mooctest/listener/SaveEventListener.java

@@ -1,68 +1,68 @@
-package com.mooctest.listener;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-
-import com.mooctest.annotation.AutoValue;
-import com.mooctest.model.SequenceId;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.data.mongodb.core.FindAndModifyOptions;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
-import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
-import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
-import org.springframework.data.mongodb.core.query.Criteria;
-import org.springframework.data.mongodb.core.query.Query;
-import org.springframework.data.mongodb.core.query.Update;
-import org.springframework.stereotype.Component;
-import org.springframework.util.ReflectionUtils;
-
-import javax.annotation.Resource;
-
-@Component
-public class SaveEventListener extends AbstractMongoEventListener<Object> {
-    @Resource(name = "mongoTemplate1")
-    private MongoTemplate mongo;
-
-    @Override
-    public void onBeforeConvert(BeforeConvertEvent<Object> event) {
-        Object source = event.getSource();
-        if (source != null) {
-            ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
-                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
-                    ReflectionUtils.makeAccessible(field);
-                    // 如果字段添加了我们自定义的AutoValue注解
-                    if (field.isAnnotationPresent(AutoValue.class) && field.get(source) instanceof Number
-                            && field.getLong(source) == 0) {
-                        // field.get(source) instanceof Number &&
-                        // field.getLong(source)==0
-                        // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID
-                        // 设置自增ID
-
-                        field.set(source, getNextId(event.getCollectionName()));
-
-                    }
-                }
-            });
-        }
-    }
-
-    /**
-     * 获取下一个自增ID
-     *
-     * @param collName
-     *            集合(这里用类名,就唯一性来说最好还是存放长类名)名称
-     * @return 序列值
-     */
-    private Long getNextId(String collName) {
-        Query query = new Query(Criteria.where("collName").is(collName));
-        Update update = new Update();
-        update.inc("seqId", 1);
-        FindAndModifyOptions options = new FindAndModifyOptions();
-        options.upsert(true);
-        options.returnNew(true);
-        SequenceId seq = mongo.findAndModify(query, update, options, SequenceId.class);
-        return seq.getSeqId();
-    }
-}
+package com.mooctest.listener;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+
+import com.mooctest.annotation.AutoValue;
+import com.mooctest.model.SequenceId;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.data.mongodb.core.FindAndModifyOptions;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
+import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
+import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
+
+import javax.annotation.Resource;
+
+@Component
+public class SaveEventListener extends AbstractMongoEventListener<Object> {
+    @Resource(name = "mongoTemplate1")
+    private MongoTemplate mongo;
+
+    @Override
+    public void onBeforeConvert(BeforeConvertEvent<Object> event) {
+        Object source = event.getSource();
+        if (source != null) {
+            ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
+                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
+                    ReflectionUtils.makeAccessible(field);
+                    // 如果字段添加了我们自定义的AutoValue注解
+                    if (field.isAnnotationPresent(AutoValue.class) && field.get(source) instanceof Number
+                            && field.getLong(source) == 0) {
+                        // field.get(source) instanceof Number &&
+                        // field.getLong(source)==0
+                        // 判断注解的字段是否为number类型且值是否等于0.如果大于0说明有ID不需要生成ID
+                        // 设置自增ID
+
+                        field.set(source, getNextId(event.getCollectionName()));
+
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * 获取下一个自增ID
+     *
+     * @param collName
+     *            集合(这里用类名,就唯一性来说最好还是存放长类名)名称
+     * @return 序列值
+     */
+    private Long getNextId(String collName) {
+        Query query = new Query(Criteria.where("collName").is(collName));
+        Update update = new Update();
+        update.inc("seqId", 1);
+        FindAndModifyOptions options = new FindAndModifyOptions();
+        options.upsert(true);
+        options.returnNew(true);
+        SequenceId seq = mongo.findAndModify(query, update, options, SequenceId.class);
+        return seq.getSeqId();
+    }
+}

+ 31 - 31
src/main/java/com/mooctest/model/AggTaskStatus.java

@@ -1,31 +1,31 @@
-package com.mooctest.model;
-
-import com.mooctest.annotation.AutoValue;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.util.Date;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Document(collection = "AggTaskStatus")
-public class AggTaskStatus {
-
-    @Id
-    @AutoValue
-    private long id;
-
-    private String taskId;
-
-    private int status;
-
-    private Date startTime;
-
-    private Date endTime;
-}
+package com.mooctest.model;
+
+import com.mooctest.annotation.AutoValue;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Document(collection = "AggTaskStatus")
+public class AggTaskStatus {
+
+    @Id
+    @AutoValue
+    private long id;
+
+    private String taskId;
+
+    private int status;
+
+    private Date startTime;
+
+    private Date endTime;
+}

+ 49 - 47
src/main/java/com/mooctest/model/Bug.java

@@ -1,47 +1,49 @@
-package com.mooctest.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-import org.springframework.data.mongodb.core.mapping.Field;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Document(collection = "bug")
-public class Bug {
-
-    @Id
-    private String id;
-
-    @Field("case_take_id")
-    private String caseTakeId;
-
-    @Field("report_id")
-    private String reportId;
-
-    private String description;
-
-    @Field("img_url")
-    private String imgUrls;
-
-    private short severity;
-
-    private short recurrent;
-
-    @Field("bug_category")
-    private String bugCategory;
-
-    @Field("create_time_millis")
-    private String createTimeMillis;
-
-    @Field("bug_page")
-    private String bugPage;
-
-    @Field("case_id")
-    private String caseId;
-}
+package com.mooctest.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Document(collection = "bug")
+public class Bug {
+
+    @Id
+    private String id;
+
+    @Field("case_take_id")
+    private String caseTakeId;
+
+    @Field("report_id")
+    private String reportId;
+
+    private String title;
+
+    private String description;
+
+    @Field("img_url")
+    private String imgUrls;
+
+    private short severity;
+
+    private short recurrent;
+
+    @Field("bug_category")
+    private String bugCategory;
+
+    @Field("create_time_millis")
+    private String createTimeMillis;
+
+    @Field("bug_page")
+    private String bugPage;
+
+    @Field("case_id")
+    private String caseId;
+}

+ 64 - 0
src/main/java/com/mooctest/model/BugHistory.java

@@ -0,0 +1,64 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.List;
+
+@Document
+public class BugHistory implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 8852808978961197553L;
+
+	@Id
+    private String id;
+	
+	private String parent;
+	
+	private List<String> children;
+	
+	private String root;
+
+	@PersistenceConstructor
+	public BugHistory(String id, String parent, List<String> children, String root) {
+		this.id = id;
+		this.parent = parent;
+		this.children = children;
+		this.root = root;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getParent() {
+		return parent;
+	}
+
+	public void setParent(String parent) {
+		this.parent = parent;
+	}
+	
+	public List<String> getChildren() {
+		return children;
+	}
+
+	public void setChildren(List<String> children) {
+		this.children = children;
+	}
+
+	public String getRoot() {
+		return root;
+	}
+
+	public void setRoot(String root) {
+		this.root = root;
+	}
+}

+ 177 - 0
src/main/java/com/mooctest/model/BugMirror.java

@@ -0,0 +1,177 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Set;
+
+@Document
+public class BugMirror implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7484726588592610736L;
+
+	@Id
+    private String id;
+
+	@Indexed
+	private String case_take_id;
+	
+	@Indexed
+	private String bug_category;
+	
+	private String report_id;
+	
+	@Indexed
+	private int severity;
+	
+	@Indexed
+	private int recurrent;
+	
+	private String title;
+	
+	private Set<String> good;
+
+	private Set<String> bad;
+	
+	private String img_url;
+	
+	private boolean flag;
+	
+	private String useCase;
+	
+	@PersistenceConstructor
+	public BugMirror(String id, String case_take_id, String bug_category, int severity, int recurrent, String title, String img_url, Set<String> good, Set<String> bad, String report_id, String useCase, boolean flag) {
+		this.id = id;
+		this.case_take_id = case_take_id;
+		this.bug_category = bug_category;
+		this.severity = severity;
+		this.recurrent = recurrent;
+		this.title = title;
+		this.img_url = img_url;
+		this.bad = bad;
+		this.good = good;
+		this.report_id = report_id;
+		this.useCase = useCase;
+		this.flag = flag;
+	}
+	
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getCase_take_id() {
+		return case_take_id;
+	}
+
+	public void setCase_take_id(String case_take_id) {
+		this.case_take_id = case_take_id;
+	}
+
+	public String getBug_category() {
+		return bug_category;
+	}
+
+	public void setBug_category(String bug_category) {
+		this.bug_category = bug_category;
+	}
+
+	public int getSeverity() {
+		return severity;
+	}
+
+	public void setSeverity(int severity) {
+		this.severity = severity;
+	}
+
+	public int getRecurrent() {
+		return recurrent;
+	}
+
+	public void setRecurrent(int recurrent) {
+		this.recurrent = recurrent;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getImg_url() {
+		return img_url;
+	}
+
+	public void setImg_url(String img_url) {
+		this.img_url = img_url;
+	}
+	
+	public Set<String> getGood() {
+		return good;
+	}
+
+	public void setGood(Set<String> good) {
+		this.good = good;
+	}
+
+	public Set<String> getBad() {
+		return bad;
+	}
+
+	public void setBad(Set<String> bad) {
+		this.bad = bad;
+	}
+
+	public String getReport_id() {
+		return report_id;
+	}
+
+	public void setReport_id(String report_id) {
+		this.report_id = report_id;
+	}
+
+	public boolean isFlag() {
+		return flag;
+	}
+
+	public void setFlag(boolean flag) {
+		this.flag = flag;
+	}
+
+	public String getUseCase() {
+		return useCase;
+	}
+
+	public void setUseCase(String useCase) {
+		this.useCase = useCase;
+	}
+	
+	@Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
+	
+	@Override
+    public boolean equals(Object o) {
+        // 比较引用
+        if(this == o) return true;
+        // 比较类型
+        if(o == null || getClass() != o.getClass()) return false;
+        // 比较内容,这里比较的是 id 值
+        BugMirror other = (BugMirror) o;
+        // 判断逻辑就是:三元运算符 的结果如果等于null 那么就返回 false
+        // 首先确定当前 id 不等于 null,然后确定当前 id 不等于被比较的 id
+        // 最后条件都满足了之后还是不等null,说明肯定不一致就返回 false 就可以了
+        if (id != null ? !id.equals(other.id) : other.id != null) return false;
+        return true;
+    }
+}

+ 80 - 0
src/main/java/com/mooctest/model/BugPage.java

@@ -0,0 +1,80 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class BugPage implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 5647215351692151191L;
+
+	@Id
+    private String id;
+	
+	@Indexed
+	private String case_take_id;
+	
+	@Indexed
+	private String page1;
+	
+	@Indexed
+	private String page2;
+	
+	@Indexed
+	private String page3;
+
+	@PersistenceConstructor
+	public BugPage(String id, String page1, String page2, String page3, String case_take_id) {
+		this.id = id;
+		this.page1 = page1;
+		this.page2 = page2;
+		this.page3 = page3;
+		this.case_take_id = case_take_id;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getPage1() {
+		return page1;
+	}
+
+	public void setPage1(String page1) {
+		this.page1 = page1;
+	}
+
+	public String getPage2() {
+		return page2;
+	}
+
+	public void setPage2(String page2) {
+		this.page2 = page2;
+	}
+
+	public String getPage3() {
+		return page3;
+	}
+
+	public void setPage3(String page3) {
+		this.page3 = page3;
+	}
+
+	public String getCase_take_id() {
+		return case_take_id;
+	}
+
+	public void setCase_take_id(String case_take_id) {
+		this.case_take_id = case_take_id;
+	}
+	
+	
+}

+ 51 - 0
src/main/java/com/mooctest/model/BugScore.java

@@ -0,0 +1,51 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class BugScore implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -2993945374555651123L;
+
+	@Id
+    private String id;
+	
+	private int grade;
+	
+	private int score;
+
+	@PersistenceConstructor
+	public BugScore(String id, int grade, int score) {
+		this.id = id;
+		this.grade = grade;
+		this.score = score;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public int getGrade() {
+		return grade;
+	}
+
+	public void setGrade(int grade) {
+		this.grade = grade;
+	}
+
+	public int getScore() {
+		return score;
+	}
+
+	public void setScore(int score) {
+		this.score = score;
+	}
+}

+ 65 - 0
src/main/java/com/mooctest/model/CaseToBug.java

@@ -0,0 +1,65 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.List;
+
+@Document
+public class CaseToBug implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1969002363605622255L;
+
+	@Id
+	private String id;  //用例id
+	
+	private String case_take_id;
+	
+	private String report_id;
+	
+	private List<String> bug_id;  //该用例下的所有bug
+	
+	@PersistenceConstructor
+	public CaseToBug(String id, List<String> bug_id, String case_take_id, String report_id) {
+		this.id = id;
+		this.bug_id = bug_id;
+		this.case_take_id = case_take_id;
+		this.report_id = report_id;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public List<String> getBug_id() {
+		return bug_id;
+	}
+
+	public void setBug_id(List<String> bug_id) {
+		this.bug_id = bug_id;
+	}
+
+	public String getCase_take_id() {
+		return case_take_id;
+	}
+
+	public void setCase_take_id(String case_take_id) {
+		this.case_take_id = case_take_id;
+	}
+
+	public String getReport_id() {
+		return report_id;
+	}
+
+	public void setReport_id(String report_id) {
+		this.report_id = report_id;
+	}
+	
+}

+ 52 - 52
src/main/java/com/mooctest/model/FinalReport.java

@@ -1,52 +1,52 @@
-package com.mooctest.model;
-
-import com.mooctest.annotation.AutoValue;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.util.Date;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Document(collection = "FinalReport")//建议名字和类名一致
-public class FinalReport {
-    @Id
-    @AutoValue
-    private long id;
-
-    
-    private String description;
-
-    
-    private String imgUrls;
-
-    
-    private short severity;
-
-    
-    private short recurrent;
-
-    
-    private int category;
-
-    
-    private long writerId;
-
-    
-    private String sourceId;
-
-    
-    private Date createTime;
-
-    
-    private long examId;
-
-    
-    private long caseId;
-}
+package com.mooctest.model;
+
+import com.mooctest.annotation.AutoValue;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.Date;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Document(collection = "FinalReport")//建议名字和类名一致
+public class FinalReport {
+    @Id
+    @AutoValue
+    private long id;
+
+    
+    private String description;
+
+    
+    private String imgUrls;
+
+    
+    private short severity;
+
+    
+    private short recurrent;
+
+    
+    private int category;
+
+    
+    private long writerId;
+
+    
+    private String sourceId;
+
+    
+    private Date createTime;
+
+    
+    private long examId;
+
+    
+    private long caseId;
+}

+ 52 - 0
src/main/java/com/mooctest/model/KeyWords.java

@@ -0,0 +1,52 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class KeyWords implements java.io.Serializable{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 3325877949872439231L;
+
+	@Id
+    private String id;
+	
+	private String title;
+	
+	private String description;
+	
+	@PersistenceConstructor
+	public KeyWords(String id, String title, String description) {
+		this.id = id;
+		this.title = title;
+		this.description = description;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+}

+ 34 - 34
src/main/java/com/mooctest/model/MasterReport.java

@@ -1,34 +1,34 @@
-package com.mooctest.model;
-
-import com.mooctest.annotation.AutoValue;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import javax.persistence.*;
-
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Document(collection = "MasterReport")
-public class MasterReport {
-    @Id
-    @AutoValue
-    private long id;
-
-    private String masterId;
-
-    private long examId;
-
-    private long caseId;
-
-    private String bugId;
-
-    private int status = 0;
-
-    private Long reviewerId;
-}
+package com.mooctest.model;
+
+import com.mooctest.annotation.AutoValue;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import javax.persistence.*;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Document(collection = "MasterReport")
+public class MasterReport {
+    @Id
+    @AutoValue
+    private long id;
+
+    private String masterId;
+
+    private long examId;
+
+    private long caseId;
+
+    private String bugId;
+
+    private int status = 0;
+
+    private Long reviewerId;
+}

+ 20 - 20
src/main/java/com/mooctest/model/SequenceId.java

@@ -1,20 +1,20 @@
-package com.mooctest.model;
-
-import lombok.Data;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-import org.springframework.data.mongodb.core.mapping.Field;
-
-@Data
-@Document(collection = "sysSequence")
-public class SequenceId {
-    @Id
-//    @Field("_id")
-    private String id;
-
-    private long seqId;
-
-    private String collName;
-
-
-}
+package com.mooctest.model;
+
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+@Data
+@Document(collection = "sysSequence")
+public class SequenceId {
+    @Id
+//    @Field("_id")
+    private String id;
+
+    private long seqId;
+
+    private String collName;
+
+
+}

+ 53 - 0
src/main/java/com/mooctest/model/StuInfo.java

@@ -0,0 +1,53 @@
+package com.mooctest.model;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class StuInfo implements java.io.Serializable{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -7968494783792967307L;
+	
+	@Id
+    private String id;  //report_id
+	
+	private String worker_id;
+	
+	private String name;
+
+	@PersistenceConstructor
+	public StuInfo(String id, String worker_id, String name) {
+		this.id = id;
+		this.worker_id = worker_id;
+		this.name = name;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getWorker_id() {
+		return worker_id;
+	}
+
+	public void setWorker_id(String worker_id) {
+		this.worker_id = worker_id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}

+ 34 - 34
src/main/java/com/mooctest/model/SupplementItem.java

@@ -1,34 +1,34 @@
-package com.mooctest.model;
-
-import com.mooctest.annotation.AutoValue;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@Document(collection = "SupplementItem")
-public class SupplementItem {
-    @Id
-    @AutoValue
-    private long id;
-
-    
-    private String masterId;
-
-    private String bugId;
-
-    private int index;
-
-    private String supplementId;
-
-    private double pageRankScore;
-
-    private String content;
-
-    private boolean isImg;
-
-}
+package com.mooctest.model;
+
+import com.mooctest.annotation.AutoValue;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Document(collection = "SupplementItem")
+public class SupplementItem {
+    @Id
+    @AutoValue
+    private long id;
+
+    
+    private String masterId;
+
+    private String bugId;
+
+    private int index;
+
+    private String supplementId;
+
+    private double pageRankScore;
+
+    private String content;
+
+    private boolean isImg;
+
+}

+ 20 - 20
src/main/java/com/mooctest/model/Task.java

@@ -1,20 +1,20 @@
-package com.mooctest.model;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class Task {
-
-    private long examId;
-    private long caseId;
-    private String name;
-    private String icon;
-    private String version;
-    private int status;
-    private String startTime;
-    private String endTime;
-}
+package com.mooctest.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Task {
+
+    private long examId;
+    private long caseId;
+    private String name;
+    private String icon;
+    private String version;
+    private int status;
+    private String startTime;
+    private String endTime;
+}

+ 104 - 104
src/main/java/com/mooctest/nlp/DistanceMatrix.java

@@ -1,104 +1,104 @@
-package com.mooctest.nlp;
-
-import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
-import com.mooctest.image.FingerPrint;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffImg;
-import com.mooctest.util.Doc2VecUtil;
-import com.mooctest.util.ImageUtil;
-
-import java.io.File;
-import java.util.List;
-
-import static com.mooctest.util.ImageUtil.IMAGE_PATH;
-import static com.mooctest.util.ImageUtil.checkFileExist;
-
-public class DistanceMatrix {
-
-    public static double[][] genWord2VecDist(List<BugDTO> bugDTOs) {
-
-        int n = bugDTOs.size();
-        double[][] proximity = new double[n][];
-        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
-
-        for (int i = 0; i < n; i++) {
-            proximity[i] = new double[i + 1];
-            for (int j = 0; j < i; j++) {
-                proximity[i][j] = 1 - docVectorModel.similarity(bugDTOs.get(i).getDescription(), bugDTOs.get(j).getDescription());
-            }
-        }
-        return proximity;
-    }
-
-    public static double[][] genImgDist(List<DiffImg> diffImgs) {
-        int n = diffImgs.size();
-        double[][] distMatrix = new double[n][];
-
-        for (int i = 0; i < n; i++) {
-            distMatrix[i] = new double[i + 1];
-            for (int j = 0; j < i; j++) {
-
-                DiffImg diffImg1 = diffImgs.get(i);
-                DiffImg diffImg2 = diffImgs.get(j);
-                File file1 = checkFileExist(IMAGE_PATH + diffImg1.getBugId() + "_" + i);
-                File file2 = checkFileExist(IMAGE_PATH + diffImg2.getBugId() + "_" + j);
-                if (file1 == null || file2 == null) {
-                    continue;
-                }
-                FingerPrint fp1 = ImageUtil.readImgFingerPrint(file1);
-                FingerPrint fp2 = ImageUtil.readImgFingerPrint(file2);
-                float sim = fp1.compare(fp2);
-                distMatrix[i][j] = 1 - sim;
-            }
-        }
-        return distMatrix;
-    }
-    public static double[][] genHybridDist(List<BugDTO> bugDTOs) {
-
-        int n = bugDTOs.size();
-        double[][] proximity = new double[n][];
-        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
-
-        for (int i = 0; i < n; i++) {
-            proximity[i] = new double[i + 1];
-            for (int j = 0; j < i; j++) {
-                double txtDist = 1 - docVectorModel.similarity(bugDTOs.get(i).getDescription(), bugDTOs.get(j).getDescription());
-                proximity[i][j] = txtDist;
-                if (checkBugImageNotNull(bugDTOs.get(i)) && checkBugImageNotNull(bugDTOs.get(j))) {
-                    double imgDist = calBugImgDist(bugDTOs.get(i), bugDTOs.get(j));
-                    if (imgDist <= 0.15) {
-                        proximity[i][j] = proximity[i][j] * 0.9;
-                    }
-                }
-
-            }
-        }
-        return proximity;
-    }
-
-    private static double calBugImgDist(BugDTO bug1, BugDTO bug2) {
-        float max_sim = 0;
-        for (int i = 0; i < bug1.getImgUrls().length; i++) {
-            for (int j = 0; j < bug2.getImgUrls().length; j++) {
-
-                File file1 = checkFileExist(IMAGE_PATH + bug1.getId() + "_" + i);
-                File file2 = checkFileExist(IMAGE_PATH + bug2.getId() + "_" + i);
-                if (file1 == null || file2 == null) {
-                    continue;
-                }
-                FingerPrint fp1 = ImageUtil.readImgFingerPrint(file1);
-                FingerPrint fp2 = ImageUtil.readImgFingerPrint(file2);
-                float sim = fp1.compare(fp2);
-                max_sim = sim > max_sim ? sim : max_sim;
-            }
-        }
-
-        return 1 - max_sim;
-    }
-
-    private static boolean checkBugImageNotNull(BugDTO bug) {
-        return ((bug.getImgUrls() != null) && bug.getImgUrls().length > 0);
-    }
-
-
-}
+package com.mooctest.nlp;
+
+import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
+import com.mooctest.image.FingerPrint;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffImg;
+import com.mooctest.util.Doc2VecUtil;
+import com.mooctest.util.ImageUtil;
+
+import java.io.File;
+import java.util.List;
+
+import static com.mooctest.util.ImageUtil.IMAGE_PATH;
+import static com.mooctest.util.ImageUtil.checkFileExist;
+
+public class DistanceMatrix {
+
+    public static double[][] genWord2VecDist(List<BugDTO> bugDTOs) {
+
+        int n = bugDTOs.size();
+        double[][] proximity = new double[n][];
+        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
+
+        for (int i = 0; i < n; i++) {
+            proximity[i] = new double[i + 1];
+            for (int j = 0; j < i; j++) {
+                proximity[i][j] = 1 - docVectorModel.similarity(bugDTOs.get(i).getDescription(), bugDTOs.get(j).getDescription());
+            }
+        }
+        return proximity;
+    }
+
+    public static double[][] genImgDist(List<DiffImg> diffImgs) {
+        int n = diffImgs.size();
+        double[][] distMatrix = new double[n][];
+
+        for (int i = 0; i < n; i++) {
+            distMatrix[i] = new double[i + 1];
+            for (int j = 0; j < i; j++) {
+
+                DiffImg diffImg1 = diffImgs.get(i);
+                DiffImg diffImg2 = diffImgs.get(j);
+                File file1 = checkFileExist(IMAGE_PATH + diffImg1.getBugId() + "_" + i);
+                File file2 = checkFileExist(IMAGE_PATH + diffImg2.getBugId() + "_" + j);
+                if (file1 == null || file2 == null) {
+                    continue;
+                }
+                FingerPrint fp1 = ImageUtil.readImgFingerPrint(file1);
+                FingerPrint fp2 = ImageUtil.readImgFingerPrint(file2);
+                float sim = fp1.compare(fp2);
+                distMatrix[i][j] = 1 - sim;
+            }
+        }
+        return distMatrix;
+    }
+    public static double[][] genHybridDist(List<BugDTO> bugDTOs) {
+
+        int n = bugDTOs.size();
+        double[][] proximity = new double[n][];
+        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
+
+        for (int i = 0; i < n; i++) {
+            proximity[i] = new double[i + 1];
+            for (int j = 0; j < i; j++) {
+                double txtDist = 1 - docVectorModel.similarity(bugDTOs.get(i).getDescription(), bugDTOs.get(j).getDescription());
+                proximity[i][j] = txtDist;
+                if (checkBugImageNotNull(bugDTOs.get(i)) && checkBugImageNotNull(bugDTOs.get(j))) {
+                    double imgDist = calBugImgDist(bugDTOs.get(i), bugDTOs.get(j));
+                    if (imgDist <= 0.15) {
+                        proximity[i][j] = proximity[i][j] * 0.9;
+                    }
+                }
+
+            }
+        }
+        return proximity;
+    }
+
+    private static double calBugImgDist(BugDTO bug1, BugDTO bug2) {
+        float max_sim = 0;
+        for (int i = 0; i < bug1.getImgUrls().length; i++) {
+            for (int j = 0; j < bug2.getImgUrls().length; j++) {
+
+                File file1 = checkFileExist(IMAGE_PATH + bug1.getId() + "_" + i);
+                File file2 = checkFileExist(IMAGE_PATH + bug2.getId() + "_" + i);
+                if (file1 == null || file2 == null) {
+                    continue;
+                }
+                FingerPrint fp1 = ImageUtil.readImgFingerPrint(file1);
+                FingerPrint fp2 = ImageUtil.readImgFingerPrint(file2);
+                float sim = fp1.compare(fp2);
+                max_sim = sim > max_sim ? sim : max_sim;
+            }
+        }
+
+        return 1 - max_sim;
+    }
+
+    private static boolean checkBugImageNotNull(BugDTO bug) {
+        return ((bug.getImgUrls() != null) && bug.getImgUrls().length > 0);
+    }
+
+
+}

+ 57 - 57
src/main/java/com/mooctest/service/AggTaskStatusService.java

@@ -1,57 +1,57 @@
-package com.mooctest.service;
-
-import com.mooctest.dao.AggTaskStatusDao;
-import com.mooctest.model.AggTaskStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.sql.Timestamp;
-import java.util.Date;
-import java.util.List;
-
-@Service
-public class AggTaskStatusService {
-    private static Logger logger = LoggerFactory.getLogger(AggTaskStatusService.class);
-    @Autowired
-    AggTaskStatusDao aggTaskStatusDao;
-
-    public AggTaskStatus getByTaskId(long examId, long caseId) {
-        String aggTaskId = genTaskId(examId, caseId);
-        List<AggTaskStatus> aggTaskStatus = aggTaskStatusDao.findByTaskIdOrderByStartTimeDesc(aggTaskId);
-        if (aggTaskStatus!= null && aggTaskStatus.size() > 0) {
-            return aggTaskStatus.get(0);
-        } else {
-            return null;
-        }
-
-    }
-
-    public AggTaskStatus create(long examId, long caseId) {
-        String aggTaskId = genTaskId(examId, caseId);
-        AggTaskStatus status = AggTaskStatus.builder()
-                .taskId(aggTaskId)
-                .status(0)
-                .startTime(new Date())
-                .build();
-        return aggTaskStatusDao.save(status);
-
-    }
-
-    public AggTaskStatus updateStatus(String taskId, Date startTime) {
-        AggTaskStatus aggTaskStatus = aggTaskStatusDao.findByTaskIdAndStartTime(taskId, startTime);
-        if (aggTaskStatus != null) {
-            aggTaskStatus.setStatus(1);
-            aggTaskStatus.setEndTime(new Date());
-            return aggTaskStatusDao.save(aggTaskStatus);
-        } else {
-            logger.error("AggTaskStatusService find null, taskId={}, startTime={}", taskId, startTime.getTime());
-            return null;
-        }
-    }
-
-    private String genTaskId(long examId, long caseId) {
-        return examId + "-" + caseId;
-    }
-}
+package com.mooctest.service;
+
+import com.mooctest.dao.AggTaskStatusDao;
+import com.mooctest.model.AggTaskStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class AggTaskStatusService {
+    private static Logger logger = LoggerFactory.getLogger(AggTaskStatusService.class);
+    @Autowired
+    AggTaskStatusDao aggTaskStatusDao;
+
+    public AggTaskStatus getByTaskId(long examId, long caseId) {
+        String aggTaskId = genTaskId(examId, caseId);
+        List<AggTaskStatus> aggTaskStatus = aggTaskStatusDao.findByTaskIdOrderByStartTimeDesc(aggTaskId);
+        if (aggTaskStatus!= null && aggTaskStatus.size() > 0) {
+            return aggTaskStatus.get(0);
+        } else {
+            return null;
+        }
+
+    }
+
+    public AggTaskStatus create(long examId, long caseId) {
+        String aggTaskId = genTaskId(examId, caseId);
+        AggTaskStatus status = AggTaskStatus.builder()
+                .taskId(aggTaskId)
+                .status(0)
+                .startTime(new Date())
+                .build();
+        return aggTaskStatusDao.save(status);
+
+    }
+
+    public AggTaskStatus updateStatus(String taskId, Date startTime) {
+        AggTaskStatus aggTaskStatus = aggTaskStatusDao.findByTaskIdAndStartTime(taskId, startTime);
+        if (aggTaskStatus != null) {
+            aggTaskStatus.setStatus(1);
+            aggTaskStatus.setEndTime(new Date());
+            return aggTaskStatusDao.save(aggTaskStatus);
+        } else {
+            logger.error("AggTaskStatusService find null, taskId={}, startTime={}", taskId, startTime.getTime());
+            return null;
+        }
+    }
+
+    private String genTaskId(long examId, long caseId) {
+        return examId + "-" + caseId;
+    }
+}

+ 179 - 179
src/main/java/com/mooctest/service/AggregationService.java

@@ -1,179 +1,179 @@
-package com.mooctest.service;
-
-import com.mooctest.cluster.ClusterAnalyzer;
-import com.mooctest.cluster.Group;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffImg;
-import com.mooctest.data.DiffText;
-import com.mooctest.data.ReportDTO;
-import com.mooctest.image.ImageDownload;
-import com.mooctest.nlp.DistanceMatrix;
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.toMap;
-
-@Service
-public class AggregationService {
-    @Autowired
-    BugReportService bugReportService;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    @Autowired
-    DiffTextService diffTextService;
-
-    @Autowired
-    DiffImgService diffImgService;
-
-    @Autowired
-    SupplementService supplementService;
-
-    public void aggregate(long examId, long caseId) {
-        downImg(examId, caseId);
-        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);
-
-        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<>();
-        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
-        double[][] distMatrix = DistanceMatrix.genHybridDist(bugs);
-        List<Set<String>> clusters = analyzer.HAC(distMatrix, bugIds, 0.23);
-
-        Map<String, BugDTO> bugMap = bugs.stream().collect(toMap(BugDTO::getId, Function.identity()));
-        bugs = null;
-        Map<String, Set<String>> masterClusterMap = new HashMap<>();
-        masterReportService.deleteAll(examId, caseId);
-        for (Set<String> cluster : clusters) {
-            String masterReport = masterReportService.findMasterReport(cluster, bugMap);
-            masterReportService.saveMasterReport(masterReport, examId, caseId, cluster);
-            masterClusterMap.put(masterReport, cluster);
-        }
-        clusters = null;
-
-        showClusterResult(masterClusterMap, bugMap);
-
-        //gen diff text
-        Map<String, List<DiffText>> masterDiffTextMap = diffTextService.genMasterDiffTextMap(masterClusterMap, bugMap);
-
-        showTextDiffResult(masterDiffTextMap, bugMap);
-
-        //gen diff img
-        Map<String, List<DiffImg>> masterDiffImgMap = diffImgService.genMasterDiffImgMap(masterClusterMap, bugMap);
-
-        //cluster diff text
-        Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap = diffTextService.genDiffTextClusters(masterDiffTextMap);
-
-        //cluster diff img
-        Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap = diffImgService.genDiffImgClusters(masterDiffImgMap);
-
-        //combine cluster
-        combineCluster(masterDiffTextClustersMap, masterDiffImgClustersMap);
-
-        //top
-        supplementService.deleteAll(examId, caseId);
-        supplementService.rankAndStoreDiffText(masterDiffTextClustersMap);
-        supplementService.rankAndStoreDiffImg(masterDiffImgClustersMap);
-    }
-
-    private void combineCluster(Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap,
-                                Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap) {
-        double LINK_THRESHOLD = 0.2;
-        masterDiffTextClustersMap.forEach((masterId, diffTextClusters) -> {
-            List<Group<String, DiffImg>> diffImgClusters = masterDiffImgClustersMap.get(masterId);
-            if (diffImgClusters != null) {
-
-                for (int i = 0; i < diffTextClusters.size(); i++) {
-                    Set<String> textBugIds = diffTextClusters.get(i).getCluster().stream().map(DiffText::getBugId).collect(Collectors.toSet());
-                    for (int j = 0; j < diffImgClusters.size(); j++) {
-                        Set<String> imgBugIds = diffImgClusters.get(j).getCluster().stream().map(DiffImg::getBugId).collect(Collectors.toSet());
-                        int inter = CollectionUtils.intersection(textBugIds, imgBugIds).size();
-                        int union = CollectionUtils.union(textBugIds, imgBugIds).size();
-                        double dist = 1.0 - (1.0 * inter) / (1.0 * union);
-                        if (dist > LINK_THRESHOLD) {
-                            diffImgClusters.get(j).setId(diffTextClusters.get(i).getId());
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    private void downImg(long examId, long caseId) {
-
-        String taskId = examId + "_" + caseId;
-        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);
-
-        bugs.forEach(bug -> {
-            if (bug.getImgUrls() != null && bug.getImgUrls().length > 0) {
-                String[] imgUrls = bug.getImgUrls();
-                for (int i = 0; i < imgUrls.length; i++) {
-                    if (imgUrls[i] == null || !imgUrls[i].startsWith("http")) {
-                        continue;
-                    }
-
-                    String fileName = bug.getId() + "_" + i;
-                    System.out.println("正在下载 " + fileName);
-                    try {
-
-                        ImageDownload.createImage(imgUrls[i], taskId, fileName);
-                    } catch (Exception e) {
-                        System.out.println(imgUrls[i]);
-                        e.printStackTrace();
-                    }
-                }
-
-            }
-        });
-    }
-
-    private void showClusterResult(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
-        System.out.println("showMasterReportResult:");
-        masterClusterMap.entrySet().forEach(entry -> {
-            System.out.println("[");
-            System.out.println("master:");
-            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
-            System.out.println();
-
-            entry.getValue().forEach(bugId -> {
-                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
-            });
-            System.out.println("]");
-        });
-
-    }
-
-
-    private void showTextDiffResult(Map<String, List<DiffText>> masterDiffTextMap, Map<String, BugDTO> bugMap) {
-        System.out.println("showDiffResult:");
-        masterDiffTextMap.entrySet().forEach(entry -> {
-            System.out.println("[");
-            System.out.println("master:");
-            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
-            System.out.println();
-
-            entry.getValue().forEach(diffText -> {
-                System.out.println(diffText.getBugId() + "_" + diffText.getIndex() + diffText.getSentence());
-            });
-            System.out.println("]");
-        });
-
-    }
-    private void showClusterResult(List<Set<String>> results, Map<String, BugDTO> bugMap) {
-        System.out.println("size: " + results.size());
-        results.forEach(cluster -> {
-            System.out.println("[");
-            cluster.forEach(bugId -> {
-                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
-            });
-            System.out.println("]");
-        });
-    }
-}
+package com.mooctest.service;
+
+import com.mooctest.cluster.ClusterAnalyzer;
+import com.mooctest.cluster.Group;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffImg;
+import com.mooctest.data.DiffText;
+import com.mooctest.data.ReportDTO;
+import com.mooctest.image.ImageDownload;
+import com.mooctest.nlp.DistanceMatrix;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.toMap;
+
+@Service
+public class AggregationService {
+    @Autowired
+    BugReportService bugReportService;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    @Autowired
+    DiffTextService diffTextService;
+
+    @Autowired
+    DiffImgService diffImgService;
+
+    @Autowired
+    SupplementService supplementService;
+
+    public void aggregate(long examId, long caseId) {
+        downImg(examId, caseId);
+        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);
+
+        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<>();
+        List<String> bugIds = bugs.stream().map(BugDTO::getId).collect(Collectors.toList());
+        double[][] distMatrix = DistanceMatrix.genHybridDist(bugs);
+        List<Set<String>> clusters = analyzer.HAC(distMatrix, bugIds, 0.23);
+
+        Map<String, BugDTO> bugMap = bugs.stream().collect(toMap(BugDTO::getId, Function.identity()));
+        bugs = null;
+        Map<String, Set<String>> masterClusterMap = new HashMap<>();
+        masterReportService.deleteAll(examId, caseId);
+        for (Set<String> cluster : clusters) {
+            String masterReport = masterReportService.findMasterReport(cluster, bugMap);
+            masterReportService.saveMasterReport(masterReport, examId, caseId, cluster);
+            masterClusterMap.put(masterReport, cluster);
+        }
+        clusters = null;
+
+        showClusterResult(masterClusterMap, bugMap);
+
+        //gen diff text
+        Map<String, List<DiffText>> masterDiffTextMap = diffTextService.genMasterDiffTextMap(masterClusterMap, bugMap);
+
+        showTextDiffResult(masterDiffTextMap, bugMap);
+
+        //gen diff img
+        Map<String, List<DiffImg>> masterDiffImgMap = diffImgService.genMasterDiffImgMap(masterClusterMap, bugMap);
+
+        //cluster diff text
+        Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap = diffTextService.genDiffTextClusters(masterDiffTextMap);
+
+        //cluster diff img
+        Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap = diffImgService.genDiffImgClusters(masterDiffImgMap);
+
+        //combine cluster
+        combineCluster(masterDiffTextClustersMap, masterDiffImgClustersMap);
+
+        //top
+        supplementService.deleteAll(examId, caseId);
+        supplementService.rankAndStoreDiffText(masterDiffTextClustersMap);
+        supplementService.rankAndStoreDiffImg(masterDiffImgClustersMap);
+    }
+
+    private void combineCluster(Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap,
+                                Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap) {
+        double LINK_THRESHOLD = 0.2;
+        masterDiffTextClustersMap.forEach((masterId, diffTextClusters) -> {
+            List<Group<String, DiffImg>> diffImgClusters = masterDiffImgClustersMap.get(masterId);
+            if (diffImgClusters != null) {
+
+                for (int i = 0; i < diffTextClusters.size(); i++) {
+                    Set<String> textBugIds = diffTextClusters.get(i).getCluster().stream().map(DiffText::getBugId).collect(Collectors.toSet());
+                    for (int j = 0; j < diffImgClusters.size(); j++) {
+                        Set<String> imgBugIds = diffImgClusters.get(j).getCluster().stream().map(DiffImg::getBugId).collect(Collectors.toSet());
+                        int inter = CollectionUtils.intersection(textBugIds, imgBugIds).size();
+                        int union = CollectionUtils.union(textBugIds, imgBugIds).size();
+                        double dist = 1.0 - (1.0 * inter) / (1.0 * union);
+                        if (dist > LINK_THRESHOLD) {
+                            diffImgClusters.get(j).setId(diffTextClusters.get(i).getId());
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private void downImg(long examId, long caseId) {
+
+        String taskId = examId + "_" + caseId;
+        List<BugDTO> bugs = bugReportService.getAllBugs(examId, caseId);
+
+        bugs.forEach(bug -> {
+            if (bug.getImgUrls() != null && bug.getImgUrls().length > 0) {
+                String[] imgUrls = bug.getImgUrls();
+                for (int i = 0; i < imgUrls.length; i++) {
+                    if (imgUrls[i] == null || !imgUrls[i].startsWith("http")) {
+                        continue;
+                    }
+
+                    String fileName = bug.getId() + "_" + i;
+                    System.out.println("正在下载 " + fileName);
+                    try {
+
+                        ImageDownload.createImage(imgUrls[i], taskId, fileName);
+                    } catch (Exception e) {
+                        System.out.println(imgUrls[i]);
+                        e.printStackTrace();
+                    }
+                }
+
+            }
+        });
+    }
+
+    private void showClusterResult(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
+        System.out.println("showMasterReportResult:");
+        masterClusterMap.entrySet().forEach(entry -> {
+            System.out.println("[");
+            System.out.println("master:");
+            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
+            System.out.println();
+
+            entry.getValue().forEach(bugId -> {
+                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
+            });
+            System.out.println("]");
+        });
+
+    }
+
+
+    private void showTextDiffResult(Map<String, List<DiffText>> masterDiffTextMap, Map<String, BugDTO> bugMap) {
+        System.out.println("showDiffResult:");
+        masterDiffTextMap.entrySet().forEach(entry -> {
+            System.out.println("[");
+            System.out.println("master:");
+            System.out.println(entry.getKey() + " " + bugMap.get(entry.getKey()).getDescription());
+            System.out.println();
+
+            entry.getValue().forEach(diffText -> {
+                System.out.println(diffText.getBugId() + "_" + diffText.getIndex() + diffText.getSentence());
+            });
+            System.out.println("]");
+        });
+
+    }
+    private void showClusterResult(List<Set<String>> results, Map<String, BugDTO> bugMap) {
+        System.out.println("size: " + results.size());
+        results.forEach(cluster -> {
+            System.out.println("[");
+            cluster.forEach(bugId -> {
+                System.out.println(bugId + " " + bugMap.get(bugId).getDescription());
+            });
+            System.out.println("]");
+        });
+    }
+}

+ 326 - 0
src/main/java/com/mooctest/service/AnalyzeService.java

@@ -0,0 +1,326 @@
+package com.mooctest.service;
+
+import com.mooctest.dao.*;
+import com.mooctest.model.*;
+import com.mooctest.util.HTTP;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class AnalyzeService {
+	
+	@Autowired
+    CTBDao ctbdao;
+	
+	@Autowired
+    BugScoreDao bsdao;
+	
+	@Autowired
+    BugHistoryDao hdao;
+	
+	@Autowired
+    BugMirrorDao mdao;
+	
+	@Autowired
+    StuInfoDao studao;
+	
+	@Autowired
+    BugExtDao bdao;
+	
+	@Autowired
+    HistoryService hservice;
+	
+	//获取所有bug
+	public List<String> getValid(String case_take_id) {
+		List<String> result = new ArrayList<String>();
+		List<BugMirror> mirrors = mdao.findValid(case_take_id);
+		System.out.println("mirrors: "+ mirrors);
+		for(BugMirror ctb : mirrors) {
+			result.add(ctb.getId());
+		}
+		return result;
+	}
+	
+	//获取所有有测试用例的bug
+	public List<String> getValidTwo(String case_take_id) {
+		List<String> result = new ArrayList<String>();
+		List<CaseToBug> lists = ctbdao.findByCase(case_take_id);
+		for(CaseToBug ctb : lists) {
+			for(String str: ctb.getBug_id()) {
+				result.add(str);
+			}
+		}
+		return result;
+	}
+	
+	public List<String> getReports(String case_take_id) {
+		List<String> result = new ArrayList<String>();
+		List<CaseToBug> lists = ctbdao.findByCase(case_take_id);
+		for(CaseToBug ctb : lists) {
+			if(!result.contains(ctb.getReport_id())) {result.add(ctb.getReport_id());}
+		}
+		return result;
+	}
+	
+	public int getGrade(String id) {
+		BugScore bs = bsdao.findById(id);
+		if(bs != null) {return bs.getGrade();}
+		return -1;
+	}
+	
+	public boolean saveGrade(String id, int grade) {
+		try {
+			bsdao.save(new BugScore(id, grade, 0));
+			return true;
+		} catch(Exception e) {
+			return false;
+		}
+	}
+	
+	public int mark(String id, Map<String, Integer> grades, BugMirror mirror) {
+		int mark = 0;
+		int grade = grades.get(id);
+		BugHistory history = hdao.findByid(id);
+		
+		int parent = 0;
+		if(!history.getParent().equals("null")) {
+			parent = grades.getOrDefault(history.getParent(), 0);
+		}
+		int count = 0;
+		for(String child : history.getChildren()) {
+			if(grades.getOrDefault(child, 3) <= 2) {count ++;}
+		}
+		
+		switch(grade) {
+			case 1:
+				if(parent == 1) {mark += 40;}
+				else {mark += 100;}
+				mark += count * 2;
+				break;
+			case 2:
+				if(parent == 1) {break;}
+				else if(parent == 2) {mark += 40;}
+				else {mark += 80;}
+				mark += count * 2;
+				break;
+			case 3:
+				mark += count;
+				break;
+		}
+		
+		if(grade <= 2) {
+			mark += 2 * (mirror.getGood().size() - mirror.getBad().size());
+		}
+		
+		return mark;
+	}
+	
+	public JSONArray getScores(String case_take_id) throws JSONException {
+		Map<String, Integer> result = new HashMap<String, Integer>(); //用户得分
+		Map<String, Integer> grades = new HashMap<String, Integer>(); //专家评价分
+		Map<String, Integer> scores = new HashMap<String, Integer>(); //计算bug得分
+		JSONArray json = new JSONArray();
+		
+		List<String> bugs = getValid(case_take_id);
+		for(String bug: bugs) {
+			BugScore temp = bsdao.findById(bug);
+			if(temp != null) {grades.put(bug, temp.getGrade());}
+			else {grades.put(bug, 0);}
+		}
+//		for(String bug: bugs) {
+//			BugMirror mirror = mdao.findById(bug);
+//			int grade = grades.get(bug);
+//			if(grade == 0) {continue;}
+//			if(grade == 1) {ThumsUp(5, result, mirror);}
+//			else if(grade == 2) {ThumsUp(3, result, mirror);}
+//			else {ThumsUp(-3, result, mirror);}
+//			result.put(mirror.getReport_id(), result.getOrDefault(mirror.getReport_id(), 0) + mark(bug, grades, mirror));
+//		}
+		countScore(case_take_id, scores, grades);
+		for(String bug: bugs) {
+			BugMirror mirror = mdao.findById(bug);
+			if(mirror == null) { continue; }
+			int grade = grades.getOrDefault(bug, 0);
+			if(grade > 0) { ThumsUp(1, result, mirror); }
+			if(grade == 0) { ThumsUp(-1, result, mirror); }
+		}
+		for(Map.Entry<String, Integer> entry : result.entrySet()) {
+			if(entry.getValue() > 20) { result.put(entry.getKey(), 20); }
+			if(entry.getValue() < 0) { result.put(entry.getKey(), 0); }
+		}
+		Map<String, Integer> temp = new HashMap<String, Integer>();
+		for(String bug: bugs) {
+			BugMirror mirror = mdao.findById(bug);
+			if(mirror == null) { continue; }
+			temp.put(mirror.getReport_id(), scores.getOrDefault(bug, 0) + temp.getOrDefault(mirror.getReport_id(), 0));
+		}
+		for(Map.Entry<String, Integer> entry : temp.entrySet()) {
+			JSONObject json_temp = new JSONObject();
+			try {
+				json_temp.put("report_id", entry.getKey());
+				json_temp.put("worker_id", findWorkerId(entry.getKey()));
+				json_temp.put("名字", report_trans(entry.getKey()));
+				json_temp.put("报告得分", entry.getValue());
+				json_temp.put("审查得分", result.getOrDefault(entry.getKey(), 0));
+			}catch (JSONException e){
+				e.printStackTrace();
+			}
+			json.put(json_temp);
+		}
+		writeScores(case_take_id, json);
+		return json;
+	}
+
+	public JSONArray getNewScores(JSONArray array) throws JSONException {
+		if(array == null || array.length() <= 0) { return array; }
+		for(int i = 0; i < array.length(); i ++) {
+			JSONObject object = array.getJSONObject(i);
+			//guochao add
+//			if(object.keySet().size() < 5) { continue; }
+			System.out.println("getNewScores object = " + object);
+			if(object.length() < 5) { continue; }
+			object.put("name", object.get("名字"));
+			object.remove("名字");
+			int score = Integer.parseInt(object.get("报告得分").toString()) + Integer.parseInt(object.get("审查得分").toString());
+			if(score > 100) { object.put("score", 100); }
+			else { object.put("score", score); }
+			object.remove("报告得分");
+			object.remove("审查得分");
+		}
+		return array;
+	}
+
+	//计算点赞得分
+	private void ThumsUp(int grade, Map<String, Integer> result, BugMirror mirror) {
+		for(String report : mirror.getGood()) {
+			result.put(report, result.getOrDefault(report, 0) + grade);
+		}
+		for(String report : mirror.getBad()) {
+			result.put(report, result.getOrDefault(report, 0) - grade);
+		}
+	}
+	
+	public Map<String, String> getThums(String case_take_id) {
+		Map<String, String> result = new HashMap<String, String>();
+		List<String> bugs = getValid(case_take_id);
+		for(String bug: bugs) {
+			BugMirror mirror = mdao.findById(bug);
+			if(mirror.getGood().size() > 0 || mirror.getBad().size() > 0) {
+				result.put(bug, mirror.getGood().size() + "," + mirror.getBad().size());
+			}
+		}
+		return result;
+	}
+	
+	public Map<String, Integer> getBugDetail(String case_take_id) {
+		Map<String, Integer> page = new HashMap<String, Integer>();
+		List<String> bugs = getValid(case_take_id);
+		for(String id : bugs) {
+			Bug bug = bdao.findByid(id);
+			page.put(bug.getBugPage(), page.getOrDefault(bug.getBugPage(), 0) + 1);
+		}
+		return page;
+	}
+	
+	public JSONObject getCaseDetail(String case_take_id) throws JSONException {
+		JSONObject result = new JSONObject();
+		Map<String, Integer> kind = new HashMap<String, Integer>();
+		List<String> bugs = getValid(case_take_id);
+		for(String id : bugs) {
+			Bug bug = bdao.findByid(id);
+			kind.put(bug.getBugCategory(), kind.getOrDefault(bug.getBugCategory(), 0) + 1);
+		}
+		result.put("page", new JSONObject(getBugDetail(case_take_id)));
+		result.put("category", new JSONObject(kind));
+		return result;
+	}
+	
+	public Map<String, Integer> getAllGrades(String case_take_id) {
+		Map<String, Integer> result = new HashMap<String, Integer>();
+		List<BugMirror> mlist = mdao.findByCase(case_take_id);
+		List<String> idlist = new ArrayList<String>();
+		for(BugMirror mirror : mlist) {
+			idlist.add(mirror.getId());
+		}
+		List<BugScore> slist = bsdao.findByIds(idlist);
+		for(BugScore bugscore: slist) {
+			result.put(bugscore.getId(), bugscore.getGrade());
+		}
+		return result;
+	}
+	
+	public List<String> getDiff(String case_take_id) {
+		List<String> bugs = getValid(case_take_id);
+		bugs.add("split");
+		for(Map.Entry<String, Integer> entry: getAllGrades(case_take_id).entrySet()) {
+			if(bugs.contains(entry.getKey())) {bugs.remove(entry.getKey());}
+			else {bugs.add(entry.getKey());}
+		}
+		return bugs;
+	}
+	
+	//评价页面获取评分
+	public List<List<String>> getScores(List<String> ids) {
+		List<List<String>> result = new ArrayList<List<String>>();
+		List<BugScore> list = bsdao.findByIds(ids);
+		for(BugScore bs: list) {
+			List<String> temp = new ArrayList<String>();
+			temp.add(bs.getId());
+			temp.add(Integer.toString(bs.getGrade()));
+			result.add(temp);
+		}
+		return result;
+	}
+	
+	//根据树状结构计算分数
+	public void countScore(String case_take_id, Map<String, Integer> result, Map<String, Integer> grades) {
+		List<String> roots = hservice.getRoots(case_take_id);
+		for(String root : roots) {
+			List<List<String>> lists = hservice.getDepth(root);
+			for(List<String> path : lists) {
+				int max = 0;
+				for(String id : path) {
+					int grade = grades.getOrDefault(id, 0);
+					result.put(id, Math.max(grade - max, 0));
+					max = Math.max(max, grade);
+				}
+			}
+		}
+	}
+
+	private void writeScores(String case_take_id, JSONArray array) throws JSONException {
+		String host = "http://www.mooctest.net";
+		String url = "/api/common/uploadCaseScore";
+		String[] ids = case_take_id.split("-");
+		String param1 = "caseId=" + ids[0] + "&examId=" + ids[1];
+		for(int i = 0; i < array.length(); i ++) {
+			JSONObject json = (JSONObject)array.get(i);
+			String worker_id = json.get("worker_id").toString();
+			int score = Integer.parseInt(json.get("报告得分").toString()) + Integer.parseInt(json.get("审查得分").toString());
+			if(score <= 0 || worker_id.equals("")) { continue; }
+			if(score > 100) { score = 100; }
+			String param2 = "&userId=" + worker_id + "&score=" + score;
+			HTTP.sendPut(host, url, param1 + param2);
+		}
+	}
+
+	private String report_trans(String report_id) {
+		String name = studao.findById(report_id);
+		if(name == null || name.equals("null")) { return report_id;}
+		return name;
+	}
+
+	private String findWorkerId(String report_id) {
+		String workerId = studao.findWorkerId(report_id);
+		if(workerId == null || workerId.equals("null")) { return "";}
+		return workerId;
+	}
+}

+ 10 - 10
src/main/java/com/mooctest/service/BugHistoryService.java

@@ -1,10 +1,10 @@
-package com.mooctest.service;
-
-import com.mooctest.data.BugHistoryDTO;
-
-import java.util.List;
-
-public interface BugHistoryService {
-
-    List<BugHistoryDTO> getBugHistory(List<String> bugIds);
-}
+package com.mooctest.service;
+
+import com.mooctest.data.BugHistoryDTO;
+
+import java.util.List;
+
+public interface BugHistoryService {
+
+    List<BugHistoryDTO> getBugHistory(List<String> bugIds);
+}

+ 17 - 17
src/main/java/com/mooctest/service/BugReportService.java

@@ -1,17 +1,17 @@
-package com.mooctest.service;
-
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.ReportDTO;
-
-import java.util.List;
-import java.util.Map;
-
-public interface BugReportService {
-    List<ReportDTO> getReports(long examId, long caseId);
-    List<BugDTO> mergeAllBugs(List<ReportDTO> reportDTOs);
-    List<BugDTO> getAllBugs(long examId, long caseId);
-    Map<String, BugDTO> getAllBugsMap(long examId, long caseId);
-//    BugDTO getBugById(String bugId);
-    BugDTO getBugById(String bugId, long examId, long caseId);
-//    Map<String, List<BugDTO>> getMasterBugMap(Map<String, List<String>> masterBugIdsMap, Map<String, BugDTO> bugsMap);
-}
+package com.mooctest.service;
+
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.ReportDTO;
+
+import java.util.List;
+import java.util.Map;
+
+public interface BugReportService {
+    List<ReportDTO> getReports(long examId, long caseId);
+    List<BugDTO> mergeAllBugs(List<ReportDTO> reportDTOs);
+    List<BugDTO> getAllBugs(long examId, long caseId);
+    Map<String, BugDTO> getAllBugsMap(long examId, long caseId);
+//    BugDTO getBugById(String bugId);
+    BugDTO getBugById(String bugId, long examId, long caseId);
+//    Map<String, List<BugDTO>> getMasterBugMap(Map<String, List<String>> masterBugIdsMap, Map<String, BugDTO> bugsMap);
+}

+ 38 - 38
src/main/java/com/mooctest/service/BugReviewService.java

@@ -1,38 +1,38 @@
-package com.mooctest.service;
-
-import com.mooctest.dao.MasterReportDao;
-import com.mooctest.model.MasterReport;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-public class BugReviewService {
-
-    @Autowired
-    MasterReportDao masterReportDao;
-
-    public boolean isBugReviewed(String bugId) {
-        MasterReport mr = masterReportDao.findByBugId(bugId);
-        return (mr != null) && (mr.getStatus() == 1);
-    }
-    public void aggReportReview(String masterId) {
-        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
-        List<String> bugIds = mrs.stream().map(MasterReport::getBugId).collect(Collectors.toList());
-
-        updateBugReviewed(bugIds);
-    }
-
-    private void updateBugReviewed(List<String> bugIds) {
-        List<MasterReport> mrs = masterReportDao.findByBugIdIn(bugIds);
-        mrs.forEach(mr -> {
-            mr.setStatus(1);
-            mr.setReviewerId(1l);
-        });
-        masterReportDao.save(mrs);
-    }
-
-
-}
+package com.mooctest.service;
+
+import com.mooctest.dao.MasterReportDao;
+import com.mooctest.model.MasterReport;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class BugReviewService {
+
+    @Autowired
+    MasterReportDao masterReportDao;
+
+    public boolean isBugReviewed(String bugId) {
+        MasterReport mr = masterReportDao.findByBugId(bugId);
+        return (mr != null) && (mr.getStatus() == 1);
+    }
+    public void aggReportReview(String masterId) {
+        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
+        List<String> bugIds = mrs.stream().map(MasterReport::getBugId).collect(Collectors.toList());
+
+        updateBugReviewed(bugIds);
+    }
+
+    private void updateBugReviewed(List<String> bugIds) {
+        List<MasterReport> mrs = masterReportDao.findByBugIdIn(bugIds);
+        mrs.forEach(mr -> {
+            mr.setStatus(1);
+            mr.setReviewerId(1l);
+        });
+        masterReportDao.save(mrs);
+    }
+
+
+}

+ 124 - 124
src/main/java/com/mooctest/service/DiffImgService.java

@@ -1,124 +1,124 @@
-package com.mooctest.service;
-
-import com.mooctest.cluster.ClusterAnalyzer;
-import com.mooctest.cluster.Group;
-import com.mooctest.image.FingerPrint;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffImg;
-import com.mooctest.nlp.DistanceMatrix;
-import com.mooctest.util.IndexUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static com.mooctest.util.ImageUtil.*;
-import static java.util.stream.Collectors.toMap;
-
-@Service
-public class DiffImgService {
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    public Map<String, List<Group<String, DiffImg>>> genDiffImgClusters(Map<String, List<DiffImg>> masterDiffImgMap) {
-        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<>();
-        Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap = new HashMap<>();
-        masterDiffImgMap.forEach((masterId, diffImgs) -> {
-            if (diffImgs.size() > 2) {
-
-                double[][] distMatrix = DistanceMatrix.genImgDist(diffImgs);
-                List<String> imgIds = diffImgs.stream()
-                        .map(diffImg -> diffImg.getBugId() + "_" + diffImg.getIndex())
-                        .collect(Collectors.toList());
-
-                Map<String, DiffImg> diffImgMap = diffImgs.stream()
-                        .collect(toMap(diffImg -> diffImg.getBugId() + "_" + diffImg.getIndex(), Function.identity()));
-                try {
-                    List<Set<String>> imgClusters = analyzer.HAC(distMatrix, imgIds, 0.01);
-                    List<Group<String, DiffImg>> diffImgSets = new ArrayList<>(imgClusters.size());
-                    for (int i = 0; i < imgClusters.size(); i++) {
-                        Set<DiffImg> diffImgSet = imgClusters.get(i).stream()
-                                .map(imgId -> diffImgMap.get(imgId))
-                                .collect(Collectors.toSet());
-                        diffImgSets.add(new Group<>(IndexUtil.joinDiffImg(masterId, String.valueOf(i)), diffImgSet));
-
-                    }
-                    masterDiffImgClustersMap.put(masterId, diffImgSets);
-                } catch (IllegalArgumentException e) {
-
-                }
-
-            } else {
-                List<Group<String, DiffImg>> diffImgSets = new ArrayList<>();
-                diffImgSets.add(new Group<>(IndexUtil.joinDiffImg(masterId, String.valueOf(0)), new HashSet<>(diffImgs)));
-
-                masterDiffImgClustersMap.put(masterId, diffImgSets);
-            }
-        });
-        return masterDiffImgClustersMap;
-    }
-
-    public Map<String, List<DiffImg>> genMasterDiffImgMap(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
-        Map<String, List<DiffImg>> masterDiffImgMap = new HashMap<>();
-        masterClusterMap.forEach((masterId, cluster) -> {
-            List<DiffImg> diffImgs = genDiffImg(masterId, cluster, bugMap);
-            masterDiffImgMap.put(masterId, diffImgs);
-        });
-        return masterDiffImgMap;
-    }
-    public List<DiffImg> genDiffImg(
-            String masterId,
-            Set<String> cluster,
-            Map<String, BugDTO> bugMap) {
-
-        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
-        long examId = ids[0];
-        long caseId = ids[1];
-        String taskId = examId + "_" + caseId;
-
-        BugDTO masterReport = bugMap.get(masterId);
-        List<DiffImg> diffImgs = new LinkedList<>();
-        cluster.forEach(bugId -> { //遍历所有报告,找出每个聚类的差异图片
-            if (!bugId.equals(masterId)) {
-                BugDTO report = bugMap.get(bugId);
-                String[] imgUrls = report.getImgUrls();
-                for (int i = 0; i < imgUrls.length; i++) {
-                    File imgFile = checkFileExist(genImagePath(taskId, bugId, i));
-                    if (imgFile == null) {
-                        continue;
-                    }
-                    boolean isSim = isSimilarWithMasterReport(masterReport, imgFile, taskId);
-                    if (!isSim) {
-                        diffImgs.add(new DiffImg(masterId, bugId, imgUrls[i], i));
-                    }
-                }
-            }
-        });
-        return diffImgs;
-    }
-
-    private boolean isSimilarWithMasterReport(BugDTO masterReport, File imgFile, String taskId) {
-
-        String[] masterImgs = masterReport.getImgUrls();
-        FingerPrint reportImgFingerPrint = readImgFingerPrint(imgFile);
-        for (int i = 0; i < masterImgs.length; i++) {
-            String imgPath2 = genImagePath(taskId, masterReport.getId(), i);
-            File img = checkFileExist(imgPath2);
-            if (img == null) {
-                continue;
-            }
-            FingerPrint masterImgFingerPrint = readImgFingerPrint(img);
-            float sim = masterImgFingerPrint.compare(reportImgFingerPrint);
-            if (sim > 0.85) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-}
+package com.mooctest.service;
+
+import com.mooctest.cluster.ClusterAnalyzer;
+import com.mooctest.cluster.Group;
+import com.mooctest.image.FingerPrint;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffImg;
+import com.mooctest.nlp.DistanceMatrix;
+import com.mooctest.util.IndexUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static com.mooctest.util.ImageUtil.*;
+import static java.util.stream.Collectors.toMap;
+
+@Service
+public class DiffImgService {
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    public Map<String, List<Group<String, DiffImg>>> genDiffImgClusters(Map<String, List<DiffImg>> masterDiffImgMap) {
+        ClusterAnalyzer<String> analyzer = new ClusterAnalyzer<>();
+        Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap = new HashMap<>();
+        masterDiffImgMap.forEach((masterId, diffImgs) -> {
+            if (diffImgs.size() > 2) {
+
+                double[][] distMatrix = DistanceMatrix.genImgDist(diffImgs);
+                List<String> imgIds = diffImgs.stream()
+                        .map(diffImg -> diffImg.getBugId() + "_" + diffImg.getIndex())
+                        .collect(Collectors.toList());
+
+                Map<String, DiffImg> diffImgMap = diffImgs.stream()
+                        .collect(toMap(diffImg -> diffImg.getBugId() + "_" + diffImg.getIndex(), Function.identity()));
+                try {
+                    List<Set<String>> imgClusters = analyzer.HAC(distMatrix, imgIds, 0.01);
+                    List<Group<String, DiffImg>> diffImgSets = new ArrayList<>(imgClusters.size());
+                    for (int i = 0; i < imgClusters.size(); i++) {
+                        Set<DiffImg> diffImgSet = imgClusters.get(i).stream()
+                                .map(imgId -> diffImgMap.get(imgId))
+                                .collect(Collectors.toSet());
+                        diffImgSets.add(new Group<>(IndexUtil.joinDiffImg(masterId, String.valueOf(i)), diffImgSet));
+
+                    }
+                    masterDiffImgClustersMap.put(masterId, diffImgSets);
+                } catch (IllegalArgumentException e) {
+
+                }
+
+            } else {
+                List<Group<String, DiffImg>> diffImgSets = new ArrayList<>();
+                diffImgSets.add(new Group<>(IndexUtil.joinDiffImg(masterId, String.valueOf(0)), new HashSet<>(diffImgs)));
+
+                masterDiffImgClustersMap.put(masterId, diffImgSets);
+            }
+        });
+        return masterDiffImgClustersMap;
+    }
+
+    public Map<String, List<DiffImg>> genMasterDiffImgMap(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
+        Map<String, List<DiffImg>> masterDiffImgMap = new HashMap<>();
+        masterClusterMap.forEach((masterId, cluster) -> {
+            List<DiffImg> diffImgs = genDiffImg(masterId, cluster, bugMap);
+            masterDiffImgMap.put(masterId, diffImgs);
+        });
+        return masterDiffImgMap;
+    }
+    public List<DiffImg> genDiffImg(
+            String masterId,
+            Set<String> cluster,
+            Map<String, BugDTO> bugMap) {
+
+        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(masterId);
+        long examId = ids[0];
+        long caseId = ids[1];
+        String taskId = examId + "_" + caseId;
+
+        BugDTO masterReport = bugMap.get(masterId);
+        List<DiffImg> diffImgs = new LinkedList<>();
+        cluster.forEach(bugId -> { //遍历所有报告,找出每个聚类的差异图片
+            if (!bugId.equals(masterId)) {
+                BugDTO report = bugMap.get(bugId);
+                String[] imgUrls = report.getImgUrls();
+                for (int i = 0; i < imgUrls.length; i++) {
+                    File imgFile = checkFileExist(genImagePath(taskId, bugId, i));
+                    if (imgFile == null) {
+                        continue;
+                    }
+                    boolean isSim = isSimilarWithMasterReport(masterReport, imgFile, taskId);
+                    if (!isSim) {
+                        diffImgs.add(new DiffImg(masterId, bugId, imgUrls[i], i));
+                    }
+                }
+            }
+        });
+        return diffImgs;
+    }
+
+    private boolean isSimilarWithMasterReport(BugDTO masterReport, File imgFile, String taskId) {
+
+        String[] masterImgs = masterReport.getImgUrls();
+        FingerPrint reportImgFingerPrint = readImgFingerPrint(imgFile);
+        for (int i = 0; i < masterImgs.length; i++) {
+            String imgPath2 = genImagePath(taskId, masterReport.getId(), i);
+            File img = checkFileExist(imgPath2);
+            if (img == null) {
+                continue;
+            }
+            FingerPrint masterImgFingerPrint = readImgFingerPrint(img);
+            float sim = masterImgFingerPrint.compare(reportImgFingerPrint);
+            if (sim > 0.85) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}

+ 146 - 146
src/main/java/com/mooctest/service/DiffTextService.java

@@ -1,146 +1,146 @@
-package com.mooctest.service;
-
-import com.hankcs.hanlp.seg.Segment;
-import com.hankcs.hanlp.seg.common.Term;
-import com.hankcs.hanlp.utility.SentencesUtil;
-import com.mooctest.cluster.Group;
-import com.mooctest.cluster.MyClusterAnalyzer;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.DiffText;
-import com.mooctest.util.IndexUtil;
-import com.mooctest.util.NLPUtil;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import static com.mooctest.util.NLPUtil.SENTENCE_LENGTH_THRESH;
-import static com.mooctest.util.NLPUtil.TXT_SIMILAR_THRESHOLD_LOW;
-import static java.util.stream.Collectors.toMap;
-
-@Service
-public class DiffTextService {
-
-    public Map<String, List<Group<String, DiffText>>> genDiffTextClusters(Map<String, List<DiffText>> masterDiffTextMap) {
-        MyClusterAnalyzer<String> diffTextAnalyzer = new MyClusterAnalyzer<String>();
-        Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap = new HashMap<>();
-        masterDiffTextMap.forEach((masterId, diffTexts) -> {
-            if (diffTexts.size() > 1) {
-
-                //<bugId_sentenceIdx, diffText>
-                Map<String, DiffText> diffTextMap = diffTexts.stream()
-                        .collect(toMap(diffText -> diffText.getBugId() + "_" + diffText.getIndex(), Function.identity()));
-
-                diffTexts.forEach(diffText ->
-                        diffTextAnalyzer.addDocument(diffText.getBugId() + "_" + diffText.getIndex(), diffText.getSentence()));
-                List<Set<String>> diffTextClusters = diffTextAnalyzer.repeatedBisection(1.0);
-                List<Group<String, DiffText>> diffTextSets = new ArrayList<>(diffTextClusters.size());
-
-                for (int i = 0; i < diffTextClusters.size(); i++) {
-                    Set<DiffText> diffTextSet = diffTextClusters.get(i).stream()
-                            .map(sentenceId -> diffTextMap.get(sentenceId))
-                            .collect(Collectors.toSet());
-                    diffTextSets.add(new Group<>(IndexUtil.joinDiffText(masterId, String.valueOf(i)), diffTextSet));
-                }
-
-                masterDiffTextClustersMap.put(masterId, diffTextSets);
-                diffTextAnalyzer.clearDocs();
-            } else if (diffTexts.size() == 1) {
-                List<Group<String, DiffText>> diffTextSets = new ArrayList<>(1);
-                Set<DiffText> set = new HashSet<>();
-                set.add(diffTexts.get(0));
-                diffTextSets.add(new Group<>(IndexUtil.joinDiffText(masterId, "0"), set));
-                masterDiffTextClustersMap.put(masterId, diffTextSets);
-            }
-        });
-        return masterDiffTextClustersMap;
-    }
-    public Map<String, List<DiffText>> genMasterDiffTextMap(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
-
-        Map<String, List<DiffText>> masterDiffTextMap = new HashMap<>();
-        masterClusterMap.forEach((masterId, cluster) -> {
-
-            List<DiffText> diffTexts = genDiffText(masterId, cluster, bugMap);
-            masterDiffTextMap.put(masterId, diffTexts);
-        });
-        return masterDiffTextMap;
-    }
-
-
-    public List<DiffText> genDiffText(
-            String masterId,
-            Set<String> cluster,
-            Map<String, BugDTO> bugMap) {
-
-        BugDTO masterReport = bugMap.get(masterId);
-
-        Segment segment = NLPUtil.getDefaultSegment();
-        List<List<Term>> masterWords = segment.seg2sentence(masterReport.getDescription(), true);
-
-        List<DiffText> diffTexts = new LinkedList<>();
-
-        cluster.forEach(bugId -> {
-            if (!bugId.equals(masterId)) {
-
-                BugDTO report = bugMap.get(bugId);
-                List<String> reportSts = SentencesUtil.toSentenceList(report.getDescription());
-
-                int sentenceIdx = 0;// 句子在报告中的顺序
-                for (String sentence : reportSts) {
-                    boolean isSimilar = isSimilarWithMasterReport(masterWords, sentence);
-                    if (!isSimilar) {
-                        //存储,masterId bugId sentence
-                        diffTexts.add(new DiffText(masterId, bugId, sentence, sentenceIdx));
-                    }
-                    sentenceIdx++;
-                }
-            }
-        });
-
-        return diffTexts;
-    }
-
-    /**
-     * 传入的句子和master report 是否相似,只要与master的任意句子相似即可
-     *
-     * @param masterWords
-     * @param sentence
-     * @return
-     */
-    public boolean isSimilarWithMasterReport(List<List<Term>> masterWords, String sentence) {
-        Segment segment = NLPUtil.getDefaultSegment();
-        List<Term> stsWords = segment.seg(sentence);
-        if (stsWords.size() <= SENTENCE_LENGTH_THRESH) {
-            return true;
-        }
-        for (List<Term> masterStsWords : masterWords) {
-
-            if (isJaccardSimilar(masterStsWords, stsWords)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean isJaccardSimilar(List<Term> stsWords1, List<Term> stsWords2) {
-        int inter = 0;
-        int union = 0;
-        for (Term term1 : stsWords1) {
-            for (Term term2 : stsWords2) {
-                if (term1.word.equals(term2.word)) {//之后换成 word2vector 改进前后对比
-                    inter = inter + 1;
-                }
-            }
-        }
-        union = stsWords1.size() + stsWords2.size() - inter;
-
-        double similar = (inter * 1.0) / (union * 1.0);
-
-        if (similar >= TXT_SIMILAR_THRESHOLD_LOW) {
-            return true;
-        }
-        return false;
-
-    }
-}
+package com.mooctest.service;
+
+import com.hankcs.hanlp.seg.Segment;
+import com.hankcs.hanlp.seg.common.Term;
+import com.hankcs.hanlp.utility.SentencesUtil;
+import com.mooctest.cluster.Group;
+import com.mooctest.cluster.MyClusterAnalyzer;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.DiffText;
+import com.mooctest.util.IndexUtil;
+import com.mooctest.util.NLPUtil;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static com.mooctest.util.NLPUtil.SENTENCE_LENGTH_THRESH;
+import static com.mooctest.util.NLPUtil.TXT_SIMILAR_THRESHOLD_LOW;
+import static java.util.stream.Collectors.toMap;
+
+@Service
+public class DiffTextService {
+
+    public Map<String, List<Group<String, DiffText>>> genDiffTextClusters(Map<String, List<DiffText>> masterDiffTextMap) {
+        MyClusterAnalyzer<String> diffTextAnalyzer = new MyClusterAnalyzer<String>();
+        Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap = new HashMap<>();
+        masterDiffTextMap.forEach((masterId, diffTexts) -> {
+            if (diffTexts.size() > 1) {
+
+                //<bugId_sentenceIdx, diffText>
+                Map<String, DiffText> diffTextMap = diffTexts.stream()
+                        .collect(toMap(diffText -> diffText.getBugId() + "_" + diffText.getIndex(), Function.identity()));
+
+                diffTexts.forEach(diffText ->
+                        diffTextAnalyzer.addDocument(diffText.getBugId() + "_" + diffText.getIndex(), diffText.getSentence()));
+                List<Set<String>> diffTextClusters = diffTextAnalyzer.repeatedBisection(1.0);
+                List<Group<String, DiffText>> diffTextSets = new ArrayList<>(diffTextClusters.size());
+
+                for (int i = 0; i < diffTextClusters.size(); i++) {
+                    Set<DiffText> diffTextSet = diffTextClusters.get(i).stream()
+                            .map(sentenceId -> diffTextMap.get(sentenceId))
+                            .collect(Collectors.toSet());
+                    diffTextSets.add(new Group<>(IndexUtil.joinDiffText(masterId, String.valueOf(i)), diffTextSet));
+                }
+
+                masterDiffTextClustersMap.put(masterId, diffTextSets);
+                diffTextAnalyzer.clearDocs();
+            } else if (diffTexts.size() == 1) {
+                List<Group<String, DiffText>> diffTextSets = new ArrayList<>(1);
+                Set<DiffText> set = new HashSet<>();
+                set.add(diffTexts.get(0));
+                diffTextSets.add(new Group<>(IndexUtil.joinDiffText(masterId, "0"), set));
+                masterDiffTextClustersMap.put(masterId, diffTextSets);
+            }
+        });
+        return masterDiffTextClustersMap;
+    }
+    public Map<String, List<DiffText>> genMasterDiffTextMap(Map<String, Set<String>> masterClusterMap, Map<String, BugDTO> bugMap) {
+
+        Map<String, List<DiffText>> masterDiffTextMap = new HashMap<>();
+        masterClusterMap.forEach((masterId, cluster) -> {
+
+            List<DiffText> diffTexts = genDiffText(masterId, cluster, bugMap);
+            masterDiffTextMap.put(masterId, diffTexts);
+        });
+        return masterDiffTextMap;
+    }
+
+
+    public List<DiffText> genDiffText(
+            String masterId,
+            Set<String> cluster,
+            Map<String, BugDTO> bugMap) {
+
+        BugDTO masterReport = bugMap.get(masterId);
+
+        Segment segment = NLPUtil.getDefaultSegment();
+        List<List<Term>> masterWords = segment.seg2sentence(masterReport.getDescription(), true);
+
+        List<DiffText> diffTexts = new LinkedList<>();
+
+        cluster.forEach(bugId -> {
+            if (!bugId.equals(masterId)) {
+
+                BugDTO report = bugMap.get(bugId);
+                List<String> reportSts = SentencesUtil.toSentenceList(report.getDescription());
+
+                int sentenceIdx = 0;// 句子在报告中的顺序
+                for (String sentence : reportSts) {
+                    boolean isSimilar = isSimilarWithMasterReport(masterWords, sentence);
+                    if (!isSimilar) {
+                        //存储,masterId bugId sentence
+                        diffTexts.add(new DiffText(masterId, bugId, sentence, sentenceIdx));
+                    }
+                    sentenceIdx++;
+                }
+            }
+        });
+
+        return diffTexts;
+    }
+
+    /**
+     * 传入的句子和master report 是否相似,只要与master的任意句子相似即可
+     *
+     * @param masterWords
+     * @param sentence
+     * @return
+     */
+    public boolean isSimilarWithMasterReport(List<List<Term>> masterWords, String sentence) {
+        Segment segment = NLPUtil.getDefaultSegment();
+        List<Term> stsWords = segment.seg(sentence);
+        if (stsWords.size() <= SENTENCE_LENGTH_THRESH) {
+            return true;
+        }
+        for (List<Term> masterStsWords : masterWords) {
+
+            if (isJaccardSimilar(masterStsWords, stsWords)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isJaccardSimilar(List<Term> stsWords1, List<Term> stsWords2) {
+        int inter = 0;
+        int union = 0;
+        for (Term term1 : stsWords1) {
+            for (Term term2 : stsWords2) {
+                if (term1.word.equals(term2.word)) {//之后换成 word2vector 改进前后对比
+                    inter = inter + 1;
+                }
+            }
+        }
+        union = stsWords1.size() + stsWords2.size() - inter;
+
+        double similar = (inter * 1.0) / (union * 1.0);
+
+        if (similar >= TXT_SIMILAR_THRESHOLD_LOW) {
+            return true;
+        }
+        return false;
+
+    }
+}

+ 152 - 152
src/main/java/com/mooctest/service/FinalReportService.java

@@ -1,152 +1,152 @@
-package com.mooctest.service;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.mooctest.dao.FinalReportDao;
-import com.mooctest.data.BugDTO;
-import com.mooctest.data.FinalReportDTO;
-import com.mooctest.data.TaskDTO;
-import com.mooctest.model.Bug;
-import com.mooctest.model.FinalReport;
-import com.mooctest.util.HttpUtil;
-import com.mooctest.util.ReportUtil;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-@Service
-public class FinalReportService {
-
-    @Autowired
-    FinalReportDao finalReportDao;
-
-    @Value("${report.export.addr}")
-    String reportExportAddr;
-
-    public FinalReportDTO save(FinalReportDTO dto) {
-
-        FinalReport finalReport = new FinalReport();
-        BeanUtils.copyProperties(dto, finalReport);
-        finalReport.setImgUrls(String.join(",", dto.getImgUrls()));
-        finalReport.setCreateTime(new Date());
-        finalReport = finalReportDao.save(finalReport);
-        BeanUtils.copyProperties(finalReport, dto);
-        return dto;
-    }
-
-    public FinalReportDTO update(long reportId, FinalReportDTO dto) {
-        FinalReport report = finalReportDao.findOne(reportId);
-        dto.setCreateTime(report.getCreateTime());
-        BeanUtils.copyProperties(dto, report);
-        report.setImgUrls(String.join(",", dto.getImgUrls()));
-        finalReportDao.save(report);
-
-        return dto;
-    }
-
-    public List<FinalReportDTO> getByExamIdAndCaseId(long examId, long caseId) {
-        List<FinalReport> frs = finalReportDao.findByExamIdAndCaseId(examId, caseId);
-        return wrap(frs);
-    }
-
-    public List<FinalReportDTO> getBySourceId(String sourceId) {
-        List<FinalReport> frs = finalReportDao.findBySourceId(sourceId);
-        return wrap(frs);
-    }
-
-    private List<FinalReportDTO> wrap(List<FinalReport> frs) {
-        return frs.stream().map(finalReport -> {
-            FinalReportDTO dto = new FinalReportDTO();
-            BeanUtils.copyProperties(finalReport, dto);
-            dto.setImgUrls(finalReport.getImgUrls().split(","));
-            return dto;
-        }).collect(Collectors.toList());
-    }
-
-    public void delete(long reportId) {
-        finalReportDao.delete(reportId);
-    }
-
-    public String getExportReportAddr(TaskDTO task) {
-        List<FinalReport> finalReports = finalReportDao.findByExamIdAndCaseId(task.getExamId(), task.getCaseId());
-
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
-
-        JSONObject reportJson = genJsonForExport(task, finalReports);
-        HttpEntity<String> request = new HttpEntity<>(reportJson.toJSONString(), headers);
-        RestTemplate rt = HttpUtil.getRestTemplate();
-
-        String url = rt.postForObject(reportExportAddr, request, String.class);
-        return url;
-    }
-
-    private JSONObject genJsonForExport(TaskDTO task, List<FinalReport> finalReports) {
-        JSONObject root = new JSONObject();
-        JSONArray projects = new JSONArray();
-        JSONObject project = new JSONObject();
-
-        project.put("projectId", task.getExamId() + "-" +task.getCaseId());
-        project.put("icon", task.getIcon());
-        project.put("name", task.getName());
-        project.put("version", task.getVersion());
-        project.put("startTime", task.getStartTime());
-        project.put("endTime", task.getEndTime());
-        project.put("reports", finalReports);
-        projects.add(project);
-        root.put("projects", projects);
-        root.put("menus", new JSONArray().fluentAdd("众包测试报告"));
-
-        JSONObject projectStatistics = new JSONObject();
-        projectStatistics.put("categorys", genAttrArray(ReportUtil.category2String));
-        projectStatistics.put("severity", genAttrArray(ReportUtil.severity2String));
-        projectStatistics.put("recurrent", genAttrArray(ReportUtil.recurrent2String));
-        root.put("projectStatistics", projectStatistics);
-        return root;
-    }
-
-    private JSONArray genAttrArray(Map map) {
-        JSONArray arr = new JSONArray();
-        map.forEach((k, v) -> {
-            JSONObject obj = new JSONObject();
-            obj.put("name", v);
-            obj.put("value", k);
-            arr.add(obj);
-        });
-        return arr;
-    }
-
-    public void transAllBug2FinalReport(List<BugDTO> bugs, long examId, long caseId) {
-        List<FinalReport> finalReports = bugs.parallelStream().map(bug -> {
-            FinalReport finalReport = new FinalReport();
-            finalReport.setDescription(bug.getDescription());
-            finalReport.setImgUrls(String.join(",", bug.getImgUrls()));
-            finalReport.setSeverity(bug.getSeverity());
-            finalReport.setRecurrent(bug.getRecurrent());
-            Integer category = ReportUtil.string2Category.get(bug.getBugCategory());
-            if (category == null) {
-                category = 7;
-            }
-            finalReport.setCategory(category);
-            finalReport.setCreateTime(new Date());
-            finalReport.setWriterId(1);
-            finalReport.setExamId(examId);
-            finalReport.setCaseId(caseId);
-            return finalReport;
-        }).collect(Collectors.toList());
-
-        finalReportDao.save(finalReports);
-    }
-
-
-}
+package com.mooctest.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.mooctest.dao.FinalReportDao;
+import com.mooctest.data.BugDTO;
+import com.mooctest.data.FinalReportDTO;
+import com.mooctest.data.TaskDTO;
+import com.mooctest.model.Bug;
+import com.mooctest.model.FinalReport;
+import com.mooctest.util.HttpUtil;
+import com.mooctest.util.ReportUtil;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class FinalReportService {
+
+    @Autowired
+    FinalReportDao finalReportDao;
+
+    @Value("${report.export.addr}")
+    String reportExportAddr;
+
+    public FinalReportDTO save(FinalReportDTO dto) {
+
+        FinalReport finalReport = new FinalReport();
+        BeanUtils.copyProperties(dto, finalReport);
+        finalReport.setImgUrls(String.join(",", dto.getImgUrls()));
+        finalReport.setCreateTime(new Date());
+        finalReport = finalReportDao.save(finalReport);
+        BeanUtils.copyProperties(finalReport, dto);
+        return dto;
+    }
+
+    public FinalReportDTO update(long reportId, FinalReportDTO dto) {
+        FinalReport report = finalReportDao.findOne(reportId);
+        dto.setCreateTime(report.getCreateTime());
+        BeanUtils.copyProperties(dto, report);
+        report.setImgUrls(String.join(",", dto.getImgUrls()));
+        finalReportDao.save(report);
+
+        return dto;
+    }
+
+    public List<FinalReportDTO> getByExamIdAndCaseId(long examId, long caseId) {
+        List<FinalReport> frs = finalReportDao.findByExamIdAndCaseId(examId, caseId);
+        return wrap(frs);
+    }
+
+    public List<FinalReportDTO> getBySourceId(String sourceId) {
+        List<FinalReport> frs = finalReportDao.findBySourceId(sourceId);
+        return wrap(frs);
+    }
+
+    private List<FinalReportDTO> wrap(List<FinalReport> frs) {
+        return frs.stream().map(finalReport -> {
+            FinalReportDTO dto = new FinalReportDTO();
+            BeanUtils.copyProperties(finalReport, dto);
+            dto.setImgUrls(finalReport.getImgUrls().split(","));
+            return dto;
+        }).collect(Collectors.toList());
+    }
+
+    public void delete(long reportId) {
+        finalReportDao.delete(reportId);
+    }
+
+    public String getExportReportAddr(TaskDTO task) {
+        List<FinalReport> finalReports = finalReportDao.findByExamIdAndCaseId(task.getExamId(), task.getCaseId());
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
+
+        JSONObject reportJson = genJsonForExport(task, finalReports);
+        HttpEntity<String> request = new HttpEntity<>(reportJson.toJSONString(), headers);
+        RestTemplate rt = HttpUtil.getRestTemplate();
+
+        String url = rt.postForObject(reportExportAddr, request, String.class);
+        return url;
+    }
+
+    private JSONObject genJsonForExport(TaskDTO task, List<FinalReport> finalReports) {
+        JSONObject root = new JSONObject();
+        JSONArray projects = new JSONArray();
+        JSONObject project = new JSONObject();
+
+        project.put("projectId", task.getExamId() + "-" +task.getCaseId());
+        project.put("icon", task.getIcon());
+        project.put("name", task.getName());
+        project.put("version", task.getVersion());
+        project.put("startTime", task.getStartTime());
+        project.put("endTime", task.getEndTime());
+        project.put("reports", finalReports);
+        projects.add(project);
+        root.put("projects", projects);
+        root.put("menus", new JSONArray().fluentAdd("众包测试报告"));
+
+        JSONObject projectStatistics = new JSONObject();
+        projectStatistics.put("categorys", genAttrArray(ReportUtil.category2String));
+        projectStatistics.put("severity", genAttrArray(ReportUtil.severity2String));
+        projectStatistics.put("recurrent", genAttrArray(ReportUtil.recurrent2String));
+        root.put("projectStatistics", projectStatistics);
+        return root;
+    }
+
+    private JSONArray genAttrArray(Map map) {
+        JSONArray arr = new JSONArray();
+        map.forEach((k, v) -> {
+            JSONObject obj = new JSONObject();
+            obj.put("name", v);
+            obj.put("value", k);
+            arr.add(obj);
+        });
+        return arr;
+    }
+
+    public void transAllBug2FinalReport(List<BugDTO> bugs, long examId, long caseId) {
+        List<FinalReport> finalReports = bugs.parallelStream().map(bug -> {
+            FinalReport finalReport = new FinalReport();
+            finalReport.setDescription(bug.getDescription());
+            finalReport.setImgUrls(String.join(",", bug.getImgUrls()));
+            finalReport.setSeverity(bug.getSeverity());
+            finalReport.setRecurrent(bug.getRecurrent());
+            Integer category = ReportUtil.string2Category.get(bug.getBugCategory());
+            if (category == null) {
+                category = 7;
+            }
+            finalReport.setCategory(category);
+            finalReport.setCreateTime(new Date());
+            finalReport.setWriterId(1);
+            finalReport.setExamId(examId);
+            finalReport.setCaseId(caseId);
+            return finalReport;
+        }).collect(Collectors.toList());
+
+        finalReportDao.save(finalReports);
+    }
+
+
+}

+ 167 - 167
src/main/java/com/mooctest/service/GraphService.java

@@ -1,167 +1,167 @@
-package com.mooctest.service;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.mooctest.dao.SupplementDao;
-import com.mooctest.model.SupplementItem;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.groupingBy;
-
-@Service
-public class GraphService {
-
-    @Autowired
-    SupplementDao supplementDao;
-
-    public JSONObject buildAggReportTree(String masterId) {
-        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
-        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()
-                .collect(groupingBy(SupplementItem::getSupplementId));
-
-        JSONObject root = new JSONObject();
-        root.fluentPut("id", "agg_" + masterId)
-                .fluentPut("group", 1)
-                .fluentPut("name", "聚合报告")
-                .fluentPut("href", "/graphDetail/aggReport?masterId=" + masterId);
-        int idx = 1;
-
-        JSONArray supNodes = new JSONArray();
-        //add sup correspond with raw node
-        for (Map.Entry<String, List<SupplementItem>> entry : supplementMap.entrySet()) {
-            String supId = entry.getKey();
-            List<SupplementItem> items = entry.getValue();
-            JSONObject supNode = new JSONObject();
-
-            //add sup report node
-            supNode.fluentPut("id", supId)
-                    .fluentPut("group", 2)
-                    .fluentPut("name", "补充点" + idx)
-                    .fluentPut("href", "/graphDetail/supReport?supId=" + supId + "&masterId=" + masterId);
-            supNodes.add(supNode);
-
-            //add raw report node
-            List<String> bugIds = items.stream()
-                    .map(SupplementItem::getBugId)
-                    .distinct()
-                    .collect(Collectors.toList());
-
-            JSONArray rawNodes = new JSONArray();
-            for (int i = 0; i < bugIds.size(); i++) {
-                String bugId = bugIds.get(i);
-                JSONObject rawNode = new JSONObject();
-                rawNode.fluentPut("id", bugId)
-                        .fluentPut("group", 3)
-                        .fluentPut("name", "R" + bugId.substring(12))
-                        .fluentPut("href", "/graphDetail/rawReport?bugId=" + bugId + "&masterId=" + masterId);
-                rawNodes.add(rawNode);
-            }
-            supNode.put("children", rawNodes);
-            idx++;
-        }
-        root.put("children", supNodes);
-        return root;
-    }
-
-    public JSONObject buildAggReportGraph(String masterId) {
-        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
-        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()
-                .collect(groupingBy(SupplementItem::getSupplementId));
-
-        JSONObject graphNodes = new JSONObject();
-        JSONArray nodes = buildNodes(masterId, supplementMap);
-        graphNodes.put("nodes", nodes);
-
-        JSONArray links = buildLinks(masterId, supplementMap);
-        graphNodes.put("links", links);
-
-        return graphNodes;
-    }
-
-    private JSONArray buildLinks(String masterId, Map<String, List<SupplementItem>> supplementMap) {
-        JSONArray links = new JSONArray();
-        String aggReportId = "agg_" + masterId;
-        supplementMap.forEach((supId, items) -> {
-
-            JSONObject supAggLink = new JSONObject();
-            supAggLink.fluentPut("source", supId)
-                    .fluentPut("target", aggReportId)
-                    .fluentPut("value", 3);
-            links.add(supAggLink);
-
-            items.forEach(item -> {
-                JSONObject bugSupLink = new JSONObject();
-                bugSupLink.fluentPut("source", item.getBugId())
-                        .fluentPut("target", supId)
-                        .fluentPut("value", 1);
-                links.add(bugSupLink);
-            });
-        });
-
-        JSONObject masterAggLink = new JSONObject();
-        masterAggLink.fluentPut("source", masterId)
-                .fluentPut("target", aggReportId)
-                .fluentPut("value", 2);
-        links.add(masterAggLink);
-        return links;
-    }
-
-    private JSONArray buildNodes(String masterId, Map<String, List<SupplementItem>> supplementMap) {
-
-        JSONArray nodes = new JSONArray();
-        int idx = 0;
-
-        //add sup correspond with raw node
-        for (Map.Entry<String, List<SupplementItem>> entry : supplementMap.entrySet()) {
-            String supId = entry.getKey();
-            List<SupplementItem> items = entry.getValue();
-            JSONObject node = new JSONObject();
-
-            //add sup report node
-            node.fluentPut("id", supId)
-                    .fluentPut("group", 2)
-                    .fluentPut("name", "Sup-" + idx)
-                    .fluentPut("href", "/graphDetail/supReport?supId=" + supId + "&masterId=" + masterId);
-            nodes.add(node);
-
-            //add raw report node
-            List<String> bugIds = items.stream()
-                    .map(SupplementItem::getBugId)
-                    .distinct()
-                    .collect(Collectors.toList());
-
-            for (int i = 0; i < bugIds.size(); i++) {
-                String bugId = bugIds.get(i);
-                JSONObject rawNode = new JSONObject();
-                rawNode.fluentPut("id", bugId)
-                        .fluentPut("group", 6)
-                        .fluentPut("name", "ML-" + bugId.substring(10))
-                        .fluentPut("href", "/graphDetail/rawReport?bugId=" + bugId + "&masterId=" + masterId);
-                nodes.add(rawNode);
-            }
-            idx++;
-        }
-        JSONObject aggReportNode = new JSONObject();
-        aggReportNode.fluentPut("id", "agg_" + masterId)
-                .fluentPut("group", 1)
-                .fluentPut("name", "ML-AG-" + masterId.substring(10))
-                .fluentPut("href", "/graphDetail/aggReport?masterId=" + masterId);
-        nodes.add(aggReportNode);
-
-        JSONObject masterNode = new JSONObject();
-        masterNode.fluentPut("id", masterId)
-                .fluentPut("group", 2.1)
-                .fluentPut("name", "Master-ML-" + masterId.substring(10))
-                .fluentPut("href", "/graphDetail/rawReport?bugId=" + masterId + "&isMaster=true" + "&masterId=" + masterId);
-        nodes.add(masterNode);
-
-        return nodes;
-    }
-
-}
+package com.mooctest.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.mooctest.dao.SupplementDao;
+import com.mooctest.model.SupplementItem;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.groupingBy;
+
+@Service
+public class GraphService {
+
+    @Autowired
+    SupplementDao supplementDao;
+
+    public JSONObject buildAggReportTree(String masterId) {
+        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
+        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()
+                .collect(groupingBy(SupplementItem::getSupplementId));
+
+        JSONObject root = new JSONObject();
+        root.fluentPut("id", "agg_" + masterId)
+                .fluentPut("group", 1)
+                .fluentPut("name", "聚合报告")
+                .fluentPut("href", "/graphDetail/aggReport?masterId=" + masterId);
+        int idx = 1;
+
+        JSONArray supNodes = new JSONArray();
+        //add sup correspond with raw node
+        for (Map.Entry<String, List<SupplementItem>> entry : supplementMap.entrySet()) {
+            String supId = entry.getKey();
+            List<SupplementItem> items = entry.getValue();
+            JSONObject supNode = new JSONObject();
+
+            //add sup report node
+            supNode.fluentPut("id", supId)
+                    .fluentPut("group", 2)
+                    .fluentPut("name", "补充点" + idx)
+                    .fluentPut("href", "/graphDetail/supReport?supId=" + supId + "&masterId=" + masterId);
+            supNodes.add(supNode);
+
+            //add raw report node
+            List<String> bugIds = items.stream()
+                    .map(SupplementItem::getBugId)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            JSONArray rawNodes = new JSONArray();
+            for (int i = 0; i < bugIds.size(); i++) {
+                String bugId = bugIds.get(i);
+                JSONObject rawNode = new JSONObject();
+                rawNode.fluentPut("id", bugId)
+                        .fluentPut("group", 3)
+                        .fluentPut("name", "R" + bugId.substring(12))
+                        .fluentPut("href", "/graphDetail/rawReport?bugId=" + bugId + "&masterId=" + masterId);
+                rawNodes.add(rawNode);
+            }
+            supNode.put("children", rawNodes);
+            idx++;
+        }
+        root.put("children", supNodes);
+        return root;
+    }
+
+    public JSONObject buildAggReportGraph(String masterId) {
+        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
+        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream()
+                .collect(groupingBy(SupplementItem::getSupplementId));
+
+        JSONObject graphNodes = new JSONObject();
+        JSONArray nodes = buildNodes(masterId, supplementMap);
+        graphNodes.put("nodes", nodes);
+
+        JSONArray links = buildLinks(masterId, supplementMap);
+        graphNodes.put("links", links);
+
+        return graphNodes;
+    }
+
+    private JSONArray buildLinks(String masterId, Map<String, List<SupplementItem>> supplementMap) {
+        JSONArray links = new JSONArray();
+        String aggReportId = "agg_" + masterId;
+        supplementMap.forEach((supId, items) -> {
+
+            JSONObject supAggLink = new JSONObject();
+            supAggLink.fluentPut("source", supId)
+                    .fluentPut("target", aggReportId)
+                    .fluentPut("value", 3);
+            links.add(supAggLink);
+
+            items.forEach(item -> {
+                JSONObject bugSupLink = new JSONObject();
+                bugSupLink.fluentPut("source", item.getBugId())
+                        .fluentPut("target", supId)
+                        .fluentPut("value", 1);
+                links.add(bugSupLink);
+            });
+        });
+
+        JSONObject masterAggLink = new JSONObject();
+        masterAggLink.fluentPut("source", masterId)
+                .fluentPut("target", aggReportId)
+                .fluentPut("value", 2);
+        links.add(masterAggLink);
+        return links;
+    }
+
+    private JSONArray buildNodes(String masterId, Map<String, List<SupplementItem>> supplementMap) {
+
+        JSONArray nodes = new JSONArray();
+        int idx = 0;
+
+        //add sup correspond with raw node
+        for (Map.Entry<String, List<SupplementItem>> entry : supplementMap.entrySet()) {
+            String supId = entry.getKey();
+            List<SupplementItem> items = entry.getValue();
+            JSONObject node = new JSONObject();
+
+            //add sup report node
+            node.fluentPut("id", supId)
+                    .fluentPut("group", 2)
+                    .fluentPut("name", "Sup-" + idx)
+                    .fluentPut("href", "/graphDetail/supReport?supId=" + supId + "&masterId=" + masterId);
+            nodes.add(node);
+
+            //add raw report node
+            List<String> bugIds = items.stream()
+                    .map(SupplementItem::getBugId)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            for (int i = 0; i < bugIds.size(); i++) {
+                String bugId = bugIds.get(i);
+                JSONObject rawNode = new JSONObject();
+                rawNode.fluentPut("id", bugId)
+                        .fluentPut("group", 6)
+                        .fluentPut("name", "ML-" + bugId.substring(10))
+                        .fluentPut("href", "/graphDetail/rawReport?bugId=" + bugId + "&masterId=" + masterId);
+                nodes.add(rawNode);
+            }
+            idx++;
+        }
+        JSONObject aggReportNode = new JSONObject();
+        aggReportNode.fluentPut("id", "agg_" + masterId)
+                .fluentPut("group", 1)
+                .fluentPut("name", "ML-AG-" + masterId.substring(10))
+                .fluentPut("href", "/graphDetail/aggReport?masterId=" + masterId);
+        nodes.add(aggReportNode);
+
+        JSONObject masterNode = new JSONObject();
+        masterNode.fluentPut("id", masterId)
+                .fluentPut("group", 2.1)
+                .fluentPut("name", "Master-ML-" + masterId.substring(10))
+                .fluentPut("href", "/graphDetail/rawReport?bugId=" + masterId + "&isMaster=true" + "&masterId=" + masterId);
+        nodes.add(masterNode);
+
+        return nodes;
+    }
+
+}

+ 189 - 0
src/main/java/com/mooctest/service/HistoryService.java

@@ -0,0 +1,189 @@
+package com.mooctest.service;
+
+import com.mooctest.dao.BugHistoryDao;
+import com.mooctest.dao.BugMirrorDao;
+import com.mooctest.dao.BugPageDao;
+import com.mooctest.model.BugHistory;
+import com.mooctest.model.BugMirror;
+import com.mooctest.model.BugPage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Service
+public class HistoryService {
+	
+	@Autowired
+    BugHistoryDao historydao;
+	
+	@Autowired
+    BugMirrorDao mirrordao;
+	
+	@Autowired
+    BugPageDao pagedao;
+	
+	@Autowired
+	RecommendService recservice;
+	
+	@Autowired
+	AnalyzeService aservice;
+	
+	public BugHistory getHistory(String id) {
+		return historydao.findByid(id);
+	}
+	
+	public List<String> parents(String id) {
+		Stack<String> stack = new Stack<String>();
+		List<String> result = new ArrayList<String>();
+		String parent = getHistory(id).getParent();
+		while(!parent.equals("null")) {
+			stack.push(parent);
+			parent = getHistory(parent).getParent();
+		}
+		while(!stack.isEmpty()) {
+			result.add(stack.pop());
+		}
+		result.add(id);
+		return result;
+	}
+	
+	public List<BugMirror> getNew(String case_take_id, String report_id) {
+		List<String> ids = historydao.findRoots(recservice.getListIds(case_take_id));
+		List<String> filter = new ArrayList<String>();
+		if(ids.size() > 2) {
+			int n = ids.size();
+			filter.add(ids.get(n - 1));
+			filter.add(ids.get(n - 2));
+		} else {
+			for(String id : ids) {
+				filter.add(id);
+			}
+		}
+		return mirrordao.findByIds(filter, report_id);
+	}
+	
+	public List<String> getRoots(String case_take_id) {
+		System.out.println("getRoots: ");
+		return historydao.findRoots(aservice.getValid(case_take_id));
+	}
+	
+	public List<String> getTreeRoots(String case_take_id) {
+		List<String> all = new ArrayList<String>();
+		for(String id : getRoots(case_take_id)) {
+			if(getHistory(id).getChildren().size() > 0) { all.add(id); }
+		}
+		return all;
+	}
+	
+	public List<String> getInvalid(Set<String> ids) {
+		List<String> result = new ArrayList<String>();
+		for(String id: ids) {
+			if(!mirrordao.findById(id).isFlag()) {result.add(id);}
+		}
+		return result;
+	}
+	
+	public List<String> getInvalid(List<String> ids) {
+		List<String> result = new ArrayList<String>();
+		for(String id: ids) {
+			if(!mirrordao.findById(id).isFlag()) {result.add(id);}
+		}
+		return result;
+	}
+	
+	public Set<String> filter(List<List<String>> lists) {
+		Set<String> set = new HashSet<String>();
+		for(List<String> list : lists) {
+			for(String id: list) {
+				set.add(id);
+			}
+		}
+		return set;
+	}
+	
+	//获取评分时树的信息
+	public List<String> getDetail(String id) {
+		List<String> result = new ArrayList<String>();
+		List<List<String>> paths = getDepth(id);
+		List<Set<String>> widths = new ArrayList<Set<String>>();
+		Set<String> ids = new HashSet<String>();
+		int max_height = 0;
+		int max_width = 0;
+		int count = 0;
+		String flag = "true";
+		for(List<String> path: paths) {
+			max_height = Math.max(max_height, path.size());
+			for(int i = 0; i < path.size(); i ++) {
+				String temp = path.get(i);
+				ids.add(temp);
+				if(widths.size() <= i) {
+					Set<String> set = new HashSet<String>();
+					set.add(temp);
+					widths.add(set);
+				}
+				else {widths.get(i).add(temp);}
+			}
+		}
+		for(Set<String> width: widths) {
+			max_width = Math.max(max_width, width.size());
+		}
+		for(String str: ids) {
+			if(aservice.getGrade(str) == -1) {
+				flag = "false";
+				break;
+			}
+		}
+		count = ids.size();
+		result.add(id);
+		result.add(Integer.toString(max_width));
+		result.add(Integer.toString(max_height));
+		result.add(Integer.toString(count));
+		result.add(flag);
+		result.add(recservice.getTitle(id));
+		return result;
+	}
+
+	public void pageFilter(List<String> all, String page) {
+		if(page.equals("null")) { return; }
+		List<BugPage> mirrors = pagedao.findByIds(all);
+		String[] pages = page.split("-");
+		for(BugPage mirror : mirrors) {
+			if(pages.length > 0 && !mirror.getPage1().equals(pages[0])) {
+				all.remove(mirror.getId());
+				continue;
+			}
+			if(pages.length > 1 && !mirror.getPage2().equals(pages[1])) {
+				all.remove(mirror.getId());
+				continue;
+			}
+			if(pages.length > 2 && !mirror.getPage3().equals(pages[2])) {
+				all.remove(mirror.getId());
+				continue;
+			}
+		}
+	}
+	
+	public List<List<String>> getDepth(String id) {
+		BugHistory root = historydao.findByid(id);
+		List<List<String>> result = new ArrayList<List<String>>();
+		if(root == null) { return result;}
+		List<String> list = new ArrayList<String>();
+		list.add(root.getId());
+		dfs(root, result, list);
+		return result;
+	}
+	
+	private void dfs(BugHistory root, List<List<String>> result, List<String> list) {
+		List<String> children = root.getChildren();
+		if(children.size() != 0) {
+			for(String child : children) {
+				list.add(child);
+				dfs(historydao.findByid(child), result, list);
+				list.remove(child);
+			}
+		} else {
+			result.add(new ArrayList<String>(list));
+		}
+	}
+}

+ 129 - 129
src/main/java/com/mooctest/service/MasterReportService.java

@@ -1,129 +1,129 @@
-package com.mooctest.service;
-
-import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
-import com.mooctest.dao.MasterReportDao;
-import com.mooctest.data.BugDTO;
-import com.mooctest.model.MasterReport;
-import com.mooctest.util.Doc2VecUtil;
-import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
-import org.jgrapht.alg.scoring.PageRank;
-import org.jgrapht.graph.DefaultWeightedEdge;
-import org.jgrapht.graph.DirectedWeightedPseudograph;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Service
-public class MasterReportService {
-    @Autowired
-    MasterReportDao masterReportDao;
-
-    public String findMasterReport(Set<String> cluster, Map<String, BugDTO> bugMap) {
-        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g = buildDirectedGraph(cluster, bugMap);
-
-        VertexScoringAlgorithm<String, Double> pr = new PageRank<>(g, 0.85, 100, 0.0001);
-
-
-        String masterId = pr.getScores().entrySet()
-                .stream()
-                .max(Comparator.comparing(Map.Entry::getValue))
-                .get()
-                .getKey();
-
-        if (masterId.equals("10010000035194")) {
-            System.out.println();
-        }
-        return masterId;
-    }
-
-    public DirectedWeightedPseudograph buildDirectedGraph(Set<String> cluster, Map<String, BugDTO> bugMap) {
-        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
-                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
-
-        cluster.forEach(bugId -> g.addVertex(bugId));
-
-        cluster.forEach(outBugId -> {
-            cluster.forEach(inBugId -> {
-                if (!outBugId.equals(inBugId) && !g.containsEdge(outBugId, inBugId)) {
-                    g.setEdgeWeight(g.addEdge(outBugId, inBugId), getSim(outBugId, inBugId, bugMap));
-                }
-            });
-        });
-        return g;
-    }
-    public double getSim(String bugId1, String bugId2, Map<String, BugDTO> bugMap) {
-        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
-        return docVectorModel.similarity(bugMap.get(bugId1).getDescription(), bugMap.get(bugId2).getDescription());
-    }
-
-    public void saveMasterReport(String masterId, long examId, long caseId, Set<String> bugIds) {
-
-        List<MasterReport> mrs = new ArrayList<>(bugIds.size() + 1);
-        bugIds.forEach(bugId -> {
-
-            MasterReport mr = MasterReport.builder()
-                    .masterId(masterId)
-                    .examId(examId)
-                    .caseId(caseId)
-                    .bugId(bugId)
-                    .build();
-            mrs.add(mr);
-        });
-        masterReportDao.save(mrs);
-    }
-
-    public long[] getExamIdAndCaseIdByMasterId(String masterId) {
-        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
-        MasterReport mr = mrs.stream().findAny().get();
-        long[] ids = new long[2];
-        ids[0] = mr.getExamId();
-        ids[1] = mr.getCaseId();
-        return ids;
-    }
-
-    public List<String> getAllMasterIdByExamIdAndCaseId(long examId, long caseId) {
-        List<MasterReport> mr = masterReportDao.findByExamIdAndCaseId(examId, caseId);
-        return mr.stream()
-                .map(MasterReport::getMasterId)
-                .distinct()
-                .collect(Collectors.toList());
-    }
-
-    public Map<String, List<String>> getMaster2BugIdsMap(List<String> masterIds) {
-        List<MasterReport> mrs = masterReportDao.findByMasterIdIn(masterIds);
-        return mrs.stream().collect(
-                Collectors.groupingBy(
-                        MasterReport::getMasterId,
-                        Collectors.mapping(MasterReport::getBugId, Collectors.toList())));
-
-    }
-
-    public List<String> getAllBugIdsByMasterId(String masterId) {
-        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
-        return mrs.stream().map(MasterReport::getBugId).collect(Collectors.toList());
-    }
-
-    public List<MasterReport> getByBugIds(List<String> bugIds) {
-        return masterReportDao.findByBugIdIn(bugIds);
-
-    }
-
-    public MasterReport getByBugId(String bugId) {
-        return masterReportDao.findByBugId(bugId);
-    }
-
-    public boolean isAggregated(long examId, long caseId) {
-        long numOfAggReport = masterReportDao.countByExamIdAndCaseId(examId, caseId);
-        return numOfAggReport > 0;
-    }
-    public void deleteAll(long examId, long caseId) {
-        masterReportDao.deleteByExamIdAndCaseId(examId, caseId);
-    }
-
-    public long getAggNum(long examId, long caseId) {
-        List<MasterReport> mrs = masterReportDao.findByExamIdAndCaseId(examId, caseId);
-        return mrs.stream().map(MasterReport::getMasterId).distinct().count();
-    }
-}
+package com.mooctest.service;
+
+import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
+import com.mooctest.dao.MasterReportDao;
+import com.mooctest.data.BugDTO;
+import com.mooctest.model.MasterReport;
+import com.mooctest.util.Doc2VecUtil;
+import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
+import org.jgrapht.alg.scoring.PageRank;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.DirectedWeightedPseudograph;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class MasterReportService {
+    @Autowired
+    MasterReportDao masterReportDao;
+
+    public String findMasterReport(Set<String> cluster, Map<String, BugDTO> bugMap) {
+        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g = buildDirectedGraph(cluster, bugMap);
+
+        VertexScoringAlgorithm<String, Double> pr = new PageRank<>(g, 0.85, 100, 0.0001);
+
+
+        String masterId = pr.getScores().entrySet()
+                .stream()
+                .max(Comparator.comparing(Map.Entry::getValue))
+                .get()
+                .getKey();
+
+        if (masterId.equals("10010000035194")) {
+            System.out.println();
+        }
+        return masterId;
+    }
+
+    public DirectedWeightedPseudograph buildDirectedGraph(Set<String> cluster, Map<String, BugDTO> bugMap) {
+        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
+                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
+
+        cluster.forEach(bugId -> g.addVertex(bugId));
+
+        cluster.forEach(outBugId -> {
+            cluster.forEach(inBugId -> {
+                if (!outBugId.equals(inBugId) && !g.containsEdge(outBugId, inBugId)) {
+                    g.setEdgeWeight(g.addEdge(outBugId, inBugId), getSim(outBugId, inBugId, bugMap));
+                }
+            });
+        });
+        return g;
+    }
+    public double getSim(String bugId1, String bugId2, Map<String, BugDTO> bugMap) {
+        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
+        return docVectorModel.similarity(bugMap.get(bugId1).getDescription(), bugMap.get(bugId2).getDescription());
+    }
+
+    public void saveMasterReport(String masterId, long examId, long caseId, Set<String> bugIds) {
+
+        List<MasterReport> mrs = new ArrayList<>(bugIds.size() + 1);
+        bugIds.forEach(bugId -> {
+
+            MasterReport mr = MasterReport.builder()
+                    .masterId(masterId)
+                    .examId(examId)
+                    .caseId(caseId)
+                    .bugId(bugId)
+                    .build();
+            mrs.add(mr);
+        });
+        masterReportDao.save(mrs);
+    }
+
+    public long[] getExamIdAndCaseIdByMasterId(String masterId) {
+        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
+        MasterReport mr = mrs.stream().findAny().get();
+        long[] ids = new long[2];
+        ids[0] = mr.getExamId();
+        ids[1] = mr.getCaseId();
+        return ids;
+    }
+
+    public List<String> getAllMasterIdByExamIdAndCaseId(long examId, long caseId) {
+        List<MasterReport> mr = masterReportDao.findByExamIdAndCaseId(examId, caseId);
+        return mr.stream()
+                .map(MasterReport::getMasterId)
+                .distinct()
+                .collect(Collectors.toList());
+    }
+
+    public Map<String, List<String>> getMaster2BugIdsMap(List<String> masterIds) {
+        List<MasterReport> mrs = masterReportDao.findByMasterIdIn(masterIds);
+        return mrs.stream().collect(
+                Collectors.groupingBy(
+                        MasterReport::getMasterId,
+                        Collectors.mapping(MasterReport::getBugId, Collectors.toList())));
+
+    }
+
+    public List<String> getAllBugIdsByMasterId(String masterId) {
+        List<MasterReport> mrs = masterReportDao.findByMasterId(masterId);
+        return mrs.stream().map(MasterReport::getBugId).collect(Collectors.toList());
+    }
+
+    public List<MasterReport> getByBugIds(List<String> bugIds) {
+        return masterReportDao.findByBugIdIn(bugIds);
+
+    }
+
+    public MasterReport getByBugId(String bugId) {
+        return masterReportDao.findByBugId(bugId);
+    }
+
+    public boolean isAggregated(long examId, long caseId) {
+        long numOfAggReport = masterReportDao.countByExamIdAndCaseId(examId, caseId);
+        return numOfAggReport > 0;
+    }
+    public void deleteAll(long examId, long caseId) {
+        masterReportDao.deleteByExamIdAndCaseId(examId, caseId);
+    }
+
+    public long getAggNum(long examId, long caseId) {
+        List<MasterReport> mrs = masterReportDao.findByExamIdAndCaseId(examId, caseId);
+        return mrs.stream().map(MasterReport::getMasterId).distinct().count();
+    }
+}

+ 434 - 0
src/main/java/com/mooctest/service/RecommendService.java

@@ -0,0 +1,434 @@
+package com.mooctest.service;
+
+import com.mooctest.dao.BugExtDao;
+import com.mooctest.dao.BugMirrorDao;
+import com.mooctest.dao.BugPageDao;
+import com.mooctest.dao.KWDao;
+import com.mooctest.model.Bug;
+import com.mooctest.model.BugMirror;
+import com.mooctest.model.BugPage;
+import com.mooctest.util.StringMatch;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpSession;
+import java.util.*;
+import java.util.Map.Entry;
+
+//import com.mooctest.util.Algorithm;
+//import com.mooctest.util.Algorithm_1;
+
+@Service
+public class RecommendService {
+	
+	@Autowired
+    BugMirrorDao mirrordao;
+	
+	@Autowired
+    BugExtDao bugdao;
+	
+	@Autowired
+    BugPageDao pagedao;
+	
+	@Autowired
+    KWDao kwdao;
+	
+	public List<BugMirror> getList (String case_take_id, String report_id) {
+//		Algorithm algorithm = new Algorithm_1();
+		List<BugMirror> results = mirrordao.findByCase(case_take_id, report_id);
+//		return algorithm.sort(results);
+		return results;
+	}
+	
+	public List<String> getListIds (String case_take_id) {
+		List<BugMirror> results = mirrordao.findByCase(case_take_id);
+		List<String> lists = new ArrayList<String>();
+		for(BugMirror mirror: results) {
+			lists.add(mirror.getId());
+		}
+		return lists;
+	}
+	
+	public Bug getDetail (String id) {
+		return bugdao.findByid(id);
+	}
+	
+	public BugMirror getMirror (String id) {
+		return mirrordao.findById(id);
+	}
+	
+	public String getTitle (String id) {
+		return bugdao.findByid(id).getTitle();
+	}
+	
+	public String getReport(String id) {
+		return bugdao.findByid(id).getReportId();
+	}
+	
+	//根据bug的本质三属性进行推荐
+//	@SuppressWarnings("unchecked")
+//	public Map<BugMirror, Float> recommend (String case_take_id, String type, String content, boolean flag, HttpSession session) {
+//		
+//		List<BugMirror> results = new ArrayList<BugMirror>();
+//		
+//		if(session.getAttribute("rec") == null) {
+//			results = findByNothing(case_take_id, type, content, (String)session.getAttribute("report"));
+//			Map<String, String> map = new LinkedHashMap<String, String>();
+//			map.put(type, content);
+//			session.setAttribute("path", map);
+//		} else {
+//			Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+//			if(map == null) { map = new LinkedHashMap<String, String>(); }
+//			if(map.containsKey(type)) {
+//				return pathExist(case_take_id, type, content, session, map);
+//			}
+//			map.put(type, content);
+//			session.setAttribute("path", map);
+//			results = findByNow(type, content, (List<BugMirror>) session.getAttribute("rec"));
+//		}
+//		
+//		session.setAttribute("rec", results);
+//		if(flag) {
+//			Algorithm algorithm = new Algorithm_1();
+//			if(results != null) {results = algorithm.sort(results);}
+//			if(session.getAttribute("title") != null) {return recommandByTitle((String)session.getAttribute("title"), session);}
+//			if(session.getAttribute("des") != null) {return recommandByDes((String)session.getAttribute("des"), session);}
+//		}
+//		
+//		Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+//		return finalScore(results, map.size());
+//	}
+	
+	//根据bug的本质三属性进行推荐
+	@SuppressWarnings("unchecked")
+	public Map<BugMirror, Float> recommend (String case_take_id, String type, String content, boolean flag, HttpSession session) {
+		
+		List<BugMirror> results = new ArrayList<BugMirror>();
+		
+		if(session.getAttribute("rec") == null) {
+			Map<String, String> map = new LinkedHashMap<String, String>();
+			map.put(type, content);
+			session.setAttribute("path", map);
+			results = getList(case_take_id, "test");
+		} else {
+			Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+			if(map == null) { map = new LinkedHashMap<String, String>(); }
+			if(map.containsKey(type)) {
+				return pathExist(case_take_id, type, content, session, map);
+			}
+			map.put(type, content);
+			session.setAttribute("path", map);
+			results = (List<BugMirror>) session.getAttribute("rec");
+		}
+		session.setAttribute("rec", results);
+		if(flag) {
+			if(session.getAttribute("title") != null) {return recommandByTitle((String)session.getAttribute("title"), session);}
+			if(session.getAttribute("des") != null) {return recommandByDes((String)session.getAttribute("des"), session);}
+		}
+		
+		Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+		return finalScore(results, map);
+	}
+	
+	//根据页面进行推荐
+	@SuppressWarnings("unchecked")
+	public Map<BugMirror, Float> recommndByPage(String case_take_id, String type, String content, boolean flag, HttpSession session){
+		
+		List<BugPage> results = new ArrayList<BugPage>();
+		List<BugMirror> mirrors = new ArrayList<BugMirror>();
+		
+		if(session.getAttribute("page") == null) {
+			results = findPages(case_take_id, type, content);
+			mirrors = findMirror(getIds(results), (String)session.getAttribute("report"));
+			Map<String, String> map = new LinkedHashMap<String, String>();
+			map.put(type, content);
+			session.setAttribute("path", map);
+		} else {
+			Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+			if(map.containsKey(type)) {
+				return pathExist(case_take_id, type, content, session, map);
+			} else {
+				map.put(type, content);
+				session.setAttribute("path", map);
+				results = findByPages(type, content, (List<BugPage>) session.getAttribute("page"));
+				mirrors = findByMirror(getIds(results), (List<BugMirror>) session.getAttribute("rec"));
+			}
+		}
+		
+		session.setAttribute("page", results);
+		session.setAttribute("rec", mirrors);
+		
+		if(flag) {
+//			Algorithm algorithm = new Algorithm_1();
+//			if(mirrors != null) {mirrors = algorithm.sort(mirrors);}
+			if(session.getAttribute("title") != null) {return recommandByTitle((String)session.getAttribute("title"), session);}
+			if(session.getAttribute("des") != null) {return recommandByDes((String)session.getAttribute("des"), session);}
+		}
+		
+		Map<String, String> map = (Map<String, String>)session.getAttribute("path");
+		return finalScore(mirrors, map);
+	}
+	
+	//根据Title进行文本匹配
+	@SuppressWarnings("unchecked")
+	public Map<BugMirror, Float> recommandByTitle(String content, HttpSession session){
+		session.setAttribute("title", content);
+		if(session.getAttribute("rec") == null) {
+			List<BugMirror> temp = mirrordao.findByCase((String)session.getAttribute("case"), (String)session.getAttribute("report"));
+			if(temp != null) {session.setAttribute("rec", temp);}
+		}
+		if(session.getAttribute("rec") != null) {return count(content, (List<BugMirror>)session.getAttribute("rec"), true, session);}
+		return null;
+	}
+	
+	//根据description进行文本匹配
+	@SuppressWarnings("unchecked")
+	public Map<BugMirror, Float> recommandByDes(String content, HttpSession session){
+		session.setAttribute("des", content);
+		if(session.getAttribute("rec") == null) {
+			List<BugMirror> temp = mirrordao.findByCase((String)session.getAttribute("case"), (String)session.getAttribute("report"));
+			if(temp != null) {session.setAttribute("rec", temp);}
+		}
+		if(session.getAttribute("rec") != null) {return count(content, (List<BugMirror>)session.getAttribute("rec"), false, session);}
+		return null;
+	}
+	
+	//从缓存中获取
+//	private List<BugMirror> findByNow(String type, String content, List<BugMirror> lists){
+//		List<BugMirror> results = new ArrayList<BugMirror>();
+//		switch(type) {
+//			case "bug_category":
+//				for(BugMirror mirror : lists) {
+//					if(mirror.getBug_category().equals(content)) {results.add(mirror);}
+//				}
+//				break;
+//			case "severity":
+//				for(BugMirror mirror : lists) {
+//					if(mirror.getSeverity() == severityTranse(content)) {results.add(mirror);}
+//				}
+//				break;
+//			case "recurrent":
+//				for(BugMirror mirror : lists) {
+//					if(mirror.getRecurrent() == recurrentTranse(content)) {results.add(mirror);}
+//				}
+//				break;
+//		}
+//		return results;
+//	}
+
+	//从数据库中获取
+//	private List<BugMirror> findByNothing(String case_take_id, String type, String content, String report_id){
+//		switch(type) {
+//			case "bug_category":
+//				return mirrordao.findByCategory(case_take_id, content, report_id);
+//			case "severity":
+//				return mirrordao.findBySeverity(case_take_id, severityTranse(content), report_id);
+//			case "recurrent":
+//				return mirrordao.findByRecurrent(case_take_id, recurrentTranse(content), report_id);
+//		}
+//		return null;
+//	}
+	
+	//从数据库中查找页面
+	private List<BugPage> findPages(String case_take_id, String type, String content){
+		switch(type) {
+			case "page1":
+				return pagedao.findByPage1(case_take_id, content);
+			case "page2":
+				return pagedao.findByPage2(case_take_id, content);
+			case "page3":
+				return pagedao.findByPage3(case_take_id, content);
+		}
+		return null;
+	}
+	
+	//从缓存中查找页面
+	private List<BugPage> findByPages(String type, String content, List<BugPage> lists){
+		List<BugPage> results = new ArrayList<BugPage>();
+		switch(type) {
+			case "page1":
+				for(BugPage page : lists) {
+					if(page.getPage1().equals(content)) {results.add(page);}
+				}
+				break;
+			case "page2":
+				for(BugPage page : lists) {
+					if(page.getPage2().equals(content)) {results.add(page);}
+				}
+				break;
+			case "page3":
+				for(BugPage page : lists) {
+					if(page.getPage3().equals(content)) {results.add(page);}
+				}
+				break;
+		}
+		return results;
+	}
+	
+	//从数据库中获取指定id的bug
+	private List<BugMirror> findMirror(List<String> ids, String report_id){
+		List<BugMirror> results = new ArrayList<BugMirror>();
+		results = mirrordao.findByIds(ids, report_id);
+		return results;
+	}
+	
+	//从缓存中进行筛选符合条件的
+	private List<BugMirror> findByMirror(List<String> ids, List<BugMirror> lists){
+		List<BugMirror> results = new ArrayList<BugMirror>();
+		for(BugMirror mirror : lists) {
+			if(ids.contains(mirror.getId())) {results.add(mirror);}
+		}
+		return results;
+	}
+	
+	//根据页面获取bug_id
+	private List<String> getIds(List<BugPage> pages) {
+		List<String> ids = new ArrayList<String>();
+		for(int i = 0; i < pages.size(); i ++) {
+			ids.add(pages.get(i).getId());
+		}
+		return ids;
+	}
+	
+	//该选项已经选择过
+	private Map<BugMirror, Float> pathExist(String case_take_id, String type, String content, HttpSession session, Map<String, String> map){
+		session.removeAttribute("rec");
+		session.removeAttribute("path");
+		session.removeAttribute("page");
+		Map<BugMirror, Float> results = new LinkedHashMap<BugMirror, Float>();
+		for(Entry<String, String> entry: map.entrySet()) {
+			if(entry.getKey().equals(type)) { continue; }
+			if(entry.getKey().contains("page")) {
+				recommndByPage(case_take_id, entry.getKey(), entry.getValue(), false, session);
+			} else {
+				recommend(case_take_id, entry.getKey(), entry.getValue(), false, session);
+			}
+		}
+		if(type.contains("page")) { results = recommndByPage(case_take_id, type, content, true, session); }
+		else { results = recommend(case_take_id, type, content, true, session); }
+		return results;
+	}
+	
+	@SuppressWarnings("unchecked")
+	private Map<BugMirror, Float> count(String content, List<BugMirror> lists, boolean type, HttpSession session) {
+		StringMatch match = new StringMatch();
+		Map<BugMirror, Float> tmap = new HashMap<BugMirror, Float>();
+		Map<BugMirror, Float> result = new LinkedHashMap<BugMirror, Float>();
+		Map<String, BugMirror> bmap = new HashMap<String, BugMirror>();
+		Map<String, String> titleMap = new HashMap<String, String>();
+		Map<String, String> desMap = new HashMap<String, String>();
+		Map<String, String> pmap = null;
+		
+		for(BugMirror mirror: lists) {
+			String id = mirror.getId();
+			bmap.put(id, mirror);
+			titleMap.put(id, kwdao.findById(id).getTitle());
+			desMap.put(id, kwdao.findById(id).getDescription());
+		}
+		for(BugMirror mirror: lists) {
+			String id = mirror.getId();
+			float score = 0;
+			if(type) {
+				score += match.score(match.Ansj(content), match.Ansj(titleMap.get(id))) * 30;
+				if(session.getAttribute("des") != null) {
+					score += match.score(match.Ansj((String)session.getAttribute("des")), match.Ansj(desMap.get(id))) * 40;
+				}
+			} else {
+				score += match.score(match.Ansj(content), match.Ansj(desMap.get(id))) * 40;
+				if(session.getAttribute("title") != null) {
+					score += match.score(match.Ansj((String)session.getAttribute("title")), match.Ansj(titleMap.get(id))) * 30;
+				}
+			}
+			tmap.put(mirror, score);
+		}
+		List<Entry<BugMirror, Float>> tlist = new ArrayList<Entry<BugMirror, Float>>(tmap.entrySet());
+		Collections.sort(tlist, (a, b) -> (Float.compare(b.getValue(), a.getValue())));
+		if(session.getAttribute("path") != null) {
+			pmap = (Map<String, String>)session.getAttribute("path");
+		}
+		
+		for(int i = 0; i < tlist.size() && i < 6; i ++) {
+			float score = (float) (tlist.get(i).getValue());
+			result.put(tlist.get(i).getKey(), score + categoryCount(tlist.get(i).getKey(), pmap));
+		}
+		tlist = new ArrayList<Entry<BugMirror, Float>>(result.entrySet());
+		Collections.sort(tlist, (a, b) -> (Float.compare(b.getValue(), a.getValue())));
+		result.clear();
+		for(Entry<BugMirror, Float> entry: tlist) {
+			result.put(entry.getKey(), entry.getValue());
+		}
+		return result;
+	}
+	
+	private Map<BugMirror, Float> finalScore(List<BugMirror> lists, Map<String, String> map) {
+		Map<BugMirror, Float> rmap = new LinkedHashMap<BugMirror, Float>();
+		for(BugMirror mirror : lists) {
+			rmap.put(mirror, categoryCount(mirror, map));
+		}
+		return rmap;
+	}
+	
+	private float categoryCount(BugMirror mirror, Map<String, String> map) {
+		if(map == null) { return 0;}
+		int score = 0;
+		int size = map.size();
+		for(Entry<String, String> entry : map.entrySet()) {
+			String type = entry.getKey();
+			String content = entry.getValue();
+			switch(type) {
+				case "bug_category":
+					size --;
+					if(content.equals(mirror.getBug_category())) { score ++; }
+					break;
+				case "severity":
+					size --;
+					if(severityTranse(content) == mirror.getSeverity()) { score ++; }
+					break;
+				case "recurrent":
+					size --;
+					if(recurrentTranse(content) == mirror.getRecurrent()) { score ++; }
+					break;
+			}		
+		}
+		return (float) ((score + size) * 5);
+	}
+	
+	private int severityTranse(String str) {
+		if(str.equals("待定")) {
+			return 1;
+		}
+		if(str.equals("较轻")) {
+			return 2;
+		}
+		if(str.equals("一般")) {
+			return 3;
+		}
+		if(str.equals("严重")) {
+			return 4;
+		}
+		if(str.equals("紧急")) {
+			return 5;
+		}
+		return 0;
+	}
+	
+	private int recurrentTranse(String str) {
+		if(str.equals("其他")) {
+			return 1;
+		}
+		if(str.equals("无规律复现")) {
+			return 2;
+		}
+		if(str.equals("小概率复现")) {
+			return 3;
+		}
+		if(str.equals("大概率复现")) {
+			return 4;
+		}
+		if(str.equals("必现")) {
+			return 5;
+		}
+		return 0;
+	}
+	
+}

+ 308 - 308
src/main/java/com/mooctest/service/SupplementService.java

@@ -1,308 +1,308 @@
-package com.mooctest.service;
-
-import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
-import com.hankcs.hanlp.utility.SentencesUtil;
-import com.mooctest.cluster.Group;
-import com.mooctest.dao.SupplementDao;
-import com.mooctest.data.*;
-import com.mooctest.image.FingerPrint;
-import com.mooctest.model.SupplementItem;
-import com.mooctest.util.Doc2VecUtil;
-import com.mooctest.util.ImageUtil;
-import com.mooctest.util.IndexUtil;
-import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
-import org.jgrapht.alg.scoring.PageRank;
-import org.jgrapht.graph.DefaultWeightedEdge;
-import org.jgrapht.graph.DirectedWeightedPseudograph;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static java.util.stream.Collectors.*;
-
-@Service
-public class SupplementService {
-
-    @Autowired
-    SupplementDao supplementDao;
-
-    @Autowired
-    MasterReportService masterReportService;
-
-    public void rankAndStoreDiffText(Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap) {
-        masterDiffTextClustersMap.forEach((masterId, diffTextClusters) -> {
-
-            diffTextClusters.forEach(group -> {
-                Set<DiffText> cluster = group.getCluster();
-                DirectedWeightedPseudograph graph = buildDirectedGraph(cluster);
-                VertexScoringAlgorithm<String, Double> pr = new PageRank<>(graph, 0.85, 100, 0.0001);
-                cluster.forEach(diffText -> {
-                    SupplementItem supplementItem = new SupplementItem(0,
-                            masterId,
-                            diffText.getBugId(),
-                            diffText.getIndex(),
-                            group.getId(),
-                            pr.getVertexScore(IndexUtil.joinByUnderLine(diffText.getBugId(), diffText.getIndex())),
-                            diffText.getSentence(),
-                            false);
-                    SupplementItem save = supplementDao.save(supplementItem);
-                });
-
-            });
-
-
-        });
-
-    }
-
-    public DirectedWeightedPseudograph buildDirectedGraph(Set<DiffText> cluster) {
-        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
-                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
-        cluster.forEach(diffText -> g.addVertex(diffText.getBugId() + "_" + diffText.getIndex()));
-        cluster.forEach(outDiffText -> {
-            String outId = outDiffText.getBugId() + "_" + outDiffText.getIndex();
-            cluster.forEach(inDiffText -> {
-                String inId = inDiffText.getBugId() + "_" + inDiffText.getIndex();
-                if (!outId.equals(inId) && !g.containsEdge(outId, inId)) {
-                    g.setEdgeWeight(g.addEdge(outId, inId), getSim(outDiffText, inDiffText));
-                }
-            });
-        });
-
-        return g;
-    }
-
-    public double getSim(DiffText diffText1, DiffText diffText2) {
-        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
-        return docVectorModel.similarity(diffText1.getSentence(), diffText2.getSentence());
-    }
-
-    public void rankAndStoreDiffImg(Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap) {
-        masterDiffImgClustersMap.forEach((masterId, diffTextClusters) -> {
-
-            diffTextClusters.forEach(group -> {
-                Set<DiffImg> cluster = group.getCluster();
-                DirectedWeightedPseudograph graph = buildDirectedGraphForDiffImg(cluster);
-                VertexScoringAlgorithm<String, Double> pr = new PageRank<>(graph, 0.85, 100, 0.0001);
-                cluster.forEach(diffImg -> {
-                    SupplementItem supplementItem = new SupplementItem(0,
-                            masterId,
-                            diffImg.getBugId(),
-                            diffImg.getIndex(),
-                            group.getId(),
-                            pr.getVertexScore(IndexUtil.joinByUnderLine(diffImg.getBugId(), diffImg.getIndex())),
-                            diffImg.getImgUrl(),
-                            true);
-                    SupplementItem save = supplementDao.save(supplementItem);
-                });
-
-            });
-
-
-        });
-
-    }
-
-    public DirectedWeightedPseudograph buildDirectedGraphForDiffImg(Set<DiffImg> cluster) {
-        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
-                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
-        cluster.forEach(diffText -> g.addVertex(diffText.getBugId() + "_" + diffText.getIndex()));
-        cluster.forEach(outDiffImg -> {
-            String outId = outDiffImg.getBugId() + "_" + outDiffImg.getIndex();
-            cluster.forEach(inDiffImg -> {
-                String inId = inDiffImg.getBugId() + "_" + inDiffImg.getIndex();
-                if (!outId.equals(inId) && !g.containsEdge(outId, inId)) {
-                    g.setEdgeWeight(g.addEdge(outId, inId), getSim(outDiffImg, inDiffImg));
-                }
-            });
-        });
-
-        return g;
-    }
-
-    public double getSim(DiffImg diffImg1, DiffImg diffImg2) {
-        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(diffImg1.getMasterId());
-        long examId = ids[0];
-        long caseId = ids[1];
-        String taskId = examId + "_" + caseId;
-
-        File img1 = new File(ImageUtil.genImagePath(taskId, diffImg1.getBugId(), diffImg1.getIndex()));
-        File img2 = new File(ImageUtil.genImagePath(taskId, diffImg2.getBugId(), diffImg2.getIndex()));
-        if (!img1.exists() || !img2.exists()) {
-            return 0;
-        }
-        FingerPrint fp1 = ImageUtil.readImgFingerPrint(img1);
-        FingerPrint fp2 = ImageUtil.readImgFingerPrint(img2);
-        return fp1.compare(fp2);
-    }
-
-    public List<SupplementDTO> getSupplementByMasterId(String masterId, Map<String, BugDTO> bugMap) {
-        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
-        List<String> sups = supplementItems.stream().map(SupplementItem::getSupplementId).distinct().collect(toList());
-        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream().collect(groupingBy(SupplementItem::getSupplementId));
-        List<SupplementDTO> sortedSupplements = new ArrayList<>(supplementMap.size());
-
-
-        sups.forEach(supId -> {
-            SupplementDTO su = buildSupplement(supId, supplementMap, bugMap);
-            sortedSupplements.add(su);
-        });
-        return sortedSupplements;
-    }
-
-    public List<SupplementDTO> getSupplementTopInfoByMasterId(String masterId) {
-        return getSupplementByMasterId(masterId, null);
-    }
-
-    private SupplementDTO buildSupplement(String supId,
-                                          Map<String, List<SupplementItem>> supplementMap,
-                                          Map<String, BugDTO> bugMap) {
-
-        List<SupplementItem> items = supplementMap.get(supId);
-
-
-        boolean hasTxt = items.stream().filter(item -> !item.isImg()).count() > 0 ? true : false;
-
-        items = items.stream().sorted(Comparator.comparingDouble(SupplementItem::getPageRankScore).reversed()).collect(Collectors.toList());
-        SupplementDTO su = SupplementDTO.builder()
-                .supplementId(supId)
-                .items(items)
-                .hasTxt(hasTxt)
-                .build();
-
-        if (bugMap != null) {
-            List<String> bugIds = items.stream()
-                    .map(SupplementItem::getBugId)
-                    .distinct()
-                    .collect(Collectors.toList());
-            su.setBugs(queryBug(bugIds, bugMap, items));
-        }
-
-        if (hasTxt) {
-            String topTxt = findTopTxt(items);
-            su.setTopTxt(topTxt);
-        } else {
-            List<String> top3Img = findTop3Img(items);
-            su.setTop3Img(top3Img);
-        }
-        return su;
-    }
-
-
-
-    private Map<String, Long> sortByValue(final Map<String, Long> wordCounts) {
-        return wordCounts.entrySet()
-                .stream()
-                .sorted((Map.Entry.<String, Long>comparingByValue().reversed()))
-                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
-    }
-
-    private List<BugDTO> queryBug(List<String> bugIds,
-                                  Map<String, BugDTO> bugMap,
-                                  List<SupplementItem> items) {
-        return bugIds.stream()
-                .map(bugId -> bugMap.get(bugId).toBuilder().build())
-                .map(bugDTO -> {
-                    bugDTO.setTaggedSentences(tagSentence(bugDTO, items));
-                    bugDTO.setTaggedImgs(tagImg(bugDTO, items));
-                    return bugDTO;
-                })
-                .collect(Collectors.toList());
-    }
-
-    private List<SentenceDTO> tagSentence(BugDTO bug,
-                                          List<SupplementItem> items) {
-        List<String> sens = SentencesUtil.toSentenceList(bug.getDescription());
-        List<SentenceDTO> sentenceDTOs = new ArrayList<>(sens.size());
-        for (int i = 0; i < sens.size(); i++) {
-            String s = sens.get(i);
-            SentenceDTO sentenceDTO = new SentenceDTO(s, false);
-            for (SupplementItem item : items) {
-                if (item.getBugId().equals(bug.getId()) && !item.isImg() && item.getIndex() == i) {
-                    sentenceDTO.setDiff(true);
-                }
-            }
-            sentenceDTOs.add(sentenceDTO);
-        }
-
-        return sentenceDTOs;
-    }
-
-    private List<ImgDTO> tagImg(BugDTO bug,
-                                List<SupplementItem> items) {
-        String[] imgUrls = bug.getImgUrls();
-        List<ImgDTO> imgDTOs = new ArrayList<>(imgUrls.length);
-        for (int i = 0; i < imgUrls.length; i++) {
-            String imgUrl = imgUrls[i];
-            ImgDTO imgDTO = new ImgDTO(imgUrl, false);
-            for (SupplementItem item : items) {
-                if (item.getBugId().equals(bug.getId()) && item.isImg() && item.getIndex() == i) {
-                    imgDTO.setDiff(true);
-                }
-            }
-            imgDTOs.add(imgDTO);
-        }
-        return imgDTOs;
-    }
-    private String findTopTxt(List<SupplementItem> items) {
-        for (SupplementItem item : items) {
-            if (item.isImg()) {
-                continue;
-            }
-            return item.getContent();
-        }
-        return "";
-    }
-
-    private List<String> findTop3Img(List<SupplementItem> items) {
-        List<String> top3Imgs = new ArrayList<>(3);
-        for (SupplementItem item : items) {
-            if (item.isImg() && top3Imgs.size() < 3) {
-                top3Imgs.add(item.getContent());
-            }
-        }
-        return top3Imgs;
-    }
-
-    public SupplementDTO findBySupId(String supId, Map<String, BugDTO> bugMap) {
-
-        List<SupplementItem> items = supplementDao.findBySupplementId(supId);
-        Map<String, List<SupplementItem>> supplementMap = items.stream().collect(groupingBy(SupplementItem::getSupplementId));
-
-        return buildSupplement(supId, supplementMap, bugMap);
-    }
-
-    public Map<String, List<String>> getMaster2BugIdsMap(List<String> masterIds) {
-        List<SupplementItem> supItems = supplementDao.findByMasterIdIn(masterIds);
-        List<String[]> masterBugs = supItems.stream()
-                .map(item -> item.getMasterId() + "-" + item.getBugId())
-                .distinct()
-                .map(s -> s.split("-"))
-                .collect(toList());
-        Map<String, List<String>> masterBugIdsMap = new HashMap<>();
-        for (String[] masterBug : masterBugs) {
-            String masterId = masterBug[0];
-            String bugId = masterBug[1];
-
-            if (masterBugIdsMap.get(masterId) == null) {
-                List<String> bugs = new ArrayList<>();
-                bugs.add(bugId);
-                masterBugIdsMap.put(masterId, bugs);
-            } else {
-                List<String> bugs = masterBugIdsMap.get(masterId);
-                bugs.add(bugId);
-                masterBugIdsMap.put(masterId, bugs);
-            }
-        }
-        return masterBugIdsMap;
-    }
-
-    public void deleteAll(long examId, long caseId) {
-
-        List<String> masterIds = masterReportService.getAllMasterIdByExamIdAndCaseId(examId, caseId);
-        supplementDao.deleteByMasterIdIn(masterIds);
-    }
-}
+package com.mooctest.service;
+
+import com.hankcs.hanlp.mining.word2vec.DocVectorModel;
+import com.hankcs.hanlp.utility.SentencesUtil;
+import com.mooctest.cluster.Group;
+import com.mooctest.dao.SupplementDao;
+import com.mooctest.data.*;
+import com.mooctest.image.FingerPrint;
+import com.mooctest.model.SupplementItem;
+import com.mooctest.util.Doc2VecUtil;
+import com.mooctest.util.ImageUtil;
+import com.mooctest.util.IndexUtil;
+import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
+import org.jgrapht.alg.scoring.PageRank;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.DirectedWeightedPseudograph;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
+
+@Service
+public class SupplementService {
+
+    @Autowired
+    SupplementDao supplementDao;
+
+    @Autowired
+    MasterReportService masterReportService;
+
+    public void rankAndStoreDiffText(Map<String, List<Group<String, DiffText>>> masterDiffTextClustersMap) {
+        masterDiffTextClustersMap.forEach((masterId, diffTextClusters) -> {
+
+            diffTextClusters.forEach(group -> {
+                Set<DiffText> cluster = group.getCluster();
+                DirectedWeightedPseudograph graph = buildDirectedGraph(cluster);
+                VertexScoringAlgorithm<String, Double> pr = new PageRank<>(graph, 0.85, 100, 0.0001);
+                cluster.forEach(diffText -> {
+                    SupplementItem supplementItem = new SupplementItem(0,
+                            masterId,
+                            diffText.getBugId(),
+                            diffText.getIndex(),
+                            group.getId(),
+                            pr.getVertexScore(IndexUtil.joinByUnderLine(diffText.getBugId(), diffText.getIndex())),
+                            diffText.getSentence(),
+                            false);
+                    SupplementItem save = supplementDao.save(supplementItem);
+                });
+
+            });
+
+
+        });
+
+    }
+
+    public DirectedWeightedPseudograph buildDirectedGraph(Set<DiffText> cluster) {
+        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
+                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
+        cluster.forEach(diffText -> g.addVertex(diffText.getBugId() + "_" + diffText.getIndex()));
+        cluster.forEach(outDiffText -> {
+            String outId = outDiffText.getBugId() + "_" + outDiffText.getIndex();
+            cluster.forEach(inDiffText -> {
+                String inId = inDiffText.getBugId() + "_" + inDiffText.getIndex();
+                if (!outId.equals(inId) && !g.containsEdge(outId, inId)) {
+                    g.setEdgeWeight(g.addEdge(outId, inId), getSim(outDiffText, inDiffText));
+                }
+            });
+        });
+
+        return g;
+    }
+
+    public double getSim(DiffText diffText1, DiffText diffText2) {
+        DocVectorModel docVectorModel = Doc2VecUtil.loadModel();
+        return docVectorModel.similarity(diffText1.getSentence(), diffText2.getSentence());
+    }
+
+    public void rankAndStoreDiffImg(Map<String, List<Group<String, DiffImg>>> masterDiffImgClustersMap) {
+        masterDiffImgClustersMap.forEach((masterId, diffTextClusters) -> {
+
+            diffTextClusters.forEach(group -> {
+                Set<DiffImg> cluster = group.getCluster();
+                DirectedWeightedPseudograph graph = buildDirectedGraphForDiffImg(cluster);
+                VertexScoringAlgorithm<String, Double> pr = new PageRank<>(graph, 0.85, 100, 0.0001);
+                cluster.forEach(diffImg -> {
+                    SupplementItem supplementItem = new SupplementItem(0,
+                            masterId,
+                            diffImg.getBugId(),
+                            diffImg.getIndex(),
+                            group.getId(),
+                            pr.getVertexScore(IndexUtil.joinByUnderLine(diffImg.getBugId(), diffImg.getIndex())),
+                            diffImg.getImgUrl(),
+                            true);
+                    SupplementItem save = supplementDao.save(supplementItem);
+                });
+
+            });
+
+
+        });
+
+    }
+
+    public DirectedWeightedPseudograph buildDirectedGraphForDiffImg(Set<DiffImg> cluster) {
+        DirectedWeightedPseudograph<String, DefaultWeightedEdge> g =
+                new DirectedWeightedPseudograph<>(DefaultWeightedEdge.class);
+        cluster.forEach(diffText -> g.addVertex(diffText.getBugId() + "_" + diffText.getIndex()));
+        cluster.forEach(outDiffImg -> {
+            String outId = outDiffImg.getBugId() + "_" + outDiffImg.getIndex();
+            cluster.forEach(inDiffImg -> {
+                String inId = inDiffImg.getBugId() + "_" + inDiffImg.getIndex();
+                if (!outId.equals(inId) && !g.containsEdge(outId, inId)) {
+                    g.setEdgeWeight(g.addEdge(outId, inId), getSim(outDiffImg, inDiffImg));
+                }
+            });
+        });
+
+        return g;
+    }
+
+    public double getSim(DiffImg diffImg1, DiffImg diffImg2) {
+        long[] ids = masterReportService.getExamIdAndCaseIdByMasterId(diffImg1.getMasterId());
+        long examId = ids[0];
+        long caseId = ids[1];
+        String taskId = examId + "_" + caseId;
+
+        File img1 = new File(ImageUtil.genImagePath(taskId, diffImg1.getBugId(), diffImg1.getIndex()));
+        File img2 = new File(ImageUtil.genImagePath(taskId, diffImg2.getBugId(), diffImg2.getIndex()));
+        if (!img1.exists() || !img2.exists()) {
+            return 0;
+        }
+        FingerPrint fp1 = ImageUtil.readImgFingerPrint(img1);
+        FingerPrint fp2 = ImageUtil.readImgFingerPrint(img2);
+        return fp1.compare(fp2);
+    }
+
+    public List<SupplementDTO> getSupplementByMasterId(String masterId, Map<String, BugDTO> bugMap) {
+        List<SupplementItem> supplementItems = supplementDao.findByMasterId(masterId);
+        List<String> sups = supplementItems.stream().map(SupplementItem::getSupplementId).distinct().collect(toList());
+        Map<String, List<SupplementItem>> supplementMap = supplementItems.stream().collect(groupingBy(SupplementItem::getSupplementId));
+        List<SupplementDTO> sortedSupplements = new ArrayList<>(supplementMap.size());
+
+
+        sups.forEach(supId -> {
+            SupplementDTO su = buildSupplement(supId, supplementMap, bugMap);
+            sortedSupplements.add(su);
+        });
+        return sortedSupplements;
+    }
+
+    public List<SupplementDTO> getSupplementTopInfoByMasterId(String masterId) {
+        return getSupplementByMasterId(masterId, null);
+    }
+
+    private SupplementDTO buildSupplement(String supId,
+                                          Map<String, List<SupplementItem>> supplementMap,
+                                          Map<String, BugDTO> bugMap) {
+
+        List<SupplementItem> items = supplementMap.get(supId);
+
+
+        boolean hasTxt = items.stream().filter(item -> !item.isImg()).count() > 0 ? true : false;
+
+        items = items.stream().sorted(Comparator.comparingDouble(SupplementItem::getPageRankScore).reversed()).collect(Collectors.toList());
+        SupplementDTO su = SupplementDTO.builder()
+                .supplementId(supId)
+                .items(items)
+                .hasTxt(hasTxt)
+                .build();
+
+        if (bugMap != null) {
+            List<String> bugIds = items.stream()
+                    .map(SupplementItem::getBugId)
+                    .distinct()
+                    .collect(Collectors.toList());
+            su.setBugs(queryBug(bugIds, bugMap, items));
+        }
+
+        if (hasTxt) {
+            String topTxt = findTopTxt(items);
+            su.setTopTxt(topTxt);
+        } else {
+            List<String> top3Img = findTop3Img(items);
+            su.setTop3Img(top3Img);
+        }
+        return su;
+    }
+
+
+
+    private Map<String, Long> sortByValue(final Map<String, Long> wordCounts) {
+        return wordCounts.entrySet()
+                .stream()
+                .sorted((Map.Entry.<String, Long>comparingByValue().reversed()))
+                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
+    }
+
+    private List<BugDTO> queryBug(List<String> bugIds,
+                                  Map<String, BugDTO> bugMap,
+                                  List<SupplementItem> items) {
+        return bugIds.stream()
+                .map(bugId -> bugMap.get(bugId).toBuilder().build())
+                .map(bugDTO -> {
+                    bugDTO.setTaggedSentences(tagSentence(bugDTO, items));
+                    bugDTO.setTaggedImgs(tagImg(bugDTO, items));
+                    return bugDTO;
+                })
+                .collect(Collectors.toList());
+    }
+
+    private List<SentenceDTO> tagSentence(BugDTO bug,
+                                          List<SupplementItem> items) {
+        List<String> sens = SentencesUtil.toSentenceList(bug.getDescription());
+        List<SentenceDTO> sentenceDTOs = new ArrayList<>(sens.size());
+        for (int i = 0; i < sens.size(); i++) {
+            String s = sens.get(i);
+            SentenceDTO sentenceDTO = new SentenceDTO(s, false);
+            for (SupplementItem item : items) {
+                if (item.getBugId().equals(bug.getId()) && !item.isImg() && item.getIndex() == i) {
+                    sentenceDTO.setDiff(true);
+                }
+            }
+            sentenceDTOs.add(sentenceDTO);
+        }
+
+        return sentenceDTOs;
+    }
+
+    private List<ImgDTO> tagImg(BugDTO bug,
+                                List<SupplementItem> items) {
+        String[] imgUrls = bug.getImgUrls();
+        List<ImgDTO> imgDTOs = new ArrayList<>(imgUrls.length);
+        for (int i = 0; i < imgUrls.length; i++) {
+            String imgUrl = imgUrls[i];
+            ImgDTO imgDTO = new ImgDTO(imgUrl, false);
+            for (SupplementItem item : items) {
+                if (item.getBugId().equals(bug.getId()) && item.isImg() && item.getIndex() == i) {
+                    imgDTO.setDiff(true);
+                }
+            }
+            imgDTOs.add(imgDTO);
+        }
+        return imgDTOs;
+    }
+    private String findTopTxt(List<SupplementItem> items) {
+        for (SupplementItem item : items) {
+            if (item.isImg()) {
+                continue;
+            }
+            return item.getContent();
+        }
+        return "";
+    }
+
+    private List<String> findTop3Img(List<SupplementItem> items) {
+        List<String> top3Imgs = new ArrayList<>(3);
+        for (SupplementItem item : items) {
+            if (item.isImg() && top3Imgs.size() < 3) {
+                top3Imgs.add(item.getContent());
+            }
+        }
+        return top3Imgs;
+    }
+
+    public SupplementDTO findBySupId(String supId, Map<String, BugDTO> bugMap) {
+
+        List<SupplementItem> items = supplementDao.findBySupplementId(supId);
+        Map<String, List<SupplementItem>> supplementMap = items.stream().collect(groupingBy(SupplementItem::getSupplementId));
+
+        return buildSupplement(supId, supplementMap, bugMap);
+    }
+
+    public Map<String, List<String>> getMaster2BugIdsMap(List<String> masterIds) {
+        List<SupplementItem> supItems = supplementDao.findByMasterIdIn(masterIds);
+        List<String[]> masterBugs = supItems.stream()
+                .map(item -> item.getMasterId() + "-" + item.getBugId())
+                .distinct()
+                .map(s -> s.split("-"))
+                .collect(toList());
+        Map<String, List<String>> masterBugIdsMap = new HashMap<>();
+        for (String[] masterBug : masterBugs) {
+            String masterId = masterBug[0];
+            String bugId = masterBug[1];
+
+            if (masterBugIdsMap.get(masterId) == null) {
+                List<String> bugs = new ArrayList<>();
+                bugs.add(bugId);
+                masterBugIdsMap.put(masterId, bugs);
+            } else {
+                List<String> bugs = masterBugIdsMap.get(masterId);
+                bugs.add(bugId);
+                masterBugIdsMap.put(masterId, bugs);
+            }
+        }
+        return masterBugIdsMap;
+    }
+
+    public void deleteAll(long examId, long caseId) {
+
+        List<String> masterIds = masterReportService.getAllMasterIdByExamIdAndCaseId(examId, caseId);
+        supplementDao.deleteByMasterIdIn(masterIds);
+    }
+}

+ 103 - 103
src/main/java/com/mooctest/service/TaskService.java

@@ -1,103 +1,103 @@
-package com.mooctest.service;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.mooctest.dao.MasterReportDao;
-import com.mooctest.data.TaskDTO;
-import com.mooctest.model.Task;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.StringHttpMessageConverter;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
-
-import java.nio.charset.Charset;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Service
-public class TaskService {
-//    List<Task> tasks = Arrays.asList(
-//            new Task(2613, 1489, "途牛旅游", "/static/images/apps/tuniu.png", "9.56.0", 0, "2018-11-12", "2018-12-20"),
-//            new Task(2613, 1489, "花田小憩", "/static/images/apps/huatianxiaoqi.png", "6.5.0", 1, "2018-10-12", "2018-10-20"),
-//            new Task(2613, 1489, "小猿搜题", "/static/images/apps/xiaoyuansouti.png", "8.5.0", 1, "2018-10-03", "2018-10-15"),
-//            new Task(2613, 1489, "途牛旅游", "/static/images/apps/tuniu.png", "9.50.0", 1, "2018-10-02", "2018-10-12"),
-//            new Task(2613, 1489, "JayMe", "/static/images/apps/JayMe.jpeg", "3.5.8", 1, "2018-10-01", "2018-11-01"),
-//            new Task(2613, 1489, "和苗智家", "/static/images/apps/hemiaozhijia.png", "1.0.8", 1, "2018-09-22", "2018-09-29"),
-//            new Task(2613, 1489, "邻里快讯", "/static/images/apps/linlikuaixun.png", "2.1.3", 1, "2018-09-18", "2018-09-29"),
-//            new Task(2613, 1489, "探记", "/static/images/apps/tanji.png", "4.1.0", 1, "2018-09-13", "2018-09-22"),
-//            new Task(2973, 1717, "月度赛", "/static/images/apps/tanji.png", "4.1.0", 1, "2018-09-13", "2018-09-22")
-//    );
-
-    @Autowired
-    MasterReportDao masterReportDao;
-
-    @Autowired
-    BugReportService bugReportService;
-
-    @Value("${task.info.addr}")
-    String taskInfoAddr;
-
-    public List<TaskDTO> getAllTasks() {
-        RestTemplate rt = new RestTemplate();
-        StringHttpMessageConverter stringHttpMessageConverter=new StringHttpMessageConverter(Charset.forName("UTF-8"));
-        List<HttpMessageConverter<?>> list=new ArrayList<HttpMessageConverter<?>>();
-        list.add(stringHttpMessageConverter);
-        rt.setMessageConverters(list);
-        JSONObject tasksJson = JSON.parseObject(rt.getForObject(taskInfoAddr, String.class));
-        ListIterator<Object> tasksIter = tasksJson.getJSONArray("data").listIterator();
-
-        List<TaskDTO> dtos = new ArrayList<>();
-        while (tasksIter.hasNext()) {
-            JSONObject taskInfo = (JSONObject) tasksIter.next();
-
-            TaskDTO dto = new TaskDTO();
-            dto.setExamId(Long.parseLong(taskInfo.getString("task_id")));
-            dto.setCaseId(Long.parseLong(taskInfo.getString("case_id")));
-            dto.setName(taskInfo.getString("name"));
-
-            dtos.add(dto);
-        }
-
-        return dtos.stream()
-                .map(taskDTO -> {
-                    long totalBugs = masterReportDao.countByExamIdAndCaseId(taskDTO.getExamId(), taskDTO.getCaseId());
-                    long undealBugs = 0;
-                    if (totalBugs == 0) {
-                        totalBugs = bugReportService.getAllBugs(taskDTO.getExamId(), taskDTO.getCaseId()).size();
-                        undealBugs = totalBugs;
-                    } else {
-                        undealBugs = masterReportDao.countByExamIdAndCaseIdAndStatus(taskDTO.getExamId(), taskDTO.getCaseId(), 0);
-                    }
-                    taskDTO.setNumOfTotalBug(totalBugs);
-                    taskDTO.setNumOfUndeal(undealBugs);
-
-                    return taskDTO;
-                }).sorted(Comparator.comparing(TaskDTO::getExamId).reversed())
-                .collect(Collectors.toList());
-
-    }
-
-    public TaskDTO getByExamIdAndCaseId(long examId, long caseId) {
-        TaskDTO taskDefault = new TaskDTO();
-        taskDefault.setExamId(examId);
-        taskDefault.setCaseId(caseId);
-        taskDefault.setName("no name");
-        List<TaskDTO> tasks = getAllTasks();
-        TaskDTO taskDTO = tasks.stream().filter(task -> task.getExamId() == examId && task.getCaseId() == caseId).findFirst().orElse(taskDefault);
-
-        long totalBugs = masterReportDao.countByExamIdAndCaseId(taskDTO.getExamId(), taskDTO.getCaseId());
-        long undealBugs = 0;
-        if (totalBugs == 0) {
-            totalBugs = bugReportService.getAllBugs(taskDTO.getExamId(), taskDTO.getCaseId()).size();
-            undealBugs = totalBugs;
-        } else {
-            undealBugs = masterReportDao.countByExamIdAndCaseIdAndStatus(taskDTO.getExamId(), taskDTO.getCaseId(), 0);
-        }
-        taskDTO.setNumOfTotalBug(totalBugs);
-        taskDTO.setNumOfUndeal(undealBugs);
-        return taskDTO;
-    }
-}
+package com.mooctest.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.mooctest.dao.MasterReportDao;
+import com.mooctest.data.TaskDTO;
+import com.mooctest.model.Task;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.Charset;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class TaskService {
+//    List<Task> tasks = Arrays.asList(
+//            new Task(2613, 1489, "途牛旅游", "/static/images/apps/tuniu.png", "9.56.0", 0, "2018-11-12", "2018-12-20"),
+//            new Task(2613, 1489, "花田小憩", "/static/images/apps/huatianxiaoqi.png", "6.5.0", 1, "2018-10-12", "2018-10-20"),
+//            new Task(2613, 1489, "小猿搜题", "/static/images/apps/xiaoyuansouti.png", "8.5.0", 1, "2018-10-03", "2018-10-15"),
+//            new Task(2613, 1489, "途牛旅游", "/static/images/apps/tuniu.png", "9.50.0", 1, "2018-10-02", "2018-10-12"),
+//            new Task(2613, 1489, "JayMe", "/static/images/apps/JayMe.jpeg", "3.5.8", 1, "2018-10-01", "2018-11-01"),
+//            new Task(2613, 1489, "和苗智家", "/static/images/apps/hemiaozhijia.png", "1.0.8", 1, "2018-09-22", "2018-09-29"),
+//            new Task(2613, 1489, "邻里快讯", "/static/images/apps/linlikuaixun.png", "2.1.3", 1, "2018-09-18", "2018-09-29"),
+//            new Task(2613, 1489, "探记", "/static/images/apps/tanji.png", "4.1.0", 1, "2018-09-13", "2018-09-22"),
+//            new Task(2973, 1717, "月度赛", "/static/images/apps/tanji.png", "4.1.0", 1, "2018-09-13", "2018-09-22")
+//    );
+
+    @Autowired
+    MasterReportDao masterReportDao;
+
+    @Autowired
+    BugReportService bugReportService;
+
+    @Value("${task.info.addr}")
+    String taskInfoAddr;
+
+    public List<TaskDTO> getAllTasks() {
+        RestTemplate rt = new RestTemplate();
+        StringHttpMessageConverter stringHttpMessageConverter=new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        List<HttpMessageConverter<?>> list=new ArrayList<HttpMessageConverter<?>>();
+        list.add(stringHttpMessageConverter);
+        rt.setMessageConverters(list);
+        JSONObject tasksJson = JSON.parseObject(rt.getForObject(taskInfoAddr, String.class));
+        ListIterator<Object> tasksIter = tasksJson.getJSONArray("data").listIterator();
+
+        List<TaskDTO> dtos = new ArrayList<>();
+        while (tasksIter.hasNext()) {
+            JSONObject taskInfo = (JSONObject) tasksIter.next();
+
+            TaskDTO dto = new TaskDTO();
+            dto.setExamId(Long.parseLong(taskInfo.getString("task_id")));
+            dto.setCaseId(Long.parseLong(taskInfo.getString("case_id")));
+            dto.setName(taskInfo.getString("name"));
+
+            dtos.add(dto);
+        }
+
+        return dtos.stream()
+                .map(taskDTO -> {
+                    long totalBugs = masterReportDao.countByExamIdAndCaseId(taskDTO.getExamId(), taskDTO.getCaseId());
+                    long undealBugs = 0;
+                    if (totalBugs == 0) {
+                        totalBugs = bugReportService.getAllBugs(taskDTO.getExamId(), taskDTO.getCaseId()).size();
+                        undealBugs = totalBugs;
+                    } else {
+                        undealBugs = masterReportDao.countByExamIdAndCaseIdAndStatus(taskDTO.getExamId(), taskDTO.getCaseId(), 0);
+                    }
+                    taskDTO.setNumOfTotalBug(totalBugs);
+                    taskDTO.setNumOfUndeal(undealBugs);
+
+                    return taskDTO;
+                }).sorted(Comparator.comparing(TaskDTO::getExamId).reversed())
+                .collect(Collectors.toList());
+
+    }
+
+    public TaskDTO getByExamIdAndCaseId(long examId, long caseId) {
+        TaskDTO taskDefault = new TaskDTO();
+        taskDefault.setExamId(examId);
+        taskDefault.setCaseId(caseId);
+        taskDefault.setName("no name");
+        List<TaskDTO> tasks = getAllTasks();
+        TaskDTO taskDTO = tasks.stream().filter(task -> task.getExamId() == examId && task.getCaseId() == caseId).findFirst().orElse(taskDefault);
+
+        long totalBugs = masterReportDao.countByExamIdAndCaseId(taskDTO.getExamId(), taskDTO.getCaseId());
+        long undealBugs = 0;
+        if (totalBugs == 0) {
+            totalBugs = bugReportService.getAllBugs(taskDTO.getExamId(), taskDTO.getCaseId()).size();
+            undealBugs = totalBugs;
+        } else {
+            undealBugs = masterReportDao.countByExamIdAndCaseIdAndStatus(taskDTO.getExamId(), taskDTO.getCaseId(), 0);
+        }
+        taskDTO.setNumOfTotalBug(totalBugs);
+        taskDTO.setNumOfUndeal(undealBugs);
+        return taskDTO;
+    }
+}

+ 45 - 45
src/main/java/com/mooctest/service/impl/BugHistoryServiceImpl.java

@@ -1,45 +1,45 @@
-package com.mooctest.service.impl;
-
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.mooctest.data.BugHistoryDTO;
-import com.mooctest.service.BugHistoryService;
-import com.mooctest.util.HttpUtil;
-import com.mooctest.util.MongoAPIUtil;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
-
-import java.util.List;
-
-import static com.mooctest.util.MongoAPIUtil.EMBEDDED_KEY;
-
-@Service
-public class BugHistoryServiceImpl implements BugHistoryService {
-
-    public List<BugHistoryDTO> getBugHistory(List<String> bugIds) {
-
-        HttpHeaders headers = MongoAPIUtil.createAuthHeaderForMongo();
-        HttpEntity<String> entity = new HttpEntity<>(headers);
-
-        String filterStr = MongoAPIUtil.genIdFilterStr(bugIds);
-
-        String url = MongoAPIUtil.genFilterUrlWithMaxPage(MongoAPIUtil.CO_REPORT_DB, MongoAPIUtil.BUG_HISTORY_COLLECTION);
-
-        RestTemplate rt = HttpUtil.getRestTemplate();
-        ResponseEntity<JSONObject> dto = rt.exchange(url, HttpMethod.GET, entity, JSONObject.class, filterStr);
-
-        return extractData(dto.getBody().getJSONArray(EMBEDDED_KEY));
-    }
-
-
-    public List<BugHistoryDTO> extractData(JSONArray jsonArray) {
-        if (jsonArray.size() == 0) {
-            return null;
-        }
-        return jsonArray.toJavaList(BugHistoryDTO.class);
-    }
-}
+package com.mooctest.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.mooctest.data.BugHistoryDTO;
+import com.mooctest.service.BugHistoryService;
+import com.mooctest.util.HttpUtil;
+import com.mooctest.util.MongoAPIUtil;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+
+import static com.mooctest.util.MongoAPIUtil.EMBEDDED_KEY;
+
+@Service
+public class BugHistoryServiceImpl implements BugHistoryService {
+
+    public List<BugHistoryDTO> getBugHistory(List<String> bugIds) {
+
+        HttpHeaders headers = MongoAPIUtil.createAuthHeaderForMongo();
+        HttpEntity<String> entity = new HttpEntity<>(headers);
+
+        String filterStr = MongoAPIUtil.genIdFilterStr(bugIds);
+
+        String url = MongoAPIUtil.genFilterUrlWithMaxPage(MongoAPIUtil.CO_REPORT_DB, MongoAPIUtil.BUG_HISTORY_COLLECTION);
+
+        RestTemplate rt = HttpUtil.getRestTemplate();
+        ResponseEntity<JSONObject> dto = rt.exchange(url, HttpMethod.GET, entity, JSONObject.class, filterStr);
+
+        return extractData(dto.getBody().getJSONArray(EMBEDDED_KEY));
+    }
+
+
+    public List<BugHistoryDTO> extractData(JSONArray jsonArray) {
+        if (jsonArray.size() == 0) {
+            return null;
+        }
+        return jsonArray.toJavaList(BugHistoryDTO.class);
+    }
+}

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio