Free marker 模板引擎介绍
free marker 是一款模板引擎,通过模板生成文件、包括 HTML,excel、Java代码等。可以极大的提高开发效率。它的逻辑主要写在自定义标签中。
集成 freemarker 依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.32</version>
</dependency>
写一个最简单的代码生成器(写啥生成啥)
- 定义模板文件 test.ftl
package nuc.zm.generator.test;
public class Test{
/**
* ID
*/
private Integer id;
}
- 书写 Java 工具类
package nuc.zm.generator.test;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestUtil {
private static String ftlPath = "generator/src/main/java/nuc/zm/generator/test";
// 注意 这里一定要由 / 结尾 要不然生成的 文件名 为 testTest.java 噶
private static String toPath = "generator/src/main/java/nuc/zm/generator/test/";
public static void main(String[] args) throws IOException, TemplateException {
// 读模板 这四步都读模板是固定写法
Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
// 设置模板引擎的模板文件在的目录。
configuration.setDirectoryForTemplateLoading(new File(ftlPath));
// 设置对象包装器
configuration.setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_32));
// 读模板路径下的具体文件
Template template = configuration.getTemplate("test.ftl");
// 生成 Java文件
FileWriter fileWriter = new FileWriter(toPath + "Test.java");
BufferedWriter writer = new BufferedWriter(fileWriter);
template.process(null,writer<p align=left>);</p>
writer.flush();
writer.close();
}
}
- 运行 工具类就会自动生成 Test.java 类
部分代码固定,封装为工具类
package nuc.zm.generator.util;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* 代码生成器工具类
* 模板引擎 free marker
* @author zm
* @date 2023/05/10
*/
public class FreemarkerUtils {
private static final String ftlPath = "generator/src/main/java/nuc/zm/generator/ftl/";
static Template template ;
/**
* 初始化配置
*
* @param ftlName ftl名字
* @throws IOException ioexception
*/
public static void initConfig(String ftlName) throws IOException {
// 读模板 这四步都读模板是固定写法
Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
// 设置模板引擎的模板文件在的目录。
configuration.setDirectoryForTemplateLoading(new File(ftlPath));
// 设置对象包装器
configuration.setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_32));
// 读模板路径下的具体文件
template = configuration.getTemplate(ftlName);
}
/**
* 发电机
*
* @param fileName 包含路径的文件名称
* @throws IOException IoException
* @throws TemplateException 模板异常
*/
public static void generator(String fileName) throws IOException, TemplateException {
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fileWriter);
template.process(null,writer);
writer.flush();
writer.close();
}
}
复制以前写过的Javaservice层单表查询代码置模板文件中
将变化部分封装为free marker 变量
例如 :将 Chapter 变为 {domain} 大小写要对应。
最终工具类
public class FreemarkerUtils {
private static final String ftlPath = "generator/src/main/java/nuc/zm/generator/ftl/";
static Template template ;
/**
* 初始化配置
*
* @param ftlName ftl名字
* @throws IOException ioexception
*/
public static void initConfig(String ftlName) throws IOException {
// 读模板 这四步都读模板是固定写法
Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
// 设置模板引擎的模板文件在的目录。
configuration.setDirectoryForTemplateLoading(new File(ftlPath));
// 设置对象包装器
configuration.setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_32));
// 读模板路径下的具体文件
template = configuration.getTemplate(ftlName);
}
/**
* 发电机
*
* @param fileName 包含路径的文件名称
* @throws IOException IoException
* @throws TemplateException 模板异常
*/
public static void generator(String fileName , Map<String,String> map) throws IOException, TemplateException {
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fileWriter);
// 第一个参数放置模型数据
template.process(map,writer);
writer.flush();
writer.close();
}
}
service 生成主类
public class GeneratorMain {
private static final String toServicePath = "your service interface dir path";
private static final String toServiceImplPath = "your serviceImpl class dir path";
private static final String toControllerPath = moudle + "your controller dir path";
// 变量都抽离出来即可。
public static void main(String[] args) throws IOException, TemplateException {
Map<String,String> map = new HashMap<>();
Scanner sc = new Scanner(System.in);
String Domain = sc.next();
String domain = sc.next();
map.put("Domain",Domain);
map.put("domain",domain);
// 接口生成器
FreemarkerUtils.initConfig("service.ftl");
FreemarkerUtils.generator(toServicePath + Domain + "Service.java" , map);
FreemarkerUtils.initConfig("service_impl.ftl");
// 实现类生成器
FreemarkerUtils.generator(toServiceImplPath + Domain + "ServiceImpl.java",map);
}
}
DTO、POJO类的生成 (freemarker 标签 list 的使用)
这个就比较复杂了 要知道的信息如下
- 数据库表的字段
- 要映射成的Java类型
- 字段大小驼峰的转换 : course_id -->
courseId | CourseId
解决数据库字段的映射问题
定义映射字段类
package nuc.zm.generator.util;
/**
* 数据库字段映射类
*
* @author zm
* @date 2023/05/11
*/
public class DbField {
private String name; // 数据库字段名
private String nameHump; // 转为小驼峰
private String nameBigHump; // 转为大驼峰
private String nameCn; // 中文名 非中文 搁置即可
private String dbType; // 数据库字段类型 ru bigint
private String javaType; // java类型
private String comment; // 字段备注
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNameHump() {
return nameHump;
}
public void setNameHump(String nameHump) {
this.nameHump = nameHump;
}
public String getNameBigHump() {
return nameBigHump;
}
public void setNameBigHump(String nameBigHump) {
this.nameBigHump = nameBigHump;
}
public String getNameCn() {
return nameCn;
}
public void setNameCn(String nameCn) {
this.nameCn = nameCn;
}
public String getDbType() {
return dbType;
}
public void setDbType(String dbType) {
this.dbType = dbType;
}
public String getJavaType() {
return javaType;
}
public void setJavaType(String javaType) {
this.javaType = javaType;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
@Override
public String toString() {
return "DbField{" +
"name='" + name + ''' +
", nameHump='" + nameHump + ''' +
", nameBigHump='" + nameBigHump + ''' +
", nameCn='" + nameCn + ''' +
", dbType='" + dbType + ''' +
", javaType='" + javaType + ''' +
", comment='" + comment + ''' +
'}';
}
}
数据库工具类 连接和映射
package nuc.zm.generator.util;
import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* 数据库工具类
* 获取数据库所有字段名 映射 为 java 类型
*
* @author zm
* @date 2023/05/11
*/
public class DbUtils {
public static final String jdbcProPath = "generator/src/main/resources/jdbc.properties";
private static Connection getConnection() throws IOException, SQLException, ClassNotFoundException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(jdbcProPath));
Properties properties = new Properties();
properties.load(bufferedInputStream);
String driver = (String) properties.get("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String passwd = properties.getProperty("jdbc.passwd");
Class.forName(driver);
return DriverManager.getConnection(url, username, passwd);
}
/**
* 得到表名 注释为表名
*
* @param tableName 表名
* @return {@link String}
* @throws SQLException sqlexception异常
* @throws IOException ioexception
* @throws ClassNotFoundException 类没有发现异常
*/
public static String getTableComment(String tableName) throws SQLException, IOException, ClassNotFoundException {
Connection connection = getConnection();
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("select table_comment from information_schema.TABLES where TABLE_NAME = '" + tableName + "'");
if (rs != null) {
while (rs.next()){
String tableNameCn = rs.getString("table_comment");
System.out.println("表的中文名称" + tableNameCn);
close(connection,statement,rs);
return tableNameCn;
}
}
return null;
}
public static List<DbField> getAllFieldInfo(String tableName) throws SQLException, IOException, ClassNotFoundException {
Connection connection = getConnection();
Statement statement = connection.createStatement();
ArrayList<DbField> ans = new ArrayList<>();
ResultSet rs = statement.executeQuery("show full columns from " + tableName );
if (rs != null) {
while (rs.next()) {
String fieldName = rs.getString("field");
String dBType = rs.getString("type");
String comment = rs.getString("comment");
DbField dbField = new DbField();
dbField.setName(fieldName);
dbField.setDbType(dBType);
dbField.setComment(comment);
if (comment.contains("|")) {
dbField.setNameCn(comment.substring(0,comment.indexOf("|")));
}
dbField.setNameHump(toNameHump(fieldName));
dbField.setNameBigHump(toBigNameHump(fieldName));
ans.add(dbField);
}
}
return ans;
}
/**
* 大名字驼峰
* 规定列名 为 xx_xx
* @param fieldName 字段名
* @return {@link String}
*/
private static String toBigNameHump(String fieldName) {
if (fieldName == null || fieldName.isEmpty()) {
return "";
}
// 开头是否大写
boolean toUpper = true;
return connectStr(fieldName,toUpper);
}
private static String toNameHump(String fieldName) {
if (fieldName == null || fieldName.isEmpty()) {
return "";
}
// 开头是否大写
boolean toUpper = false;
return connectStr(fieldName,toUpper);
}
private static void close(Connection con, Statement st, ResultSet rs) {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static String connectStr(String fieldName , boolean toUpper) {
StringBuilder sb = new StringBuilder(fieldName.length());
for (char ch : fieldName.toCharArray()) {
if (ch == '_') {
toUpper = true;
continue;
}
sb.append(toUpper ? Character.toUpperCase(ch) : ch);
toUpper = false;
}
return sb.toString();
}
}
最终的代码生成器工具类
/**
* 代码生成器工具类
* 模板引擎 free marker
* @author zm
* @date 2023/05/10
*/
public class FreemarkerUtils {
private static final String ftlPath = "generator/src/main/java/nuc/zm/generator/ftl/";
static Template template ;
/**
* 初始化配置
*
* @param ftlName ftl名字
* @throws IOException ioexception
*/
public static void initConfig(String ftlName) throws IOException {
// 读模板 这四步都读模板是固定写法
Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
// 设置模板引擎的模板文件在的目录。
configuration.setDirectoryForTemplateLoading(new File(ftlPath));
// 设置对象包装器
configuration.setObjectWrapper(Configuration.getDefaultObjectWrapper(Configuration.VERSION_2_3_32));
// 读模板路径下的具体文件
template = configuration.getTemplate(ftlName);
}
/**
* 发电机
*
* @param fileName 包含路径的文件名称
* @throws IOException IoException
* @throws TemplateException 模板异常
*/
public static void generator(String fileName , Map<String,Object> map) throws IOException, TemplateException {
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fileWriter);
// 第一个参数放置模型数据
template.process(map,writer);
writer.flush();
writer.close();
}