版权声明:本文为博主原创文章,未经博主允许不得转载。安卓五千源码下载--https://blog.csdn.net/wuqilianga/article/details/89185887 https://blog.csdn.net/wuqilianga/article/details/82698371
前序
你有没有觉得自己常常写重复的代码,面试造轮船,上班拧螺丝?
你有没有常觉得,自己明明可以更快地写好功能模块,却要不断地 Ctrl + C 、Ctrl + V ?
一、java代码自动生成系统开发
1.1 开发环境
- java JDK 8或更新
- Tomcat 6及以上,tomcat8以上更佳,或者jetty7以上
- intellij idea 或者 eclipse
- maven
- mysql 5.7及以上(非必须)
- idea 需要安装lombok插件,一块缩减代码的getter setter log等的插件
1.2 已实现目标
- 通过配置实体模板自动生成MVC层,及mysql的脚本
- 通过配置现有系统的开发模板(或者开发流程),进行全自动生成各层的代码
1.3 系统推介
系统模块结构图,如下图所示,图中展示了,模板层,基础层,代码自动生成层,以及各层的必备工具utils层。
生成的系统模块逻辑代码如下图所示,这些代码完全是根据模板,通过IO流,配置规则,自动读取包名进行切割完成IO输出,注释和配置分层都会自动生成,代码可以随意更改,完全符合你需要更改成自己的模块生成的自由度。
二、系统亮点展示
2.1 亮点一、自动读取实体,根据注释生成js table所需的代码
如下图,是js table节选代码块,如果是做管理后台的页面,bootstrap 里头有js table控件 这是标配了。
而这一部分,代码的相似性,可以不夸张地说,所有的模块,所有目录下的页面都会包含,如果,每次都要去开发,都要去复制粘贴修改,这是多么痛苦的领悟!
举例说明: 下面有这么一个实体,实现的是机构信息这么个实体。
package com.xxx.cum.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 机构信息
* @author XXX
* @version Id; OrgInfo, 2018/8/9 16:17 XXX Exp $$
*/
@Data
public class OrgInfo implements Serializable {
private static final long serialVersionUID = ${gETSerialVersionUID };
/**
* ID
*/
private Long id;
/**
* 机构编号
*/
private String orgCode;
/**
* 机构名称
*/
private String orgName;
/**
* 机构全称
*/
private String orgFullName;
/**
* 收款开户行银行编码
*/
private String bankCode;
/**
* 收款开户行名称
*/
private String bankName;
/**
* 收款银行卡账号'
*/
private String bankCardNo;
/**
* 银联分润比例
*/
private BigDecimal unionpayBenefitRate;
/**
* 品牌服务费率
*/
private BigDecimal brandRate;
/**
* 转接清算费率
*/
private BigDecimal transferRate;
/**
* 付款摘要
*/
private String payoutSummary;
/**
* 是否集团结算 0否 1是
*/
private String groupSettle;
/**
* 是否再付 0否 1是
*/
private String payAgain;
/**
* 公私标识 0对公,1对私
*/
private String perEntFlag;
/**
* 清结算模式 1自主清算 2代理清算 3自主清算+代理清算
*/
private String settleType;
/**
* 协议有效期
*/
private Date expiredAt;
/**
* 机构是否停用状态码(默认0,0未停用、1停用、其他待定)
*/
private String state;
/**
* 创建时间
*/
private Date createdAt;
/**
* 创建人
*/
private String createdBy;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 更新人
*/
private String updatedBy;
}
实现步骤:
1)、先读取文件
/**
* 通过类实体获取DataTable
* @return
* @throws IOException
*/
public static String doSomeThing() throws IOException {
StringBuilder outputSb = new StringBuilder();
//读文件
File directory = new File("F:\\study\\project\\noUsage\\codeGenerator\\dedd\\com.william\\src\\main\\java\\com\\william\\auto\\temp_help\\template_oss_web");
for (File tempFile : directory.listFiles()) {
if (tempFile.getName().indexOf(".xml") != -1) {
FileReader fileReader = new FileReader(tempFile);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String s = null;
StringBuilder sb = new StringBuilder();
while(( s = bufferedReader.readLine() ) != null ) {
//System.out.println(s);
sb.append(s);
}
List<String> annoList = getRegexAnnotationExp("\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*\\/",sb);
List<String> fieldList = getRegexFieldExp("private\\s+([a-zA-Z]*)*\\s+([a-zA-Z]*)*",sb);
for (int i=0;i<fieldList.size();i++) {
if (fieldList.size() > i) {
if (fieldList.get(i).equalsIgnoreCase("final")) {
continue;
}
//{'title': '选择', 'column': 'id'},
String item = "{'title':'"+annoList.get(i)+",'column':'"+fieldList.get(i)+"'},";
outputSb.append(item+"\n");
//System.out.println(item);
}
}
//输出结果
System.out.println(outputSb.toString());
}
}
return outputSb.toString();
}
2)、读取实体,以注释作为js table的title,属性作为值
/**
* 读取注释文字
* @param regexExp
* @param sb
*/
private static List<String> getRegexAnnotationExp(String regexExp, StringBuilder sb) {
List<String> resultList = new ArrayList<String>();
Pattern pattern = Pattern.compile(regexExp);
String searchPlainText = sb.toString();
Matcher matcher = pattern.matcher(searchPlainText);
while (matcher.find()) {
String groupExp = matcher.group(0).replaceAll("/\\*+\\s+\\*","").replaceAll("\\s+\\*/","");
resultList.add(groupExp);
//System.out.println("匹配到:"+groupExp+" 位置:(" + matcher.start()+","+matcher.end()+")");
}
return resultList;
}
/**
* 读取属性field
* @param regexExp
* @param sb
*/
private static List<String> getRegexFieldExp(String regexExp,StringBuilder sb) {
List<String> resultList = new ArrayList<String>();
Pattern pattern = Pattern.compile(regexExp);
String searchPlainText = sb.toString();
Matcher matcher = pattern.matcher(searchPlainText);
while (matcher.find()) {
String groupExp = matcher.group(0).replaceAll("private\\s+([a-zA-Z]*)*\\s+","");
resultList.add(groupExp);
//System.out.println("匹配到:"+groupExp+" 位置:(" + matcher.start()+","+matcher.end()+")");
}
return resultList;
}
生成的结果如下:
{'title':' 机构编号,'column':'orgCode'},
{'title':' 机构名称,'column':'orgName'},
{'title':' 机构全称,'column':'orgFullName'},
{'title':' 收款开户行银行编码,'column':'bankCode'},
{'title':' 收款开户行名称,'column':'bankName'},
{'title':' 收款银行卡账号','column':'bankCardNo'},
{'title':' 银联分润比例,'column':'unionpayBenefitRate'},
{'title':' 品牌服务费率,'column':'brandRate'},
{'title':' 转接清算费率,'column':'transferRate'},
{'title':' 付款摘要,'column':'payoutSummary'},
{'title':' 是否集团结算 0否 1是,'column':'groupSettle'},
{'title':' 是否再付 0否 1是,'column':'payAgain'},
{'title':' 公私标识 0对公,1对私,'column':'perEntFlag'},
{'title':' 清结算模式 1自主清算 2代理清算 3自主清算+代理清算,'column':'settleType'},
{'title':' 协议有效期,'column':'expiredAt'},
{'title':' 机构是否停用状态码(默认0,0未停用、1停用、其他待定),'column':'state'},
{'title':' 创建时间,'column':'createdAt'},
{'title':' 创建人,'column':'createdBy'},
{'title':' 更新时间,'column':'updatedAt'},
{'title':' 更新人,'column':'updatedBy'},
2.2 自动替换代码模板的内容(代码为节选块)
File templateDirectory = new File(mybatisPath);
if (templateDirectory.isDirectory()) {
File[] templateFiles = templateDirectory.listFiles();
for (File templateFileItem : templateFiles) {
String suffixGenerate = ".xml";
String template = "";
FileReader fr = new FileReader(templateFileItem);
BufferedReader br = new BufferedReader(fr);
String s,packagePath = "";
while ((s = br.readLine()) != null) {
if(s.trim().startsWith("package ")){
suffixGenerate = ".java";
packagePath = s;
packagePath = packagePath.replaceAll("package","").trim().toLowerCase().replaceAll(";","");
logger.info("package path: " + packagePath + "\n");
}
template += s + "\n";
}
fr.close();
// 替换内容
template = StringUtils.toReplaceTemplateKey(template, new String[]{
"Template",
"template",
"author",
"TemplateCN",
"DateTime",
"TemplateUpdateReturn",
"TemplateDeleteReturn",
"TemplateAddReturn",
"TemplateReturnUpdateType",
"TemplateReturnDeleteType",
"TemplateReturnAddType"
},
new String[]{
className,
StringUtils.toLower(className),
author,
classCNName,
new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date()),
TemplateUpdateReturn,
TemplateDeleteReturn,
TemplateAddReturn,
TemplateReturnUpdateType,
TemplateReturnDeleteType,
TemplateReturnAddType
});
String realProjectFilePath = "";
for (String tempPath:packagePath.split("\\.")) {
logger.info("tempPath:" + tempPath + "\tpackagePath:"+packagePath);
if (StringUtils.isNull(realProjectFilePath)) {
realProjectFilePath = realProjectFilePath + tempPath ;
} else {
realProjectFilePath = realProjectFilePath +File.separator+ tempPath ;
}
logger.info("切割后生成的目录为:==> packagePath:"+realProjectFilePath);
}
String path = PROJECT_PATH + File.separator + PropertiesHelper.getValueByKey("rootPackage").replaceAll("\\.","\\\\") + File.separator + yyyyMMddHHmmss + File.separator+ realProjectFilePath + File.separator;
File file = new File(path);
if(!file.exists()){
file.mkdirs();
}
//File fileBiz = new File(path + "\\" + fileNameTemplate + suffixTemplate);
String fileItemName = templateFileItem.getName().replaceAll("_","").replaceAll("CustInfoConfig",className).replaceAll("Template",className).split("\\.")[0];
FileWriter fw = new FileWriter(path + File.separator + fileItemName + suffixGenerate);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(template);
bw.close();
logger.info("生成测试类文件:[" + fileItemName + suffixGenerate + "]成功" );
logger.info("文件根目录点击打开:[" + "file:" + File.separator + File.separator+ File.separator + path + "]成功" );
}
如你所有的模板中,有个类注解
/**
* ${TemplateCN}查询请求
* @author ${author}
* @version Id: ${Template}QueryRequest.java , ${DateTime} ${author} Exp $
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ${Template}QueryRequest extends CumRequest {
模板中的${TemplateCN} ,${author} ,${Template},${DateTime}
可以通过全局文件的替换功能,实现替换
替换后的效果:
/**
* 商户查询请求
* @author zs
* @version Id: OssCustInstRateQueryRequest.java , 2018-09-03 17:08 zs Exp $
*/
2.3 自动生成各层的MVC代码,及数据库
/**
* 开始执行自动生成代码
* @param className
*/
private static void autoGenerator(String className) {
try{
//生成实体对象
Class.forName(entityPackage + "." + className);
//生成实体文件
writeEntity(className);
//生成dao
writeDao(className);
//生成service
writeService(className);
//生成service的实现类
writeServiceImpl(className);
//生成controller类
writeController(className);
//生成xml文件
writeXml(className);
//生成ServiceTest的实现类
writeFileBeforeReplace(className,"TemplateManageServiceTest",className + "ManageServiceTest",".xml",".java");
//生成dubbo-service-provider.xml配置文件
writeDubboProviderXml(className);
System.out.println("\n======生成的建表语句如下:======");
System.out.println(SqlGenerator.generateSql(entityPackage + "." + className,"id"));
}catch (Exception e){
logger.error(e.getStackTrace(),e);
}
}
如dao层、sql脚本生成的代码节选:
/**
* 生成dao代码
* @param className
*/
private static void writeDao(String className) {
String daoPath = StringUtils.getJavaPath() + templatePackage;
try {
String targetDao = PROJECT_PATH + File.separator + PropertiesHelper.getValueByKey("rootPackage").replaceAll("\\.","/") + File.separator + "dao//";
File file = new File(targetDao);
if(!file.exists()){
file.mkdirs();
}
File fileAction = new File(targetDao + className + "Dao.java");
if (!fileAction.exists()) {
String template = "";
FileReader fr = new FileReader(daoPath + "TemplateDao.java");
BufferedReader br = new BufferedReader(fr);
String s;
boolean started = false;
while ((s = br.readLine()) != null) {
if(s.startsWith("package")){
//重新赋值
s = "package " + PropertiesHelper.getValueByKey("rootPackage") + ".dao;";
}
if(!started){
if(s.startsWith("import")){
String entityClass = PropertiesHelper.getValueByKey("rootPackage") + ".entity." + className + ";";
template += "import " + entityClass + "\n";
started = true;
}
}
template += s + "\n";
}
fr.close();
// 替换内容
template = template.replaceAll("Template", className).replaceAll("template", className);
FileWriter fw = new FileWriter(targetDao + className + "Dao.java");
BufferedWriter bw = new BufferedWriter(fw);
bw.write(template);
bw.close();
}
logger.info("生成dao类:[" + className + "Dao]成功" );
} catch (Exception e) {
e.printStackTrace();
}
}
sql脚本根据配置的实体生成:
public class SqlGenerator {
static Logger logger = Logger.getLogger(SqlGenerator.class);
public static void main(String[] args) {
String className = "User";
System.out.println(generateSql(className,"id"));
}
/**
* 根据实体类生成建表语句
* @author
* @param className 全类名
*/
public static String generateSql(String className,String indexKey){
try {
Class<?> clz = Class.forName(className);
className = clz.getSimpleName();
Field[] fields = clz.getDeclaredFields();
StringBuffer column = new StringBuffer();
String varchar = " varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,";
for (Field f : fields) {
boolean isStatic = Modifier.isStatic(f.getModifiers());
if(!isStatic) {
if (indexKey.equals(f.getName())) {
column.append("\n\t`" + f.getName() + "` int(11) NOT NULL AUTO_INCREMENT,");
} else {
Class type = f.getType();
if (type == String.class) {
column.append("\n\t`" + f.getName() + "`" + varchar);
}
}
}
}
StringBuffer sql = new StringBuffer();
sql.append("DROP TABLE IF EXISTS `"+ RuleUtils.getTableNameByBean(className) + "`; ")
.append("\nCREATE TABLE `"+ RuleUtils.getTableNameByBean(className) + "`(")
.append(column)
.append(" \n\t PRIMARY KEY (`" + indexKey + "`) USING BTREE")
.append("\n) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci;");
return sql.toString();
} catch (ClassNotFoundException e) {
e.printStackTrace();
logger.debug("该类未找到!");
return null;
}
}
}
代码下载
对本代码感兴趣的同学,可以下载下来使用,下载地址
对本代码感兴趣的同学,可以下载下来使用,下载地址
对本代码感兴趣的同学,可以下载下来使用,下载地址