zoukankan      html  css  js  c++  java
  • 三个 DAL 相关的Java代码小工具

      最近在做 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 += "
    	@Resource
    ";
                    fileContents += "	private " + daoClassName + " " + daoRefName + ";
    
    ";
                    daoFlag = false;
                }
                else if (line.contains("interface")) {
                    fileContents += "@Component
    public class " + serviceClassName + " { 
    ";
                    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 = " {
    		return " + daoRefName + "." + parsed.get(0) + "(" + parsed.get(1) + ");
    	}
    ";
                        String accessQualifier = "";
                        if (!line.contains("public")) {
                            accessQualifier = "public ";
                        }
                        fileContents += "	" + accessQualifier + " " + line.trim().replace(";", replaceStr);
                    }
                    else if (line.contains("package")) {
                        System.out.println(line);
                        fileContents += line.replace("dao", "service") + "
    
    ";
                        fileContents += "import " + daocls.getPackage().getName() + "." + daoClassName + ";
    ";
                        fileContents += "import javax.annotation.Resource;
    " +
                                        "import org.springframework.stereotype.Component;
    " +
                                        "import java.util.List;";
                    }
                    else {
                        fileContents += line + "
    ";
                    }
                }
                else {
                    fileContents += line + "
    ";
                }
            }
    
            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;
    " +
                "
    " +
                "import cc.lovesq.model.$modelClsName;
    " +
                "import cc.lovesq.pojo.$doClsName;
    
    " +
                "public class $modelClsNameDataTransfer { 
    
    " +
                indent(4) + "$doToModelMethod
    
    " +
                indent(4) + "$modelToDOMethod
    
    " +
                "}";
    
        private static final String doToModelTpl =
                "public static $modelClsName transfer2TO($doClsName $doInstName) {
    " +
                indent(8) + "if ($doInstName == null) {
    " +
                indent(12) + "return null;
    "               +
                indent(8) + "}
    "                          +
                "
    "                               +
                indent(8) + "$modelClsName $modelInstName = new $modelClsName();
    " +
                indent(0) + "$setStatement
    "              +
                indent(8) + "return $modelInstName;
    "     +
                indent(4) + "}" ;
    
        private static final String modelToDOTpl =
                "public static $doClsName transfer2DO($modelClsName $modelInstName) {
    " +
                indent(8) + "if ($modelInstName == null) {
    " +
                indent(12) + "return null;
    " +
                indent(8) + "}
    " +
                "
    " +
                indent(8) + "$doClsName $doInstName = new $doClsName();
    " +
                indent(0) + "$setStatement
    "              +
                indent(8) + "return $doInstName;
    " +
                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());
    ", 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());
    ", 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("
    \s*
    ", "
    
    ");
            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 + "
    ");
                }
                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); 
    ", 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;
        }
    
    }

         小结:

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

  • 相关阅读:
    Mybatis数据库操作的返回值
    Java中设置classpath、path、JAVA_HOME的作用?
    mysql备份与还原,增量备份;使用ibd和frm文件恢复数据
    SQLAlchemy会话与事务控制:互斥锁和共享锁
    log4j设置,以及中文乱码,通过过滤器输出指定级别的日志,或者指定级别范围的日志
    SQL重复记录查询-count与group by having结合查询重复记录
    css样式美化 下拉框 select 样式
    人人都是 DBA(XIII)索引信息收集脚本汇编
    java线程安全问题之静态变量、实例变量、局部变量
    java uuid第一次性能
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/5463841.html
Copyright © 2011-2022 走看看