最近在做 DAL (Data Access Layer 数据访问层) 的服务化,发现有不少地方是人工编写比较繁琐的,因此写了几个小工具来完成。

  

  1.  从 DAO 类自动生成 CoreService 类, CoreService 直接调用 DAO 类

  思路: 通过正则表达式解析方法参数, 使用正则替换及源 DAO 文件来生成 CoreService 源文件。

package zzz.study.utils;

import cc.lovesq.dao.CreativeDAO;

import java.util.List;
import static zzz.study.utils.BaseTool.*; public class AutoGenerateCoreService { public static void main(String[] args) {
testParseMethod();
generateCoreServiceFile(CreativeDAO.class); } public static void generateCoreServiceFile(Class<?> daocls) { String daoClassName = daocls.getSimpleName();
String packageName = daocls.getPackage().getName();
String daoRelativePath = "/" + packageName.replaceAll("\\.", "/");
String daoFileName = ALLIN_PROJ_PATH_SRC + "/" + daoRelativePath +
"/" + daocls.getSimpleName() + ".java";
String bizType = getBizType(packageName); String writeFilename = ALLIN_PROJ_PATH_SRC + "/cc/lovesq/service/" + daoClassName.replace("DAO", "CoreService") + ".java";
String serviceClassName = daoClassName.replace("DAO", "CoreService");
String daoRefName = firstToLower(daoClassName); List<String> lines = readLines(daoFileName);
String fileContents = "";
boolean daoFlag = false;
for (String line: lines) { if (daoFlag) {
fileContents += "\n\t@Resource\n";
fileContents += "\tprivate " + daoClassName + " " + daoRefName + ";\n\n";
daoFlag = false;
}
else if (line.contains("interface")) {
fileContents += "@Component\npublic class " + serviceClassName + " { \n";
daoFlag = true;
}
else if (line.contains(";")) {
if (!line.contains("import") && !line.contains("package")) {
System.out.println(line);
System.out.println("parsed: " + parseMethod(line));
List<String> parsed = transform(parseMethod(line));
String replaceStr = " {\n\t\treturn " + daoRefName + "." + parsed.get(0) + "(" + parsed.get(1) + ");\n\t}\n";
String accessQualifier = "";
if (!line.contains("public")) {
accessQualifier = "public ";
}
fileContents += "\t" + accessQualifier + " " + line.trim().replace(";", replaceStr);
}
else if (line.contains("package")) {
System.out.println(line);
fileContents += line.replace("dao", "service") + "\n\n";
fileContents += "import " + daocls.getPackage().getName() + "." + daoClassName + ";\n";
fileContents += "import javax.annotation.Resource;\n" +
"import org.springframework.stereotype.Component;\n" +
"import java.util.List;";
}
else {
fileContents += line + "\n";
}
}
else {
fileContents += line + "\n";
}
} writeFile(writeFilename, fileContents);
} }

  2.  根据对应数据库的 DO 类生成业务 Model 类及转换类 DataTransfer

思路: 模板、反射、正则替换

package zzz.study.utils;

import cc.lovesq.pojo.CreativeDO;

import java.lang.reflect.Field;

import static zzz.study.utils.BaseTool.*;

