寫作背景
換了家公司後,公司裡沒有公共的代碼生成工具。每次來個新需求,從建表到實體Bean、dao、service等等這樣一直做重複的工作會比較煩躁又很費時間。于是自己想寫一個玩玩,這裡說明一下,公司技術選型為springboot + jdbc templates沒有使用到像mybatis等orm架構,是以不需要生成mapper.xml檔案。
代碼執行個體
package com.chenyulian.util;
import java.io.*;
import java.sql.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.text.MessageFormat.format;
/**
* @author 沉魚
* @date 2018/3/18 15:51
*/
public class GenerateJavaFileUtils {
// 定義資料庫常用類型
private static final String TYPE_CHAR = "char";
private static final String TYPE_DATE = "date";
private static final String TYPE_TIMESTAMP = "timestamp";
private static final String TYPE_INT = "int";
private static final String TYPE_BIGINT = "bigint";
private static final String TYPE_TEXT = "text";
private static final String TYPE_BIT = "bit";
private static final String TYPE_DECIMAL = "decimal";
private static final String TYPE_BLOB = "blob";
// 配置檔案存放位址
private static final String PACKAGEPATH = "D:\\workspace\\entity\\";
private static final String BEAN_PATH = PACKAGEPATH + "entity_bean";
private static final String SERVICE_PATH = PACKAGEPATH + "entity_service";
private static final String MAPPER_PATH = PACKAGEPATH + "entity_mapper";
private static final String XML_PATH = PACKAGEPATH + "entity_mapper/xml";
// 配置檔案包名稱 , 這些值需要根據各自的項目配置
private static final String MODULENAME = "com.chenyulian";
private static final String BEAN_PACKAGE = MODULENAME + ".entity";
private static final String MAPPER_PACKAGE = MODULENAME + ".dao";
private static final String SERVICE_PACKAGE = MODULENAME + ".service";
private static final String SERVICEIMPL_PACKAGE = MODULENAME + ".service.impl";
// 配置資料庫連接配接資訊
private static final String DRIVERNAME = "com.mysql.jdbc.Driver";
private static final String USER = "root";
private static final String PASSWORD = "123456";
private static final String URL = "jdbc:mysql://localhost:3306/chenyulian?characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
// 方法統一命名
private static final String save = "insert";
private static final String update = "updateById";
private static final String countTotalNum = "count";
private static final String queryById = " selectById";
private static final String delete = "deleteById";
// sql語句
private static final String showTablesName = "show tables"; // 擷取資料庫的所有表名
private static final String showTablesInfo = "show table status"; // 擷取資料庫的所有表詳情資訊(包括注釋)
private static final String showFields = "show full fields from "; // 擷取指定表的所有字段詳情
// 定義系統中使用到的全局變量
private String tableName;
private String beanName;
private String serviceName;
private String serviceImplName;
private String controllerName;
private String lowerBeanName;
private String mapperName;
private List columns = new ArrayList<>();
private List types = new ArrayList<>();
private List comments = new ArrayList<>();
private Connection conn;
// 常用的配置項
/** 用于指定生成類檔案的表, 當值為空時會将資料庫的所有表都生成類檔案 */
private static final String TABLE_NAME = "gift";
/** 表名中的這些值将不會轉換為類名的一部分 */
private static final String[] TABLE_PREFIXS = {"app","lms","wms","zwms", "v2"};
/**
* 删除指定目錄下所有檔案,若目錄不存在則建立該目錄
*/
private static void mkdirs(Runtime runtime) throws IOException {
File file = new File(PACKAGEPATH);
if (file.exists()) {
runtime.exec("cmd /c del /q/a/f/s "+ file.getAbsolutePath());
}
file.mkdirs();
}
/**
* 擷取連接配接
*/
private void initConnection() throws ClassNotFoundException, SQLException {
Class.forName(DRIVERNAME);
conn = DriverManager.getConnection(URL, USER, PASSWORD);
}
/**
* 擷取所有的表名
*/
private List<String> getTables() throws SQLException {
List<String> tables = new ArrayList<>();
PreparedStatement pstate = conn.prepareStatement(showTablesName);
ResultSet results = pstate.executeQuery();
while (results.next()) {
String tableName = results.getString();
// if ( tableName.toLowerCase().startsWith("yy_") ) {
tables.add(tableName);
// }
}
return tables;
}
/**
* 根據表名生成實體類名稱及所有相關的檔案名
*/
private void initNameByTable(String table) {
tableName = table;
beanName = getBeanName(table);
lowerBeanName = lowerCaseFirstLitter(beanName);
mapperName = beanName + "Mapper";
serviceName = beanName + "Service";
serviceImplName = serviceName + "Impl";
}
/**
* 根據表名擷取實體類名
*/
private String getBeanName(String table) {
StringBuilder entityName = new StringBuilder(table.length());
String tableLower = table.toLowerCase();
String[] tables = tableLower.split("_");
String temp = null;
for (int i = ; i < tables.length; i++) {
temp = tables[i].trim();
if(canUseTemp(temp)){
entityName.append(upperCaseFirstLitter(temp));
}
}
return entityName.toString();
}
/**
* 判斷表名字首是否要加到實體類名上
*/
private Boolean canUseTemp(String temp) {
if(isEmpty(temp)){
return false;
}
for(String tablePrefix: TABLE_PREFIXS){
if (tablePrefix.equalsIgnoreCase(temp)) {
return false;
}
}
return true;
}
/**
* 擷取實體類屬性的資料類型
*/
private String processType(String type) {
if (type.indexOf(TYPE_CHAR) > -) {
return "String";
} else if (type.indexOf(TYPE_BIGINT) > -) {
return "Long";
} else if (type.indexOf(TYPE_INT) > -) {
return "Integer";
} else if (type.indexOf(TYPE_DATE) > -) {
return "Date";
} else if (type.indexOf(TYPE_TEXT) > -) {
return "String";
} else if (type.indexOf(TYPE_TIMESTAMP) > -) {
return "Date";
} else if (type.indexOf(TYPE_BIT) > -) {
return "Boolean";
} else if (type.indexOf(TYPE_DECIMAL) > -) {
return "BigDecimal";
} else if (type.indexOf(TYPE_BLOB) > -) {
return "byte[]";
}
return null;
}
/**
* 将字段名轉換為實體類的屬性名
*/
private String processField(String field) {
StringBuilder sb = new StringBuilder(field.length());
String[] fields = field.split("_");
sb.append(fields[]);
for (int i = ; i < fields.length; i++) {
sb.append(upperCaseFirstLitter(fields[i].trim()));
}
return sb.toString();
}
/**
* 建構類上面的注釋
*/
private void buildClassComment(BufferedWriter bw, String text) throws IOException {
bw.newLine();
bw.newLine();
bw.write("/**");
bw.newLine();
bw.write(" * " + text);
bw.newLine();
bw.write(" */");
}
/**
* 建構方法上面的注釋
*/
private void buildMethodComment(BufferedWriter bw, String text) throws IOException {
bw.newLine();
bw.write("\t/**" + text + "*/");
}
/**
* 生成實體類
*/
private void buildEntityBean(List<String> columns, List<String> types, List<String> comments, String tableComment)
throws IOException {
instanceFolder(BEAN_PATH);
BufferedWriter bw = instanceBufferedWriter(BEAN_PATH, beanName + ".java");
writeBeanHead(tableComment, bw);
writeBeanColumns(columns, types, comments, bw);
writeGetSetMethod(columns, types, bw);
writeEnd(bw);
}
/**
* 寫類結尾處代碼
*/
private void writeEnd(BufferedWriter bw) throws IOException {
bw.newLine();
bw.write("}");
bw.newLine();
bw.flush();
bw.close();
}
/**
* 寫實體類的get,set方法
*/
private void writeGetSetMethod(List<String> columns, List<String> types, BufferedWriter bw) throws IOException {
String uppperField = null;
String lowerField = null;
String tempType = null;
for (int i = ; i < columns.size(); i++) {
tempType = processType(types.get(i));
lowerField = processField(columns.get(i));
uppperField = upperCaseFirstLitter(lowerField);
bw.newLine();
bw.write("\tpublic void set" + uppperField + "(" + tempType + " " + lowerField + "){");
bw.newLine();
bw.write("\t\tthis." + lowerField + " = " + lowerField + ";");
bw.newLine();
bw.write("\t}");
bw.newLine();
bw.newLine();
bw.write("\tpublic " + tempType + " get" + uppperField + "(){");
bw.newLine();
bw.write("\t\treturn this." + lowerField + ";");
bw.newLine();
bw.write("\t}");
bw.newLine();
}
bw.newLine();
bw.newLine();
}
/**
* 寫實體類屬性代碼
*/
private void writeBeanColumns(List<String> columns, List<String> types, List<String> comments, BufferedWriter bw)
throws IOException {
for (int i = ; i < columns.size(); i++) {
if (isNotEmpty(comments.get(i))) {
bw.write("\t/**" + comments.get(i) + "*/");
bw.newLine();
}
bw.write("\tprivate " + processType(types.get(i)) + " " + processField(columns.get(i)) + ";");
bw.newLine();
bw.newLine();
}
bw.newLine();
}
/**
* 寫實體類頭部代碼
*/
private void writeBeanHead(String tableComment, BufferedWriter bw) throws IOException {
bw.write("package " + BEAN_PACKAGE + ";");
bw.newLine();
bw.write("import java.io.Serializable;");
bw.newLine();
bw.write("import java.util.Date;");
bw.newLine();
buildClassComment(bw, tableComment + "實體類");
bw.newLine();
bw.write("public class " + beanName + " implements Serializable {");
bw.newLine();
}
/**
* 根據路徑建立檔案及輸出流
*/
private BufferedWriter instanceBufferedWriter(String parent, String child) throws FileNotFoundException {
File beanFile = new File(parent, child);
return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
}
/**
* 根據路徑建立目錄
*/
private void instanceFolder(String folderPath) {
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdir();
}
}
/**
* 建構方法代碼
*
* @param comment 方法注釋
* @param returnType 方法傳回類型
* @param name 方法名
* @param param 方法參數
*/
private void buildMethod(BufferedWriter bw, String comment, String returnType, String name, String param) throws IOException{
buildMethodComment(bw, comment);
bw.newLine();
String result = format("\t{0} {1}({2});", returnType, name, param);
bw.write(result);
bw.newLine();
}
/**
* 建構Dao檔案
*/
private void buildMapper() throws IOException {
instanceFolder(MAPPER_PATH);
BufferedWriter bw = instanceBufferedWriter(MAPPER_PATH, mapperName + ".java");
writeMapperHead(bw);
writeMethod(bw);
writeEnd(bw);
}
/**
* 寫Mapper及Service中方法代碼
*/
private void writeMethod(BufferedWriter bw) throws IOException {
buildMethod(bw, "查詢(根據主鍵ID查詢", beanName, queryById, "String id");
buildMethod(bw, "删除(根據主鍵ID删除)", "int", delete, "String id");
buildMethod(bw, "添加", "int", save, beanName + " " + lowerBeanName);
buildMethod(bw, "修改", "int", update, beanName + " " + lowerBeanName);
}
/**
* 寫Mapper類頭部代碼
*/
private void writeMapperHead(BufferedWriter bw) throws IOException {
bw.write("package " + MAPPER_PACKAGE + ";");
bw.newLine();
bw.newLine();
bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
bw.newLine();
bw.write("import java.util.List;");
bw.newLine();
bw.write("import java.util.Map;");
bw.newLine();
bw.write("import org.apache.ibatis.annotations.Param;");
buildClassComment(bw, mapperName + "資料庫操作接口類");
bw.newLine();
bw.write("public interface " + mapperName + "{");
bw.newLine();
}
/**
* 建構Service檔案
*/
private void buildServie() throws IOException {
instanceFolder(SERVICE_PATH);
BufferedWriter bw = instanceBufferedWriter(SERVICE_PATH, serviceName + ".java");
writeServiceHead(bw);
writeMethod(bw);
writeEnd(bw);
}
/**
* 寫service接口頭部代碼
*/
private void writeServiceHead(BufferedWriter bw) throws IOException {
bw.write("package " + SERVICE_PACKAGE + ";");
bw.newLine();
bw.newLine();
bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
bw.newLine();
bw.write("import java.util.List;");
bw.newLine();
bw.write("import java.util.Map;");
bw.newLine();
bw.write("import org.apache.ibatis.annotations.Param;");
buildClassComment(bw, serviceName + "資料庫操作接口類");
bw.newLine();
bw.write("public interface " + serviceName + " {");
bw.newLine();
}
/**
* 建構ServiceImpl檔案
*/
private void buildServieImpl() throws IOException {
instanceFolder(SERVICE_PATH);
BufferedWriter bw = instanceBufferedWriter(SERVICE_PATH, serviceImplName + ".java");
writeServiceImplHead(bw);
writeServieImplMethod(bw);
writeEnd(bw);
}
/**
* 寫serveImpl中的方法
*/
private void writeServieImplMethod(BufferedWriter bw) throws IOException {
String lowerMapperName = lowerCaseFirstLitter(mapperName);
buildServiceImplMethod(bw, beanName, queryById, "String id", lowerMapperName);
buildServiceImplMethod(bw, "int", delete, "String id", lowerMapperName);
buildServiceImplMethod(bw, "int", save, beanName + " " + lowerBeanName, lowerMapperName);
buildServiceImplMethod(bw, "int", update, beanName + " " + lowerBeanName, lowerMapperName);
}
/**
* 寫serveImpl中的方法
*/
private void buildServiceImplMethod(BufferedWriter bw, String returnType, String name, String param, String lowerMapperName) throws IOException {
bw.write("\[email protected]");
bw.newLine();
bw.write(format("\tpublic {0} {1}({2})", returnType, name, param));
bw.write("{");
bw.newLine();
bw.write(format("\t\treturn {0}.{1}({2});", lowerMapperName, name.trim(), param.split(" ")[]));
bw.newLine();
bw.write("\t}");
bw.newLine();
bw.newLine();
}
/**
* 寫serviceImpl頭部代碼
*/
private void writeServiceImplHead(BufferedWriter bw) throws IOException {
String lowerMapperName = lowerCaseFirstLitter(mapperName);
bw.write("package " + SERVICEIMPL_PACKAGE + ";");
bw.newLine();
bw.newLine();
bw.write("import java.util.List;");
bw.newLine();
bw.write("import org.springframework.beans.factory.annotation.Autowired;");
bw.newLine();
bw.write("import org.springframework.stereotype.Service;");
bw.newLine();
bw.write("import " + BEAN_PACKAGE + "." + beanName + ";");
bw.newLine();
buildClassComment(bw, serviceImplName + "資料庫操作接口類");
bw.newLine();
bw.newLine();
bw.write("@Service");
bw.newLine();
bw.write("public class " + serviceImplName + " implements " + serviceName + " {");
bw.newLine();
bw.newLine();
bw.write("\[email protected]");
bw.newLine();
bw.write("\tprivate " + mapperName + " " + lowerMapperName + ";");
bw.newLine();
bw.newLine();
}
/**
* 擷取所有的資料庫表名及注釋
*/
private Map<String,String> getTableComment() throws SQLException {
Map maps = new HashMap<>();
//全部表
PreparedStatement pstate = conn.prepareStatement(showTablesInfo);
ResultSet results = pstate.executeQuery();
while (results.next()) {
String tableName = results.getString("NAME");
String comment = results.getString("COMMENT");
maps.put(tableName, comment);
}
return maps;
}
public static Boolean isEmpty(String str) {
return null == str || "".equals(str);
}
public static Boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* 将字元串首字母小寫
*/
public static String lowerCaseFirstLitter(String str) {
if(isEmpty(str)){
return "";
}else {
return str.substring(, ).toLowerCase() + str.substring();
}
}
/**
* 将字元串首字母大寫
*/
public static String upperCaseFirstLitter(String str) {
if(isEmpty(str)){
return "";
}else {
return str.substring(, ).toUpperCase() + str.substring();
}
}
/**
* 根據某一個表生成實體類,service,mapper
*/
private void generateByTable(Map tableComments, String table) throws SQLException, IOException {
columns.clear();
types.clear();
comments.clear();
PreparedStatement pstate = conn.prepareStatement(showFields + table);
ResultSet results = pstate.executeQuery();
while (results.next()) {
columns.add(results.getString("FIELD"));
types.add(results.getString("TYPE"));
comments.add(results.getString("COMMENT"));
}
initNameByTable(table);
String tableComment = (String) tableComments.get(table);
buildEntityBean(columns, types, comments, tableComment);
buildMapper();
buildServie();
buildServieImpl();
}
/**
* 擷取所有的表資訊并循環生成相應檔案
*/
public void generate() throws ClassNotFoundException, SQLException, IOException {
initConnection();
Map<String,String> tableComments = getTableComment();
if(isNotEmpty(TABLE_NAME)){
generateByTable(tableComments, TABLE_NAME);
}else {
List<String> tables = getTables();
for (String table : tables) {
generateByTable(tableComments, table);
}
}
conn.close();
}
}
測試
執行這個main方法後,後彈出下面的圖
public static void main(String[] args) {
try {
Runtime runtime = Runtime.getRuntime();
mkdirs(runtime);
new GenerateJavaFileUtils().generate();
// 自動打開生成檔案的目錄
runtime.exec("cmd /c start explorer " + PACKAGEPATH);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2Lc1TTE1UeFpHWxwGWZFDatVGaKJDTwYVbiVHNHpleO1GTulzRilWO5x0LcRHelR3LcJzLctmch1mclRXY39jNzITO0YTM0EDMyMDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)