在开发中,一般是表结构设计好了之后,然后生成实体类,所以如果手写,你会哭,因为这些代码基本是类是的,而且手写还容易出错,所以一般通过自动生成的工具来生成,这个是控制台打印出来的效果,具体是咋生成类文件啥的,我就没有做了,主要是这玩意具体是生成到哪个包啊,类叫啥名称啊,不同的项目业务也不一样,所以没有必要接着写了,接着的看你自己的了。
生成效果
实现原理代码
这个里面,通过java的工具类,将oracle的表字段信息都获取了,然后打印出来,这个里面需要注意其中的原理,就是查询oracle表USER_COL_COMMENTS
和USER_TAB_COLUMNS
,通过他们来获取表字段信息。
修改版本:2017/11/15 对于Number判断进行了修改
package com.yellowcong.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CreateEntity {
private static final String DB_URL = "jdbc:oracle:thin:@10.0.7.170:1522:ORCL5";
private static final String DB_USER = "SOFINAM_HENSEI";
//venas2017 SOFINAM_HENSEI
private static final String DB_PASSWORD = "SOFINAM_HENSEI";
private static Connection conn = null;
//设定set方法的模版
private static final StringBuffer GET_METHOD_TEMPLATE = new StringBuffer();
//设定get方法的模版
private static final StringBuffer SET_METHOD_TEMPLATE = new StringBuffer();
//类的名称
private static final StringBuffer CLASS_TEMPLATE = new StringBuffer();
//测试类
public static void main(String[] args) throws Exception {
String tableName = "TEST_DEMO";
String result = createClass(tableName);
System.out.println(result);
}
static {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
//创建Get方法的模版
GET_METHOD_TEMPLATE.append("@Column(\"%s\")\r\n");
GET_METHOD_TEMPLATE.append("public %s get%s() {\r\n");
GET_METHOD_TEMPLATE.append("\treturn %s;\r\n");
GET_METHOD_TEMPLATE.append("}");
//设定set方法的模版
SET_METHOD_TEMPLATE.append("public void set%s(%s %s) {\r\n");
SET_METHOD_TEMPLATE.append("\tthis.%s=%s;\r\n");
SET_METHOD_TEMPLATE.append("}");
//方法体的生成
CLASS_TEMPLATE.append("@Bean(table=\"%s\")\r\n");
CLASS_TEMPLATE.append("public class %s implements Serializable{\r\n");
CLASS_TEMPLATE.append("private static final long serialVersionUID = 1L;\r\n");
CLASS_TEMPLATE.append("%s");
CLASS_TEMPLATE.append("\r\n}");
} catch (Exception e) {
e.printStackTrace();
}
}
public static String createClass(String tableName) throws Exception{
StringBuffer sbBody = new StringBuffer();
List<String> classBody = CreateEntity.createClassBody(tableName);
for(String classInfo :classBody){
sbBody.append(classInfo);
sbBody.append("\r\n");
}
return String.format(CLASS_TEMPLATE.toString(), tableName,underline2Camel(tableName,false),sbBody.toString());
}
/**
* 生成class的内容
* @param tableName
* @return
* @throws Exception
*/
public static List<String> createClassBody(String tableName) throws Exception{
List<EntityInfo> infos = getEntityInfo(tableName);
//类的方法体
List<String> classBody = new ArrayList<String>();
for(EntityInfo info:infos){
String comments = info.getComment();
String dataType = info.getType();
String filed = underline2Camel(info.getField());
//当是String类型的
String fieldResult = String.format("/** %s*/\r\nprivate %s %s;\r\n",comments,dataType,filed);
classBody.add(fieldResult);
}
//setter和getter方法
for(EntityInfo info:infos){
//生成get方法
String strGetMethod = createGetterMethod(info);
classBody.add(strGetMethod);
//生成set方法
String strSetMethod = createSetterMethod(info);
classBody.add(strSetMethod);
}
return classBody;
}
/**
* 生成get方法
* @param info
* @return
*/
private static String createGetterMethod(EntityInfo info){
String strGetMethod = String.format(
GET_METHOD_TEMPLATE.toString(),
info.getField(),//注解数据
info.getType(),//返回的数据类型格式
underline2Camel(info.getField(),false), //getUserName
underline2Camel(info.getField()));//userName
return strGetMethod;
}
/**
* 生成set的方法
* @param info
* @return
*/
private static String createSetterMethod(EntityInfo info){
String strSetMethod = String.format(
SET_METHOD_TEMPLATE.toString(), //模版
underline2Camel(info.getField(),false), //大驼峰 setUserName
info.getType(),//数据类型
underline2Camel(info.getField()), //小驼峰 userName
underline2Camel(info.getField()), //小驼峰 userName
underline2Camel(info.getField()) //小驼峰 userName
);
return strSetMethod.toString();
}
/**
* 根据传入的数据类型来字符的类型
* 如果你是其他的数据库,可以根据自己的需求来更改这一块
* @param dataType oracle字段的类型
* @param len 字符的长度
* @return
*/
private static String getFieldType(String dataType,int len){
String fieldType = "";
//当是String类型的
switch(dataType){
case "CHAR" :
fieldType = "String";
break;
case "VARCHAR2":
fieldType = "String";
break;
case "BLOB":
fieldType = "BLOB";
break;
case "DATE":
fieldType = "Date";
break;
case "NUMBER":
if(len == 0){
fieldType = "Long";
}else{
fieldType = len <12?"Integer":"Long";
}
break;
case "FLOAT":
fieldType = len <12?"Float":"Double";
break;
}
return fieldType;
}
/**
* 获取连接
* @return
*/
public static Connection getConnection() {
try {
if (conn == null) {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
}
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取实体类的字段信息
* @param tableName
* @return
* @throws Exception
*/
public static List<EntityInfo> getEntityInfo(String tableName) throws Exception {
Connection con = CreateEntity.getConnection();
//查询USER_COL_COMMENTS 和USER_TAB_COLUMNS 两个表,查询出字段信息
String sql = "SELECT COL.COLUMN_NAME, COL.COMMENTS, " +
" case TAB.DATA_TYPE when 'NUMBER' then decode(sign(NVL(TAB.DATA_SCALE,0)),0,'NUMBER','FLOAT') else TAB.DATA_TYPE end as DATA_TYPE," +
" DECODE(TAB.DATA_TYPE, 'NUMBER', TAB.DATA_PRECISION + TAB.DATA_SCALE , TAB.DATA_LENGTH) AS DATA_LENGTH "
+ "FROM USER_COL_COMMENTS COL, USER_TAB_COLUMNS TAB WHERE COL.TABLE_NAME = ? "
+ "AND TAB.TABLE_NAME = COL.TABLE_NAME AND TAB.COLUMN_NAME = COL.COLUMN_NAME ";
PreparedStatement ps = con.prepareStatement(sql);
System.out.println(sql);
ps.setString(1, tableName);
ResultSet rs = ps.executeQuery();
//将查询的信息都放到集合里面,然后回
List<EntityInfo> infos = new ArrayList<EntityInfo>();
while (rs.next()) {
//字段名次
String colNm = rs.getString(1);
//备注
String comments = rs.getString(2);
//oracle 数据类型
String dataType = rs.getString(3);
//oralce 数据长度
Integer len = rs.getInt(4);
//获取对应的java苏汇聚类型
String fieldType = getFieldType(dataType,len);
infos.add(new CreateEntity.EntityInfo(colNm,comments,fieldType,len));
}
ps.close();
con.close();
return infos;
}
/**
* 下划线转驼峰法(默认小驼峰)
*
* @param line
* 源字符串
* @param smallCamel
* 大小驼峰,是否为小驼峰(驼峰,第一个字符是大写还是小写)
* @return 转换后的字符串
*/
public static String underline2Camel(String line, boolean ... smallCamel) {
if (line == null || "".equals(line)) {
return "";
}
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile("([A-Za-z\\d]+)(_)?");
Matcher matcher = pattern.matcher(line);
//匹配正则表达式
while (matcher.find()) {
String word = matcher.group();
//当是true 或则是空的情况
if((smallCamel.length ==0 || smallCamel[0] ) && matcher.start()==0){
sb.append(Character.toLowerCase(word.charAt(0)));
}else{
sb.append(Character.toUpperCase(word.charAt(0)));
}
int index = word.lastIndexOf('_');
if (index > 0) {
sb.append(word.substring(1, index).toLowerCase());
} else {
sb.append(word.substring(1).toLowerCase());
}
}
return sb.toString();
}
/**
* 驼峰法转下划线
*
* @param line
* 源字符串
* @return 转换后的字符串
*/
public static String camel2Underline(String line) {
if (line == null || "".equals(line)) {
return "";
}
line = String.valueOf(line.charAt(0)).toUpperCase()
.concat(line.substring(1));
StringBuffer sb = new StringBuffer();
Pattern pattern = Pattern.compile("[A-Z]([a-z\\d]+)?");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
String word = matcher.group();
sb.append(word.toUpperCase());
sb.append(matcher.end() == line.length() ? "" : "_");
}
return sb.toString();
}
/**
* 用于存储实体类字段信息
* @author zhangrw
*
*/
static class EntityInfo {
private String field;
private String comment;
private String type;
private Integer length;
/**
*
*/
public EntityInfo() {
super();
}
/**
* @param field
* @param comment
* @param type
* @param length
*/
public EntityInfo(String field, String comment, String type,
Integer length) {
super();
this.field = field;
this.comment = comment;
this.type = type;
this.length = length;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
}
生成效果
这个是控制台打印出来的效果,具体是咋生成类文件啥的,我就没有做了,主要是这玩意具体是生成到哪个包啊,类叫啥名称啊,不同的项目业务也不一样,所以没有必要接着写了,接着的看你自己的了。
类的头信息
注意细节
number类型的数据在oracle中的长度是 22,但是我们并不需要这个长度,而是后面的DATA_PRECISION
和DATA_SCALE
两个字段了,所以要么在SQL上下文章,要么在java处理做文章,这种情况,我们希望在oracle上做文章,这样效率跟高一点
优化SQL语句
SELECT COL.COLUMN_NAME,
COL.COMMENTS,
case TAB.DATA_TYPE when 'NUMBER' then
--当是number的情况,判断 DATA_SCALE 是否为0 如果是0 就是number类型
--如果非0 就是FLOAT类型,这个地方,我就这么简单做判断了
decode(sign(TAB.DATA_SCALE),0,'NUMBER','FLOAT')
else
TAB.DATA_TYPE
end as DATA_TYPE,
DECODE(TAB.DATA_TYPE,
'NUMBER',
TAB.DATA_PRECISION + TAB.DATA_SCALE ,
TAB.DATA_LENGTH) AS DATA_LENGTH
FROM USER_COL_COMMENTS COL, USER_TAB_COLUMNS TAB
WHERE COL.TABLE_NAME = 'K_TRN_OUTLINE'
AND TAB.TABLE_NAME = COL.TABLE_NAME
AND TAB.COLUMN_NAME = COL.COLUMN_NAME
对于number类型进行特殊的处理,这样字段的长度就正确了,同时将数据类型为number的,如果是浮点,就反回float