相信你们对代码质量规范已经不陌生,通常大公司都会进行代码质量检查,用来管理N多项目的质量,若是达不到要求,那么很差意思,请去搞搞代码,从今日后就成为领导重点管理对象。
在质量管理当中,我负责去管理整个团队的CQM问题,由此走上代码规范的道路。
从管理手段来说,开个会,提醒你们要按照公司的规范,根据工具(SonarLint等),提交代码前,用工具check一下,有问题及时修改。宣传后你们的反响不大,并且问题愈来愈多,你们明显不自觉,
都认为这个没什么用啦,浪费时间,不造成习惯。你们都知道,不造成习惯的规范,就像制度摆在这里木有人执行,可悲的管理者。
对于我来讲,也以为很难执行,有时候我只能呵呵一下,但仍是要想办法管理起来,由此想经过可视化界面展示起来,让全部都看到,CQM问题不控制,会愈来愈多的不规范代码横空出世,下面讲讲如何
创建CQM可视化界面,
一、思考Sonar的结果如何才能获取到?
Sonar编译后,会记录历史记录,Sonar提供http访问接口,返回json报文格式,可获取到你想要的结果,这下有点小兴奋,有渠道获取了。
访问URL:http://ip:port/api/resources?resource=${project_key}&&metrics=${metrics_key}
返回格式:[{"id":793214,"uuid":"1234","key":"com.myjob","name":"CRM_JOB","scope":"PRJ","qualifier":"TRK","date":"2016-11-25T19:18:35+0800","creationDate":"2016-04-25T10:26:12+0800","lname":"CRM_JOB","version":"1.0","description":"","msr":[{"key":"critical_violations","val":0.0,"frmt_val":"0"}]}]
开始编码:
public Map reqeustIde(String resource, String metrics){
final HttpConnectionManagerParams params = new HttpConnectionManagerParams();
params.setConnectionTimeout(AbstractQuery.DEFAULT_TIMEOUT_MILLISECONDS);
params.setSoTimeout(AbstractQuery.DEFAULT_TIMEOUT_MILLISECONDS);
params.setDefaultMaxConnectionsPerHost(4);
params.setMaxTotalConnections(40);html
final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
connectionManager.setParams(params);
HttpClient httpClient = new HttpClient(connectionManager);
httpClient.getParams().setAuthenticationPreemptive(true);
Credentials defaultcreds = new UsernamePasswordCredentials("abcdefg", "123456");
httpClient.getState().setCredentials(AuthScope.ANY, defaultcreds);
final PostMethod post = new PostMethod("http://localhost:8080/api/resources?resource=" + resource + "&metrics=" + metrics);
try {
httpClient.executeMethod(post);
String jsonStr = post.getResponseBodyAsString();
System.out.println(jsonStr);
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(jsonStr.substring(1, jsonStr.length() - 1), Map.class);
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return new HashMap();
}
二、如何把这些信息转换成模型呢?
模型考虑维度:
①编译的分支项目,就是要扫描的编译项目
②扫描的issuess类型
③扫描Sonar后的结果记录,定时扫描,若是已经扫描过就不记录
④分支项目的临界值,保证这个值不能被超过,若是超过则告警
通过我慎重思考,产出一下模型:
create table tb_project(
id bigint UNSIGNED not null auto_increment comment '主键标识',
project_name varchar(100) not null default '' comment '编译项目名称',
project_key varchar(100) not null default '' comment '项目key',
create_time timestamp NOT NULL DEFAULT '1980-01-01 00:00:00' COMMENT '记录建立时间',
last_update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录最后修改时间',
PRIMARY KEY (`id`)
);java
create table tb_type(
id bigint UNSIGNED not null auto_increment comment '主键标识',
type_name varchar(100) not null default '' comment '扫描类型中文名称',
type_key varchar(100) not null default '' comment '扫描key',
create_time timestamp NOT NULL DEFAULT '1980-01-01 00:00:00' COMMENT '记录建立时间',
last_update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录最后修改时间',
PRIMARY KEY (`id`)
);json
create table tb_scan_critical_value(
id bigint UNSIGNED not null auto_increment comment '主键标识',
project_key varchar(100) not null default '' comment '项目key',
type_key varchar(100) not null default '' comment '扫描key',
critical_val bigint(20) not null default 0 comment '临界值',
current_val bigint(20) not null default 0 comment '当前值',
create_time timestamp NOT NULL DEFAULT '1980-01-01 00:00:00' COMMENT '记录建立时间',
last_update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录最后修改时间',
PRIMARY KEY (`id`)
);api
create table tb_scan_record(
id bigint UNSIGNED not null auto_increment comment '主键标识',
project_name varchar(100) not null default '' comment '编译项目名称',
project_key varchar(100) not null default '' comment '项目key',
uuid varchar(100) not null default '' comment '项目uuid',
version varchar(100) not null default '' comment '版本号,以时间维度',
key_date varchar(50) not null default '' comment '',
key_creationdate varchar(50) not null default '' comment '',
lname varchar(100) not null default '' comment '',
description varchar(200) not null default '' comment '描述',
type_key varchar(100) not null default '' comment '扫描key',
type_val bigint(20) not null default 0 comment '扫描值',
PRIMARY KEY (`id`)
);
三、action请求处理逻辑思考
有如下步骤:
①查询须要扫描的内容
select a.project_key,b.type_key from tb_project a , tb_type b
②查出重复的信息
select distinct project_key,version from tb_scan_record where project_key ='${project_key}' and version ='${version}'
③把扫描结果插入到结果表中:tb_scan_record
④:插入临界值表:tb_scan_critical_value,若是已经存在则更新critical_val、current_val值,若是critical_val>current_val,则临界值之后以current_val为准,这里控制会愈来愈小。
⑤统计结果输出
select project_name,project_key,sum(critical_val) as total_critical_val,sum(current_val) as total_current_val from (
select a.project_name,b.project_key,b.critical_val,b.current_val
from tb_project a,tb_scan_critical_value b where a.project_key = b.project_key order by a.project_key) c group by project_name,project_key
⑥查询类型的输出:
select a.project_name,b.project_key,b.critical_val as critical_val,b.type_key,b.current_val as current_val from tb_project a,tb_scan_critical_value b where a.project_key = b.project_key order by project_key
四、编写图形界面app
Jsp页面:
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CQM可视化界面</title>
<script language="JavaScript">
function myrefresh()
{
window.location.reload();
}
setTimeout('myrefresh()',60000 * 10 ); //指定1秒刷新一次
</script>
</head>
<body>
<table cellpadding="1" cellspacing="0" width="100%" style="border-width: 1px;font-size:55px;" >
<tr align="center">
<td>CQM可视化界面</td>
</tr>
</table>
<table cellpadding="1" cellspacing="0" width="100%" style="border-width: 1px;font-size:55px;" >
<c:forEach items="${totalPageMap}" var="totalObj">
<tr>
<c:if test="${totalObj.status== 'fail'}">
<td style="background-color: red">
${totalObj.project_name}【临界值:${totalObj.total_critical_val}当前值:${totalObj.total_current_val}】
</td>
</c:if>
<c:if test="${totalObj.status== 'succeed'}">
<td style="background-color: green">
${totalObj.project_name}【临界值:${totalObj.total_critical_val}当前值:${totalObj.total_current_val}】
</td>
</c:if>
</tr>
</c:forEach>
</table>
<table cellpadding="1" cellspacing="0" width="100%" style="border-width: 1px;font-size:18px;" >
<tr style="background-color: green">
<td>项目</td>
<td>等级类型</td>
<td>临界值</td>
<td>当前值</td>
</tr>
<c:forEach items="${pageMap}" var="obj">
<c:if test="${obj.status == 'fail'}">
<tr style="background-color: red">
<td >
${obj.project_name}
</td>
<td >
${obj.type_key}
</td>
<td >
${obj.critical_val}
</td>
<td >
${obj.current_val}
</td>
</tr>
</c:if>
<c:if test="${obj.status== 'succeed'}">
<tr style="background-color: green">
<td >
${obj.project_name}
</td>
<td >
${obj.type_key}
</td>
<td >
${obj.critical_val}
</td>
<td >
${obj.current_val}
</td>
</tr>
</c:if>
</c:forEach>
</table>
</body>
</html>
做者:godsferjsp