1 SonarQube安装及部署
1.0 在安装sonarqube时,必须先安装jdk1.8,并配置了环境变量,
1.1 下载SonarQube https://www.sonarqube.org/downloads/ 默认下载sonarqube-7.1.zip
1.2 解压并放置在任意文件夹下
1.3进行bin目录,然后选择win*****与电脑相应的文件夹,点击StartSonar.bat启动启动后,若出现一下界面则表示成功

2 安装数据库
:以安装2014 sqlserver中安装数据库为例
2.1新建数据库,数据库名称为sonar
执行如下语句
Use master
EXEC sp_dboption ‘sonar’, ‘Single User’, ‘TRUE’
EXEC sp_renamedb ‘sonar’, ‘sonar7’
EXEC sp_dboption ‘sonar7’, ‘Single User’, ‘FALSE’
GO
alter database sonar7 collate Chinese_PRC_CS_AS
GO
EXEC sp_renamedb ‘sonar7’, ‘sonar’
GO

如sp_dboption存储过程没有,则可sp_dboption.sql文件创建或成sql2008中复制一个过来
在sonarqube7\conf\下,打开sonar.properties文件写入
sonar.jdbc.url=jdbc:sqlserver://10.100.3.198:1433;databaseName=sonar
sonar.jdbc.username=sonar
sonar.jdbc.password=111111
sonar.sorceEncoding=UTF-8
sonar.login=admin
sonar.password=admin

2.4 打开浏览器进入http://localhost:9000,将会显示一下界面

此时如果出现以下界面并且SonarQube已经启动, 登陆,默认用户名和密码都是admin

2.6 下载中文包插件,汉化网页
链接:https://docs.sonarqube.org/display/PLUG/Plugin+Library 在右下角

进入

点击Lasttest version对应链接便可以下载,下载成功后,放在E:\sonarqube7\extensions\plugins文件夹下。

3 使用sonar-scanner扫描
3.1 安装sonar-scanner
1.解压sonar-scanner-cli-3.1.0.1141-windows.zip到E:\sonarqube7\下,重命名为sonarScanner3
3.2 配置sonar-scanner环境变量
a.新建变量,name=SONAR_RUNNER_HOME. value=E:\sonarqube7\sonarScanner3
b.打开path,增加%SONAR_RUNNER_HOME%\bin;
c. sonar-scanner -v,出现以下信息,则表示环境变量设置成功

3.3 编辑 ${sonar-runner_home}/conf/sonar-runner.properties 配置数据库

sonar.host.url= http://10.100.3.43:9000 sonar.jdbc.url=jdbc:sqlserver://10.100.3.220:1422;databaseName=sonar
sonar.jdbc.username=sa
sonar.jdbc.password=111111
sonar.sourceEncoding=UTF-8
sonar.login=admin
sonar.password=admin
3.4 使用命令行通过maven进行分析
3.4.1 配置maven的环境变量:配置settings.xml文件


org.sonarsource.scanner.maven



sonar

true


<sonar.host.url>
http://10.100.3.43:9000 </sonar.host.url>
<sonar.inclusions>src/main/java/com/dse/</sonar.inclusions>
<sonar.exclusions>src/main/java/com/dse/common/gen/
</sonar.exclusions>
<sonar.login>admin</sonar.login>
<sonar.password>admin</sonar.password>




3.4.2 打开cmd命令窗口,定位到相应要分析项目目录下
在命令行下运行mvn clean verify sonar:sonar
运行结束以后,到web上查看结果,运行较慢

插件打包命令: mvn clean && mvn package -Dmaven.test.skip=true
如果报 java.lang.NoClassDefFoundError: org/sonarsource/scanner/api/LogOutput错误,可使用如下命令生成
mvn clean install org.sonarsource.scanner.maven:sonar-maven-plugin:3.3.0.603:sonar
4 使用SonarLint插件动态检查
4.1 SonarLint插件安装

 在线安装:IDEA菜单栏选择File->Settings,左边栏选择Plugins ,在线安装选择Browse repositories,搜索Sonar,选择SonarLint进行安装,之后重启IDEA

 离线安装:IDEA菜单栏选择File->Settings,左边栏选择Plugins ,在线安装选择Install plugins from disk,选择离线安装包,之后重启IDEA 。

4.2 SonarQube服务器配置
4.2.1 1.安装成功后,进入到Other Setting界面

点击+添加SonarQube服务器:配置地址为:http://10.100.3.43:9000/ 4.2.2 Configuration Name就是标志这个服务器的名字

4.2.3 下拉选择Token登陆还是login/password登陆

建议使用login\password登陆,都填写admin,这样即使你没有在网页上登陆,依然可以进行分析。

4.2.4 最后点击next,finish,便看到添加成功

3.6在Other Setting中SonarLint Project Setting中设置绑定服务器

3.7点击ok,完成SonarQube服务器交互配置

4.3 IDEA SonarLint使用
4.3.1 自动检查
安装SonarLint插件重启后,IDEA Tool Windows部分会出现SonarLint View。当前打开的java文件会在current file中自动检查

