手寫建表sql生成javaBean檔案(PostgreSQL版本)
阿新 • • 發佈:2019-01-08
前言
在公司開發應用中,資料庫表、欄位的命名通常要與類、屬性命名相對應,例如欄位命名為user_id,對應的屬性名為userId,這樣駝峰式的命名。
開發一個模組去維護單表資料時,當確定好表結構時準備開發的時候,執行完建表sql,一開始編寫實體類,這個過程相當無聊,由於有了編寫這樣的工具類的想法。
先看看常用的建表sql(PostgreSQL版本),如下
ts是專案資料庫的字首,一般每個專案對應一個字首。CREATE TABLE ts_user ( id BIGINT NOT NULL, name VARCHAR(100) NOT NULL, sex NUMERIC(1,0) NOT null, remark VARCHAR(500), create_by VARCHAR(50) NOT NULL, create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, update_by VARCHAR(50), update_time TIMESTAMP WITHOUT TIME ZONE, CONSTRAINT pk_ts_user PRIMARY KEY (id) ); COMMENT ON TABLE ts_user IS '使用者表'; COMMENT ON COLUMN ts_user.id IS '主鍵'; COMMENT ON COLUMN ts_user.name IS '使用者名稱'; COMMENT ON COLUMN ts_user.sex IS '性別(1.男2.女)'; COMMENT ON COLUMN ts_user.remark IS '備註'; COMMENT ON COLUMN ts_user.create_by IS '建立者'; COMMENT ON COLUMN ts_user.create_time IS '建立時間'; COMMENT ON COLUMN ts_user.update_by IS '更新者'; COMMENT ON COLUMN ts_user.update_time IS '更新時間';
由以上sql指令碼,去掉表字首,根據駝峰式的命名,類名應該為User,對應的屬性名為id、name、sex、remark、createBy、createTime、updateBy、updateTime,對應的get/set方法與註釋(儘管寫註釋過程很鬱悶)。
實現程式碼如下:
package demo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Sql2Java {
/** sql指令碼檔案*/
private static String sqlFile = "C:/Users/user/Desktop/assign_dept.sql";
/** 本地路徑 */
private static String localPath = "E:/mavenwork/timesheet/src/main/java/";
/** 專案通用路徑 */
private static String projectPath = "cn/com/pc/timesheet/";
/** 模組目錄 */
private static String myPath = projectPath + "workform/";
/** 資料庫表的字首 */
public static String table_prefix = "ts";
/** 作者*/
private static String author = "@author wangweihong";
/** 實體類的包名 */
private static String packageName = "package @ [email protected];\r\n\r\[email protected]@\r\n\r\n/** \r\n * @[email protected]\r\n * " + author + "\r\n */\r\n";
/** 匯入Date*/
private static String importDate = "import java.util.Date;";
/** 存檔名稱 */
private static Map<String, String> fileNameMap = new LinkedHashMap<String, String>();
/** 存類註釋 */
private static Map<String, String> tipMap = new LinkedHashMap<String, String>();
/** 存get/set方法 */
private static Map<String, String> methodMap = new LinkedHashMap<String, String>();
/** 存欄位 */
private static Map<String, Map<String, String>> dataMap = new HashMap<String, Map<String, String>>();
/** pg欄位型別的集合 */
private static List<String> isFieldList = new ArrayList<String>();
private static List<String> longList = Arrays.asList("BIGINT", "INT8", "BIGSERIAL", "SERIAL8");
private static List<String> intList = Arrays.asList("SMALLINT", "INT2", "NUMERIC", "SERIAL", "SERIAL4" );
private static List<String> doubleList = Arrays.asList("DECIMAL", "REAL", "FLOAT4", "DOUBLE", "FLOAT8");
private static List<String> stringList = Arrays.asList("CHARACTER", "VARCHAR", "CHAR", "TEXT");
private static List<String> timeList = Arrays.asList("INTERVAL", "TIMESTAMP", "DATE", "TIME");
static {
isFieldList.addAll(longList);
isFieldList.addAll(intList);
isFieldList.addAll(doubleList);
isFieldList.addAll(stringList);
isFieldList.addAll(timeList);
}
/**
* 資料庫型別轉程式碼型別
* @param fieldType 欄位型別
* @return String
*/
public static String getClassType(String fieldType) {
String type = fieldType;
int idx = type.indexOf("(");
if (idx >= 0) {
type = type.substring(0, idx);
}
if (longList.contains(type)) {
return "long";
} else if (intList.contains(type)) {
if ("NUMERIC".equals(type)) {
String[] arr = fieldType.replaceAll("NUMERIC", "").replace("(", "").replace(")", "").split(",");
if (Integer.parseInt(arr[1]) > 1) {
return "double";
} else if (Integer.parseInt(arr[0]) > 5) {
return "long";
}
}
return "int";
} else if (doubleList.contains(type)) {
return "double";
} else if (stringList.contains(type)) {
return "String";
} else if (timeList.contains(type)) {
return "Date";
}
return "";
}
/**
* 校驗是否為資料庫欄位
* @param str 欄位
* @return boolean
*/
public static boolean checkField(String str) {
if (str.indexOf("NUMERIC") >= 0 || str.indexOf("VARCHAR") >= 0) {
return true;
}
return isFieldList.contains(strToArr(str.toUpperCase())[1]);
}
/**
* 多個空格轉為一個空格並將字串轉為陣列
* @param str
* @return String[]
*/
public static String[] strToArr(String str) {
str = dealSpace(str);
String[] arr = str.split(" ");
if (arr.length < 2) {
return Arrays.copyOf(arr, 2);
}
return arr;
}
/**
* 處理空格(去掉首尾空格且將多個空格轉為一個空格)
* @param str 字串
* @return String
*/
public static String dealSpace(String str) {
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher(str.trim());
return m.replaceAll(" ");
}
/**
* 建立javabean檔案
* @param inFile sql指令碼路徑
* @param outPath 目標目錄
* @throws Exception
*/
public static void createBean(String inFile, String outPath) throws Exception {
BufferedReader reader = getReader(inFile);
String sign = null; //每一次讀一行的資料
String className = null; //類名
String packagePath = myPath.replaceAll("/", ".") + entity
packageName = packageName.replace("@ [email protected]", packagePath);
while ((sign = reader.readLine()) != null) {
int index = 0;
sign = dealSpace(sign);
String upperSign = sign.toUpperCase(); //資料轉大寫
if ((index = upperSign.indexOf("CREATE TABLE")) >= 0) { //儲存型別
className = getClassName(sign.substring(index + "CREATE TABLE".length(), sign.length()).replaceAll(" ", "").replace("(","").replace(table_prefix, ""));
fileNameMap.put(className, outPath + className);
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("classHead", packageName + "public class " + className + " {\r\n\r\n");
dataMap.put(className, map);
} else if (checkField(upperSign)) { //儲存屬性與get/set方法
String[] arr = strToArr(sign);
String fieldName = getClassName(arr[0]); //屬性名
String classType = getClassType(arr[1]); //屬性型別
Map<String, String> fieldMap = dataMap.get(className);
String classHead = fieldMap.get("classHead");
if ("Date".equals(classType) && classHead.indexOf("@[email protected]") >= 0) {
classHead = classHead.replace("@[email protected]", importDate);
fieldMap.put("classHead", classHead);
}
String fieldVal = "\tprivate " + classType + " " + fieldName + ";\r\n\r\n";
fieldMap.put(fieldName, fieldVal);
String oldMethod = methodMap.get(className);
String method = "\tpublic " + classType + " get"+ getMethodName(fieldName) + "() {\r\n\t\treturn " + fieldName
+ ";\r\n\t}\r\n\r\n\tpublic void set" + getMethodName(fieldName) + "(" + classType + " " + fieldName+") {\r\n\t\tthis."
+ fieldName + " = " + fieldName+";\r\n\t}\r\n\r\n";
if (oldMethod == null) {
methodMap.put(className, method);
} else {
methodMap.put(className, oldMethod + method);
}
} else if ((index = upperSign.indexOf("COMMENT ON TABLE")) >= 0) { //儲存類註釋
int idx = sign.indexOf(" IS ");
sign = sign.substring(idx + 5, sign.length() - 2);
sign = sign.replace("表", "");
tipMap.put(className, sign);
sign = sign + "實體類";
Map<String, String> fieldMap = dataMap.get(className);
String classHead = fieldMap.get("classHead");
classHead = classHead.replace("@[email protected]", sign);
fieldMap.put("classHead", classHead);
} else if ((index = upperSign.indexOf("COMMENT ON COLUMN")) >= 0) { //儲存屬性註釋
int idx = sign.indexOf(" IS ");
String field = getClassName(sign.substring(sign.indexOf(".") + 1, idx));
String tip = sign.substring(idx + 5, sign.length() - 2);
Map<String, String> fieldMap = dataMap.get(className);
String val = fieldMap.get(field);
if (val != null) {
fieldMap.put(field, "\t/** " + tip + " */\r\n" + val);
}
} else if ((index = upperSign.indexOf("CONSTRAINT")) >= 0 || (index = upperSign.indexOf(");")) >= 0) {
continue;
}
}
reader.close();
for (Entry<String, Map<String, String>> entryMap : dataMap.entrySet()) {
String key = entryMap.getKey();
String outFilePath = fileNameMap.get(key);
BufferedWriter writer = getWriter(outFilePath + ".java");
Map<String, String> fieldMap = entryMap.getValue();
String classHead = fieldMap.get("classHead");
if (classHead.indexOf("@[email protected]") >= 0) {
fieldMap.put("classHead", classHead.replace("@[email protected]", ""));
}
for (Entry<String, String> entry : fieldMap.entrySet()) {
writer.write(entry.getValue());
}
writer.write(methodMap.get(key));
writer.write("}");
writer.close();
}
System.out.println("beanOver");
}
/**
* 將資料庫欄位格式轉為類名格式
* @param str
* @return
*/
public static String getClassName(String str) {
int firIdx = 0;
while ((firIdx = str.indexOf("_")) >= 0) {
String first = str.substring(firIdx + 1, firIdx + 2);
str = str.replace("_"+first, first.toUpperCase());
}
return str;
}
/**
* 字串轉為首字母大寫
* @param str 字串
* @return String
*/
public static String getMethodName(String str) {
str = getClassName(str);
String firstName = str.substring(0, 1);
if (firstName.equals(firstName.toLowerCase())) {
str = firstName.toUpperCase() + str.substring(1);
}
return str;
}
/**
* 字串轉為變數格式
* @param str 字串
* @return String
*/
public static String getFieldName(String str) {
str = getClassName(str);
String firstName = str.substring(0, 1);
if (!firstName.equals(firstName.toLowerCase())) {
str = firstName.toLowerCase() + str.substring(1);
}
return str;
}
/**
* 獲取緩衝輸入流
* @param file 路徑
* @return BufferedWriter
* @throws IOException
*/
public static BufferedReader getReader(String fileUrl) throws IOException {
String filePath = fileUrl.substring(0, fileUrl.lastIndexOf("/") + 1);
<span style="white-space:pre"> </span>File file = new File(filePath);
<span style="white-space:pre"> </span>if (!file.exists() && !file.mkdirs()) {
<span style="white-space:pre"> </span>throw new Exception("建立目錄失敗");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return new BufferedReader(new FileReader(fileUrl));
}
/**
* 獲取緩衝輸出流
* @param file 路徑
* @return BufferedWriter
* @throws IOException
*/
public static BufferedWriter getWriter(String file) throws IOException {
return new BufferedWriter(new FileWriter(file));
}
public static void main(String[] args) throws Exception {
createBean(sqlFile, localPath + myPath + "entity/");
}
}
複製程式碼後的使用方法及注意事項:
修改的變數
sqlFile:指定目錄的sql指令碼檔案
localPath:本地環境的存java程式碼的目錄
projectPath:專案的包路徑
table_prefix:資料庫表的字首(沒有可以不填)
author:作者
注意事項:
1、sql指令碼以ANSI格式編碼(或是跟專案編碼一致),否則程式會報錯(可使用NotePad++轉)
2、sql指令碼現階段只支援PostgreSQL(建表sql需要執行成功)
3、生成javabean檔案如果喜歡放在專案目錄上,可以一早配置好了路徑,想做測試或擔心型別重複會覆蓋程式碼可在呼叫createBean函式的第二個引數上寫指定路徑即可
執行後效果如下:
package cn.pconline.autooa.approval.domain;
import java.util.Date;
/**
* 使用者實體類
* @author wangweihong
*/
public class User {
/** 主鍵 */
private long id;
/** 使用者名稱 */
private String name;
/** 性別(1.男2.女) */
private int sex;
/** 備註 */
private String remark;
/** 建立者 */
private String createBy;
/** 建立時間 */
private Date createTime;
/** 更新者 */
private String updateBy;
/** 更新時間 */
private Date updateTime;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
連註釋都有,是不是很方便,偷懶成功!23333
由於筆者比較懶,沒有對其他資料庫做相容,筆者是根據自身編寫的sql風格去生成的,無法滿足所有sql風格,請見諒;如發現程式碼有bug,歡迎來訪;程式碼如果看不懂,歡迎留言。