Windows中使用Java执行shell命令运行检测,通过sonarqube的webapi获取扫描结果

目录

1,实验环境

2,前言(环境配置)

3,通过Java执行shell命令扫描项目

3.1 主要思路

3.2 参考代码

3.3 运行效果

4,通过sonarqube的webapi获取项目扫描结果

4.1 主要思路

4.2 参考代码

4.3 运行结果


1,实验环境

Windows10

sonarqube-6.7.4

sonar-scanner-2.8

2,前言(环境配置)

具体安装配置过程教程比较多,这里就不再详细介绍了。

1,在官网下载sonarqube和sonar-scanner后,解压、修改配置(主要是连接数据库);

2,在sonarqube的bin目录下运行StartSonar.bat后,可以看到证明启动成功了;

3,浏览器地址栏输入localhost:9000(默认端口号)就能进入sonarqube登录界面,账号密码默认都是admin;

4,执行代码扫描的功能主要通过sonar-scanner进行,通常的扫描方法是在sonar-scanner/conf下,编辑sonar-scanner.properties文件,配置数据库及编码信息:

#Configure here general information about the environment, such as SonarQube server connection details for example
#No information about specific project should appear here

#----- Default SonarQube server
#sonar.host.url=http://localhost:9000
sonar.host.url=http://127.0.0.1:9000

#----- Default source code encoding
#sonar.sourceEncoding=UTF-8
sonar.sourceEncoding=UTF-8

sonar.jdbc.url=jdbc:mysql://127.0.0.1:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
sonar.jdbc.username=填写数据库sonar对应的用户名
sonar.jdbc.password=填写数据库sonar对应的用户名密码
sonar.language=java 
#----- sonar登录账户
sonar.login=admin
sonar.password=admin
http.authentication.preemptive=true
http.socket.timeout = 60000

编辑wrapper.conf文件,添加jdk版本信息

在待扫描项目的主目录下新建sonar-project.properties文件,编写项目相关的配置:

# must be unique in a given SonarQube instance
sonar.projectKey=news
# this is the name displayed in the SonarQube UI
sonar.projectName=news
sonar.projectVersion=1.0
 
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# Since SonarQube 4.2, this property is optional if sonar.modules is set. 
# If not set, SonarQube starts looking for source code from the directory containing 
# the sonar-project.properties file.
# 源代码目录
sonar.sources=src
# 编译生成的class文件存放目录(有的项目是存放在target目录中)
sonar.java.binaries=build/classes
 
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8

有同学在sonarqube中安装sonarjava插件版本过高,所以配置文件中不添加sonar.java.binaries 就会报错,如果想采用静态代码检测(不经过编译,没有生成的classes文件),可以这样编写属性,解决方法来自这篇文章的【评论@pengyuan_D【解决新版sonar-java插件需要配置sonar.java.binaries参数的问题】

在待扫描项目的主目录中打开命令行,运行sonar-scanner就可以看到执行流程了

5,如果出现是因为sonar-scanner支持jdk11版本,和项目所支持的Java1.8版本冲突,可以更换sonar-scanner为2.8版本解决,具体可以参考这里@<予安>【SonarQube执行代码分析时,报错ERROR: Unable to create symbol table for : /**/*.java java.lang.IllegalArgumentException: Unsupported class file major version 55】,亲测有效

