- 代码生成器顾名思义就生成代码的一个软件。 为了节省人力成本, 在日常的企业开发中, 代码生成器使用的较为普遍。
- 简单说:可以生成代码的程序
- 例如:
- 可以得出如下结论
- jsp就是一个模板
- tomcat根据jsp和数据生成了html代码
- tomcat内部有一个代码生成器可以生成html代码
- 代码生成器=模板+数据+合成机制
- 对比如下两个mapper接口
- 代码生成器的好处
- 节省人力成本
- 易于代码规范控制
- 代码生成器三要素
- 模板: 生成文件的模板文件
- 数据: 生成文件所需要的关键数据
- 合成机制: 使用数据置换模板中的占位符, 生成新的文件的机制
- 其中数据我们可以从数据库中进行获取, 模板文件,以及根据模板文件生成代码的机制我们选用较为成熟的模板引擎: FreeMarker,velocity,thymeleaf
- FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本 (HTML 网页、 电子邮件、 配置文件、 源代码等) 的通用工具。 FreeMarker 是免费的, 基于 Apache 许可证 2.0 版本发布。 其模板编写为 FreeMarker Template Language(FTL) , 属于简单、 专用的语言。
- 原理图
- freemarker数据合成
- 下载freemarker的jar包
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
</dependencies>
- 创建Configuration对象
- 作用:环境初始化
- 常用API
-
创建Template对象- 作用:模板实例化,执行代码生成
- 常用API
- 入门案例
- java代码
public void test1() throws IOException, TemplateException {
// 初始化freemarker配置
// 创建configuration对象实例
Configuration configuration = new Configuration();
// 获取源文件夹的位置
String path = this.getClass().getClassLoader().getResource("").getPath();
// 设置模板文件位置
configuration.setDirectoryForTemplateLoading(new File(path));
// 通过configuration对象获根据模板名称取到template
Template template = configuration.getTemplate("/templates/demo.ftl");
// 组装数据
Map map = new HashMap();
map.put("name", "jerry");
// 传参生成数据
template.process(map, new OutputStreamWriter(new FileOutputStream(new File("d:/a.html"))));
}- 模板代码
<head>
</head>
<body>
hello ${name}<br>
</body>
</html>
freemarker基本语法
- 输出基本数据类型或对象属性
- 输出数据/对象的属性
- 语法规则:${数据}或者${对象.属性}
- 输出集合
- #list sequence as item>
<#ifitem_has_next>
......
<#else>
......
</#if>
</#list>
<#list users as u>
${u.username}<br>
</#list><hr>- 判断条件
- #if condition1>...
<#elseif condition2>
......
<#elseif condition3>
......
<#else>
......
</#if>
<#list users as u>
<#if u.username != "张三">
${u.username}<br>
</#if>
</#list>
<hr>
<#list users as u>
<#if u_has_next>
${u.username},
<#else>
${u.username}
</#if>
</#list>
<hr>
<#list users as u>
<#if u.username ="张三">
${u.username}<br>
<#elseif u.username="李四">
hello${u.username}<br>
<#else>
你好${u.username}<br>
</#if>
</#list>
<hr>
- 我们只需要获取到表的数据,就能够通过代码生成器生成mapper
- 使用JDBC连接数据库
- <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
- 获取DatabaseMetaData元数据
- 获取方式:conn.getMetaData()
- 获取数据库表信息(主要为表名)
- ResultSet resultSet = dbmd.getTables(null, null, null, new String[]{"TABLE"})
- String tableName = resultSet.getString("TABLE_NAME")
/**
* 获取表信息demo
*/
public class TableDemo {
public static final String DBDRIVER = PropertiesUtils.get("database.properties", "mysql.driver");
public static final String DBURL = PropertiesUtils.get("database.properties", "mysql.url");
public static final String DBUSER = PropertiesUtils.get("database.properties", "mysql.user");
public static final String DBPWD = PropertiesUtils.get("database.properties", "mysql.password");
private static Connection conn;
private static DatabaseMetaData metaData;
static {
try {
// 加载驱动
Class.forName(DBDRIVER);
// 获取数据库连接
conn = DriverManager.getConnection(DBURL, DBUSER, DBPWD);
// 得到DatabaseMetaData对象
metaData = conn.getMetaData();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 获取表名
public static void getTable() {
try {
// 拿到表的结果集
ResultSet resultSet = metaData.getTables(null, null, null, new String[]{"TABLE"});
// 遍历结果集
while (resultSet.next()) {
String tableName = resultSet.getString("TABLE_NAME");
System.out.println(tableName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void test() {
getTable();
}
}
- 获取列信息
- 根据表名获取列信息
- ResultSet rs = dbmd.getColumns(null, "%", tableName, "%");
- 获取列名
- rs.getString("COLUMN_NAME")
- 获取列注释
- rs.getString("REMARKS")
- 获取列类型
- rs.getString("TYPE_NAME")
- 根据表名获取列信息
// 获取表的列信息
public static void getColumns(String tableName) {
try {
// 拿到表的列信息结果集
ResultSet resultSet = metaData.getColumns(null, "%", tableName, "%");
// 遍历结果集
while (resultSet.next()) {
// 获取列名
String column_name = resultSet.getString("COLUMN_NAME");
// 获取列类型
String type_name = resultSet.getString("TYPE_NAME");
// 获取列注释
String remarks = resultSet.getString("REMARKS");
System.out.println(table_name + "-" + type_name + "-" + remarks);
}
} catch (Exception e) {
e.printStackTrace();
}
}
- 使用Freemarker编写程序源码模板
- Module.ftl
- Mapper.ftl
- Service.ftl
- ServiceImpl.ftl
- 分层集成
- 模板、数据、合成机制
- 统一配置
- 配置文件
编写pojo的代码生成器
- 先将pojo.java改造为pojo.ftl模板
public class 根据表命转化的类名 implements Serializable {
private 表的列类型-java类型 表的列名称;
public void set表的列名首字母大写 (表的列类型-java类型 表的列名称){
this.表的列名称=表的列名称;
}
public Long get表的列名首字母大写(){
return this.表的列名称;
}
}
- 封装table和column对象
public class Table {
// 数据库表名
private String tableName;
// 表名转化的类名
private String className;
// 表中的列
private List<Column> list;
}
public class Column {
// 列名
private String columnName;
// 属性名(如果列名和属性名不一致需要转换)
private String fieldName;
// 属性名首字母大写
private String upperFieldName;
// 列类型
private String columnType;
// 列类型转换的java类型
private String javaType;
// 列注释
private String remarks;
}
- 抽取TableUtil工具类
/**
* 获取表信息工具类
*/
public class TableUtil {
public static final String DBDRIVER = PropertiesUtils.get("database.properties", "mysql.driver");
public static final String DBURL = PropertiesUtils.get("database.properties", "mysql.url");
public static final String DBUSER = PropertiesUtils.get("database.properties", "mysql.user");
public static final String DBPWD = PropertiesUtils.get("database.properties", "mysql.password");
private static Connection conn;
private static DatabaseMetaData metaData;
static {
try {
// 加载驱动
Class.forName(DBDRIVER);
// 获取数据库连接
conn = DriverManager.getConnection(DBURL, DBUSER, DBPWD);
// 得到DatabaseMetaData对象
metaData = conn.getMetaData();
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取表的列信息
public static List<Column> getColumns(String tableName) {
List<Column> columnList = new ArrayList<Column>();
try {
// 拿到表的列信息结果集
ResultSet resultSet = metaData.getColumns(null, "%", tableName, "%");
// 遍历结果集
while (resultSet.next()) {
Column column = new Column();
// 获取列名
String column_name = resultSet.getString("COLUMN_NAME");
// 获取列类型
String type_name = resultSet.getString("TYPE_NAME");
// 获取列注释
String remarks = resultSet.getString("REMARKS");
//封装columnList
column.setColumnName(column_name);
column.setColumnType(type_name);
column.setFieldName(column_name);
column.setJavaType(StringUtils.switchType(type_name));
column.setRemarks(remarks);
column.setUpperFieldName(StringUtils.captureName(column_name));
columnList.add(column);
}
} catch (Exception e) {
e.printStackTrace();
}
return columnList;
}
// 获取表名
public static List<Table> getTable() {
List<Table> tableList = new ArrayList<Table>();
try {
// 拿到表的结果集
ResultSet resultSet = metaData.getTables(null, null, null, new String[]{"TABLE"});
// 遍历结果集
while (resultSet.next()) {
Table table = new Table();
String tableName = resultSet.getString("TABLE_NAME");
table.setClassName(StringUtils.putOffUnderline(tableName));
table.setTableName(tableName);
List<Column> columnList = getColumns(tableName);
table.setList(columnList);
tableList.add(table);
}
} catch (Exception e) {
e.printStackTrace();
}
return tableList;
}
}
- 修改模板
public class ${table.className} implements Serializable {
<#list table.list as column>
// ${column.remarks}
private ${column.javaType} ${column.fieldName};
</#list>
<#list table.list as column>
public void set${column.upperFieldName} (${column.javaType} ${column.fieldName}){
this.${column.fieldName}=${column.fieldName};
}
public ${column.javaType} get${column.upperFieldName}(){
return this.${column.fieldName};
}
</#list>
}
- 改造生成器GeneratorUtils
public class GeneratorUtil {
private static Configuration configuration = new Configuration();
public static void proceed(Map<String, Object> map, String tempName, String savePath) {
try {
// 通过configuration对象获根据模板名称取到template
Template template = configuration.getTemplate(tempName);
// 传参生成数据
template.process(map, new OutputStreamWriter(new FileOutputStream(new File(savePath))));
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
public static void init(String path) {
try {
// 设置模板文件位置
configuration.setDirectoryForTemplateLoading(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 编写pojo的生成器并测试
public class PojoHandler {
public void execute() {
GeneratorUtil.init(this.getClass().getClassLoader().getResource("templates").getPath());
List<Table> tables = TableUtil.getTable();
for (Table table : tables) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("table", table);
GeneratorUtil.proceed(map, "pojo.ftl", "d:/data/" + table.getClassName() + ".java");
}
}
@Test
public void test() {
PojoHandler handler = new PojoHandler();
handler.execute();
}
}