From c910eecbf6347d2a215353e30222edad8c7f52bb Mon Sep 17 00:00:00 2001
From: guange <8863824@gmail.com>
Date: Thu, 2 Jan 2020 13:52:24 +0800
Subject: [PATCH] init
---
.gitignore | 33 ++
error.csv | 157 +++++++
error.xlsx | 157 +++++++
pom.xml | 104 +++++
post.sh | 1 +
.../educoder/ecsonar/EcsonarApplication.java | 13 +
.../ecsonar/config/ThreadPoolConfig.java | 17 +
.../ecsonar/controller/MainController.java | 38 ++
.../net/educoder/ecsonar/dao/ProjectDao.java | 29 ++
.../net/educoder/ecsonar/model/Metrics.java | 190 ++++++++
.../net/educoder/ecsonar/model/Project.java | 43 ++
.../educoder/ecsonar/model/api/Person.java | 41 ++
.../ecsonar/model/api/ResultRequest.java | 13 +
.../ecsonar/model/api/SonarRequest.java | 34 ++
.../ecsonar/services/EcsonarService.java | 405 ++++++++++++++++++
.../ecsonar/services/ReportService.java | 224 ++++++++++
.../ecsonar/services/SonarService.java | 123 ++++++
.../net/educoder/ecsonar/utils/DateUtils.java | 160 +++++++
.../net/educoder/ecsonar/utils/ExcelUtil.java | 225 ++++++++++
.../net/educoder/ecsonar/utils/FileUtil.java | 33 ++
.../educoder/ecsonar/utils/SystemUtil.java | 76 ++++
.../net/educoder/ecsonar/utils/UrlUtil.java | 73 ++++
src/main/resources/26321-he.xlsx | Bin 0 -> 127943 bytes
src/main/resources/26321.xlsx | Bin 0 -> 112228 bytes
src/main/resources/application.properties | 35 ++
src/main/resources/logback-spring.xml | 42 ++
src/main/resources/template.xlsx | Bin 0 -> 121926 bytes
.../ecsonar/EcsonarApplicationTests.java | 54 +++
test.rb | 18 +
29 files changed, 2338 insertions(+)
create mode 100644 .gitignore
create mode 100644 error.csv
create mode 100644 error.xlsx
create mode 100644 pom.xml
create mode 100644 post.sh
create mode 100644 src/main/java/net/educoder/ecsonar/EcsonarApplication.java
create mode 100644 src/main/java/net/educoder/ecsonar/config/ThreadPoolConfig.java
create mode 100644 src/main/java/net/educoder/ecsonar/controller/MainController.java
create mode 100644 src/main/java/net/educoder/ecsonar/dao/ProjectDao.java
create mode 100644 src/main/java/net/educoder/ecsonar/model/Metrics.java
create mode 100644 src/main/java/net/educoder/ecsonar/model/Project.java
create mode 100644 src/main/java/net/educoder/ecsonar/model/api/Person.java
create mode 100644 src/main/java/net/educoder/ecsonar/model/api/ResultRequest.java
create mode 100644 src/main/java/net/educoder/ecsonar/model/api/SonarRequest.java
create mode 100644 src/main/java/net/educoder/ecsonar/services/EcsonarService.java
create mode 100644 src/main/java/net/educoder/ecsonar/services/ReportService.java
create mode 100644 src/main/java/net/educoder/ecsonar/services/SonarService.java
create mode 100644 src/main/java/net/educoder/ecsonar/utils/DateUtils.java
create mode 100644 src/main/java/net/educoder/ecsonar/utils/ExcelUtil.java
create mode 100644 src/main/java/net/educoder/ecsonar/utils/FileUtil.java
create mode 100644 src/main/java/net/educoder/ecsonar/utils/SystemUtil.java
create mode 100644 src/main/java/net/educoder/ecsonar/utils/UrlUtil.java
create mode 100644 src/main/resources/26321-he.xlsx
create mode 100644 src/main/resources/26321.xlsx
create mode 100644 src/main/resources/application.properties
create mode 100644 src/main/resources/logback-spring.xml
create mode 100644 src/main/resources/template.xlsx
create mode 100644 src/test/java/net/educoder/ecsonar/EcsonarApplicationTests.java
create mode 100644 test.rb
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ed05661
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
+
+### VS Code ###
+.vscode/
+
+.DS_Store
+*.json
+*.log
diff --git a/error.csv b/error.csv
new file mode 100644
index 0000000..30c98a3
--- /dev/null
+++ b/error.csv
@@ -0,0 +1,157 @@
+"2015551306","李明洋","未发现附件"
+"2015551317","佘思博","未发现附件"
+"2015551432","周蓝","未发现附件"
+"2015551407","李绍禹","未发现附件"
+"2015551406","刘蕴泽","未发现附件"
+"2015962037","张鋆","未发现附件"
+"2015962015","邓联杰","未发现附件"
+"2015962039","周铭锐","未发现附件"
+"2015962133","袁凌","未发现附件"
+"2015962125","王芳华","未发现附件"
+"2015962131","易程","未发现附件"
+"2014551331","周敏敏","未发现附件"
+"2014551309","周杨萍","未发现附件"
+"2015962036","张星","未发现附件"
+"2015962011","曹峻源","未发现附件"
+"2015962037","张鋆","未发现附件"
+"2015801008","杨旭","未发现附件"
+"2015962005","林慧","未发现附件"
+"","p79601584","未发现附件"
+"2015962033","肖巨","未发现附件"
+"2015962023","廖广平","未发现附件"
+"2015962039","周铭锐","未发现附件"
+"2015962034","杨坤","未发现附件"
+"2015962031","王耀武","未发现附件"
+"2015551127","符燕群","未发现附件"
+"2015962132","尹李杰","未发现附件"
+"2013960815","李明烈","未发现附件"
+"2015962118","刘清伟","未发现附件"
+"2015962103","刘芳芳","未发现附件"
+"2015551226","张斌","未发现附件"
+"2015962127","吴俊杰","未发现附件"
+"2015551217","陈鑫祯","未发现附件"
+"2015962130","杨旭","未发现附件"
+"2015962115","李德安","未发现附件"
+"","p26485079","未发现附件"
+"2015551220","丁弟","未发现附件"
+"2015551301","殷昌健","未发现附件"
+"","txuboy","未发现附件"
+"2015551216","梁晶","未发现附件"
+"2015551225","周杰","未发现附件"
+"20159200204","阳文献","未发现附件"
+"20159201014","邹子怡","未发现附件"
+"","p57032168","未发现附件"
+"20159201017","朱春霖","未发现附件"
+"2015962102","赖慰锋","未发现附件"
+"20159200205","李泽湘","未发现附件"
+"2015551506","姚金城","未发现附件"
+"","p45037219","未发现附件"
+"","杨奇为","未发现附件"
+"2015551535","ZHUxueyi","未发现附件"
+"edu2015551505","李小庆","未发现附件"
+"2015551619","唐昭敏","未发现附件"
+"","p10928657","未发现附件"
+"2015551614","戴宁","未发现附件"
+"","p80674219","未发现附件"
+"","p25804791","未发现附件"
+"","p95284761","未发现附件"
+"2015551624","白杰","未发现附件"
+"2013551512","柯维隆","未发现附件"
+"2015962036","张星","未发现附件"
+"","m29345816","未发现附件"
+"2015551625","斯海洋","未发现附件"
+"20159200213","黄海兵","未发现附件"
+"","p92780145","未发现附件"
+"2015651103","孟世斌","未发现附件"
+"2015551339","王孟轩","未发现附件"
+"2015551328","肖兰建","未发现附件"
+"2015551335","靳付棋","未发现附件"
+"2015551326","黄趾雄","未发现附件"
+"2015551302","谢伟胜","未发现附件"
+"2015551313","罗钦","未发现附件"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","陈雅丽","检测出错"
+"","周怡","项目文件夹不存在"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","周怡","项目文件夹不存在"
+"","温豪杰","检测出错"
+"","金徽","项目文件夹不存在"
+"","李航","项目文件夹不存在"
+"","李一鸣","项目文件夹不存在"
+""," 董国超","项目文件夹不存在"
+"","李超","项目文件夹不存在"
+"","刘圣凯","项目文件夹不存在"
+"","黄岩珍","项目文件夹不存在"
+"","周为","项目文件夹不存在"
+"","李邓平","项目文件夹不存在"
+"","尹嘉俊","项目文件夹不存在"
+"","殷昌健","项目文件夹不存在"
+"","李小庆","项目文件夹不存在"
+"","李鸿伟","项目文件夹不存在"
+"","胡锦宇","项目文件夹不存在"
+"","陈怀泽","项目文件夹不存在"
+"","高宇博","项目文件夹不存在"
+"","李耀","项目文件夹不存在"
+"","杨帆","项目文件夹不存在"
+"","周蓝","项目文件夹不存在"
+"","梁晶","项目文件夹不存在"
+"","刘洋","项目文件夹不存在"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","周怡","项目文件夹不存在"
+"","金徽","项目文件夹不存在"
+"","李航","项目文件夹不存在"
+"","李一鸣","项目文件夹不存在"
+""," 董国超","项目文件夹不存在"
+"","李超","项目文件夹不存在"
+"","刘圣凯","项目文件夹不存在"
+"","黄岩珍","项目文件夹不存在"
+"","周为","项目文件夹不存在"
+"","李邓平","项目文件夹不存在"
+"","尹嘉俊","项目文件夹不存在"
+"","殷昌健","项目文件夹不存在"
+"","李小庆","项目文件夹不存在"
+"","李鸿伟","项目文件夹不存在"
+"","胡锦宇","项目文件夹不存在"
+"","陈怀泽","项目文件夹不存在"
+"","高宇博","项目文件夹不存在"
+"","李耀","项目文件夹不存在"
+"","杨帆","项目文件夹不存在"
+"","周蓝","项目文件夹不存在"
+"","梁晶","项目文件夹不存在"
+"","刘洋","项目文件夹不存在"
+"","阮会姗","项目文件夹不存在"
+"","毛胤灿","项目文件夹不存在"
+"","张斌","项目文件夹不存在"
+"","王梦媛","项目文件夹不存在"
+"","陈藏宇","项目文件夹不存在"
+"","曾苗","项目文件夹不存在"
+"","吴嘉杰","项目文件夹不存在"
+"","邹昱夫","项目文件夹不存在"
+"","Claudrick","项目文件夹不存在"
+"","肖瀚","项目文件夹不存在"
+"","张萌","项目文件夹不存在"
+"","王芳华","项目文件夹不存在"
+"","赵新阳","项目文件夹不存在"
+"","佘思博","项目文件夹不存在"
+"","王立杰","项目文件夹不存在"
+"","武张浩","项目文件夹不存在"
+"","江杰","项目文件夹不存在"
+"","刘卫","项目文件夹不存在"
+"","唐耀辉","项目文件夹不存在"
+"","李谦","项目文件夹不存在"
+"","李成龙","项目文件夹不存在"
+"","袁双雄","项目文件夹不存在"
+"","赵新宇","项目文件夹不存在"
+"","黄文","项目文件夹不存在"
+"","林滨","项目文件夹不存在"
+"","张铃崎","项目文件夹不存在"
+"","张皓钦","项目文件夹不存在"
+"","袁骏","项目文件夹不存在"
+"","吴俊杰","项目文件夹不存在"
+"","蒋浩","项目文件夹不存在"
diff --git a/error.xlsx b/error.xlsx
new file mode 100644
index 0000000..7fa9f3e
--- /dev/null
+++ b/error.xlsx
@@ -0,0 +1,157 @@
+"2015551306","李明洋","未发现附件"
+"2015551317","佘思博","未发现附件"
+"2015551432","周蓝","未发现附件"
+"2015551407","李绍禹","未发现附件"
+"2015551406","刘蕴泽","未发现附件"
+"2015962037","张鋆","未发现附件"
+"2015962015","邓联杰","未发现附件"
+"2015962039","周铭锐","未发现附件"
+"2015962133","袁凌","未发现附件"
+"2015962125","王芳华","未发现附件"
+"2015962131","易程","未发现附件"
+"2014551331","周敏敏","未发现附件"
+"2014551309","周杨萍","未发现附件"
+"2015962036","张星","未发现附件"
+"2015962011","曹峻源","未发现附件"
+"2015962037","张鋆","未发现附件"
+"2015801008","杨旭","未发现附件"
+"2015962005","林慧","未发现附件"
+"","p79601584","未发现附件"
+"2015962033","肖巨","未发现附件"
+"2015962023","廖广平","未发现附件"
+"2015962039","周铭锐","未发现附件"
+"2015962034","杨坤","未发现附件"
+"2015962031","王耀武","未发现附件"
+"2015551127","符燕群","未发现附件"
+"2015962132","尹李杰","未发现附件"
+"2013960815","李明烈","未发现附件"
+"2015962118","刘清伟","未发现附件"
+"2015962103","刘芳芳","未发现附件"
+"2015551226","张斌","未发现附件"
+"2015962127","吴俊杰","未发现附件"
+"2015551217","陈鑫祯","未发现附件"
+"2015962130","杨旭","未发现附件"
+"2015962115","李德安","未发现附件"
+"","p26485079","未发现附件"
+"2015551220","丁弟","未发现附件"
+"2015551301","殷昌健","未发现附件"
+"","txuboy","未发现附件"
+"2015551216","梁晶","未发现附件"
+"2015551225","周杰","未发现附件"
+"20159200204","阳文献","未发现附件"
+"20159201014","邹子怡","未发现附件"
+"","p57032168","未发现附件"
+"20159201017","朱春霖","未发现附件"
+"2015962102","赖慰锋","未发现附件"
+"20159200205","李泽湘","未发现附件"
+"2015551506","姚金城","未发现附件"
+"","p45037219","未发现附件"
+"","杨奇为","未发现附件"
+"2015551535","ZHUxueyi","未发现附件"
+"edu2015551505","李小庆","未发现附件"
+"2015551619","唐昭敏","未发现附件"
+"","p10928657","未发现附件"
+"2015551614","戴宁","未发现附件"
+"","p80674219","未发现附件"
+"","p25804791","未发现附件"
+"","p95284761","未发现附件"
+"2015551624","白杰","未发现附件"
+"2013551512","柯维隆","未发现附件"
+"2015962036","张星","未发现附件"
+"","m29345816","未发现附件"
+"2015551625","斯海洋","未发现附件"
+"20159200213","黄海兵","未发现附件"
+"","p92780145","未发现附件"
+"2015651103","孟世斌","未发现附件"
+"2015551339","王孟轩","未发现附件"
+"2015551328","肖兰建","未发现附件"
+"2015551335","靳付棋","未发现附件"
+"2015551326","黄趾雄","未发现附件"
+"2015551302","谢伟胜","未发现附件"
+"2015551313","罗钦","未发现附件"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","陈雅丽","Mapper method itive return type (float)."
+"","周怡","项目文件夹不存在"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","周怡","项目文件夹不存在"
+"","温豪杰","连接超时 (Read failed)"
+"","金徽","项目文件夹不存在"
+"","李航","项目文件夹不存在"
+"","李一鸣","项目文件夹不存在"
+""," 董国超","项目文件夹不存在"
+"","李超","项目文件夹不存在"
+"","刘圣凯","项目文件夹不存在"
+"","黄岩珍","项目文件夹不存在"
+"","周为","项目文件夹不存在"
+"","李邓平","项目文件夹不存在"
+"","尹嘉俊","项目文件夹不存在"
+"","殷昌健","项目文件夹不存在"
+"","李小庆","项目文件夹不存在"
+"","李鸿伟","项目文件夹不存在"
+"","胡锦宇","项目文件夹不存在"
+"","陈怀泽","项目文件夹不存在"
+"","高宇博","项目文件夹不存在"
+"","李耀","项目文件夹不存在"
+"","杨帆","项目文件夹不存在"
+"","周蓝","项目文件夹不存在"
+"","梁晶","项目文件夹不存在"
+"","刘洋","项目文件夹不存在"
+"","陶索菲","项目文件夹不存在"
+"","刘振","项目文件夹不存在"
+"","杨志","项目文件夹不存在"
+"","周怡","项目文件夹不存在"
+"","金徽","项目文件夹不存在"
+"","李航","项目文件夹不存在"
+"","李一鸣","项目文件夹不存在"
+""," 董国超","项目文件夹不存在"
+"","李超","项目文件夹不存在"
+"","刘圣凯","项目文件夹不存在"
+"","黄岩珍","项目文件夹不存在"
+"","周为","项目文件夹不存在"
+"","李邓平","项目文件夹不存在"
+"","尹嘉俊","项目文件夹不存在"
+"","殷昌健","项目文件夹不存在"
+"","李小庆","项目文件夹不存在"
+"","李鸿伟","项目文件夹不存在"
+"","胡锦宇","项目文件夹不存在"
+"","陈怀泽","项目文件夹不存在"
+"","高宇博","项目文件夹不存在"
+"","李耀","项目文件夹不存在"
+"","杨帆","项目文件夹不存在"
+"","周蓝","项目文件夹不存在"
+"","梁晶","项目文件夹不存在"
+"","刘洋","项目文件夹不存在"
+"","阮会姗","项目文件夹不存在"
+"","毛胤灿","项目文件夹不存在"
+"","张斌","项目文件夹不存在"
+"","王梦媛","项目文件夹不存在"
+"","陈藏宇","项目文件夹不存在"
+"","曾苗","项目文件夹不存在"
+"","吴嘉杰","项目文件夹不存在"
+"","邹昱夫","项目文件夹不存在"
+"","Claudrick","项目文件夹不存在"
+"","肖瀚","项目文件夹不存在"
+"","张萌","项目文件夹不存在"
+"","王芳华","项目文件夹不存在"
+"","赵新阳","项目文件夹不存在"
+"","佘思博","项目文件夹不存在"
+"","王立杰","项目文件夹不存在"
+"","武张浩","项目文件夹不存在"
+"","江杰","项目文件夹不存在"
+"","刘卫","项目文件夹不存在"
+"","唐耀辉","项目文件夹不存在"
+"","李谦","项目文件夹不存在"
+"","李成龙","项目文件夹不存在"
+"","袁双雄","项目文件夹不存在"
+"","赵新宇","项目文件夹不存在"
+"","黄文","项目文件夹不存在"
+"","林滨","项目文件夹不存在"
+"","张铃崎","项目文件夹不存在"
+"","张皓钦","项目文件夹不存在"
+"","袁骏","项目文件夹不存在"
+"","吴俊杰","项目文件夹不存在"
+"","蒋浩","项目文件夹不存在"
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..8e3af44
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,104 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.5.RELEASE
+
+
+ net.educoder
+ ecsonar
+ 0.0.1
+ ecsonar
+ educoder sonar
+
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.0.1
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.8.1
+
+
+
+
+
+ org.apache.poi
+ poi
+ 3.16
+
+
+ org.apache.poi
+ poi-ooxml
+ 3.14
+
+
+
+ net.sourceforge.jexcelapi
+ jxl
+ 2.6.10
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
+ maven-aliyun
+ maven-aliyun
+ http://maven.aliyun.com/nexus/content/groups/public
+
+
+
+
+
+
+ maven-aliyun
+ maven-aliyun
+ http://maven.aliyun.com/nexus/content/groups/public
+
+
+
+
diff --git a/post.sh b/post.sh
new file mode 100644
index 0000000..08daf5e
--- /dev/null
+++ b/post.sh
@@ -0,0 +1 @@
+cat post1.json | curl -H "Content-Type:application/json" -X POST -d @- http://localhost:8081/api/sonar
diff --git a/src/main/java/net/educoder/ecsonar/EcsonarApplication.java b/src/main/java/net/educoder/ecsonar/EcsonarApplication.java
new file mode 100644
index 0000000..2a74104
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/EcsonarApplication.java
@@ -0,0 +1,13 @@
+package net.educoder.ecsonar;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class EcsonarApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(EcsonarApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/config/ThreadPoolConfig.java b/src/main/java/net/educoder/ecsonar/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..9c4a9ae
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/config/ThreadPoolConfig.java
@@ -0,0 +1,17 @@
+package net.educoder.ecsonar.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Configuration
+public class ThreadPoolConfig {
+
+ @Bean
+ public ExecutorService getThreadPool(){
+ return Executors.newFixedThreadPool(10);
+ }
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/controller/MainController.java b/src/main/java/net/educoder/ecsonar/controller/MainController.java
new file mode 100644
index 0000000..d5cf607
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/controller/MainController.java
@@ -0,0 +1,38 @@
+package net.educoder.ecsonar.controller;
+
+import net.educoder.ecsonar.model.api.SonarRequest;
+import net.educoder.ecsonar.services.EcsonarService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+
+@RestController
+@RequestMapping("/api")
+public class MainController {
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+
+ @Autowired
+ EcsonarService ecsonarService;
+
+ @RequestMapping(value = "/sonar", method = RequestMethod.POST)
+ @CrossOrigin
+ public String sonar(@RequestBody SonarRequest sonarRequest) throws IOException {
+ log.info("sonar: {}", sonarRequest);
+ ecsonarService.sonar(sonarRequest);
+ return "success";
+ }
+
+
+ @RequestMapping(value = "/fit", method = RequestMethod.GET)
+ public String fit(@RequestParam String fileName,
+ @RequestParam String homeworkId) throws Exception {
+ ecsonarService.fit(fileName, homeworkId);
+ return "success";
+ }
+
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/dao/ProjectDao.java b/src/main/java/net/educoder/ecsonar/dao/ProjectDao.java
new file mode 100644
index 0000000..b3635bf
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/dao/ProjectDao.java
@@ -0,0 +1,29 @@
+package net.educoder.ecsonar.dao;
+
+import net.educoder.ecsonar.model.Project;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@Mapper
+public interface ProjectDao {
+
+ @Select("select * from projects where name = #{name}")
+ Project findByName(@Param("name")String name);
+
+
+ @Select("select COALESCE(value,0) from project_measures where component_uuid = #{uuid} and metric_id = 19 order by id desc limit 1")
+ float getComplexity(@Param("uuid") String uuid);
+
+ @Select("select COALESCE(value,0) from project_measures where component_uuid = #{uuid} and metric_id = 1 order by id desc limit 1")
+ int getLines(@Param("uuid") String uuid);
+
+ @Select("select text_value from project_measures where component_uuid = #{uuid} and metric_id = #{metric_id} order by id desc limit 1")
+ String getLevel(@Param("uuid") String uuid, @Param("metric_id") int metric_id);
+
+ @Select("SELECT count(*) FROM issues where project_uuid=#{uuid} and " +
+ "status='OPEN' and issue_type=#{issue_type} and severity=#{severity}")
+ int getIndicator(@Param("uuid") String uuid, @Param("issue_type") int issue_type, @Param("severity") String severity);
+}
diff --git a/src/main/java/net/educoder/ecsonar/model/Metrics.java b/src/main/java/net/educoder/ecsonar/model/Metrics.java
new file mode 100644
index 0000000..dfaf52c
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/model/Metrics.java
@@ -0,0 +1,190 @@
+package net.educoder.ecsonar.model;
+
+public class Metrics {
+
+ private String complexity;
+
+ private int lines;
+
+ //漏洞
+ private int block_violations;
+ private int critical_violations;
+ private int major_violations;
+ private int minor_violations;
+ private String violations;
+
+
+ //缺陷
+ private int block_bugs;
+ private int critical_bugs;
+ private int major_bugs;
+ private int minor_bugs;
+ private String bugs;
+
+ //代码风格
+ private int block_code_smells;
+ private int critical_code_smells;
+ private int major_code_smells;
+ private int minor_code_smells;
+ private String code_smells;
+
+
+ public String getComplexity() {
+ return complexity;
+ }
+
+ public void setComplexity(String complexity) {
+ this.complexity = complexity;
+ }
+
+ public int getLines() {
+ return lines;
+ }
+
+ public void setLines(int lines) {
+ this.lines = lines;
+ }
+
+ public int getBlock_violations() {
+ return block_violations;
+ }
+
+ public void setBlock_violations(int block_violations) {
+ this.block_violations = block_violations;
+ }
+
+ public int getCritical_violations() {
+ return critical_violations;
+ }
+
+ public void setCritical_violations(int critical_violations) {
+ this.critical_violations = critical_violations;
+ }
+
+ public int getMajor_violations() {
+ return major_violations;
+ }
+
+ public void setMajor_violations(int major_violations) {
+ this.major_violations = major_violations;
+ }
+
+ public int getMinor_violations() {
+ return minor_violations;
+ }
+
+ public void setMinor_violations(int minor_violations) {
+ this.minor_violations = minor_violations;
+ }
+
+ public String getViolations() {
+ return violations;
+ }
+
+ public void setViolations(String violations) {
+ this.violations = violations;
+ }
+
+ public int getBlock_bugs() {
+ return block_bugs;
+ }
+
+ public void setBlock_bugs(int block_bugs) {
+ this.block_bugs = block_bugs;
+ }
+
+ public int getCritical_bugs() {
+ return critical_bugs;
+ }
+
+ public void setCritical_bugs(int critical_bugs) {
+ this.critical_bugs = critical_bugs;
+ }
+
+ public int getMajor_bugs() {
+ return major_bugs;
+ }
+
+ public void setMajor_bugs(int major_bugs) {
+ this.major_bugs = major_bugs;
+ }
+
+ public int getMinor_bugs() {
+ return minor_bugs;
+ }
+
+ public void setMinor_bugs(int minor_bugs) {
+ this.minor_bugs = minor_bugs;
+ }
+
+ public String getBugs() {
+ return bugs;
+ }
+
+ public void setBugs(String bugs) {
+ this.bugs = bugs;
+ }
+
+ public int getBlock_code_smells() {
+ return block_code_smells;
+ }
+
+ public void setBlock_code_smells(int block_code_smells) {
+ this.block_code_smells = block_code_smells;
+ }
+
+ public int getCritical_code_smells() {
+ return critical_code_smells;
+ }
+
+ public void setCritical_code_smells(int critical_code_smells) {
+ this.critical_code_smells = critical_code_smells;
+ }
+
+ public int getMajor_code_smells() {
+ return major_code_smells;
+ }
+
+ public void setMajor_code_smells(int major_code_smells) {
+ this.major_code_smells = major_code_smells;
+ }
+
+ public int getMinor_code_smells() {
+ return minor_code_smells;
+ }
+
+ public void setMinor_code_smells(int minor_code_smells) {
+ this.minor_code_smells = minor_code_smells;
+ }
+
+ public String getCode_smells() {
+ return code_smells;
+ }
+
+ public void setCode_smells(String code_smells) {
+ this.code_smells = code_smells;
+ }
+
+ @Override
+ public String toString() {
+ return "Metrics{" +
+ "complexity='" + complexity + '\'' +
+ ", lines=" + lines +
+ ", block_violations=" + block_violations +
+ ", critical_violations=" + critical_violations +
+ ", major_violations=" + major_violations +
+ ", minor_violations=" + minor_violations +
+ ", violations='" + violations + '\'' +
+ ", block_bugs=" + block_bugs +
+ ", critical_bugs=" + critical_bugs +
+ ", major_bugs=" + major_bugs +
+ ", minor_bugs=" + minor_bugs +
+ ", bugs='" + bugs + '\'' +
+ ", block_code_smells=" + block_code_smells +
+ ", critical_code_smells=" + critical_code_smells +
+ ", major_code_smells=" + major_code_smells +
+ ", minor_code_smells=" + minor_code_smells +
+ ", code_smells='" + code_smells + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/model/Project.java b/src/main/java/net/educoder/ecsonar/model/Project.java
new file mode 100644
index 0000000..96e5855
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/model/Project.java
@@ -0,0 +1,43 @@
+package net.educoder.ecsonar.model;
+
+
+public class Project {
+ private int id;
+
+ private boolean enabled;
+
+ private String project_uuid;
+ private String name;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getProject_uuid() {
+ return project_uuid;
+ }
+
+ public void setProject_uuid(String project_uuid) {
+ this.project_uuid = project_uuid;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/model/api/Person.java b/src/main/java/net/educoder/ecsonar/model/api/Person.java
new file mode 100644
index 0000000..a8d831e
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/model/api/Person.java
@@ -0,0 +1,41 @@
+package net.educoder.ecsonar.model.api;
+
+public class Person {
+ private String uid;
+ private String name;
+ private String downloadUrl;
+
+
+ public String getUid() {
+ return uid;
+ }
+
+ public void setUid(String uid) {
+ this.uid = uid;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDownloadUrl() {
+ return downloadUrl;
+ }
+
+ public void setDownloadUrl(String downloadUrl) {
+ this.downloadUrl = downloadUrl;
+ }
+
+ @Override
+ public String toString() {
+ return "Person{" +
+ "uid='" + uid + '\'' +
+ ", name='" + name + '\'' +
+ ", downloadUrl='" + downloadUrl + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/model/api/ResultRequest.java b/src/main/java/net/educoder/ecsonar/model/api/ResultRequest.java
new file mode 100644
index 0000000..39fefee
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/model/api/ResultRequest.java
@@ -0,0 +1,13 @@
+package net.educoder.ecsonar.model.api;
+
+public class ResultRequest {
+ private int homeworkId;
+
+ public int getHomeworkId() {
+ return homeworkId;
+ }
+
+ public void setHomeworkId(int homeworkId) {
+ this.homeworkId = homeworkId;
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/model/api/SonarRequest.java b/src/main/java/net/educoder/ecsonar/model/api/SonarRequest.java
new file mode 100644
index 0000000..0a287a9
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/model/api/SonarRequest.java
@@ -0,0 +1,34 @@
+package net.educoder.ecsonar.model.api;
+
+import java.util.List;
+
+public class SonarRequest {
+ private int homeworkId;
+
+ private List personList;
+
+ public List getPersonList() {
+ return personList;
+ }
+
+ public void setPersonList(List personList) {
+ this.personList = personList;
+ }
+
+ public int getHomeworkId() {
+ return homeworkId;
+ }
+
+ public void setHomeworkId(int homeworkId) {
+ this.homeworkId = homeworkId;
+ }
+
+
+ @Override
+ public String toString() {
+ return "SonarRequest{" +
+ "homeworkId=" + homeworkId +
+ ", personList=" + personList +
+ '}';
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/services/EcsonarService.java b/src/main/java/net/educoder/ecsonar/services/EcsonarService.java
new file mode 100644
index 0000000..aa82f38
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/services/EcsonarService.java
@@ -0,0 +1,405 @@
+package net.educoder.ecsonar.services;
+
+
+import net.educoder.ecsonar.dao.ProjectDao;
+import net.educoder.ecsonar.model.Metrics;
+import net.educoder.ecsonar.model.Project;
+import net.educoder.ecsonar.model.api.Person;
+import net.educoder.ecsonar.model.api.SonarRequest;
+import net.educoder.ecsonar.utils.FileUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+@Service
+public class EcsonarService {
+
+ Logger log = LoggerFactory.getLogger(getClass());
+
+ @Autowired
+ private ExecutorService executorService;
+
+ @Autowired
+ ProjectDao projectDao;
+
+ @Autowired
+ SonarService sonarService;
+
+ @Autowired
+ ReportService reportService;
+
+ @Value("${zip.save.path}")
+ String zipSavePath;
+
+ @Value("${force.parse:false}")
+ boolean forceParse;
+
+
+
+ public static class Row {
+ public int i;
+ public Person person;
+ public String key;
+ }
+
+ public void sonar(SonarRequest sonarRequest) {
+ String zipUsePath = String.format("%s%d/", zipSavePath, sonarRequest.getHomeworkId());
+
+ if (!new File(zipUsePath).exists()) {
+ new File(zipUsePath).mkdir();
+ }
+
+ String csvPath = zipUsePath + String.format("%d.csv", sonarRequest.getHomeworkId());
+
+ List uids = readAllUids(csvPath);
+
+ List rows = new ArrayList<>();
+
+ executorService.execute(() -> {
+ int i = 0;
+ for (Person person : sonarRequest.getPersonList()) {
+ i++;
+
+ //数据库如果有就不检测了
+
+ log.info("{}/{} 开始处理: {} ", i, sonarRequest.getPersonList().size(), person);
+ if (person.getDownloadUrl().startsWith("http")) {
+ try {
+ //毕业设计项目完整代码
+
+ String key = String.format("%d-%s", sonarRequest.getHomeworkId(), person.getUid());
+ if (forceParse || (!isChecked(uids, person.getUid())) ) {
+
+
+ Row row = new Row();
+ row.i = i;
+ row.key = key;
+ row.person = person;
+ rows.add(row);
+
+
+ if (isSonared(key)){
+ writeResult(csvPath, row.i, row.person, row.key);
+ } else {
+ sonarService.scan(
+ zipUsePath,
+ person.getDownloadUrl(),
+ sonarRequest.getHomeworkId(),
+ person.getUid(), 1);
+
+ //毕业设计项目个人开发代码
+ sonarService.scan(
+ zipUsePath,
+ person.getDownloadUrl(),
+ sonarRequest.getHomeworkId(),
+ person.getUid(),
+ 2);
+
+
+ writeResult(csvPath, row.i, row.person, row.key);
+ }
+ }
+
+ } catch (Exception e) {
+ log.error("sonar scan error: ", e);
+ log.error("检测出错: {}-{}, 原因: {}",
+ person.getName(),
+ person.getUid(),
+ e.getMessage());
+
+ writeFailResult(csvPath, i, person, e.getMessage());
+ }
+
+
+ } else {
+ log.error("未发现附件:{}", person);
+ writeFailResult(csvPath, i, person, "没有上传附件");
+ }
+ }
+
+
+ });
+ }
+
+ /**
+ * 是否提交过sonar结果
+ * @param key
+ * @return
+ */
+ private boolean isSonared(String key) {
+ Project project = projectDao.findByName(key+"-2");
+ return project!=null;
+ }
+
+ private void writeFailResult(String filePath, int i, Person person, String message) {
+ try {
+ StringBuffer stringBuffer = getFailString(i, person, message);
+
+ FileWriter fileWritter = new FileWriter(filePath, true);
+ fileWritter.write(stringBuffer.toString());
+ fileWritter.close();
+ } catch (Exception e) {
+ log.error("文件写入出错: {}-{}, 原因: {}",
+ person.getName(),
+ person.getUid(),
+ e.getMessage());
+ }
+ }
+
+ private StringBuffer getFailString(int i, Person person, String message) {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append(i);
+ stringBuffer.append(",");
+ stringBuffer.append(person.getUid());
+ stringBuffer.append(",");
+ stringBuffer.append(person.getName());
+ stringBuffer.append(",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,");
+ stringBuffer.append(message);
+ stringBuffer.append("\n");
+ return stringBuffer;
+ }
+
+ private void writeResult(String filePath, int i, Person person, String key) {
+ try {
+ StringBuffer stringBuffer = getPersonLine(i, person, key);
+
+
+ FileWriter fileWritter = new FileWriter(filePath, true);
+ fileWritter.write(stringBuffer.toString());
+ fileWritter.close();
+ } catch (Exception e) {
+ log.error("文件写入出错: {}-{}, 原因: {}",
+ person.getName(),
+ person.getUid(),
+ e.getMessage());
+
+ writeFailResult(filePath, i, person, e.getMessage());
+ }
+ }
+
+ private StringBuffer getPersonLine(int i, Person person, String key) {
+ Metrics metrics = reportService.getMetrics(key + "-1");
+
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append(i);
+ stringBuffer.append(",");
+ stringBuffer.append(person.getUid());
+ stringBuffer.append(",");
+ stringBuffer.append(person.getName());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getViolations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCode_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getComplexity());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getLines());
+
+
+ metrics = reportService.getMetrics(key + "-2");
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_bugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBugs());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getViolations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getBlock_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCritical_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMajor_violations());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getMinor_code_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getCode_smells());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getComplexity());
+ stringBuffer.append(",");
+ stringBuffer.append(metrics.getLines());
+ stringBuffer.append("\n");
+ return stringBuffer;
+ }
+
+ private boolean isChecked(List uids, String uid) {
+ for (String s : uids) {
+ if (StringUtils.equals(s, uid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 读取所有的uid
+ *
+ * @param csvPath
+ * @return
+ */
+ private List readAllUids(String csvPath) {
+ List objects = new ArrayList<>();
+
+ if (!new File(csvPath).exists()) return objects;
+
+ try {
+ // 使用一个字符串集合来存储文本中的路径 ,也可用String []数组
+ FileInputStream fis = new FileInputStream(csvPath);
+ // 防止路径乱码 如果utf-8 乱码 改GBK eclipse里创建的txt 用UTF-8,在电脑上自己创建的txt 用GBK
+ InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
+ BufferedReader br = new BufferedReader(isr);
+ String line = "";
+ while ((line = br.readLine()) != null) {
+ String[] split = line.split(",");
+ if (split.length > 1) {
+ objects.add(split[1]);
+ }
+ }
+ br.close();
+ isr.close();
+ fis.close();
+ } catch (Exception e) {
+ log.error("读取uids出错", e);
+ }
+
+ return objects;
+ }
+
+
+ /**
+ * 修正已有的结果
+ * @param fileName
+ */
+ public void fit(String fileName, String homeworkId) throws Exception {
+ String filePath = String.format("%s%s", zipSavePath, fileName);
+ if(!new File(filePath).exists()){
+ throw new Exception("找不到文件:"+filePath);
+ }
+
+
+ List lines = new ArrayList<>();
+
+ try {
+ // 使用一个字符串集合来存储文本中的路径 ,也可用String []数组
+ FileInputStream fis = new FileInputStream(filePath);
+ // 防止路径乱码 如果utf-8 乱码 改GBK eclipse里创建的txt 用UTF-8,在电脑上自己创建的txt 用GBK
+ InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
+ BufferedReader br = new BufferedReader(isr);
+ String line = "";
+ while ((line = br.readLine()) != null) {
+ String[] split = line.split(",");
+
+ if (split.length<3){
+ continue;
+ }
+
+ Person person = new Person();
+ person.setUid(split[1]);
+ person.setName(split[2]);
+
+ int i = Integer.parseInt(split[0]);
+
+ String key = String.format("%s-%s", homeworkId, split[1]);
+
+ if (StringUtils.isNoneEmpty(split[3])) { //有结果
+ //修正结果
+
+ log.info("开始处理: {}", key);
+
+ StringBuffer stringBuffer = getPersonLine(
+ i,
+ person,
+ key
+ );
+ lines.add(stringBuffer.toString());
+ } else {
+ log.info("重新找查: {}", key);
+ try{
+ StringBuffer stringBuffer = getPersonLine(
+ i,
+ person,
+ key
+ );
+ lines.add(stringBuffer.toString());
+ } catch (Exception e){
+ StringBuffer failString = getFailString(i, person, split[split.length - 1]);
+ lines.add(failString.toString());
+ }
+
+ }
+
+ }
+ br.close();
+ isr.close();
+ fis.close();
+ } catch (Exception e) {
+ log.error("读取uids出错", e);
+ }
+
+ //重新写正确结果
+ String newFilePath = String.format("%s%s.new", zipSavePath, fileName);
+ try {
+ FileWriter fileWritter = new FileWriter(newFilePath, true);
+
+ for (String line : lines) {
+ fileWritter.write(line);
+ }
+
+ fileWritter.close();
+ } catch (Exception e) {
+ log.error("文件写入出错 原因: {}",
+ e.getMessage());
+
+ }
+
+
+ }
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/services/ReportService.java b/src/main/java/net/educoder/ecsonar/services/ReportService.java
new file mode 100644
index 0000000..999977a
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/services/ReportService.java
@@ -0,0 +1,224 @@
+package net.educoder.ecsonar.services;
+
+import net.educoder.ecsonar.dao.ProjectDao;
+import net.educoder.ecsonar.model.Metrics;
+import net.educoder.ecsonar.model.Project;
+import net.educoder.ecsonar.utils.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+@Service
+public class ReportService {
+
+ @Autowired
+ ProjectDao projectDao;
+
+
+ /**
+ * 获取分析指标数据
+ *
+ * @param name
+ * @return
+ */
+ public Metrics getMetrics(String name) {
+ Project project = projectDao.findByName(name);
+ if (project==null){
+ return null;
+ }
+ String uuid = project.getProject_uuid();
+
+ Metrics metrics = new Metrics();
+ metrics.setComplexity(getComplexity(uuid));
+ metrics.setLines(getLines(uuid));
+ metrics.setBlock_bugs(getBlockBugs(uuid));
+ metrics.setBlock_code_smells(getBlockCodeSmells(uuid));
+ metrics.setBlock_violations(getBlockViolations(uuid));
+ metrics.setCritical_bugs(getCriticalBugs(uuid));
+ metrics.setCritical_code_smells(getCriticalCodeSmells(uuid));
+ metrics.setCritical_violations(getCriticalViolations(uuid));
+ metrics.setMajor_bugs(getMajorBugs(uuid));
+ metrics.setMajor_code_smells(getMajorCodeSmells(uuid));
+ metrics.setMajor_violations(getMajorViolations(uuid));
+ metrics.setMinor_bugs(getMinorBugs(uuid));
+ metrics.setMinor_code_smells(getMinorCodeSmells(uuid));
+ metrics.setMinor_violations(getMinorViolations(uuid));
+ metrics.setBugs(getBugs(uuid));
+ metrics.setViolations(getViolations(uuid));
+ metrics.setCode_smells(getCodeSmells(uuid));
+
+ return metrics;
+ }
+
+
+ /**
+ * 将结果写进excel
+ *
+ * @param metrics
+ */
+ public void writeToExcel(String stuId, String name,
+ Metrics metrics, String excelPath, int index) throws IOException {
+// ExcelUtil.writeMetrics(metrics, stuId, name, excelPath, index);
+ }
+
+ /**
+ * 获取复杂度
+ *
+ * @return
+ */
+ private String getComplexity(String uuid) {
+ return "" + projectDao.getComplexity(uuid);
+ }
+
+
+ /**
+ * 获取总行数
+ *
+ * @return
+ */
+ private int getLines(String uuid) {
+ return projectDao.getLines(uuid);
+ }
+
+ /**
+ * 漏洞-阻断
+ *
+ * @return
+ */
+ private int getBlockViolations(String uuid) {
+ return projectDao.getIndicator(uuid, 3, "BLOCKER");
+ }
+
+ /**
+ * 漏洞-严重
+ *
+ * @return
+ */
+ private int getCriticalViolations(String uuid) {
+ return projectDao.getIndicator(uuid, 3, "CRITICAL");
+ }
+
+ /**
+ * 漏洞-主要
+ *
+ * @return
+ */
+ private int getMajorViolations(String uuid) {
+ return projectDao.getIndicator(uuid, 3, "MAJOR");
+ }
+
+ /**
+ * 漏洞-次要
+ *
+ * @return
+ */
+ private int getMinorViolations(String uuid) {
+ return projectDao.getIndicator(uuid, 3, "MINOR");
+
+ }
+
+ /**
+ * 漏洞-等级
+ *
+ * @return
+ */
+ private String getViolations(String uuid) {
+ //93
+ return projectDao.getLevel(uuid, 93);
+ }
+
+
+ /**
+ * 缺陷-阻断
+ *
+ * @return
+ */
+ private int getBlockBugs(String uuid) {
+ return projectDao.getIndicator(uuid, 2, "BLOCKER");
+ }
+
+ /**
+ * 缺陷-严重
+ *
+ * @return
+ */
+ private int getCriticalBugs(String uuid) {
+ return projectDao.getIndicator(uuid, 2, "CRITICAL");
+ }
+
+ /**
+ * 缺陷-主要
+ *
+ * @return
+ */
+ private int getMajorBugs(String uuid) {
+ return projectDao.getIndicator(uuid, 2, "MAJOR");
+ }
+
+ /**
+ * 缺陷-次要
+ *
+ * @return
+ */
+ private int getMinorBugs(String uuid) {
+ return projectDao.getIndicator(uuid, 2, "MINOR");
+ }
+
+ /**
+ * 缺陷-等级
+ *
+ * @return
+ */
+ private String getBugs(String uuid) {
+ //89
+ return projectDao.getLevel(uuid, 89);
+ }
+
+
+ /**
+ * 缺陷-阻断
+ *
+ * @return
+ */
+ private int getBlockCodeSmells(String uuid) {
+ return projectDao.getIndicator(uuid, 1, "BLOCKER");
+ }
+
+ /**
+ * 缺陷-严重
+ *
+ * @return
+ */
+ private int getCriticalCodeSmells(String uuid) {
+ return projectDao.getIndicator(uuid, 1, "CRITICAL");
+ }
+
+ /**
+ * 缺陷-主要
+ *
+ * @return
+ */
+ private int getMajorCodeSmells(String uuid) {
+ return projectDao.getIndicator(uuid, 1, "MAJOR");
+ }
+
+ /**
+ * 缺陷-次要
+ *
+ * @return
+ */
+ private int getMinorCodeSmells(String uuid) {
+ return projectDao.getIndicator(uuid, 1, "MINOR");
+ }
+
+ /**
+ * 缺陷-等级
+ *
+ * @return
+ */
+ private String getCodeSmells(String uuid) {
+ //80
+ return projectDao.getLevel(uuid, 80);
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/services/SonarService.java b/src/main/java/net/educoder/ecsonar/services/SonarService.java
new file mode 100644
index 0000000..0ba8068
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/services/SonarService.java
@@ -0,0 +1,123 @@
+package net.educoder.ecsonar.services;
+
+
+import net.educoder.ecsonar.utils.SystemUtil;
+import net.educoder.ecsonar.utils.UrlUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+
+@Service
+public class SonarService {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+
+ @Value("${sonar.url}")
+ String sonarUrl;
+
+ @Value("${extract.path}")
+ String extractProgramPath;
+
+ /**
+ * 提交一个任务
+ *
+ * @param zipUrl
+ */
+ public String scan(String zipSavePath, String zipUrl, int homeworkId, String uid, int index) throws Exception {
+ String key = String.format("%d-%s", homeworkId, uid);
+
+ String[] split = StringUtils.split(zipUrl, "/");
+
+ String zipFilename = UrlUtil.getURLDecoderString(split[split.length - 1]);
+ String savePath = zipSavePath + zipFilename;
+
+ //1. 下载文件
+ if (index==1) {
+ download(zipUrl, savePath);
+ }
+
+ //2. 解压目录
+ String extractPath = zipSavePath + key;
+ if (index==1) {
+ extract(savePath, extractPath);
+ }
+
+ //3. 执行检测
+ String subPath = "/" + zipFilename.substring(0, zipFilename.length()-4) ;
+ if (index != 1) {
+ subPath += "/毕业设计项目个人开发代码";
+ } else {
+ subPath += "/毕业设计项目完整代码";
+ }
+
+ if (!new File(extractPath + subPath).exists()){
+ throw new Exception("项目文件夹不存在");
+ }
+
+
+ key = String.format("%s-%d", key, index);
+
+ sonar(extractPath + subPath, key);
+
+ return key;
+ }
+
+
+ private void sonar(String projectPath, String key) {
+ SystemUtil.executeAndGetExitStatus("sonar-scanner " +
+ "-Dsonar.host.url=" + sonarUrl + " " +
+ "-Dsonar.sourceEncoding=utf-8 " +
+ "-Dsonar.projectKey=" + key + " " +
+ "-Dsonar.java.binaries=./ "+
+ "-Dsonar.projectBaseDir=" + projectPath);
+ }
+
+
+ /**
+ * 解压zip文件
+ *
+ * @param zipFile
+ */
+ private void extract(String zipFile, String extractPath) throws Exception {
+ File extractFile = new File(extractPath);
+ if (extractFile.exists()){
+ extractFile.delete();
+ }
+ extractFile.mkdir();
+
+ SystemUtil.ExecuteResp executeResp = SystemUtil.executeAndGetExitStatus("cd "
+ + extractPath
+ + " && "+extractProgramPath+" -encoding GBK " + zipFile);
+ }
+
+ /**
+ * 下载文件
+ *
+ * @param zipUrl
+ */
+ private void download(String zipUrl, String zipPath) throws IOException {
+ log.debug("下载文件: {}-{}", zipUrl, zipPath);
+
+ try (BufferedInputStream in = new BufferedInputStream(new URL(zipUrl).openStream());
+ FileOutputStream fileOutputStream = new FileOutputStream(zipPath)) {
+ byte dataBuffer[] = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
+ fileOutputStream.write(dataBuffer, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ log.error("文件下载失败: {}-{}", zipUrl, zipPath);
+ throw e;
+ }
+
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/utils/DateUtils.java b/src/main/java/net/educoder/ecsonar/utils/DateUtils.java
new file mode 100644
index 0000000..ecbcffd
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/utils/DateUtils.java
@@ -0,0 +1,160 @@
+package net.educoder.ecsonar.utils;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.ZoneId;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * mapper.stylefeng.guns.modular.lendchain.utils
+ *
+ * 日期工具类
+ * dell
+ * 2018/5/22 11:53
+ */
+
+public class DateUtils {
+
+
+ /**
+ * 日期加减
+ * @param date
+ * @param days
+ * @return
+ */
+ public static final Integer addDays(Integer date ,Integer days){
+ int resultDate = 0;
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
+ try {
+ Date date2 = simpleDateFormat.parse(date.toString());
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date2);
+ calendar.add(Calendar.DATE,days);
+ resultDate = Integer.valueOf(simpleDateFormat.format(calendar.getTime().getTime()));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return resultDate;
+ }
+
+
+
+ public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+
+ //获取年月日时分(H:24小时制,h:12小时制)
+ public static SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyyMMddHHmm");
+ //获取秒
+ public static SimpleDateFormat dateFormat3 = new SimpleDateFormat("ss");
+
+
+
+
+
+ /**
+ * @Description: 获取当日的开始时间戳
+ * @Method:
+ * @Param:
+ * @return:
+ * @throws:
+ * @Author:
+ * @Date: 2018/5/22 9:47
+ */
+ public static Long getStartTime(){
+ long startTime = (System.currentTimeMillis()/86400000 )*86400000 - 8*60*60*1000;
+ return startTime / 1000;
+ }
+
+ /**
+ * @Description: 获取当日的截止时间戳
+ * @Method:
+ * @Param:
+ * @return:
+ * @throws:
+ * @Author:
+ * @Date: 2018/5/22 9:47
+ */
+ public static Long getEndTime(){
+ long endTime = (System.currentTimeMillis()/86400000 )*86400000 - 8*60*60*1000 + 86400000;
+ return endTime / 1000;
+ }
+
+
+
+ /**
+ * 根据Unix时间戳获取时间字符串
+ * @param unixTimestamp
+ * @return
+ */
+ public static String formatDate(Integer unixTimestamp){
+ return getDateByTimestamp(unixTimestamp,"yyyy-MM-dd HH:mm:ss","Asia/Shanghai");
+ }
+
+ public static String formatDate(Date date){
+ SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
+ ZoneId zid = ZoneId.of("Asia/Shanghai");
+ sd.setTimeZone(TimeZone.getTimeZone(zid));
+ return sd.format(date);
+ }
+
+ /**
+ * 根据Unix时间戳获取时间字符串
+ * @param unixTimestamp
+ * @param format
+ * @return
+ */
+ public static String formatDate(Integer unixTimestamp,String format){
+ return getDateByTimestamp(unixTimestamp,format,"Asia/Shanghai");
+ }
+
+ /**
+ * 根据Unix时间戳获取时间字符串
+ * @param unixTimestamp
+ * @param format
+ * @param zone
+ * @return
+ */
+ public static String getDateByTimestamp(Integer unixTimestamp, String format, String zone){
+ SimpleDateFormat sd = new SimpleDateFormat(format);
+ ZoneId zid = ZoneId.of(zone);
+ sd.setTimeZone(TimeZone.getTimeZone(zid));
+ Long create_time = ((long)unixTimestamp)* 1000;
+ return sd.format(new Date(create_time));
+ }
+
+
+ /**
+ * 日期加减
+ * @param timestamp
+ * @param minutes
+ * @return
+ */
+ public static final String addMinutes(String timestamp ,Integer minutes){
+ String resultDate = "";
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ try {
+ Date date2 = simpleDateFormat.parse(timestamp);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date2);
+ calendar.add(Calendar.MINUTE,minutes);
+ resultDate = simpleDateFormat.format(calendar.getTime().getTime());
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return resultDate;
+ }
+
+ public static final String addMin(String timestamp ,Integer minutes){
+ String resultDate = "";
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ try {
+ Date date2 = simpleDateFormat.parse(timestamp);
+ System.out.println("格式化后的日期为:"+date2);
+ resultDate = String.valueOf(date2.getTime()/1000);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return resultDate;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/educoder/ecsonar/utils/ExcelUtil.java b/src/main/java/net/educoder/ecsonar/utils/ExcelUtil.java
new file mode 100644
index 0000000..d93d77f
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/utils/ExcelUtil.java
@@ -0,0 +1,225 @@
+package net.educoder.ecsonar.utils;
+
+import net.educoder.ecsonar.model.Metrics;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import java.io.*;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelUtil {
+
+
+ private static final String EXCEL_XLS = "xls";
+ private static final String EXCEL_XLSX = "xlsx";
+
+
+ /**
+ * 检查此用户是否查验过
+ *
+ * @param excelPath
+ * @param uid
+ * @return
+ */
+ public static boolean isChecked(String excelPath, String uid) {
+ try {
+ File finalXlsxFile = new File(excelPath);
+ Workbook workBook = getWorkbok(finalXlsxFile);
+ Sheet sheet = workBook.getSheetAt(0);
+ int rowNumber = sheet.getLastRowNum();
+ for (int i = 0; i < rowNumber + 1; ++i) {
+ Row row = sheet.getRow(3 + i);
+ Cell cell = row.getCell(1);
+ cell.setCellType(Cell.CELL_TYPE_STRING);
+ if (StringUtils.equals(cell.getStringCellValue(), uid)) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ return false;
+ }
+
+ return false;
+ }
+
+ public static Workbook openExcel(String excelPath) throws IOException {
+ // 读取Excel文档
+ File finalXlsxFile = new File(excelPath);
+ Workbook workBook = getWorkbok(finalXlsxFile);
+
+ return workBook;
+ }
+
+ public static void writeMetrics(Metrics metrics, String uid,
+ String name,
+ Workbook workBook, int index) throws IOException {
+
+
+ // sheet 对应一个工作页
+ Sheet sheet = workBook.getSheetAt(0);
+ /**
+ * 删除原有数据,除了属性列
+ */
+ int rowNumber = sheet.getLastRowNum(); // 第一行从0开始算
+
+ //从第三行开始
+ Row newRow = null;
+
+ for (int i = 0; i < rowNumber+1; ++i) {
+ Row row = sheet.getRow(i);
+
+ if (row != null) {
+ Cell cell = row.getCell(1);
+ cell.setCellType(Cell.CELL_TYPE_STRING);
+ if (StringUtils.isEmpty(cell.getStringCellValue())
+ || StringUtils.equals(cell.getStringCellValue(), uid)) {
+
+ newRow = row;
+ break;
+ }
+ }
+ }
+
+ if (newRow == null) {
+ newRow = sheet.createRow(rowNumber+1);
+ }
+
+ //一直往下找,直到找到空的,或者与学号匹配的行,进行写入
+ //学号
+ Cell uidCell = newRow.createCell(1);
+ uidCell.setCellType(Cell.CELL_TYPE_STRING);
+ uidCell.setCellValue(uid);
+
+ Cell cell2 = newRow.createCell(2);
+ cell2.setCellType(Cell.CELL_TYPE_STRING);
+ cell2.setCellValue(name);
+
+ int offset = 0;
+ if (index == 2) {
+ offset = 17;
+ }
+ Cell cell3 = newRow.createCell(3 + offset);
+ cell3.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell3.setCellValue(metrics.getBlock_bugs());
+
+ Cell cell4 = newRow.createCell(4 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getCritical_bugs());
+
+ cell4 = newRow.createCell(5 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMajor_bugs());
+
+ cell4 = newRow.createCell(6 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMinor_bugs());
+
+ cell4 = newRow.createCell(7 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_STRING);
+ cell4.setCellValue(metrics.getBugs());
+
+
+ cell4 = newRow.createCell(8 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getBlock_violations());
+
+ cell4 = newRow.createCell(9 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getCritical_violations());
+
+ cell4 = newRow.createCell(10 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMajor_violations());
+
+ cell4 = newRow.createCell(11 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMinor_violations());
+
+ cell4 = newRow.createCell(12 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_STRING);
+ cell4.setCellValue(metrics.getViolations());
+
+
+ cell4 = newRow.createCell(13 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getBlock_code_smells());
+
+
+ cell4 = newRow.createCell(14 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getCritical_code_smells());
+
+ cell4 = newRow.createCell(15 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMajor_violations());
+
+ cell4 = newRow.createCell(16 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getMinor_code_smells());
+
+ cell4 = newRow.createCell(17 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_STRING);
+ cell4.setCellValue(metrics.getCode_smells());
+
+
+ cell4 = newRow.createCell(18 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getComplexity());
+
+ cell4 = newRow.createCell(19 + offset);
+ cell4.setCellType(Cell.CELL_TYPE_NUMERIC);
+ cell4.setCellValue(metrics.getLines());
+
+
+ }
+
+
+ public static void saveExcel(Workbook workBook, String excelPath) throws Exception {
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(excelPath);
+ workBook.write(out);
+
+ } finally {
+ try {
+ if (out != null) {
+ out.flush();
+ out.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ /**
+ * 判断Excel的版本,获取Workbook
+ *
+ * @return
+ * @throws IOException
+ */
+ public static Workbook getWorkbok(File file) throws IOException {
+ Workbook wb = null;
+ FileInputStream in = new FileInputStream(file);
+ if (file.getName().endsWith(EXCEL_XLS)) { //Excel 2003
+ wb = new HSSFWorkbook(in);
+ } else if (file.getName().endsWith(EXCEL_XLSX)) { // Excel 2007/2010
+ wb = new XSSFWorkbook(in);
+ }
+ return wb;
+ }
+
+
+ // 去读Excel的方法readExcel,该方法的入口参数为一个File对象
+ public List readExcel(File file) {
+
+ return null;
+ }
+}
diff --git a/src/main/java/net/educoder/ecsonar/utils/FileUtil.java b/src/main/java/net/educoder/ecsonar/utils/FileUtil.java
new file mode 100644
index 0000000..8421f64
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/utils/FileUtil.java
@@ -0,0 +1,33 @@
+package net.educoder.ecsonar.utils;
+
+import java.io.*;
+
+public class FileUtil {
+
+
+ public static String readFile(String fileName) {
+ String encoding = "UTF-8";
+ File file = new File(fileName);
+ Long filelength = file.length();
+ byte[] filecontent = new byte[filelength.intValue()];
+ try {
+ FileInputStream in = new FileInputStream(file);
+ in.read(filecontent);
+ in.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ return new String(filecontent, encoding);
+ } catch (UnsupportedEncodingException e) {
+ System.err.println("The OS does not support " + encoding);
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/utils/SystemUtil.java b/src/main/java/net/educoder/ecsonar/utils/SystemUtil.java
new file mode 100644
index 0000000..1a4f40c
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/utils/SystemUtil.java
@@ -0,0 +1,76 @@
+package net.educoder.ecsonar.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Created by guange on 26/02/2017.
+ */
+public class SystemUtil {
+
+ private static final Logger logger = LoggerFactory.getLogger(SystemUtil.class);
+
+ private static ExecutorService executor;
+
+ public static class ExecuteResp{
+ int status;
+ String output;
+
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public String getOutput() {
+ return output;
+ }
+
+ public void setOutput(String output) {
+ this.output = output;
+ }
+ }
+
+ /**
+ * 执行命令并获得输出以及退出码
+ */
+ public static ExecuteResp executeAndGetExitStatus(String command) {
+ ExecuteResp resp = new ExecuteResp();
+
+ logger.debug("execute: {}", command);
+
+ StringBuffer out = new StringBuffer();
+ Integer exitStatus = -1;
+
+ ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/sh", "-c", command});
+ pb.redirectErrorStream(true);
+ try {
+ Process process = pb.start();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ out.append(line);
+ out.append(System.getProperty("line.separator"));
+ }
+ exitStatus = process.waitFor();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.info("executeAndGetExitStatus: {}", command);
+ logger.error("executeAndGetExitStatus: ",e);
+ }
+
+ logger.debug("out: {}", out.toString());
+ resp.setOutput(out.toString().trim());
+ resp.setStatus(exitStatus);
+
+ return resp;
+ }
+
+}
diff --git a/src/main/java/net/educoder/ecsonar/utils/UrlUtil.java b/src/main/java/net/educoder/ecsonar/utils/UrlUtil.java
new file mode 100644
index 0000000..f3130c1
--- /dev/null
+++ b/src/main/java/net/educoder/ecsonar/utils/UrlUtil.java
@@ -0,0 +1,73 @@
+package net.educoder.ecsonar.utils;
+
+import java.io.UnsupportedEncodingException;
+/**
+ * url转码、解码
+ *
+ * @author lifq
+ * @date 2015-3-17 下午04:09:35
+ */
+public class UrlUtil {
+ private final static String ENCODE = "UTF8";
+ /**
+ * URL 解码
+ *
+ * @return String
+ * @author lifq
+ * @date 2015-3-17 下午04:09:51
+ */
+ public static String getURLDecoderString(String str) {
+ String result = "";
+ if (null == str) {
+ return "";
+ }
+ try {
+ result = java.net.URLDecoder.decode(str, ENCODE);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+ /**
+ * URL 转码
+ *
+ * @return String
+ * @author lifq
+ * @date 2015-3-17 下午04:10:28
+ */
+ public static String getURLEncoderString(String str) {
+ String result = "";
+ if (null == str) {
+ return "";
+ }
+ try {
+ result = java.net.URLEncoder.encode(str, ENCODE);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @return void
+ * @author lifq
+ * @date 2015-3-17 下午04:09:16
+ */
+ public static void main(String[] args) {
+ //System.out.println(getURLDecoderString("15408100208-%E8%B0%A2%E9%91%AB-%E6%9C%AC%E7%A7%91%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E4%BB%A3%E7%A0%81"));
+ long startTime = System.currentTimeMillis();
+ long endTime = startTime + 6000;
+ long index = 0;
+ while(true){
+ double x = Math.sqrt(index);
+ long now = System.currentTimeMillis();
+ if (now > endTime) {
+ break;
+ }
+ index++;
+ }
+ System.out.println(index+" Loops in 6 seconds");
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/26321-he.xlsx b/src/main/resources/26321-he.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..00026404db10a85b5acd051a35caa353fd109152
GIT binary patch
literal 127943
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