PS D:\news> sonar-scanner
C:\Program Files\sonar-scanner-2.8\bin\..
INFO: Scanner configuration file: C:\Program Files\sonar-scanner-2.8\bin\..\conf\sonar-scanner.properties
INFO: Project root configuration file: D:\news\sonar-project.properties
INFO: SonarQube Scanner 2.8
INFO: Java 1.8.0_271 Oracle Corporation (64-bit)
INFO: Windows 10 10.0 amd64
INFO: User cache: C:\Users\许逍遥\.sonar\cache
INFO: Publish mode
INFO: Load global settings
INFO: Load global settings (done) | time=70ms
INFO: Server id: AXdNgQHKmLEJg0fPaxh9
INFO: User cache: C:\Users\许逍遥\.sonar\cache
INFO: Load plugins index
INFO: Load plugins index (done) | time=55ms
INFO: SonarQube server 6.7.4
INFO: Default locale: "zh_CN", source code encoding: "GBK" (analysis is platform dependent)
INFO: Process project properties
INFO: Load project repositories
INFO: Load project repositories (done) | time=100ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=30ms
INFO: Load active rules
INFO: Load active rules (done) | time=559ms
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=32ms
WARN: SCM provider autodetection failed. No SCM provider claims to support this project. Please use sonar.scm.provider to define SCM of your project.
INFO: Project key: news
INFO: -------------  Scan news
INFO: Load server rules
INFO: Load server rules (done) | time=54ms
INFO: Base dir: D:\news
INFO: Working dir: D:\news\.sonar
INFO: Source paths: src
INFO: Source encoding: GBK, default locale: zh_CN
INFO: Index files
INFO: 32 files indexed
INFO: Quality profile for java: Sonar way
INFO: Quality profile for xml: Sonar way
INFO: Sensor JavaSquidSensor [java]
INFO: Configured Java source version (sonar.java.source): none
INFO: JavaClasspath initialization
WARN: Bytecode of dependencies was not provided for analysis of source files, you might end up with less precise results. Bytecode can be provided using sonar.java.libraries property
INFO: JavaClasspath initialization (done) | time=25ms
INFO: JavaTestClasspath initialization
INFO: JavaTestClasspath initialization (done) | time=2ms
INFO: Java Main Files AST scan
INFO: 22 source files to be analyzed
INFO: 22/22 source files have been analyzed
INFO: Java Main Files AST scan (done) | time=2406ms
INFO: Java Test Files AST scan
INFO: 0 source files to be analyzed
INFO: Java Test Files AST scan (done) | time=1ms
INFO: 0/0 source files have been analyzed
INFO: Sensor JavaSquidSensor [java] (done) | time=3189ms
INFO: Sensor SurefireSensor [java]
INFO: parsing [D:\news\target\surefire-reports]
INFO: Sensor SurefireSensor [java] (done) | time=5ms
INFO: Sensor JaCoCoSensor [java]
INFO: Sensor JaCoCoSensor [java] (done) | time=2ms
INFO: Sensor SonarJavaXmlFileSensor [java]
INFO: 7 source files to be analyzed
INFO: Sensor SonarJavaXmlFileSensor [java] (done) | time=189ms
INFO: 7/7 source files have been analyzed
INFO: Sensor XML Sensor [xml]
INFO: Sensor XML Sensor [xml] (done) | time=520ms
INFO: Sensor Analyzer for "php.ini" files [php]
INFO: Sensor Analyzer for "php.ini" files [php] (done) | time=11ms
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=97ms
INFO: Sensor CPD Block Indexer
INFO: Sensor CPD Block Indexer (done) | time=100ms
INFO: No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: 8 files had no CPD blocks
INFO: Calculating CPD for 14 files
INFO: CPD calculation finished
INFO: Analysis report generated in 319ms, dir size=123 KB
INFO: Analysis reports compressed in 129ms, zip size=71 KB
INFO: Analysis report uploaded in 36ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/news
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://localhost:9000/api/ce/task?id=AXdRaLa6jIZ5qmW-FA5u
INFO: Task total time: 8.065 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 11.348s
INFO: Final Memory: 52M/261M
INFO: ------------------------------------------------------------------------

至此,已经可以通过常规方法使用sonarqube扫描一个Java项目了,下面正片开始ε=ε=ε=(~ ̄▽ ̄)~


 以下步骤均在sonarqube开启的前提下进行


3,通过Java执行shell命令扫描项目

3.1 主要思路

用户输入项目路径projectPath、项目名称/标识符projectName(这里默认将项目名称作为key);

在项目目录下创建sonarqube扫描所需的配置文件sonar-project.properties,并填入配置信息;

通过Runtime.getRuntime().exec执行命令行程序,并通过Process对象的waitFor函数了解进程的运行结果;

3.2 参考代码

import java.io.*;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Scanner;

import com.alibaba.fastjson.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Objects;

public class Main {
    public static Scanner input = new Scanner(System.in);
    public static void main(String[] args) {
        // 输入配置信息
        System.out.println("输入待扫描项目地址:");
        String projectPath = input.nextLine();
        String fileName = "sonar-project.properties";// 配置文件名称
        System.out.println("输入项目名称:");
        String projectName = input.nextLine();
        String projectVersion = "1.0";
        String sources = "src";
        String binaries = "./";

        // 创建配置文件
        createFile(projectPath.concat("/"), fileName, projectName, projectVersion, sources, binaries);

        // 运行命令行
        runShell(projectPath);

    }