/**
* Created by shuqin on 16/5/3.
*/
public class AutoGenerateDataTransfer { private static final String dataTransferTpl =
"package cc.lovesq.transfer;\n" +
"\n" +
"import cc.lovesq.model.$modelClsName;\n" +
"import cc.lovesq.pojo.$doClsName;\n\n" +
"public class $modelClsNameDataTransfer { \n\n" +
indent(4) + "$doToModelMethod\n\n" +
indent(4) + "$modelToDOMethod\n\n" +
"}"; private static final String doToModelTpl =
"public static $modelClsName transfer2TO($doClsName $doInstName) {\n" +
indent(8) + "if ($doInstName == null) {\n" +
indent(12) + "return null;\n" +
indent(8) + "}\n" +
"\n" +
indent(8) + "$modelClsName $modelInstName = new $modelClsName();\n" +
indent(0) + "$setStatement\n" +
indent(8) + "return $modelInstName;\n" +
indent(4) + "}" ; private static final String modelToDOTpl =
"public static $doClsName transfer2DO($modelClsName $modelInstName) {\n" +
indent(8) + "if ($modelInstName == null) {\n" +
indent(12) + "return null;\n" +
indent(8) + "}\n" +
"\n" +
indent(8) + "$doClsName $doInstName = new $doClsName();\n" +
indent(0) + "$setStatement\n" +
indent(8) + "return $doInstName;\n" +
indent(4) + "}"; public static void main(String[] args) { autoGenDataTransfer(CreativeDO.class);
} /**
* 根据 DO 类自动生成 Model 类以及 DataTransfer 类
* @param doCls DO 类
*/
public static void autoGenDataTransfer(Class<?> doCls) { String doClassName = doCls.getSimpleName();
Field[] fields = doCls.getDeclaredFields();
String doInstName = firstToLower(doClassName);
String modelInstName = strip(doInstName, "DO");
String modelClsName = firstToUpper(modelInstName);
StringBuilder setStatementAll = new StringBuilder();
for (Field f: fields) {
String fieldName = f.getName();
String setStatement = String.format("%s%s.set%s(%s.get%s());\n", indent(8),
modelInstName, firstToUpper(fieldName), doInstName, firstToUpper(fieldName));
setStatementAll.append(setStatement);
}
String setStatementAllStr = setStatementAll.toString();
String do2modelMethod = doToModelTpl.replaceAll("\\$modelClsName", modelClsName)
.replaceAll("\\$modelInstName", modelInstName)
.replaceAll("\\$doClsName", doClassName)
.replaceAll("\\$doInstName", doInstName)
.replaceAll("\\$setStatement", setStatementAllStr); StringBuilder setStatementAllBuilder2 = new StringBuilder();
for (Field f: fields) {
String fieldName = f.getName();
String setStatement = String.format("%s%s.set%s(%s.get%s());\n", indent(8),
doInstName, firstToUpper(fieldName), modelInstName, firstToUpper(fieldName));
setStatementAllBuilder2.append(setStatement);
}
String setStatementAll2 = setStatementAllBuilder2.toString();
String model2doMethod = modelToDOTpl.replaceAll("\\$modelClsName", modelClsName)
.replaceAll("\\$modelInstName", modelInstName)
.replaceAll("\\$doClsName", doClassName)
.replaceAll("\\$doInstName", doInstName)
.replaceAll("\\$setStatement", setStatementAll2); String packageName = doCls.getPackage().getName();
String bizType = getBizType(packageName);
String dataTransferClassContent = dataTransferTpl.replaceAll("\\$modelClsName", modelClsName)
.replaceAll("\\$doClsName", doClassName)
.replaceAll("\\$bizType", bizType)
.replaceAll("\\$doToModelMethod", do2modelMethod)
.replaceAll("\\$modelToDOMethod", model2doMethod); //System.out.println(dataTransferClassContent); String doClsRelativePath = "/cc/lovesq/pojo/" + doClassName + ".java";
String doClsPath = ALLIN_PROJ_PATH_SRC + doClsRelativePath;
String doClsContent = readFile(doClsPath); System.out.println(doClsContent);
String modelClsContent = doClsContent.replace(doClassName, modelClsName)
.replace("pojo", "model"); String modelClsRelativePath = "/cc/lovesq/model/" + modelClsName + ".java";
String modelClsPath = ALLIN_PROJ_PATH_SRC + modelClsRelativePath;
writeFile(modelClsPath, modelClsContent); String transferRelativePath = "/cc/lovesq/transfer";
String qualifiedPath = ALLIN_PROJ_PATH_SRC + transferRelativePath + "/";
System.out.println(dataTransferClassContent);
String writeFilePath = qualifiedPath + modelClsName + "DataTransfer.java";
System.out.println("Write: " + writeFilePath);
writeFile(writeFilePath, dataTransferClassContent);
} }

