在web開發過程中,尤其是后台管理系統的開發中,少不了增刪改成的基礎操作,原來我自己的做法是一份一份的拷貝粘貼,然后修改其中的不同,然而這樣既枯燥無味又浪費了大量的時間,所以根據自己項目結構的特點寫了一個自動生成結構代碼的工具jar包,可以根據數據庫表直接生成相應數據庫模型對象(DMO)以及對表的增刪改查代碼。
之前我考慮過多種自動生成代碼的提供方式,比如web的方式,通過在頁面文本框里面輸入各種參數,比如模板文件地址,生成文件地址,數據庫名,數據庫用戶名和密碼等,點擊生成按鈕就可以生成源代碼文件。但這樣需要部署啟動這個web程序。使用java的圖形用戶界面,但我對java圖形的相關API並不了解,最后決定使用一個jar包的方式,方便簡潔。
由於模板文件使用的是freemarker,數據庫使用的是mysql,所以引入其他的兩個jar文件。

如上圖,AutoGenerationJavaCode.jar 是將原本工程里的 AutoGenerationJavaCode.java文件打包生成的,也是最終的形式。通過在AutoGenerationDemo類main函數中設置參數,直接調用即可自動生成代碼。
配置好參數后在左圖右鍵運行java程序即可生成右圖代碼文件:

調用如下:
1 public class AutoGenerationDemo {
2
3 public static void main(String[] args) throws ClassNotFoundException, SQLException, IOException, TemplateException {
4 //數據庫地址
5 String url = "jdbc:mysql://10.27.209.137:3306/sample";
6 //用戶名
7 String name = "root";
8 //密碼
9 String passWord = "root";
10 //驅動
11 String driver = "com.mysql.jdbc.Driver";
12 //表名
13 String tableName = "t_operate_log";
14 //模板路徑
15 String templateDir = "F:\\template";
16 //生成文件路徑
17 String autoGeneratedFile = "F:\\autoGenerated";
18 //實例化
19 AutoGenerationJavaCode autoGenerationJavaCode = new AutoGenerationJavaCode(url, name, passWord, driver,
20 tableName,autoGeneratedFile,templateDir);
21
22 //調用生成java代碼方法
23 autoGenerationJavaCode.autoGenerationJavaCode();
24 }
25
26 }
在main方法中配置好所需參數,由於代碼包含注釋,不在贅述,調用jar包中 AutoGenerationJavaCode的autoGenerationJavaCode方法即可生成,控制台會打印文件生產完成
我的Web項目的結構采用的是三層結構,Controller層調用service層,從service層調用dao層(數據操作層),所以決定自己生成service層,dao層代碼。其實質就是將模板文件中的變量進行替換。模板文件及對應生成的java代碼如下:



jar包的源代碼如下:
package com.sun.autoGenerated;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class AutoGenerationJavaCode {
private String url;
private String name;
private String passWord;
private String driver;
private String sql;
private String tableName;
private String templateDir;
private String autoGeneratedFile;
private static String[][] fileNameArray = new String[5][2];
static {
fileNameArray[0][0] = "dmoTemplate.ftl";
fileNameArray[0][1] = "DMO.java";
fileNameArray[1][0] = "serviceTemplate.ftl";
fileNameArray[1][1] = "Service.java";
fileNameArray[2][0] = "serviceImplTemplate.ftl";
fileNameArray[2][1] = "ServiceImpl.java";
fileNameArray[3][0] = "daoTemplate.ftl";
fileNameArray[3][1] = "Dao.java";
fileNameArray[4][0] = "daoImplTemplate.ftl";
fileNameArray[4][1] = "DaoImpl.java";
}
public AutoGenerationJavaCode(String url, String name, String passWord, String driver, String tableName,
String autoGeneratedFile,String templateDir) {
this.url = url;
this.name = name;
this.passWord = passWord;
this.driver = driver;
this.sql = "select * from " + tableName;
this.tableName = tableName;
this.templateDir = templateDir;
this.autoGeneratedFile = autoGeneratedFile;
}
public void autoGenerationJavaCode() throws IOException, TemplateException, ClassNotFoundException,
SQLException {
Configuration cfg = new Configuration();
cfg.setDefaultEncoding("utf-8");
String className = dealTableName();
String fileName = dealClassName(className);
Map<String, Object> columnMap = getColumn();
//設置模板文件路徑
cfg.setDirectoryForTemplateLoading(new File(templateDir));
Map<String, Object> rootMap = new HashMap<String, Object>();
rootMap.put("className", className);
rootMap.put("columnMap", columnMap);
File dir = new File(autoGeneratedFile + "\\");
//檢查目錄是否存在,不存在則創建
if (!dir.exists()) {
dir.mkdir();
}
for (int i = 0; i < fileNameArray.length; i++) {
Template temp = cfg.getTemplate(fileNameArray[i][0]);
File docFile = new File(autoGeneratedFile + "\\" + fileName + fileNameArray[i][1]);
Writer docout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
//輸出文件
temp.process(rootMap, docout);
}
System.out.println("==============文件生產成功===============");
}
//獲取數據庫表字段名放入map中
public Map<String, Object> getColumn() throws ClassNotFoundException, SQLException {
Connection conn;
PreparedStatement pStemt = null;
Class.forName(driver);
conn = DriverManager.getConnection(url, name, passWord);
pStemt = conn.prepareStatement(sql);
ResultSetMetaData rsmd = pStemt.getMetaData();
Map<String, Object> columnMap = new HashMap<String, Object>();
int size = rsmd.getColumnCount();
for (int i = 0; i < size; i++) {
String columnName = dealColumnName(rsmd, i);
columnMap.put(columnName, columnName);
}
conn.close();
return columnMap;
}
//將表名轉換為DMO的字段名,比如 operate_type 轉換后為 operateType
private String dealColumnName(ResultSetMetaData rsmd, int i) throws SQLException {
String columnName = rsmd.getColumnName(i + 1).toLowerCase();
String charAfterLine = String.valueOf(columnName.charAt((columnName.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
columnName = columnName.replace("_" + charAfterLine, convertedChar);
return columnName;
}
//將表名轉換為類型類名 比如 t_operate_log 轉換后為 operateLog ,類名首字母應為大寫,這里在freemarker的模板里直接轉換
private String dealTableName() {
String className = tableName.toLowerCase().substring(tableName.indexOf("_") + 1);
String charAfterLine = String.valueOf(className.charAt((className.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
className = className.replace("_" + charAfterLine, convertedChar);
return className;
}
//將類名轉換為文件名,java公共類名與其文件名應該相同,這里將首字母轉換為大寫 如operateLog 轉換后為 OperateLog
private String dealClassName(String className) {
String first = className.substring(0, 1).toUpperCase();
String rest = className.substring(1, className.length());
String fileName = new StringBuffer(first).append(rest).toString();
return fileName;
}
}