2.SonarLint安装完后,默认情况下是自动检测项目代码的。若觉得影响效率,可通过菜单Settings->Other Settings->SonarLint General Settings进行设置

4.3.2 手动检测

  1. 在Tool Windows中选择Scope(可选择All project files或者VCS changed files),再点击左侧的Analyze按钮进行检测
  2. 检测完毕后,会在SonarLint Tool View中显示出检测的问题,以类名称进行分类。各类的issue,分为阻断、严重、主要、提示和次要,问题严重性依次降低。点击issue,在右侧会出现对应的Rule,可参照进行修改

5 Sonar 代码检查规范
5.1 Sonar检查类型及要求
Sonar按严重性可分为以下几种
指标名 关键词 描述
阻断 /致命的 Blocker 操作/安全风险: 在生产中这个问题可能会使整个应用程序不稳定。 例如: 调用垃圾收集器,而不是关闭套接字等等
严重 /关键的 Critical 操作/安全风险: 在生产过程中这个问题可能导致出现意外行为,而不会影响整个应用程序的完整性。 例如:NullPointerException,严
重捕获异常,缺少单元测试等
主要 Major 这个问题可能会对生产效率产生影响。 例如: 太复杂的方法,包装循环等
次要 /微小的 Minor 这个问题可能会对生产效率产生影响。 例如:命名约定,终结器只调用超类终结器等等
提示 Info 可能会对生产效率产生影响的未知或尚未明确定义的安全风险
对所有已开发系统sonar检查:需解决Blocker,Critical,Major三种类型的问题。对新开发的系统在提交代码前必须解决Blocker,Critical,Major,Minor四种类型的问题,由系统开发负责人检查开发人员所提交代码,公司会定期扫描抽检