3.  移除指定类的 Javadoc 注释

  知识点: 多行的正则匹配, 正则替换; 非贪婪匹配。 注意到  (\\\/\*.*?\\*\\/) 里面有个问号, 如果没有这个问号, 这个正则会从第一个 /* 匹配到最后一个 */ ,相当于整个文件都匹配进去了,显然不是期望的。加上问号后,该正则是非贪婪匹配,每次只要匹配到 */ 就会结束此次匹配。

package zzz.study.utils;

import cc.lovesq.service.CreativeService;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import static zzz.study.utils.BaseTool.*; /**
* 移除指定类的 Javadoc 注释
* Created by shuqin on 16/5/4.
*/
public class RemoveJavadocComments { private static final String javadocRegexStr = "(\\\/\*.*?\\*\\/)";
private static final Pattern javadocPattern = Pattern.compile(javadocRegexStr, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);

    public static void main(String[] args) {

        // 移除指定包下面的类 Javadoc 注释
String tradeDALPackage = ALLIN_PROJ_PATH_SRC + "/cc/lovesq/controller";
List<Class> classes = getClasses(tradeDALPackage);
for (Class c: classes) {
if (c.getSimpleName().endsWith("Controller")) {
removeJavadoc(c);
}
} // 移除单个类的 Javadoc 注释
removeJavadoc(CreativeService.class);
} public static void removeJavadoc(Class<?> coreServiceCls) { String coreServiceName = coreServiceCls.getSimpleName();
String packageName = coreServiceCls.getPackage().getName();
String packagePath = "/" + packageName.replaceAll("\\.", "/"); String coreServiceClsRelativePath = packagePath + "/" + coreServiceName + ".java";
String coreServiceClsPath = ALLIN_PROJ_PATH_SRC + coreServiceClsRelativePath;
String coreServiceContent = readFile(coreServiceClsPath); Matcher m = javadocPattern.matcher(coreServiceContent);
String newContent = coreServiceContent;
while(m.find()) {
String matchedJavadoc = coreServiceContent.substring(m.start(), m.end());
newContent = newContent.replace(matchedJavadoc, "");
}
newContent = newContent.replaceAll("\n\\s*\n", "\n\n");
writeFile(coreServiceClsPath, newContent);
} }

基本工具类:

  

