这两天在写一个java程序,可以检测其他的java项目的代码是否符合规范。并且能够对SVN中的项目进行检查。
第一步是先实现本地文件的扫描,很简单,就是一个文件遍历找出所有文件的代码:
/*
* 递归调用查找指定文件加下所有文件
*/
public static String GetFiles(String path) throws RowsExceededException, WriteException{
File rootDir = new File(path);
if(!rootDir.isDirectory()){
//调用检测代码的方法
checkLine(rootDir);
//清楚上下文记录
context.clear();
}else{
String[] fileList = rootDir.list();
for (int i = 0; i < fileList.length; i++) {
path = rootDir.getAbsolutePath()+"\\"+fileList[i];
GetFiles(path);
}
}
return null;
}
第二步:循环读取文件中的每一行,并对每行进行分析:
if(rootDir.getName().endsWith(".java")){
String path = rootDir.getAbsolutePath();
System.out.println(path);
FileInputStream scanFile = null;
BufferedInputStream bin = null;
InputStreamReader inread = null;
BufferedReader br = null;
try {
scanFile = new FileInputStream(path);
bin = new BufferedInputStream(scanFile);
inread = new InputStreamReader(bin);
br = new BufferedReader(inread);
String str = "";
int i =1;
while((str = br.readLine())!=null){//读取每一行代码,并调用parseLine方法来解析和检查
parseLine(path, str, i);
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
inread.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
第三步,对代码进行检测,这里使用正则表达式来判断当前行代码是属性,还是常量,还是方法定义,还是控制语句(if,for,while,switch)等,
这段检测的代码都是本人用正则来判断,也可以使用ASTView组件的API来获取java类中的属性,方法名,等,类似于反射技术。
//如果当前行是定义属性,常量,或则局部变量
if(temp.matches("(private|public|protecte)?\\s?[\\w<,>]*\\s\\w*;")
|| temp.matches("(final)?\\s?[\\w<,>]*\\s\\w*(;|\\s?=\\s?\\w*;|"
+ "\\s?=\\s?new\\s[\\w<,>]*\\(([\\w<,>\\s]*)?\\);|\\s?=\\s?\\(\\w*\\)\\s?[\\w\\.\\)\\(\"\\s]*;)")){
//获取上下文中,当前行的前面一行代码
String pre = context.get(i-2);
//判断该属性,常量,或则局部变量的前面一行如果不是注释,则不符合规范。下面的正则可以匹配双斜杠和斜杠星
if(!pre.trim().matches("/([\\w*]|[^\\x00-\\xff]|\\s)*/")){
printXLS("错误规范66","定义的局部变量,常量,字段/属性必须有注释", path, "第"+i+"行");
isStatus = true;
}
}
代码规范多达七八十条,在这里就不一一列举。
printXLS("错误规范66","定义的局部变量,常量,字段/属性必须有注释", path, "第"+i+"行");
printXLS是把错误报告写到Excel文件中。
第四部:编写代码从SVN中检出项目,这里需要用到SVNKit库,SVNKit是一个纯java的subversion客户端库。
代码如下:
/*第一步:
*导入可能用到的类
*/
import java.io.*;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
public class SVNUtil {
/*
* 第二步: 声明客户端管理类SVNClientManager。
*/
private static SVNClientManager ourClientManager;
public static void checkOut() throws SVNException {
/*
* 第三步: 对版本库进行初始化操作 (在用版本库进行其他操作前必须进行初始化) 对于通过使用 http:// 和 https://
* 访问,执行DAVRepositoryFactory.setup(); 对于通过使用svn:// 和
* svn+xxx://访问,执行SVNRepositoryFactoryImpl.setup();
* 对于通过使用file:///访问,执行FSRepositoryFactory.setup(); 本程序框架用svn://来访问
*/
SVNRepositoryFactoryImpl.setup();
/*
* 第四步: 要访问版本库的相关变量设置
*/
// 版本库的URL地址
SVNURL repositoryURL = null;
try {
repositoryURL = SVNURL.parseURIEncoded("svn://192.168.9.60/temp");
} catch (SVNException e) {
//
}
// 版本库的用户名
String name = "test";
// 版本库的用户名密码
String password = "111111";
// 工作副本目录
String myWorkingCopyPath = "F:/SVN_JAVAScan";
// 驱动选项
ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
/*
* 第五步: 创建SVNClientManager的实例。提供认证信息(用户名,密码) 和驱动选项。
*/
ourClientManager = SVNClientManager.newInstance((DefaultSVNOptions) options, name, password);
/*
* 第六步: 通过SVNClientManager的实例获取要进行操作的client实例(如 * SVNUpdateClient)
* 通过client实例来执行相关的操作。 此框架以check out操作来进行说明,其他操作类似。
*/
/* 工作副本目录创建 */
File wcDir = new File(myWorkingCopyPath);
if (wcDir.exists()) {
System.out.println("the destination directory '" + wcDir.getAbsolutePath() + "' already exists!");
} else {
wcDir.mkdirs();
}
try {
/*
* 递归的把工作副本从repositoryURL check out 到 wcDir目录。 SVNRevision.HEAD
* 意味着把最新的版本checked out出来。
*/
SVNUpdateClient updateClient = ourClientManager.getUpdateClient();
updateClient.setIgnoreExternals(false);
//需要遍历多个文件夹时,要传入递归深度参数为无限SVNDepth.INFINITY
long workingVersion = updateClient.doCheckout(repositoryURL, wcDir, SVNRevision.HEAD, SVNRevision.HEAD,SVNDepth.INFINITY, true);
System.out.println("把版本:"+workingVersion+" check out 到目录:"+wcDir+"中。");
} catch (SVNException svne) {
svne.printStackTrace();
}
}
}
上面就是检出SVN项目到本地中的方法,既然项目以及可以检出到本地指定的文件夹中。那么执行完上面的代码,下面的代码就是扫描文件,只需要将前面扫描文件的代码执行即可。