5.2 Sonar 代码检查要点详解
 5.2.1 “@RequestMapping” methods should be “public”
 @RequestMapping("/greet", method = GET)
 private String greet(String greetee) { //✗ avoid 
 @RequestMapping("/greet", method = GET)
 public String greet(String greetee) {//✓ ok
 5.2.2 “main” should not “throw” anything
 public static void main(String args[]) throws Exception { //✗ avoid 
 5.2.3 “switch” statements should not contain non-case labels, Switch cases should end with an unconditional “break” statement,“default” clauses should be lastswitch (day) {
 case MONDAY:/ /✗ avoid 
 case TUESDAY:
 …}
 5.2.4 “wait(…)” should be used instead of “Thread.sleep(…)” when a lock is held
 public void doSomething(){
 synchronized(monitor) {
 while(notReady()){
 Thread.sleep(200); / /✗ avoid 
//monitor.wait(200); //✓ ok
 }
 process();
 }
 …
 }5.2.5 Child class fields should not shadow parent class fields
5.2.6 Resources should be closed
 5.2.7 Exit methods should not be called
 System.exit(0); / /✗ avoid 
 Runtime.getRuntime().exit(0); / /✗ avoid 
 Runtime.getRuntime().halt(0); / /✗ avoid 
 5.2.8 Methods “wait(…)”, “notify()” and “notifyAll()” should not be called on Thread instances
 Thread myThread = new Thread(new RunnableJob());
 myThread.wait(2000); / /✗ avoid5.2.9 Threads should not be started in constructors
 public class MyClass {
 Thread thread = null;
 public MyClass(Runnable runnable) {
 thread = new Thread(runnable);
 thread.start(); // ✗ avoid
 }
 }5.2.10 无继承Cloneable则不能复写clone,有则必须Override clone
5.2.11 “if … else if” constructs should end with “else” clauses
if (x == 0) {
 doSomething();
 } else if (x == 1) {
 doSomethingElse();
 }// ✗ avoid
 5.2.12 “Object.wait(…)” and “Condition.await(…)” should be called inside a “while” loop
 synchronized (obj) {
 while (){
 obj.wait(timeout);// ✗ avoid
 } … .}
 5.2.13 “Serializable” classes should have a version id
 public class Raspberry extends Fruit
 implements Serializable {
 private static final long serialVersionUID = 1; //✓ ok
 // private final long serialVersionUID = 1; // ✗ avoid
 5.2.14 Cognitive Complexity of methods should not be too high:不能大于15
 注多重循环嵌套(复杂度)计算:由以下数来测量
 &&和||,if, while,do,for,?:,catch,switch,case, return和throw…5.2.15 Comparators should be “Serializable”
 public class FruitComparator implements Comparator, Serializable {
 private static final long serialVersionUID = 1;
 …}5.2.16 常量不允许在接口中声明,也不允许出现static
 5.2.17 Control flow statements “if”, “for”, “while”, “switch” and “try” should not be nested too deeply:不允许超过3层
 if (condition1) {
 /* … /
 if (condition2) {
 / … /
 for(int i = 0; i < 10; i++) {
 / … */
 if (condition4) { // ✗ avoid …
 }
 return;
 }
 }
 }
 }
 5.2.18 Finally块中不允许再抛出异常
 5.2.19 Lazy initialization of “static” fields should be “synchronized”rivate static Properties fPreferences = null;
 private static synchronized Properties getPreferences() {//去除synchronized则是错误的
 if (fPreferences == null) {
 fPreferences = new Properties();
 fPreferences.put(“loading”, “true”);
 fPreferences.put(“filterstack”, “true”);
 readPreferences();
 }
 return fPreferences;
 }
 }
 5.2.20 Locks should be released
 public class MyClass {
 private Lock lock = new Lock();public void doSomething() {
 lock.lock(); // ✗ avoid
 if (isInitialized()) {
 // lock.lock(); //✓ ok
 …
 lock.unlock();
 }
 }
 }5.2.21 Try-with-resources should be used
 Java 7引入了try-with-resources语句,该语句确保有问题的资源将被关闭,比旧的try/ catch/ finally要手动关闭要安全
 旧的方法
 FileReader fr = null;
 BufferedReader br = null;
 try {
 fr = new FileReader(fileName);
 br = new BufferedReader(fr);
 return br.readLine();
 } catch (…) {
 } finally {
 if (br != null) {
 try {
 br.close();
 } catch(IOException e){…}
 }
 if (fr != null ) {
 try {
 br.close();
 } catch(IOException e){…}
 }
 }
 新的方法
 try (
 FileReader fr = new FileReader(fileName);
 BufferedReader br = new BufferedReader(fr)
 ) {
 return br.readLine();
 }
 catch (…) {}
 5.2.22 不应该使用通配符导入
 import java.sql.*; // ✗ avoid5.2.23 “@Override” should be used on overriding and implementing methods
 5.2.24 “hashCode” and “toString” should not be called on array instances
 public static void main( String[] args )
 {
 String argStr = args.toString();// ✗ avoid
 int argHash = args.hashCode();// ✗ avoid
 String argStr1 = Arrays.toString(args); //✓ ok
 int argHash1 = Arrays.hashCode(args); //✓ ok
 }
 5.2.25 “java.lang.Error” should not be extended5.2.26 “NullPointerException” 不应该被捕捉,或者抛出
 public int lengthPlus(String str) {
 int len = 2;
 try {
 len += str.length();// ✗ avoid
 }
 catch (NullPointerException e) {
log.info(“argument was null”);
 }
 return len;
 }
 正确写法:
 if (str != null) {
 len += str.length();
 }
 else {
log.info(“argument was null”);
 }5.2.27 “read” and “readLine” return values should be used
 while (buffReader.readLine() != null) { //✗ avoidString line = null;
 while ((line = buffReader.readLine()) != null) {//✓ ok5.2.28 “static” members should be accessed statically
 public class A {
 public static int counter = 0;
 }
 private A first = new A();
 first.counter ++; //✗ avoid
 A.counter ++; // ✓ ok5.2.29 “wait”, “notify” and “notifyAll” should only be called when a lock is obviously held on an object
 private void removeElement() {
 // private synchronized void removeElement() {// ✓ ok
 synchronized(obj) {// ✓ ok
 while (!suitableCondition()){
 obj.wait();
 }
 …
 }
 }
 5.2.30 Classes and enums with private members should have a constructor
 class A {
 private int field;
 A(int field) {
 this.field = field;
 }
 }
 5.2.31 Empty arrays and collections should be returned instead of null
 public static List getResults() {
 return Collections.emptyList(); // ✓ ok
 //return null; // ✗ avoid
 }
 5.2.32 Exception should not be created without being thrown
 if (x < 0)
 new IllegalArgumentException(“x must be nonnegative”); // ✗ avoid
 // throw new IllegalArgumentException(“x must be nonnegative”); // ✓ ok5.2.33 一个类为能超过1000行,一个方法中不能超过75行,一行不能超过120个字符
 5.2.34 Non-serializable classes should not be written,
 Non-serializable objects should not be stored in “HttpSession” objectspublic class Vegetable {
 //…
 }
 public class Menu {
 public void meal() throws IOException {
 Vegetable veg;
 FileOutputStream fout = new FileOutputStream(veg.getName());
 ObjectOutputStream oos = new ObjectOutputStream(fout);
 oos.writeObject(veg); // ✗ avoid
 HttpSession session = request.getSession();
 session.setAttribute("veg ", veg); // ✗ avoid
 }
 }
 正确做法
 public class Vegetable implements Serializable {
 //…
 }5.2.35 Public methods should throw at most one checked exception
 注Error或者RuntimeException的异常称为unchecked异常,所有其他的异常成为checked异常
 public void delete() throws IOException, SQLException { // ✗ avoid
 /* … */
 }5.2.36 Standard outputs should not be used directly to log anything
 System.out.println(“My Message”); //✗ avoid
 logger.log(“My Message”);5.2.37 Static fields should not be updated in constructors
 public class Person {
 Date dateOfBirth;
 static int expectedFingers;
 public Person(date birthday) {
 dateOfBirth = birthday;
 expectedFingers = 10; // ✗ avoid
 }
 }
 5.2.38 Synchronized classes Vector, Hashtable, Stack and StringBuffer should not be used
 • ArrayList or LinkedList instead of Vector
 • Deque instead of Stack
 • HashMap instead of Hashtable
 • StringBuilder instead of StringBuffer5.2.39 删除没有用的import、field、class、method。