package zzz.study.utils;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* Created by shuqin on 16/5/4.
*/
public class BaseTool { public static final String ALLIN_PROJ_PATH = System.getProperty("user.dir");
public static final String ALLIN_PROJ_PATH_SRC = ALLIN_PROJ_PATH + "/src/main/java"; public static String strip(String origin, String toStrip) {
int index = origin.indexOf(toStrip);
if (index == -1) {
return origin;
}
else {
return origin.substring(0, index);
}
} public static String firstToLower(String doClassName) {
return "" + String.valueOf(doClassName.charAt(0)).toLowerCase() + doClassName.substring(1);
} public static String firstToUpper(String fieldName) {
return "" + String.valueOf(fieldName.charAt(0)).toUpperCase() + fieldName.substring(1);
} public static String getBizType(String packageName) {
int preIndex = packageName.indexOf("common.");
if (preIndex == -1) {
return "";
}
String bizPart = packageName.substring(preIndex+"common.".length());
int bizIndex = bizPart.indexOf(".");
if (bizIndex == -1) {
return "";
}
return bizPart.substring(0, bizIndex);
} public static String indent(int n) {
StringBuilder spaces = new StringBuilder();
for (int i=0; i<n; i++) {
spaces.append(' ');
}
return spaces.toString();
} public static String readFile(String filePath) {
String fileContent = "";
try {
BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)));
StringBuilder doClsContentBuilder = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
doClsContentBuilder.append(line + "\n");
}
fileContent = doClsContentBuilder.toString();
} catch (IOException ioe) {
System.err.println("Failed to Read File " + filePath + " : " + ioe.getMessage());
}
return fileContent;
} public static List<String> readLines(String filePath) {
List<String> lines = new ArrayList<String>();
try {
BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)));
String line = "";
while ((line = reader.readLine()) != null) {
lines.add(line);
}
} catch (IOException ioe) {
System.err.println("Failed to Read File " + filePath + " : " + ioe.getMessage());
}
return lines;
} public static void writeFile(String filePath, String fileContent) {
try {
BufferedWriter modelFileW = new BufferedWriter(new FileWriter(new File(filePath)));
modelFileW.write(fileContent);
modelFileW.close();
} catch (IOException ioe) {
System.err.println("Failed to write Java File " + filePath + " : " + ioe.getMessage());
}
} public static List<String> fetchAllFiles(String path) {
List<String> fetchedFiles = new ArrayList<String>();
fetchFiles(path, fetchedFiles);
return fetchedFiles;
} public static void fetchFiles(String path, List<String> fetchedFiles) {
File[] dirAndfiles = (new File(path)).listFiles();
if (dirAndfiles!=null && dirAndfiles.length > 0) {
for (File file: dirAndfiles) {
if (file.isFile()) {
fetchedFiles.add(file.getAbsolutePath());
}
} for (File file: dirAndfiles) {
if (file.isDirectory()) {
fetchFiles(file.getAbsolutePath(), fetchedFiles);
}
}
}
} public static List<Class> getClasses(String path) {
List<String> files = fetchAllFiles(path);
List<Class> result = new ArrayList<Class>();
ClassLoader cld = Thread.currentThread().getContextClassLoader();
for (String fname: files) {
String fn = fname.replace(ALLIN_PROJ_PATH_SRC + "/", "").replace(".java", "");
String qualifiedClassName = fn.replaceAll("/", ".");
try {
Class<?> cls = cld.loadClass(qualifiedClassName);
result.add(cls);
} catch (ClassNotFoundException cnfe) {
System.err.println("Failed to load class " + qualifiedClassName + " : " + cnfe.getMessage());
} }
return result;
} public static final String methodNameRegexStr = "\\s*(?:\\w+\\s+)?\\w+<?\\w+>?\\s+(\\w+)";
public static final String singleParamRegexStr = "[^,]*\\w+<?\\w+>?\\s+(\\w+)\\s*";
public static final String simpleMethodSignRexStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "\\)\\s*;\\s*";
public static final String twoParamMethodSignRegStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "," + singleParamRegexStr + "\\);\\s*";
//val generalParamMethodSignRegStr = methodNameRegexStr + "\\((" + singleParamRegexStr + "(?:," + singleParamRegexStr + ")*)\\);\\s*";
public static final String generalParamMethodSignRegStr = methodNameRegexStr + "\\((.*)\\);\\s*"; public static final Pattern singleParamPattern = Pattern.compile(singleParamRegexStr);
public static final Pattern generalParamMethodSignPattern = Pattern.compile(generalParamMethodSignRegStr); /**
* 从方法签名中解析出方法名称\参数列表
* @param methodSign 方法签名
* @return ["方法名称", "参数1, 参数2, ..., 参数N"]
*/
public static List<String> parseMethod(String methodSign) { Matcher m = generalParamMethodSignPattern.matcher(methodSign);
String methodName = "";
String args = "";
List<String> parsed = new ArrayList<String>(); if (m.find()) {
methodName = m.group(1);
args = m.group(2);
}
else {
return Arrays.asList(new String[]{"", ""});
}
parsed.add(methodName);
String[] params = args.split(",");
for (String param: params) {
String arg = extractArgName(param);
parsed.add(arg);
}
return parsed;
} public static String extractArgName(String singleParam) {
Matcher m = singleParamPattern.matcher(singleParam);
return m.find() ? m.group(1) : "";
} public static List<String> transform(List<String> parsed) {
if (parsed == null || parsed.isEmpty()) {
return parsed;
}
List<String> result = new ArrayList<String>();
result.add(parsed.get(0));
if (parsed.size() == 2) {
result.add(parsed.get(1));
}
else {
int size = parsed.size();
StringBuilder argBuilder = new StringBuilder();
for (int i=1; i< size-1; i++) {
argBuilder.append(parsed.get(i) + ", ");
}
argBuilder.append(parsed.get(size-1));
result.add(argBuilder.toString());
}
return result;
} public static void testParseMethod() {
Map<String,List<String>> testMethods = new HashMap<String, List<String>>();
testMethods.put(" List<OrderDO> queryOrder(int kdtId); ", Arrays.asList(new String[]{"queryOrder", "kdtId"}));
testMethods.put(" List<OrderDO> queryOrder( int kdtId ); ", Arrays.asList(new String[]{"queryOrder", "kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"kdtId\") int kdtId); ", Arrays.asList(new String[]{"queryOrder", "kdtId"}));
testMethods.put(" List<OrderDO> queryOrder(List<String> orderNos); " , Arrays.asList(new String[]{"queryOrder", "orderNos"}));
testMethods.put(" List<OrderDO> queryOrder(@Param(\"orderNos\") List<String> orderNos); ", Arrays.asList(new String[]{"queryOrder", "orderNos"}));
testMethods.put(" OrderDO queryOrder(String orderNo, Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNo, kdtId"}));
testMethods.put(" OrderDO queryOrder(String orderNo, @Param(\"kdtId\") Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNo, kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"orderNo\") String orderNo, Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNo, kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"orderNo\") String orderNo, @Param(\"kdtId\") Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNo, kdtId"}));
testMethods.put(" OrderDO queryOrder(List<String> orderNos, Integer kdtId); \n", Arrays.asList(new String[]{"queryOrder", "orderNos, kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNos, kdtId"}));
testMethods.put(" OrderDO queryOrder(List<String> orderNos, @Param(\"kdtId\") Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNos, kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, @Param(\"kdtId\") Integer kdtId); ", Arrays.asList(new String[]{"queryOrder", "orderNos, kdtId"}));
testMethods.put(" OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, @Param(\"page\") Integer page, @Param(\"pageSize\") Integer pageSize); ", Arrays.asList(new String[]{"queryOrder", "orderNos, page, pageSize"})); Set<Map.Entry<String, List<String>>> entries = testMethods.entrySet();
for (Map.Entry entry: entries) {
String methodSign = (String)entry.getKey();
List<String> expected = (List<String>)entry.getValue();
List<String> actual = transform(parseMethod(methodSign));
if (!assertListEqual(actual, expected)) {
System.err.println("failed: " + methodSign);
System.err.println("expected: " + expected);
System.err.println("actual: " + actual);
}
} System.out.println("Test ParseMethod passed"); } public static boolean assertListEqual(List<String> list1, List<String> list2) {
if (list1 == null && list2 == null) {
return true;
}
if ((list1 == null && list2 !=null) || (list1 != null && list2 ==null)) {
return false;
}
if (list1.size() != list2.size()) {
return false;
}
for (int i=0; i< list1.size(); i++) {
if (!list1.get(i).equals(list2.get(i))) {
return false;
}
}
return true;
} }

