jdbc元数据自动生成pojo代码
前言
在阅读如下生成的代码之前,可以先看看我另一篇根据元数据获得表名、主键、外键、字段信息的博客。
https://blog.****.net/weixin_44112790/article/details/86804021
生成pojo
pojo作为数据库的映射,不难根据刚刚获得的元数据来生成pojo代码,当然这是在数据库的命名都遵循着一定规范的情况才能实现。
分析pojo
随便拿了一个pojo来看看,其中Table和Column都是我自定义的注解
@Table(value="users",pkName="userId")
public class Users {
@Column("userId")
private long userId;
@Column("userName")
private String userName;
@Column("phoneNumber")
private long phoneNumber;
public Users() {
super();
}
public Users(long userId, String userName, long phoneNumber) {
super();
this.userId = userId;
this.userName = userName;
this.phoneNumber = phoneNumber;
}
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public long getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(long phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
可以看出代码其实就是在重复映射数据库,那么根据元数据循环起来应该很好解决;先把刚刚那个完整的代理简化一下
//表名和主键都能通过数据库的元数据得到,这里应该没什么问题
@Table(value="users",pkName="userId")
//类名只需要将表名首字母大写即可
public class Users {
//将之前获得的字段名循环起来可以生成这个字段,值得注意的是java中的类型
@Column("userId")
private long userId;
//这里只演示一个无参的构造器,有参的只需根据字段补充属性
public Users() {
super();
}
//每个属性的get、set方法,循环所得字段就能生成全部的
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
}
模型设计
根据之前的分析我们可以设计几个模型便于我们重复利用
库模型
我的想法是在创建库模型的时候,就将集合中表模型的表名和主键赋好值,在这里用一个map来存
public class DataBaseModel {
private Map<String,String> tables = new HashMap<String,String>();
public DataBaseModel()throws SQLException{
Connection conn = ConnectionPool.getInstance().getConnection();
DatabaseMetaData dbmd = conn.getMetaData();
String[] types = {"TABLE"};
//获得表信息
ResultSet rs = dbmd.getTables(null, null, "%", types);
while(rs.next()) {
String tableName = rs.getString(3);
ResultSet pks = dbmd.getPrimaryKeys(null, null, tableName);
while(pks.next()){
//主键和表名一同放入map
tables.put(tableName, pks.getString(4));
}
}
}
public Map<String, String> getTables() {
return tables;
}
public void setTables(Map<String, String> tables) {
this.tables = tables;
}
}
表模型
表模型记录表名、主键名以及字段模型
public class TableModel {
private String tableName;
private List<ColumnModel> columns;
private String pkName;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public List<ColumnModel> getColumns() {
return columns;
}
public void setColumns(List<ColumnModel> columns) {
this.columns = columns;
}
public String getPkName() {
return pkName;
}
public void setPkName(String pkName) {
this.pkName = pkName;
}
}
列模型
记录字段名与类型
public class ColumnModel {
private String columnType;
private String columnName;
public String getColumnType() {
return columnType;
}
public void setColumnType(String columnType) {
this.columnType = columnType;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public ColumnModel(String columnName){
this.columnName = columnName;
}
public ColumnModel(){
}
}
代码生成
我准备通过一个util工具对象来生成代码,其中封装一些方法,分步来实现代码的自动生成
处理类型
元数据得到的数据类型是整数代指,我这里把常用的几种考虑进去,做一个和java中类型的映射方法
/**
* @param type String:1-CHAR;12-VARCHAR;-1-LONGVARCHAR
* String:91-date;92-time;93-TIMESTAMP
* Integer:4-INTEGER;-5-BIGINT;5-SMALLINT;
* Double:8-DOUBLE
* FLOAT:7-REAL
* @return
*/
private String getJavaType(int type) {
if(type==1 || type==12 || type == -1
|| type==91 || type==92 || type == 93) {
return "String";
}else if(type==4 || type == -5) {
return "Integer";
}else if(type==8){
return "Double";
}else if(type==7){
return "Float";
}
System.err.println(type+"没有对应映射");
return null;
}
处理命名
首字母大写即可
private String getFirstUpperName(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
初始化
我希望在初始化的时候就获得每张表的字段信息,结合库模型获得的表名主键用于生成pojo
public GenePojoUtil()throws Exception{
//数据库模型
DataBaseModel dbModel = new DataBaseModel();
//获取数据库中的所有表信息
Map<String,String> tables = dbModel.getTables();
//获取连接
Connection conn = ConnectionPool.getInstance().getConnection();
for(String tableName:tables.keySet()){
//根据sql获得表格的元数据,从而得到每个表格的字段名
String sql = "SELECT * FROM "+tableName+" WHERE 1 = 0";
Statement stmt = conn.createStatement();
ResultSet results = stmt.executeQuery(sql);
ResultSetMetaData rmd = results.getMetaData();
//用于存储当前表的所有字段模型
List<ColumnModel> columns = new ArrayList<ColumnModel>();
for(int i = 1;i <= rmd.getColumnCount();i++){
//列模型存储字段名与类型
ColumnModel column = new ColumnModel();
String columnName = rmd.getColumnName(i);
column.setColumnName(columnName);
String columnType = this.getJavaType(rmd.getColumnType(i));
column.setColumnType(columnType);
columns.add(column);
}
//将表名、主键名、字段信息存入工具类中的表模型列表
TableModel tableModel = new TableModel();
tableModel.setTableName(tableName);
tableModel.setPkName(tables.get(tableName));
tableModel.setColumns(columns);
this.tableModels.add(tableModel);
}
}
书写代码
准备一个写代码的方法,根据路径和codes列表来生成代码
private void writeCode(String path,List<String> codes){
//为了截取而进行的替换
path = path.replace("\\\\", "/");
//截取获得父目录
File parentPathFile = new File(path.substring(0, path.lastIndexOf("/")));
//不存在则新建父目录
if(!parentPathFile.exists()) {
parentPathFile.mkdirs();
}
//准备一个流对象用于书写
BufferedWriter bw =null;
try {
bw = new BufferedWriter(new FileWriter(new File(path)));
for(String code:codes){
bw.write(code);
bw.newLine(); //一行一行地写
}
} catch (IOException e) {
e.printStackTrace();
} finally{
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
构造代码
将之前简化的pojo简单编辑,建议使用小红本、notepad++等高级文本编辑工具
一部分一部分的剪切到java中并用表里替换相应的部分(注意字符串拼凑不要出问题),将构造的代码都写到一个根目录下
public void genePojo(String rootPath) throws SQLException {
for(TableModel tableModel:tableModels){
String tableName = tableModel.getTableName();
List<ColumnModel> columns = tableModel.getColumns();
List<String> codes = new ArrayList<String>();
//包名
codes.add("package biz.pojo;");
//表名与主键
codes.add("//表名和主键都能通过数据库的元数据得到,这里应该没什么问题");
codes.add("@Table(value=\""+tableName+"\",pkName=\""+tableModel.getPkName()+"\")");
//类名
codes.add("//类名只需要将表名首字母大写即可");
codes.add("public class Users {");
//属性
for(ColumnModel column:columns){
String columnName = column.getColumnName();
String columnType = column.getColumnType();
codes.add(" @Column(+\""+columnName+"\")");
codes.add(" private "+columnType+" "+columnName+";");
}
//get、set方法
codes.add("//get、set方法");
for(ColumnModel column:columns){
String columnName = column.getColumnName();
String UpName = getFirstUpperName(columnName);
String columnType = column.getColumnType();
codes.add(" public "+columnType+" get"+UpName+"() {");
codes.add(" return "+columnName+";");
codes.add(" }");
codes.add(" public void set"+UpName+"("+columnType+" "+columnName+") {");
codes.add(" this."+columnName+" = "+columnName+";");
codes.add(" }");
}
codes.add("}");
String path = rootPath+getFirstUpperName(tableName)+".java" ;
this.writeCode(path, codes);
}
}
结果展示
利用刚刚的工具对象将我所连数据库的pojo全部生成到test下
public static void main(String[] args) throws Exception {
GenePojoUtil util = new GenePojoUtil();
util.genePojo("E:/test/");
}
秒出代码,想想要是手写这个得花多久时间啊
也符合之前构造的规范,和自己手写的没什么区别