讓myql中的資料庫表自動生成javaBean的模板
阿新 • • 發佈:2018-12-14
不積跬步,無以至千里
問題所在
今天重構以前的程式碼,因為資料庫有比較大的改動,所以需要寫很多javaBean!
作為一個程式設計師,重複意味著沒有效率,更意味著無聊,一旦無聊便沒有想程式設計的慾望,程式碼質量肯定刷刷刷的下降,質量下降了就意味著重寫。。。。
so,為了集中精力在業務邏輯的程式碼上,減少不必要的時間浪費,於是花了一點時間寫了一個把資料庫中表的欄位自動對映到 javaBean 中。
需求說明
輸入所生成 檔案的存放路徑、檔案的名稱(預設是表名)、包名(生成的是java檔案,一定要指定包名)、是否使用lombok外掛(考慮到自己實現getter/setter方法有一定的困難,直接藉助lombok外掛),判斷每一個表中的欄位的型別,生成一個標準的javaBean檔案
實現
依賴
- jdk1.8
- mysql-connector-java 驅動包
實現方法
- 使用mysql-connector-java連線需要操作的資料庫;
- 得到資料庫中所有的表名;
- 根據表名和資料庫名稱得到表的欄位以及欄位的型別;
- 根據表名和欄位的型別,生成目標檔案最重要的部分內容;
- 一個建立檔案並向檔案輸入內容的方法;
- 對上述方法進行封裝!
- 測試+完工;
- 記錄+完善。
假想的條件
- 資料庫的表名使用 下劃線區分各個單詞 來命名,eg: registed_user , approved_user;
- 資料庫中的欄位也如同表名的命名一樣;
show程式碼
檔案結構說明
ConnectionUtil.java
得到資料庫的連線
package connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionUtil {
public static Connection getConn(String dbName, String username, String password) {
String driver = "com.mysql.jdbc.Driver" ;
String url = "jdbc:mysql://localhost:3306/"+dbName+"?useUnicode=true&characterEncoding=utf-8&useSSL=false";
Connection conn = null;
try {
Class.forName(driver);
conn = (Connection) DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
MapperUtil.java
這裡寫的是上述需要封裝的所有方法
package mapper;
import connection.ConnectionUtil;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.sql.*;
import java.util.*;
public class MapperUtil {
private DatabaseMetaData databaseMetaData;
Connection connection;
public MapperUtil(String dbName, String username, String password) throws SQLException {
connection = ConnectionUtil.getConn(dbName, username, password);
databaseMetaData = connection.getMetaData();
}
/**
* 只是檔名(不包含副檔名)
* @param fileName 檔名稱
* @param dir 檔案所處的目錄
* @param mainContent 檔案的主要內容
* @param isLombok 是否包含lombok常見的一些方法?包含:不包含
*/
public void createFile(String fileName, String dir, String packagePath, String mainContent, boolean isLombok) throws Exception {
if (fileName == null || fileName.trim().equals("") || dir == null || dir.trim().equals("")){
throw new Exception("傳入引數不正確");
}
/**
* 1.首先檢測是否有這個資料夾路徑
* 2.如果不存在則新建
*/
File fileDir = new File(dir);
if (!fileDir.exists()){
fileDir.setWritable(true);
fileDir.mkdirs();
}
/**
* 如果沒有出錯,那麼建立檔案,這裡統一建立java檔案
*/
File javaFile = new File(fileDir, fileName+".java");
javaFile.createNewFile();
/**
* 向檔案中輸送內容
* 使用
*/
DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(javaFile)));
dataOutputStream.writeBytes("package " + packagePath + ";\n");
dataOutputStream.writeBytes("\n");
if (isLombok){
dataOutputStream.writeBytes(
"import lombok.*;\n\n"+
"@Data\n" +
"@ToString\n" +
"@Builder\n" +
"@AllArgsConstructor\n" +
"@NoArgsConstructor\n");
}
dataOutputStream.writeBytes("public class " + fileName + "{\n");
dataOutputStream.writeBytes(mainContent);
dataOutputStream.writeBytes("}");
dataOutputStream.close();
}
/**
* 構造對應的字串。
* @param map
* @return
*/
public String generateString(Map<String, String> map){
String result = "";
Set set = map.entrySet();
/**
* 對map進行遍歷
*/
for(Iterator iter = set.iterator(); iter.hasNext();)
{
Map.Entry entry = (Map.Entry)iter.next();
String key = (String)entry.getKey();
//把欄位的下劃線去掉,下劃線後一位變為大寫
StringBuilder sb = new StringBuilder(key);
for (int i = 1; i < key.length(); i++) {
if (i+1 < key.length() && key.substring(i,i+1).equals("_")){
sb.replace(i, i+2, key.substring(i+1,i+2).toUpperCase());
}
}
String value = (String)entry.getValue();
System.out.println("key: " + key + " sb: " + sb +" :" + value);
result += " private " + value + " " + sb + ";\n";
}
return result;
}
/**
* 返回欄位名稱和屬性
* @param tableName
* @return
*/
public Map<String, String> getFiledAndType(String tableName) throws SQLException {
if (tableName == null || tableName.trim().equals("")){return null;}
ResultSet resultSet = connection.prepareStatement("select * from " + tableName).executeQuery();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
//得到所有的列名資訊
int count = resultSetMetaData.getColumnCount();
Map<String, String> map = new HashMap<String, String>();
for (int i = 1; i <= count; i++) {
String type = resultSetMetaData.getColumnTypeName(i);
type = typeTransform(type);
map.put(resultSetMetaData.getColumnName(i), type);
}
return map;
}
/**
* 得到所有表的名稱
* @return 含有所有表名的列表
*/
public List<String> getTableNames() throws SQLException {
List<String> tables = new ArrayList<String>();
ResultSet resultSet = databaseMetaData.getTables(null, null, "%", null);
while (resultSet.next()){
String tableName = resultSet.getString("TABLE_NAME");
tables.add(tableName);
System.out.println(tableName);
}
return tables;
}
/**
* 型別轉換: 目前針對常見的幾個型別
* @return
*/
public String typeTransform(String sqlType){
if (sqlType == null || sqlType.trim().equals("")){
return null;
}
sqlType = sqlType.toLowerCase();
if (matchFloatNumber(sqlType)){
return "double";
}else if (matchInt(sqlType)){
return "int";
}else if (matchString(sqlType)){
return "String";
}
return "String";
}
public boolean match(String target, String[] datas) {
if (target == null || "".equals(target.trim()) || datas.length == 0){
return false;
}
for (String a:datas) {
if (a.equals(target)){
return true;
}
}
return false;
}
public boolean matchString(String target){
String[] datas = {"char", "varchar", "date", "text", "timestamp", "datetime", "tinytext", "longtext"};
return match(target, datas);
}
public boolean matchFloatNumber(String target){
String[] datas = {"float", "double"};
return match(target, datas);
}
public boolean matchInt(String target){
String[] datas = {"int", "tinyint"};
return match(target, datas);
}
}
MapperDo.java
封裝MapperUtil.java當中存在的方法
package mapper;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class MapperDo {
private String dbName;
private String username;
private String password;
private String baseDir;
private String packagePath;
private boolean isLombok;
MapperUtil mapperUtil;
public MapperDo(String dbName, String username, String password) throws SQLException {
this.dbName = dbName;
this.username = username;
this.password = password;
mapperUtil = new MapperUtil(dbName, username, password);
}
/**
* 建立單個文字檔案
* @param baseDir
* @param packagePath
* @param isLombok
* @param tableName
* @throws Exception
*/
public void generateFileModel(String baseDir, String packagePath, boolean isLombok, final String tableName) throws Exception {
List<String> list = mapperUtil.getTableNames();
boolean isExist = list.stream().noneMatch((s) -> s.equals(tableName));
if (isExist){
return;
}
String fileName = toCamelCase(tableName);
Map<String, String> map = mapperUtil.getFiledAndType(tableName);
String mainContent = mapperUtil.generateString(map);
mapperUtil.createFile(fileName, baseDir, packagePath, mainContent, true);
}
/**
* 建立這個資料庫中所有的模板檔案、
* @param baseDir
* @param packagePath
* @param isLombok
*/
public void generateFileModels( String baseDir, String packagePath, boolean isLombok) throws Exception {
List<String> list = mapperUtil.getTableNames();
for (String tableName:list) {
String fileName = toCamelCase(tableName);
Map<String, String> map = mapperUtil.getFiledAndType(tableName);
String mainContent = mapperUtil.generateString(map);
mapperUtil.createFile(fileName, baseDir, packagePath, mainContent, true);
}
}
public String toCamelCase(String s){
if (s == null){
return null;
}
/**
* 1. 把全部轉成小寫
* 2. 把下劃線全部去掉
* 3. 把下劃線之後的一個字母變成大寫
* 4. 首個字母變成大寫
*/
StringBuilder sb = new StringBuilder(s.toLowerCase());
for (int i = 1; i < sb.length(); i++) {
if (i+1 < sb.length() && sb.substring(i,i+1).equals("_")){
sb.replace(i, i+2, sb.substring(i+1,i+2).toUpperCase());
}
}
sb.replace(0,1, s.substring(0,1).toUpperCase());
return sb.toString();
}
/**
*------------------此處省略getter/setter方法
**/
}
Main.java
測試程式碼
package run;
import mapper.MapperDo;
public class Main {
public static void main(String[] args) throws Exception {
MapperDo mapperDo = new MapperDo("bonetest","root","root");
//測試生成資料庫中所有表的javaBean
mapperDo.generateFileModels("/home/liudong/code/evaluate_bone/src/test/java/cn/edu/cqupt/mis/evaluate_bone/test", "liudong", false);
//測試生成advices一個表的javaBean
mapperDo.generateFileModel("/home/liudong/code/evaluate_bone/src/test/java/cn/edu/cqupt/mis/evaluate_bone/test", "liudong", false,"advices");
}
}
測試的效果圖如下:
- 資料庫的結構
- advices表的結構
- 首先執行Main.java方法中單獨生成一個javaBean.java的方法 generateFileModel 4.執行另一個生成所有表的javaBean方法generateFileModels
總結
程式碼和邏輯雖然簡單,但是實現之後再次記錄,就會溫故而知新。 程式碼我會繼續完善,希望有問題大家可以一起探討探討。