手写建表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 @packPath@;\r\n\r\n@date@\r\n\r\n/** \r\n * @sign@\r\n * " + author + "\r\n */\r\n";
	
	/** 导入Date*/
	private static String importDate = "import java.util.Date;";
	
	/** 存文件名称 */
	private static Map fileNameMap = new LinkedHashMap();
	
	/** 存类注释 */
	private static Map tipMap = new LinkedHashMap();
	
	/** 存get/set方法 */
	private static Map methodMap = new LinkedHashMap();
	
	/** 存字段 */
	private static Map> dataMap = new HashMap>();
	
	
	/** pg字段类型的集合 */
	private static List isFieldList = new ArrayList();
	private static List longList = Arrays.asList("BIGINT", "INT8", "BIGSERIAL", "SERIAL8");
	private static List intList = Arrays.asList("SMALLINT", "INT2", "NUMERIC", "SERIAL", "SERIAL4"  );
	private static List doubleList = Arrays.asList("DECIMAL", "REAL", "FLOAT4", "DOUBLE", "FLOAT8");
	private static List stringList = Arrays.asList("CHARACTER", "VARCHAR", "CHAR", "TEXT");
	private static List 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("@packPath@", 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 map = new LinkedHashMap();
				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 fieldMap = dataMap.get(className);
				String classHead = fieldMap.get("classHead");
				if ("Date".equals(classType) && classHead.indexOf("@date@") >= 0) {
					classHead = classHead.replace("@date@", 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 fieldMap = dataMap.get(className);
				String classHead = fieldMap.get("classHead");
				classHead = classHead.replace("@sign@", 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 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> entryMap : dataMap.entrySet()) {
			String key = entryMap.getKey();
			String outFilePath = fileNameMap.get(key);
			BufferedWriter writer = getWriter(outFilePath + ".java");
			Map fieldMap = entryMap.getValue();
			String classHead = fieldMap.get("classHead");
			if (classHead.indexOf("@date@") >= 0) {
				fieldMap.put("classHead", classHead.replace("@date@", ""));
			}
			for (Entry 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);
		File file = new File(filePath);
		if (!file.exists() && !file.mkdirs()) {
			throw new Exception("创建目录失败");
		}
		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,欢迎来访;代码如果看不懂,欢迎留言。











你可能感兴趣的:(java)