小结:

   任何繁琐容易出错的技术含量不高的活,都可以转化为技术含量"相对有挑战"的活, 就看方案与思路。只要看上去比较有规律的事情, 通常是可以自动化地完成的, 包括生成源代码文件。 方案与思路总体上决定了解决质量的高度。正则很强大!

三个 DAL 相关的Java代码小工具的更多相关文章

  1. 把调试好的SQL语句转换为JAVA代码小工具

    关键点:Pattern实现SQL拆解.ZeroClipboard.js实现复制到剪切板 主要代码: <%@ page language="java" import=" ...

  2. SQL转Java代码小工具

    工作中使用SQL的时候很多,当使用hibernate的时候,经常遇到多行的SQL,通常在PL/SQL或其他地方写好SQL,测试没问题后,需要将SQL写到程序代码中,多行SQL需要拼接字符串,手动一行行 ...

  3. 请阐述调用Activity有哪几种方法,并写出相关的Java代码

    请阐述调用Activity有哪几种方法,并写出相关的Java代码. 答案:可以采用两种方式调用Activity:显示调用和隐式调用.显示调用直接指定了Activity,代码如下: Intent int ...

  4. Java代码混淆工具ProGuard

    目录 Java代码混淆工具ProGuard 简介 描述 作用的环境 功能 工作原理 下载 使用时注意事项 版本问题 JDK位数问题 Java的字节码验证问题 关于使用类似于Hibernate的对象关系 ...

  5. eclipse Java代码折叠工具

      eclipse Java代码折叠工具 CreateTime--2018年5月17日15点09分 Author:Marydon 1.问题描述 eclipse自带的代码折叠工具,无法折叠try{}ca ...

  6. JSON生成c#类代码小工具

    JSON生成c#类代码小工具 为什么写这么个玩意 最近的项目中需要和一个服务端程序通讯,而通讯的协议是基于流行的json,由于是.net,所以很简单的从公司代码库里找到了Newtonsoft.dll( ...

  7. JS-在线运行代码小工具

    原理:window.open()方法,open一个新的空白页,然后把文本框中粘贴的代码通过DOM操作,写到新的代码页中, 再利用document.write的功能(写进去之前把其他的全部删掉,并且写进 ...

  8. java 编写小工具 尝试 学习(七)

    1.在java 编写小工具 尝试 学习(六)里学会了,控件 的随意摆放, 以及大小(x,y,width,height),又根据前面学习的按钮 被点击 的事件监控 的方法 ,点击 按钮 在显示区域显示“ ...

  9. Java代码度量分析工具:Designite简介

    前言 在Java面向对象课程的学习过程中,我们需要使用度量工具来分析自己程序的代码结构.此类的度量工具有许多,或以插件形式存在于各个IDE中,或以.jar包的形式供用户使用.在这里,笔者向大家简单的介 ...

随机推荐

  1. Ohana Cleans Up

    Ohana Cleans Up Description Ohana Matsumae is trying to clean a room, which is divided up into an n  ...

  2. iosiPhone屏幕尺寸、分辨率及适配

    iosiPhone屏幕尺寸.分辨率及适配     1.iPhone尺寸规格 设备 iPhone 宽 Width 高 Height 对角线 Diagonal 逻辑分辨率(point) Scale Fac ...

  3. python 获得当前路径

    先要装载 os模块: import os print os.getcwd() 或者 print os.path.abspath(os.curdir) print os.path.abspath('.' ...

  4. [转载]CRect::DeflateRect

    1基本内容 void DeflateRect(int x,int y); void DeflateRect(SIZE size); void DeflateRect(LPCRECT lpRect); ...

  5. hdu Dragon Balls

    这题是一道简单的并查集的运用.龙珠所在的城市.该城市龙珠数目都是很简单的问题,稍微麻烦一点的就是龙珠被移动的次数,因为每一次要移动的是一个城市中所有的龙珠,所以每次移动该城市中所有龙珠的移动次数都要加 ...

  6. ListView的深入学习

    ListView通常有两个职责: 将数据填充到布局 : 处理用户的点击选择操作 二.创建ListView需要3个元素 ListView的每一列的View View的数据或者图片 连接数据与ListVi ...

  7. 使用PowerShell向SharePoint中写入数据

    本文介绍了如何在命令行方式下, 创建自定义列表, 将外部数据导入到列表以及生成视图. $listname = "contact0422" $column_text = @( &qu ...

  8. sublime添加PHP语法检查

    1.找到php文件目录 如E:\xampp\php 放到环境变量的path中   2.sublime 工具-编译系统-新编译系统  {     "cmd": ["php& ...

  9. Elasticsearch学习笔记(一)

    批量建索引: curl -s -XPOST 'localhost:9200/_bulk' --data-binary @documents.json 查看索引mappingmyindex/_mappi ...

  10. 安装LNMP之后出现 Access denied.解决方法

    权限问题, 执行 sudo chown -R www:www /home/wwwroot