内容简介:为了提高开发效率,通常会想办法把一些模式固定的重复性的劳动抽取出来,以后再使用的时候,拿来主义就可以了。这样既可以提高开发效率,又降低了出错的风险。这一思想在我们的日常工作中可以说随处可见,我们完成一项复杂的工程,并不需要面面俱到什么都自己写,我们完全可以利用第三方的jar包让我们达到事半功倍的效果,比如经常使用的apche的commons-lang3包。再比如java中的继承、我们自己封装的工具类等等。 另外一方面,对于源码文件,如果公司有成熟的框架,我们的开发都是遵循着框架制定的约定来进行开发的,我们在
为了提高开发效率,通常会想办法把一些模式固定的重复性的劳动抽取出来,以后再使用的时候,拿来主义就可以了。这样既可以提高开发效率,又降低了出错的风险。
这一思想在我们的日常工作中可以说随处可见,我们完成一项复杂的工程,并不需要面面俱到什么都自己写,我们完全可以利用第三方的jar包让我们达到事半功倍的效果,比如经常使用的apche的commons-lang3包。再比如 java 中的继承、我们自己封装的 工具 类等等。 另外一方面,对于源码文件,如果公司有成熟的框架,我们的开发都是遵循着框架制定的约定来进行开发的,我们在创建某一个业务的控制层、业务层、持久层的时候,实际上有相当一部分的工作是重复的。
那么对于源码文件的编写我们能否偷偷懒呢?答案肯定是可以的,我们可以利用模板引擎技术,将不变的部分写在模板文件中,将可变的部分作为变量传递到模板引擎的上下文中,最终生成我们想要的源码文件。
模板引擎的产品有很多,比如前端模板artTemplate、后端模板Velocity、FreeMarker等 本文以Velocity为例,总结一下它在实战中的应用
1.基础知识
2.搭建工程
2.1模块目录
代码生成功能,在我设计的后台框架中,作为一个独立的模块存在,使用Maven构建。
builder目录:建造者模式应用。由于代表表结构的Table实体稍显复杂,因此使用了建造者模式构建Table对象。其实不用也可以,因为Table不是很复杂,只是为了复习一下所学过的 设计模式 知识
factory目录:工厂模式应用。在构建源码文件的时候,由于涉及到了Controller、Service、Dao、Domain这几种类型的文件,因此针对不同类型的文件,要使用其对应的处理类,因此使用了工厂模式
handler目录:生成源文件的核心代码
model目录:在生成domain的时候,由于字段需要从数据库中的表中读取,因此构造了与表对应的实体类方便处理
utils目录:工具类
Generator.java:程序主文件,调用入口
test目录:单元测试
. ├── generator.iml ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── wt │ │ └── master │ │ └── generator │ │ ├── Generator.java │ │ ├── builder │ │ │ ├── MySqlTableBuilder.java │ │ │ └── TableBuilder.java │ │ ├── factory │ │ │ └── GeneratorFactory.java │ │ ├── handler │ │ │ ├── BaseGenerator.java │ │ │ ├── ControllerGeneratorHandler.java │ │ │ ├── DomainGeneratorHandler.java │ │ │ ├── MapperGeneratorHandler.java │ │ │ └── ServiceGeneratorHandler.java │ │ ├── model │ │ │ └── Table.java │ │ └── util │ │ ├── JdbcUtils.java │ │ ├── SpringContextUtils.java │ │ ├── TableColumnUtils.java │ │ └── TableInfoUtils.java │ └── resources │ ├── config │ │ ├── applicationContext.xml │ │ └── db.properties │ └── template │ ├── controller.java.vm │ ├── dao.java.vm │ ├── domain.java.vm │ ├── service.java.vm │ └── serviceimpl.java.vm └── test └── com.wt.master.generator └── GeneratorTest.java
2.2引入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>j2ee</artifactId> <groupId>com.wt.master</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../version/</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>generator</artifactId> <dependencies> <!-- 模板引擎 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>com.wt.master</groupId> <artifactId>core</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.4</version> </dependency> </dependencies> </project>
3.核心代码
3.1模板文件的定义
以controller层生成模板为例
将不变的部分直接写到.vm文件中
将模板文件中,有可能发生变化的部分,抽取为变量,变量的值从VelocityContext中获取
在Velocity架构中,有一个上下文的定义,通过上下文,程序将变量放入上下文对象中。而模板从上下文中获取对应变量的值,获取的方式是${变量名},关于Velocity模板文件中的语法,参见上文提到的两篇文章
package ${packagePath}.controller; import ${packagePath}.domain.${moduleName}; import ${packagePath}.service.${moduleName}Service; import com.wt.master.core.base.BaseController; import com.wt.master.core.helper.QueryHelper; import com.wt.master.core.request.HttpResultEntity; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.List; import java.util.Map; /** * ${moduleNameCN}控制器 * * @author * @date */ @Api(value = "${moduleNameCN}控制器", tags = "${moduleName}Controller", description = "${moduleNameCN}控制器" ) @RestController @RequestMapping("/${moduleName}" ) @Slf4j public class ${moduleName}Controller extends BaseController<${moduleName}, ${moduleName}Service> { @Autowired private ${moduleName}Service ${lowerModuleName}Service; @Override protected ${moduleName}Service getService() { return ${lowerModuleName}Service; } }
3.2工厂类定义
根据源码文件类型的不同,定义了不同的处理类,通过工厂模式返回对应的处理类
package com.wt.master.generator.factory; import com.wt.master.generator.Generator; import com.wt.master.generator.handler.*; /** * 生成器工厂 * * @author lichking2019@aliyun.com * @date Jun 18, 2019 at 4:02:23 PM */ public class GeneratorFactory { public static BaseGenerator create(Generator.GenerateItem item) { BaseGenerator baseGenerator = null; switch (item) { case service: baseGenerator = new ServiceGeneratorHandler(); break; case controller: baseGenerator = new ControllerGeneratorHandler(); break; case mapper: baseGenerator = new MapperGeneratorHandler(); break; case domain: baseGenerator = new DomainGeneratorHandler(); break; default: baseGenerator = new ControllerGeneratorHandler(); } return baseGenerator; } }
3.3源码生成处理类定义
以controller处理类为例
定义抽象类,作为基类
定义了抽象方法generate,生成源码文件的处理方法
定义了抽象方法getFilePath,获取生成文件的路径
方法的实现由具体的实现类来实现
package com.wt.master.generator.handler; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; /** * 生成器抽象 * * @author lichking2019@aliyun.com * @date May 12, 2019 at 10:44:53 AM */ public abstract class BaseGenerator { /** * 生成代码 * * @param tableName 表名 * @param moduleName 模块英文名 * @param moduleNameCN 模块中文名 * @param packagePath 包路径 * @return */ public abstract BaseGenerator generate(String tableName, String moduleName, String moduleNameCN, String packagePath); /** * 生成文件路径 * @param packagePath * @return */ public abstract String getFilePath(String packagePath,String moduleName); /** * 获取 模板 * * @param templateName 模板文件名称 * @return */ Template getTemplate(String templateName) { VelocityEngine ve = new VelocityEngine(); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath" ); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.setProperty("input.encoding","utf-8"); ve.setProperty("output.encoding","utf-8"); ve.init(); Template t = ve.getTemplate("/template/" + templateName); return t; } protected void merge(Template template, VelocityContext ctx, String path) { File file = new File(path); if(!file.exists()){ new File(file.getParent()).mkdirs(); }else{ System.out.println("替换文件"+file.getAbsolutePath()); } PrintWriter writer = null; try { writer = new PrintWriter(path); template.merge(ctx, writer); writer.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { writer.close(); } } /** * 获得根目录 * @return */ protected String getRootPath(){ String rootPath = ""; try { File file = new File(BaseGenerator.class.getResource("/").getFile()); rootPath = file.getParent(); rootPath = java.net.URLDecoder.decode(rootPath.substring(0, rootPath.indexOf("target") - 1), "utf-8"); return rootPath+"/src/main/java"; } catch (Exception e) { e.printStackTrace(); } return rootPath; } /** * 转换包路径为文件路径 * @param packagePath * @return */ protected String convertPackagePathToFilePath(String packagePath){ StringBuilder path = new StringBuilder(); path.append("/" ); path.append(packagePath.replace(".", "/" )); path.append("/"); return path.toString(); } }
3.4工具类的定义
该类主要是获取表的信息及对应的字段信息
package com.wt.master.generator.util; import com.wt.master.generator.model.Table; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.util.CollectionUtils; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 表操作类 * * @author lichking2019@aliyun.com * @date Apr 23, 2019 at 11:36:30 PM */ public class TableInfoUtils { public static final String JDBC_TEMPLATE = "jdbcTemplate"; public static Table getTableColumnList(String tableName) { JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringContextUtils.getBean(JDBC_TEMPLATE); List<Map<String,Object>> tableInfo = jdbcTemplate.queryForList(getTableStructureSql(tableName)); if (CollectionUtils.isEmpty(tableInfo)) { throw new RuntimeException("表:" + tableName + "不存在" ); } List<Map<String,Object>> columns = jdbcTemplate.queryForList(getColumnStructureSql(tableName)); return TableColumnUtils.convertToColumn(columns, tableInfo.get(0)); } /** * 获取查询表字段属性的SQL * * @param tableName 表名 * @return */ private static String getColumnStructureSql(String tableName) { StringBuilder sql = new StringBuilder(); sql.append("select column_name, data_type,column_comment,column_key " ); sql.append("from information_schema.columns " ); sql.append("where table_name = '" + tableName + "'" ); return sql.toString(); } /** * 获取表的信息 * @param tableName * @return */ private static String getTableStructureSql(String tableName) { StringBuilder sql = new StringBuilder(); sql.append("select table_name,table_comment " ); sql.append("from information_schema.tables " ); sql.append("where table_name= '" + tableName + "'" ); return sql.toString(); } }
3.5应用入口
代用create方法来生成源码文件
package com.wt.master.generator; import com.wt.master.generator.builder.MySqlTableBuilder; import com.wt.master.generator.builder.TableBuilder; import com.wt.master.generator.factory.GeneratorFactory; import com.wt.master.generator.handler.BaseGenerator; import com.wt.master.generator.model.Table; import com.wt.master.generator.util.TableInfoUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.util.Assert; import java.util.List; /** * 代码生成工具 * * @author lichking2019@aliyun.com * @date Apr 23, 2019 at 10:41:51 PM */ public class Generator { /** * 生成代码入口 * * @param tableName 表名 * @param moduleName 模块英文名 * @param moduleNameCN 模块中文名 * @param packagePath 打包路径 * @param item 生成项目 */ public static void create(String tableName, String moduleName, String moduleNameCN, String packagePath, GenerateItem... item) { if (StringUtils.isBlank(tableName) || StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleNameCN) || StringUtils.isBlank(packagePath)) { throw new IllegalArgumentException("参数非法!" ); } for (GenerateItem generateItem : item) { BaseGenerator baseGenerator = GeneratorFactory.create(generateItem); baseGenerator.generate(tableName, moduleName, moduleNameCN, packagePath); } } public enum GenerateItem { controller, service, mapper, domain } }
4.单元测试
package com.wt.master.generator; import org.junit.Test; import org.junit.Before; import org.junit.After; /** * Generator Tester. * * @author <Authors name> * @version 1.0 * @since <pre>Jun 18, 2019</pre> */ public class GeneratorTest { @Test public void testCreate() throws Exception { //TODO: Test goes here... Generator.create("SecurityRoleT", "SecurityRole", "角色管理", "com.wt.common.security", Generator.GenerateItem.controller, Generator.GenerateItem.service, Generator.GenerateItem.mapper, Generator.GenerateItem.domain); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learn Python the Hard Way
Zed Shaw / Example Product Manufacturer / 2011
This is a very beginner book for people who want to learn to code. If you can already code then the book will probably drive you insane. It's intended for people who have no coding chops to build up t......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!
RGB转16进制工具
RGB HEX 互转工具
RGB HSV 转换
RGB HSV 互转工具