1. 程式人生 > >手寫建表sql生成javaBean檔案(PostgreSQL版本)

手寫建表sql生成javaBean檔案(PostgreSQL版本)

前言

在公司開發應用中,資料庫表、欄位的命名通常要與類、屬性命名相對應,例如欄位命名為user_id,對應的屬性名為userId,這樣駝峰式的命名。

開發一個模組去維護單表資料時,當確定好表結構時準備開發的時候,執行完建表sql,一開始編寫實體類,這個過程相當無聊,由於有了編寫這樣的工具類的想法。

先看看常用的建表sql(PostgreSQL版本),如下

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 '更新時間';
ts是專案資料庫的字首,一般每個專案對應一個字首。

由以上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,歡迎來訪;程式碼如果看不懂,歡迎留言。