Freemarker简单实现一个代码生成器
首先文件如下:

我的模板配置如下:
package ${packageName}; import java.util.Date; public class ${className}{ <#-- 循环类型及属性 --> <#list attrs as attr> private ${attr.type} ${attr.name}; //${attr.remarks} </#list> <#-- 循环生成set get方法 --> <#list attrs as attr> public void set${attr.name}(${attr.type} ${attr.name}) { this.${attr.name} = ${attr.name}; } public ${attr.type} get${attr.name}() { return ${attr.name}; } </#list> }
Freemarker加载类:
package cn.itrip.beans.util;
import java.io.File;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
public class FreeMarkerInit {
private static FreeMarkerInit single= new FreeMarkerInit();
private FreeMarkerInit() {}
//静态工厂方法
public static FreeMarkerInit getInstance() {
return single;
}
public Template getDefinedTemplate(String templateName) throws Exception{
//配置类
Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
cfg.setDirectoryForTemplateLoading(new File("E:/springBootLearn/itrip-test/itripbeans/src/main/resources/template/"));
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
return cfg.getTemplate(templateName);
}
}
Freemarker提供了3种加载模板目录的方法。 它使用Configuration类加载模板。
三种方法分别是:
public void setClassForTemplateLoading(Class clazz, String pathPrefix);
public void setDirectoryForTemplateLoading(File dir) throws IOException;
public void setServletContextForTemplateLoading(Object servletContext, String path);
第一种:基于类路径,HttpWeb包下的framemaker.ftl文件
configuration.setClassForTemplateLoading(this.getClass(), "/HttpWeb");
configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板
第二种:基于文件系统
configuration.setDirectoryForTemplateLoading(new File("/template"))
configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板
第三种:基于Servlet Context,指的是基于WebRoot下的template下的framemaker.ftl文件
HttpServletRequest request = ServletActionContext.getRequest();
configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/template");
configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板
连接数据库获取元信息,得到表名,列信息。
package cn.itrip.beans.util;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 负责获取表的元信息
* 列的元信息
*/
public class MetadataUtil {
private static Connection conn;
private static DatabaseMetaData meta;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
}catch (ClassNotFoundException e){
e.printStackTrace();
System.out.println("数据库连接失败!");
}
}
public static void openConnection(){
try {
if (conn==null||conn.isClosed()){
conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/itripdb",
"root","root");
meta=conn.getMetaData();
}
}catch (SQLException e){
e.printStackTrace();
}
}
//获取注解
public static String getCommentByTableName(String tableName) throws Exception{
openConnection();
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery("SHOW CREATE TABLE "+tableName);
String comment=null;
if (rs!=null&&rs.next()){
comment=rs.getString(2);
}
rs.close();
stmt.close();
conn.close();
return comment;
}
//获取所有表名称
public static List<String> getTableNames(){
openConnection();
ResultSet rs=null;
List<String> nameList=new ArrayList<>();
try {
rs=meta.getTables(null,null,null,new String[]{"TABLE"});
while (rs.next()){
String tName=rs.getString("TABLE_NAME");
nameList.add(tName);
}
}catch (Exception e){
e.printStackTrace();
}
return nameList;
}
/**
* 列信息数组的集合。List中每个元素是一个数组,代表一个列的信息;
* 每个数组的元素1是列名,元素2是注释,元素3是类型
* @return
*/
public static List<String[]> getTableColumnsInfo(String tableName) throws Exception{
openConnection();
ResultSet rs=meta.getColumns(null,"%",tableName,"%");
List<String[]> columnInfoList=new ArrayList<>();
while (rs.next()){
String[] colInfo=new String[3];
colInfo[0] =rs.getString("COLUMN_NAME");
colInfo[1] =rs.getString("REMARKS");
colInfo[2] =rs.getString("TYPE_NAME");
columnInfoList.add(colInfo);
}
return columnInfoList;
}
public static DatabaseMetaData getMeta() {
return meta;
}
public static void setMeta(DatabaseMetaData meta) {
MetadataUtil.meta = meta;
}
public static Connection getConn() {
return conn;
}
public static void setConn(Connection conn) {
MetadataUtil.conn = conn;
}
}
直接获取的表名,列信息有时候并不满足需求规范所有我们Java规范或者项目需求,所以我又编写了一个元信息转换工具类。
package cn.itrip.beans.util;
/**
* java类名、属性名、方法名转换工具类
*
* @author imagines
*/
public class JavaNameUtil {
/**
* 将数据库(表、字段)转换以java命名方式帕斯卡或者骆驼
* @param unberscoreName
* @param isPascal 是否将首字母转化大写,true则转化为骆驼命名,false则转换为帕斯卡命名
* @return 骆驼或帕斯卡命名字符串
*/
public static String translate(String unberscoreName, boolean isPascal) {
StringBuilder result = new StringBuilder();
//从第一个字母
if (unberscoreName != null && unberscoreName.length() !=0) {
boolean flag = false;
char firstChar = unberscoreName.charAt(0); //得到首字母
if (isPascal) {
result.append(Character.toUpperCase(firstChar));
} else {
result.append(firstChar);
}
//从第二个字母以后开始
for (int i = 1, length = unberscoreName.length(); i < length; i++) {
char ch = unberscoreName.charAt(i);
if ('_' == ch) {
flag = true;
} else {
if (flag) { //标记上一个是下划线,就转化为大写。
result.append(Character.toUpperCase(ch));
flag = false;
} else {
result.append(ch);
}
}
}
}
return result.toString();
}
/**
* 调用translate() 转换为帕斯卡命名
* @param unberscoreName 数据库(表名、字段名)
* @return
*/
public static String toPascal(String unberscoreName) {
return translate(unberscoreName, true);
}
/**
* 调用translate() 转换为骆驼命名
* @param unberscoreName 数据库(表名、字段名)
* @return
*/
public static String toCamel(String unberscoreName) {
return translate(unberscoreName, false);
}
/**
*
* 将获取数据库类型转化为java类型
* @param dbTypeName 实际的数据库类型
* @return
*/
public static String dbTypeChangeJavaType(String dbTypeName){
String javaType=null;
switch(dbTypeName){
case "VARCHAR" :javaType="String";break;
case "BIGINT" :javaType="Long";break;
case "INT" :javaType="Integer";break;
case "DATETIME" :javaType="Date";break;
default:javaType="String";break;
}
return javaType;
}
public static void main(String[] args) {
String javaname = JavaNameUtil.toPascal("imagines_age_name");
System.out.println(javaname);
}
}
然后测试类进行测试:
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.itrip.beans.util.Attribute;
import cn.itrip.beans.util.FreeMarkerInit;
import cn.itrip.beans.util.JavaNameUtil;
import cn.itrip.beans.util.MetadataUtil;
import freemarker.template.Template;
public class TemplateTest {
//生成bean
public void gen1() throws Exception{
//生成路径
String savePath="E://springBootLearn//itrip-test//itripbeans//src//main//java//cn//itrip//beans//pojo";
//获取模板
Template temp = FreeMarkerInit.getInstance().getDefinedTemplate("javabean.ftl");
//获取表名集合
List<String> strs=MetadataUtil.getTableNames();
for (String str1: strs
) {
//Attribute里面封装模板使用属性
List<String[]> strList=MetadataUtil.getTableColumnsInfo(str1);
List<Attribute> attr_list = new ArrayList<Attribute>();
for (String[] c:strList
) {
attr_list.add(new Attribute(JavaNameUtil.dbTypeChangeJavaType(c[2]), JavaNameUtil.toCamel(c[0]),c[1]));
}
//装换为帕斯卡命名
String str=JavaNameUtil.toPascal(str1);
Map<String, Object> root = new HashMap<String, Object>();
root.put("packageName", "cn.itrip.beans.pojo");
root.put("className", str);
root.put("attrs", attr_list);
OutputStream fos = new FileOutputStream( new File(savePath, str+".java"));
Writer out = new OutputStreamWriter(fos);
temp.process(root, out);
fos.flush();
fos.close();
}
}
public static void main(String[] args) {
TemplateTest test = new TemplateTest();
try {
test.gen1();
} catch (Exception e) {
e.printStackTrace();
}
}
}
浙公网安备 33010602011771号