Spring boot 代码生成器,基于Freemarker编写,代码粗劣,大神勿喷
此代码生成器依赖JAR包比较少,除了必用Freemarker 和JDBC之外基本上完全个人编写,代码结构以及生成借鉴过zhangyao 大神的逻辑思路,望大神体谅,ta的码云 https://gitee.com/beany/mySpringBoot
代码生成器我也是第一次编写,编写前查询过大量的资料,感觉mybatis 的****总会有各种各样不尽人意的地方
也许是我小白不会用吧,勿喷!所以思前想后还是自己写了个代码生成器,初次编写,有些地方感觉还是比较青涩。
废话不多说,代码生成器支持model、Mapper、Dao、Service、ServiceImpl、Controller 一次性的生成,支持同时生
成多张表,下面上代码
生成器结构
package com.anka.apps.generator;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* @Description 代码生成器,基于Freemarker 2.3.28
* Jar包依赖由Maven代理。只要有依赖包,本生成器可以单独拿出使用
* @author AnkaRebirth
* @date 2019-01-25 23:44
* @version 1.0.0
*/
public class AnkaGenerator {
// private static final String driver = "oracle.jdbc.OracleDriver";
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://127.0.0.1:3306/anka?serverTimezone=GMT%2B8";
private static final String USER_NAME = "root";
private static final String PASS_WORD = "123456";
// 表名称,不限大小写,可包含单字符通配符("_"),或多字符通配符("%");
private static final String TALBE_NAME = "CORE_USER";
// 项目基础包名称,根据自己公司的项目修改
private static final String BASE_PACKAGE = "com.anka.apps";
// Model所在包
private static final String MODEL_PACKAGE = BASE_PACKAGE + ".model";
// Dao所在包
private static final String DAO_PACKAGE = BASE_PACKAGE + ".dao";
// Service所在包
private static final String SERVICE_PACKAGE = BASE_PACKAGE + ".service";
// ServiceImpl所在包
private static final String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl";
// Controller所在包
private static final String CONTROLLER_PACKAGE = BASE_PACKAGE + ".controller";
// java文件路径
private static final String JAVA_PATH = "src/main/java";
// resource文件路径
private static final String RESOURCES_PATH = "src/main/resources";
// mapper所在路径
private static final String MAPPER_PATH = "/mapper/";
// 模板位置
private static final String TEMPLATE_FILE_PATH = "src/test/resources/template/generator";
public static void main(String[] args) throws SQLException {
Connection con = JDBCConnection.INSTANCE.getConnection(DRIVER, URL, USER_NAME, PASS_WORD);
DatabaseMetaData data = con.getMetaData();
System.out.println(data.getDriverName());
System.out.println(data.getURL());
System.out.println(data.getUserName());
System.out.println("");
List<Map<String, Object>> list = GetTablesData.getTablesData(TALBE_NAME,
data, BASE_PACKAGE, SERVICE_PACKAGE, SERVICE_IMPL_PACKAGE, MODEL_PACKAGE,
DAO_PACKAGE, CONTROLLER_PACKAGE);
GeneratorUtils.closeConnection(con);
System.out.println("生成表"+list.size()+"个!SUCCESS");
//==================================代码生成主体部分==================================
for (Map<String, Object> map : list) {
//model 生成
genModel(map, GeneratorUtils.packageConvertPath(MODEL_PACKAGE));
//Mapper 生成
genMapper(map,MAPPER_PATH);
//Dao 生成
genDao(map, GeneratorUtils.packageConvertPath(DAO_PACKAGE));
//Service 生成
genService(map, GeneratorUtils.packageConvertPath(SERVICE_PACKAGE));
//ServiceImpl 生成
genServiceImpl(map, GeneratorUtils.packageConvertPath(SERVICE_IMPL_PACKAGE));
//Controller 生成
genController(map, GeneratorUtils.packageConvertPath(CONTROLLER_PACKAGE));
}
//==================================代码生成主体部分==================================
}
/**
* 生成Model
* @param tableData
* @param PACKAGE_PATH_MODEL
*/
private static void genModel(Map<String, Object> tableData, String PACKAGE_PATH_MODEL) {
String path = JAVA_PATH + PACKAGE_PATH_MODEL + tableData.get("claszName") + ".java";
GeneratorUtils.generatorCode(tableData, path, "model.ftl", TEMPLATE_FILE_PATH);
}
/**
* 生成Mapper
* @param tableData
*/
private static void genMapper(Map<String, Object> tableData,String MAPPER_PATH) {
String path = RESOURCES_PATH + MAPPER_PATH + tableData.get("claszName") + "Mapper.xml";
GeneratorUtils.generatorCode(tableData, path, "mapper.ftl", TEMPLATE_FILE_PATH);
}
/**
* 生成Dao
* @param tableData
* @param PACKAGE_PATH_DAO
*/
private static void genDao(Map<String, Object> tableData, String PACKAGE_PATH_DAO) {
String path = JAVA_PATH + PACKAGE_PATH_DAO + tableData.get("claszName") + "Dao.java";
GeneratorUtils.generatorCode(tableData, path, "dao.ftl", TEMPLATE_FILE_PATH);
}
/**
* 生成Service
* @param tableData
* @param PACKAGE_PATH_SERVICE
*/
private static void genService(Map<String, Object> tableData, String PACKAGE_PATH_SERVICE) {
String path = JAVA_PATH + PACKAGE_PATH_SERVICE + tableData.get("claszName") + "Service.java";
GeneratorUtils.generatorCode(tableData, path, "service.ftl", TEMPLATE_FILE_PATH);
}
/**
* 生成ServiceImpl
* @param tableData
* @param PACKAGE_PATH_SERVICE_IMPL
*/
private static void genServiceImpl(Map<String, Object> tableData, String PACKAGE_PATH_SERVICE_IMPL) {
String path = JAVA_PATH + PACKAGE_PATH_SERVICE_IMPL + tableData.get("claszName") + "ServiceImpl.java";
GeneratorUtils.generatorCode(tableData, path, "service-impl.ftl", TEMPLATE_FILE_PATH);
}
/**
* 生成Controller
* @param tableData
* @param PACKAGE_PATH_CONTROLLER
*/
private static void genController(Map<String, Object> tableData, String PACKAGE_PATH_CONTROLLER) {
String path = JAVA_PATH + PACKAGE_PATH_CONTROLLER + tableData.get("claszName") + "Controller.java";
GeneratorUtils.generatorCode(tableData, path, "controller.ftl", TEMPLATE_FILE_PATH);
}
}
package com.anka.apps.generator;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.SQLException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
public class GeneratorUtils {
/**
* 下划线转驼峰法
*
* @param line
* 源字符串
* @param smallCamel
* 大小驼峰,是否为小驼峰
* @return 转换后的字符串
*/
public static String underlineCamel(String line, boolean smallCamel) {
if (line == null || "".equals(line)) {
return "";
}
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile("([A-Za-z\\d]+)(_)?");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
String word = matcher.group();
sb.append(smallCamel && matcher.start() == 0 ? Character.toLowerCase(word.charAt(0))
: Character.toUpperCase(word.charAt(0)));
int index = word.lastIndexOf('_');
if (index > 0) {
sb.append(word.substring(1, index).toLowerCase());
} else {
sb.append(word.substring(1).toLowerCase());
}
}
return sb.toString();
}
/**
* @author AnkaRebirth
* @param type java.sql.Types 对应的值
* @return
*/
public static String jdbcTojava(int type) {
String temp = null;
switch (type) {
case -7:// BIT
temp = "Boolean";
break;
case -6:// TINYINT
temp = "Byte";
break;
case 5:// SMALLINT
temp = "Short";
break;
case 4:// INTEGER
temp = "Integer";
break;
case -5:// BIGINT
temp = "Integer";
break;
case 6:// FLOAT
temp = "Double";
break;
case 7:// REAL
temp = "Float";
break;
case 8:// DOUBLE
temp = "Double";
break;
case 2:// NUMERIC
temp = "java.math.BigDecimal";
break;
case 3:// DECIMAL
temp = "java.math.BigDecimal";
break;
case 1:// CHAR
temp = "String";
break;
case 12:// VARCHAR
temp = "String";
break;
case -1:// LONGVARCHAR
temp = "String";
break;
case 91:// DATE
temp = "Date";
break;
case 92:// TIME
temp = "java.sql.Time";
break;
case 93:// TIMESTAMP
temp = "Date";
break;
case -2:// BINARY
temp = "Byte[]";
break;
case -3:// VARBINARY
temp = "Byte[]";
break;
case -4:// LONGVARBINARY
temp = "Byte[]";
break;
case 0:// NULL
temp = null;
break;
case 1111:// OTHER
temp = null;
break;
case 2000:// JAVA_OBJECT
temp = null;
break;
case 2001:// DISTINCT
temp = null;
break;
case 2002:// STRUCT
temp = "java.sql.Struct";
break;
case 2003:// ARRAY
temp = "java.sql.Array";
break;
case 2004:// BLOB
temp = "java.sql.Blob";
break;
case 2005:// CLOB
temp = "String";
break;
case 2006:// REF
temp = "java.sql.Ref";
break;
case 70:// DATALINK
temp = "java.net.URL";
break;
case 16:// BOOLEAN
temp = "Boolean";
break;
// -------------------------JDBC 4.0 ------------------------------
case -8:// ROWID
temp = "java.sql.RowId";
break;
case -15:// NCHAR
temp = "String";
break;
case -9:// NVARCHAR
temp = "String";
break;
case -16:// LONGNVARCHAR
temp = "String";
break;
case 2011:// NCLOB
temp = "java.sql.NClob";
break;
case 2009:// SQLXML
temp = "java.sql.SQLXML";
break;
// --------------------------JDBC 4.2 -----------------------------
case 2012:// REF_CURSOR
temp = null;
break;
case 2013:// TIME_WITH_TIMEZONE
temp = "Date";
break;
case 2014:// TIMESTAMP_WITH_TIMEZONE
temp = "Date";
break;
default:
break;
}
return temp;
}
/**
* DATE DATETIME统一定义TIMESTAMP,CLOB转VARCHAR
* @param jdbcType
* @return
*/
public static String getJdbcTypeSame(String jdbcType) {
String temp = jdbcType;
if (jdbcType.equals(JDBCType.DATE.getName())) {
temp = JDBCType.TIMESTAMP.getName();
}
if (jdbcType.equals(JDBCType.CLOB.getName())) {
temp = JDBCType.VARCHAR.getName();
}
return temp;
}
/**
* 关闭数据库连接
*
* @param conn
*/
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 获取freemarker cfg
* @return
* @throws IOException
*/
public static freemarker.template.Configuration getConfiguration(String TEMPLATE_FILE_PATH) {
freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_28);
try {
cfg.setDirectoryForTemplateLoading(new File(TEMPLATE_FILE_PATH));
} catch (IOException e) {
e.printStackTrace();
}
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
return cfg;
}
/**
* 路径转换,.替换为/
* @param packageName
* @return
*/
public static String packageConvertPath(String packageName) {
return String.format("/%s/", packageName.contains(".") ? packageName.replaceAll("\\.", "/") : packageName);
}
/**
* 代码生成
* @param tableData 表数据
* @param path 生成路径
* @param ftl 模版
* @param TEMPLATE_FILE_PATH 模版路径
*/
public static void generatorCode(Map<String, Object> tableData, String path, String ftl, String TEMPLATE_FILE_PATH){
freemarker.template.Configuration cfg = getConfiguration(TEMPLATE_FILE_PATH);
try {
File file = new File(path);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
try {
cfg.getTemplate(ftl).process(tableData, new FileWriter(file));
} catch (TemplateException e) {
e.printStackTrace();
}
System.out.println("路径:" + path + " 生成成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.anka.apps.generator;
import java.sql.DatabaseMetaData;
import java.sql.JDBCType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
public class GetTablesData {
public static List<Map<String, Object>> getTablesData(String tableName, DatabaseMetaData data,
String BASE_PACKAGE, String SERVICE_PACKAGE, String SERVICE_IMPL_PACKAGE, String MODEL_PACKAGE,
String DAO_PACKAGE, String CONTROLLER_PACKAGE) throws SQLException {
System.out.println(data.getDriverName());
System.out.println(data.getURL());
System.out.println(data.getUserName());
System.out.println("");
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
/**
* 获取给定类别中使用的表的描述。 方法原型:ResultSet getTables(String catalog,String
* schemaPattern,String tableNamePattern,String[] types); catalog -
* 表所在的类别名称;""表示获取没有类别的列,null表示获取所有类别的列。 schema -
* 表所在的模式名称(oracle中对应于Tablespace);""表示获取没有模式的列,null标识获取所有模式的列;
* 可包含单字符通配符("_"),或多字符通配符("%"); tableNamePattern -
* 表名称;可包含单字符通配符("_"),或多字符通配符("%"); types - 表类型数组;
* "TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL
* TEMPORARY"、"ALIAS" 和 "SYNONYM";
* null表示包含所有的表类型;可包含单字符通配符("_"),或多字符通配符("%");
*/
ResultSet rs = data.getTables(null, null, tableName == "" ? null : tableName, new String[] { "TABLE" });
while (rs.next()) {
System.out.println("表名:" + rs.getString("TABLE_NAME").toUpperCase());
System.out.println("表类型:" + rs.getString("TABLE_TYPE"));
System.out.println("表所属数据库:" + rs.getString("TABLE_CAT"));
System.out.println("表备注:" + rs.getString("REMARKS"));
Map<String, Object> map = getDateMap(rs.getString("TABLE_NAME").toUpperCase(), rs.getString("REMARKS"),
data, BASE_PACKAGE, SERVICE_PACKAGE, SERVICE_IMPL_PACKAGE, MODEL_PACKAGE,
DAO_PACKAGE, CONTROLLER_PACKAGE);
list.add(map);
}
rs.close();
return list;
}
/**
* 封装表数据
*
* @param tableName
* 表名
* @param reMarks
* 表备注
* @param data
* DatabaseMetaData data 对象
* @return Map<String, Object> 封装表信息数据
* @throws SQLException
*/
private static Map<String, Object> getDateMap(String tableName, String reMarks, DatabaseMetaData data,
String BASE_PACKAGE, String SERVICE_PACKAGE, String SERVICE_IMPL_PACKAGE, String MODEL_PACKAGE,
String DAO_PACKAGE, String CONTROLLER_PACKAGE) throws SQLException {
Assert.hasText(tableName, "表名称不能为空!");
Map<String, Object> map = new HashMap<String, Object>();
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
map.put("tableName", tableName);
map.put("claszName", GeneratorUtils.underlineCamel(tableName, false));
map.put("className", GeneratorUtils.underlineCamel(tableName, true));
map.put("reMarks", reMarks);
map.put("author", "AnkaRebirth");
map.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date()));
map.put("version", "1.0.0");
map.put("basePackage", BASE_PACKAGE);
map.put("basePackageService", SERVICE_PACKAGE);
map.put("basePackageServiceImpl", SERVICE_IMPL_PACKAGE);
map.put("basePackageModel", MODEL_PACKAGE);
map.put("basePackageDao", DAO_PACKAGE);
map.put("basePackageController", CONTROLLER_PACKAGE);
map.put("baseRequestMapping", GeneratorUtils.underlineCamel(tableName, true));
/**
* 获取可在指定类别中使用的表列的描述。 方法原型:ResultSet getColumns(String catalog,String
* schemaPattern,String tableNamePattern,String columnNamePattern)
* catalog - 表所在的类别名称;""表示获取没有类别的列,null表示获取所有类别的列。 schema -
* 表所在的模式名称(oracle中对应于Tablespace);""表示获取没有模式的列,null标识获取所有模式的列;
* 可包含单字符通配符("_"),或多字符通配符("%"); tableNamePattern -
* 表名称;可包含单字符通配符("_"),或多字符通配符("%"); columnNamePattern - 列名称;
* ""表示获取列名为""的列(当然获取不到);null表示获取所有的列;可包含单字符通配符("_"),或多字符通配符("%");
*/
ResultSet cols = data.getColumns(null, "%", tableName, "%");
while (cols.next()) {
System.out.println("字段名:" + cols.getString("COLUMN_NAME") + "------ JAVA名:"
+ GeneratorUtils.underlineCamel(cols.getString("COLUMN_NAME"), false) + "------" + "类型:"
+ cols.getString("TYPE_NAME") + "------" + "长度:" + cols.getString("COLUMN_SIZE") + "------" + "备注:"
+ cols.getString("REMARKS"));
Map<String, String> col = new HashMap<String, String>();
col.put("columnName", cols.getString("COLUMN_NAME"));
col.put("javaNameUp", GeneratorUtils.underlineCamel(cols.getString("COLUMN_NAME"), false));
col.put("javaNameLo", GeneratorUtils.underlineCamel(cols.getString("COLUMN_NAME"), true));
Assert.hasText(GeneratorUtils.jdbcTojava(cols.getInt("DATA_TYPE")),
"未能获取到对应的java变量类型,请检查【" + cols.getString("COLUMN_NAME") + "】数据库中对应类型!");
col.put("javaType", GeneratorUtils.jdbcTojava(cols.getInt("DATA_TYPE")));
col.put("jdbcType", GeneratorUtils.getJdbcTypeSame(JDBCType.valueOf(cols.getInt("DATA_TYPE")).getName()));
col.put("remarks", cols.getString("REMARKS"));
list.add(col);
}
cols.close();
map.put("columns", list);
return map;
}
}
package com.anka.apps.generator;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
*
* @Description: Connection 单例模式
* @author AnkaRebirth
* @date 2019-01-25 16:13
* @version 1.0.0
*
*/
public enum JDBCConnection {
INSTANCE;
public Connection getConnection(String driver, String url, String userName, String passWord){
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
System.out.println("加载数据库驱动失败!");
e.printStackTrace();
}
Connection conn = null;
try {
conn = DriverManager.getConnection(url, userName, passWord);
} catch (SQLException e) {
System.out.println("数据库连接失败!");
e.printStackTrace();
}
return conn;
}
}
下面是项目源码,直接导入MAVEN 项目即可,CSDN还在审核,给出百度网盘连接
链接: https://pan.baidu.com/s/1I5F1uy2uzHEkbTym8MfA9g
提取码: r5u4