    /**
     * 创建配置文件
     * @param projectPath
     * @param fileName
     * @param projectName
     * @param projectVersion
     * @param sources
     * @param binaries
     */
    public static void createFile(String projectPath, String fileName,String projectName,
                                  String projectVersion, String sources, String binaries) {

        // 创建配置文件
        File file = new File(projectPath, fileName);
        if(file.exists()) {
            System.out.println("配置文件已存在,开始更新配置");
        } else {
            try {
                file.createNewFile();
                System.out.println("配置文件创建成功,开始更新配置");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 向文件中添加配置信息
        FileWriter fw;
        try {
            fw = new FileWriter(projectPath + fileName);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write("sonar.projectKey=" + projectName + "\n");
            bw.write("sonar.projectName=" + projectName + "\n");
            bw.write("sonar.projectVersion=" + projectVersion + "\n");
            bw.write("sonar.sources=" + sources + "\n");
            bw.write("sonar.java.binaries=" + binaries + "\n");
            bw.write("sonar.sourceEncoding=UTF-8\n");

            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(2);
        }
    }

    /**
     * 打开命令行,切换到对应目录,执行sonar-scanner指令
     * @param projectPath
     */
    public static void runShell (String projectPath) {
        try {
            long startTime =  System.currentTimeMillis();
            Process proc = Runtime.getRuntime().exec("cmd.exe /c cd " + projectPath + "&& sonar-scanner");

            int processCode = proc.waitFor();
            if(processCode == 0) {
                System.out.println("扫描完成");
                long endTime =  System.currentTimeMillis();
                // 获取扫描时间
                long usedTime = (endTime - startTime) / 1000;
                System.out.println("扫描用时" + usedTime + "s");
                System.out.println("-----------------------------");
            } else {
                System.out.println("扫描失败");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

3.3 运行效果


4,通过sonarqube的webapi获取项目扫描结果

4.1 主要思路

向接口(http://localhost:9000/api/measures/component?component=项目的key&metricKeys=想要获得的指标)发送HTTP请求,获得返回的json字符串;

借助阿里爸爸的fastJSON将json字符串转换为jsonObject对象,并通过不断解析,得到想要得到的字段(这里指bugs/code_smells/vulnerabilities的数目);

4.2 参考代码

    /**
     * 根据项目名称获取sonarqube扫描结果(bugs、codeSmells、vulnerabilities)
     * @param projectName
     */
    public static void getJsonData(String projectName) {
        String param1 = "component=" + projectName + "&metricKeys=bugs";
        String param2 = "component=" + projectName + "&metricKeys=code_smells";
        String param3 = "component=" + projectName + "&metricKeys=vulnerabilities";

        System.out.println("bugs:" + getSonarMeasures(param1));
        System.out.println("codeSmells:" + getSonarMeasures(param2));
        System.out.println("vulnerabilities:" + getSonarMeasures(param3));

    }

    /**
     * 根据参数获得相应的指标
     * @param param 向接口发送的参数(bugs、codeSmells、vulnerabilities)
     * @return 各种参数的值
     */
    public static int getSonarMeasures(String param) {
        PrintWriter out = null;
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        int value = 0;

        try {
            String api = "http://localhost:9000/api/measures/component?";
            URL url = new URL(api);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            // 发送参数
            connection.setDoOutput(true);
            out = new PrintWriter(connection.getOutputStream());
            out.print(param);
            out.flush();

            // 接受结果
            is = connection.getInputStream();
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            // 通过流读取结果
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

            // 解析json数据
            String backJson = sb.toString();                                    // 获得json字符串
            JSONObject jsonObject = JSONObject.parseObject(backJson);           // 将字符串转换为JSONObject对象
            JSONObject componentObj = jsonObject.getJSONObject("component");    // 获取component的JSONObject对象
            JSONArray measuresAry = componentObj.getJSONArray("measures");      // 由于是数组形式,先获取measures的JSONArray对象
            JSONObject measuresObj = measuresAry.getJSONObject(0);              // 获取measures的JSONObject对象
            value = measuresObj.getIntValue("value");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(is != null) is.close();
                if(br != null) br.close();
                if(out != null) out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return value;
    }

4.3 运行结果

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/113418504