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 手动检测
- 在Tool Windows中选择Scope(可选择All project files或者VCS changed files),再点击左侧的Analyze按钮进行检测
- 检测完毕后,会在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。