Panda ORM源码-数据库表自动生成Java实体类
一,整体思路
1,首先明确目标,需要通过指定数据库名,自动生成该数据库中所有表对应的Java实体类。
2,数据库名及其他一些参数(跟数据库url、用户、密码、实体类保存路径)通过配置文件设定。
3,连接数据库后,通过数据库名获取该数据库中所有的表。对于MySQL来说,可以通过select table_name from information_schema.tables where table_schema='XXX'
,来获取XXX数据库中所有的表名。PS:对于information_schema数据库不了解的可以打开看下,information_schema.tables保存了运行在MySQL上表的信息。
4,通过Java代码读取表结构信息,生成对应的Java类字符串,将字符串写入文件。
二,参数设置
参数保存在src目录下config.properties文件下,通过Constants的static方法获取配置文件信息,具体代码如下:
config.properties代码如下,注意前五个参数为数据库连接需要的参数,table_schema表示数据库名,entity_package_name表示生成实体类的包名,两个path分别表示实体类文件及日志保存路径。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/bank_performance?useUnicode=true&characterEncoding=utf-8
user=root
password=Pass1234
table_schema=bank_performance
entity_package_name=panda.bank.entity
file_save_path=D\:\\Java\\AutoEntity\\
file_log_path=D\:\\Java\\AutoEntity\\
读取配置文件是通过Constants 中的static方法实现:
package panda.orm.util;
public class Constants {
//Property类代码在下面
public static Property CONFIG_PROPERTY;
public static String getFormatDateTime(){
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return formater.format(new Date());
}
public static String getLogFormatDateTime(){
SimpleDateFormat formater = new SimpleDateFormat("yyyyMMddhhmmss");
return formater.format(new Date());
}
static{
Properties fileProperties = new Properties();
InputStream inputStream = fileProperties.getClass().getResourceAsStream("/config.properties");
CONFIG_PROPERTY=new Property();
try{
fileProperties.load(inputStream);
CONFIG_PROPERTY.setDriver(fileProperties.getProperty("driver"));
CONFIG_PROPERTY.setUrl(fileProperties.getProperty("url"));
CONFIG_PROPERTY.setUser(fileProperties.getProperty("user"));
CONFIG_PROPERTY.setPassword(fileProperties.getProperty("password"));
CONFIG_PROPERTY.setTable_schema(fileProperties.getProperty("table_schema"));
CONFIG_PROPERTY.setFile_save_path(fileProperties.getProperty("file_save_path"));
CONFIG_PROPERTY.setFile_log_path(fileProperties.getProperty("file_log_path"));
CONFIG_PROPERTY.setEntity_package_name(fileProperties.getProperty("entity_package_name"));
}catch (IOException ex){
ex.printStackTrace();
}finally{
try {
inputStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
package panda.orm.util;
public class Property{
private String driver;
private String url;
private String user;
private String password;
private String table_schema;
private String file_save_path;
private String file_log_path;
private String entity_package_name;
//省略get set
三,EntityGenerater.generateClasses()方法直接生成数据库中所有表对应实体类,直接上代码看注释部分即可:
package panda.orm.util;
import java.io.File;
import java.io.FileOutputStream;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import panda.orm.database.MySQLHandler;
import panda.orm.exception.SqlExcuteException;
/**
* 由MySQL数据库自动生成Java实体类
* @author 猫哥
* @date 2017.3.23
*/
public class EntityGenerater {
//在配置完config.properties之后,直接调用EntityGenerater类的静态方法generateClasses即可生成对应Java实体类
public static void main(String[] args) {
EntityGenerater.generateClasses();
}
//generateClasses方法做了三件事
//1,构造方法获取需要的参数
//2,init方法生成数据库对应的表-类结构
//3,write方法负责将类结构转换为实体类代码字符串并写入文件
public static void generateClasses(){
EntityGenerater eg=new EntityGenerater(Constants.CONFIG_PROPERTY.getTable_schema(),
Constants.CONFIG_PROPERTY.getEntity_package_name(),Constants.CONFIG_PROPERTY.getFile_save_path());
eg.init();
eg.write();
System.out.println("Panda ORM generate success!");
}
//tables保存了数据库的结构,tables的key表示表名,key对应的结合表示该表的所有列名集合
private Map<String,Set<String>> tables=new HashMap<String,Set<String>>();
private String table_schema;
private String entity_package_name;
private String entity_save_path;
public EntityGenerater(String table_schema,String entity_package_name,String entity_save_path){
this.table_schema=table_schema;
this.entity_package_name=entity_package_name;
this.entity_save_path=entity_save_path;
}
public void init(){
MySQLHandler hand=new MySQLHandler();
ResultSet rs=null;
//数据库名
String table_schema =Constants.CONFIG_PROPERTY.getTable_schema();
//获取数据库下所有表的sql语句
String sql="select table_name from information_schema.tables where table_schema='"+table_schema+"'";
tables.clear();
try {
rs=hand.query(sql);
while(rs.next()){
String tableName=rs.getString("table_name");
//getColumns方法获取表对应的列
Set<String> columns=getColumns(tableName);
//将表和对应列结合放入tables
tables.put(tableName, columns);
}
} catch (Exception ex) {
new SqlExcuteException(ex.getMessage(),this.getClass().getName(),"sql执行异常",sql);
}finally{
hand.sayGoodbye();
}
}
//获取表对应的列名集合
private Set<String> getColumns(String tableName){
MySQLHandler hand=new MySQLHandler();
ResultSet rs=null;
String sql="select * from "+tableName;
Set<String> columns=new HashSet<String>();
try {
rs=hand.query(sql);
ResultSetMetaData meta=rs.getMetaData();
int count=meta.getColumnCount();
for(int i=0;i<meta.getColumnCount();i++){
columns.add(meta.getColumnName(i+1));
}
}catch (Exception ex) {
new SqlExcuteException(ex.getMessage(),this.getClass().getName(),"sql执行异常",sql);
}finally{
hand.sayGoodbye();
}
return columns;
}
//转换tables信息为实体类代码对应的字符串,并写入文件
public void write(){
Iterator iter = tables.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String tableName = (String)entry.getKey();
Set<String> columns = (Set<String>)entry.getValue();
//核心方法,将表明和对应列信息转换为实体类代码
String entityString=getEntityString(tableName,columns);
//写文件
try{
String path=entity_save_path+turnFirstUp(tableName)+".java";
File file=new File(path);
if(!file.exists())
file.createNewFile();
FileOutputStream out=new FileOutputStream(file,true);
out.write(entityString.getBytes("utf-8"));
out.close();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
//核心方法,将表明和对应列信息转换为实体类代码
private String getEntityString(String tableName,Set<String> columns){
StringBuilder sb=new StringBuilder();
//包名及类注释
sb.append("package "+entity_package_name+";\r\n");
sb.append("/**\r\n");
sb.append("* " + new Date() + "\r\n");
sb.append("* Panda ORM atuo generate: " + tableName + " \r\n");
sb.append("*/ \r\n");
//类定义
sb.append("public class " + turnFirstUp(tableName) + "{\r\n");
//属性
for(String colName:columns){
sb.append("\tprivate String "+colName+";\r\n");
}
//方法
for(String colName:columns){
sb.append("\tpublic String get"+turnFirstUp(colName)
+"(){\r\n");
sb.append("\t\treturn "+colName+";\r\n");
sb.append("\t}\r\n");
sb.append("\tpublic void set"+turnFirstUp(colName)
+ "(String "+colName+"){\r\n");
sb.append("\t\tthis."+colName+"="+colName+";\r\n");
sb.append("\t}\r\n");
}
sb.append("}");
return sb.toString();
}
//首字母大写
private String turnFirstUp(String str) {
char[] ch = str.toCharArray();
if(ch[0]>='a'&&ch[0]<='z'){
ch[0]=(char)(ch[0]-32);
}
return new String(ch);
}
}
四,测试,以马上要开始讲解的银行业绩系统数据库为例,表结构如下图(具体含义先不解释,只是演示由数据库生成实体代码):
然后运行,注意配置文件就按开头说的配置的。
public static void main(String[] args) {
EntityGenerater.generateClasses();
}
运行后,控制台提示:Panda ORM generate success!
,表示成功,根据配置文件在目录下发现:
打开User.java,成功。
package panda.bank.entity;
/**
* Thu Mar 23 11:30:12 CST 2017
* Panda ORM atuo generate: user
*/
public class User{
private String user_name;
private String user_role;
private String user_job;
private String user_password;
private String user_id;
private String user_department;
public String getUser_name(){
return user_name;
}
public void setUser_name(String user_name){
this.user_name=user_name;
}
public String getUser_role(){
return user_role;
}
public void setUser_role(String user_role){
this.user_role=user_role;
}
public String getUser_job(){
return user_job;
}
public void setUser_job(String user_job){
this.user_job=user_job;
}
public String getUser_password(){
return user_password;
}
public void setUser_password(String user_password){
this.user_password=user_password;
}
public String getUser_id(){
return user_id;
}
public void setUser_id(String user_id){
this.user_id=user_id;
}
public String getUser_department(){
return user_department;
}
public void setUser_department(String user_department){
this.user_department=user_department;
}
}
五,补充说明
根据Panda ORM整体的设计,所有类属性都是String类型,其实可以根据表中的数据类型转换属性类型,此处不再加以演示。
有了实体类代码后,需要添加主键、外键注释,并需要将外键对应属性类型改为外键指向表实体类型,然后就可以直接利用Panda ORM生成常用的增、删、改、查方法。
增、删、改没有问题,查的话只提供了最基本的查数量、分页查、查全部、按主键查的功能。更加复杂的查询还是要写原生的sql代码,有点遗憾。但是想想MyBatis每个都要单独写sql和Hibernate复杂的配置,心里又好受了很多,哈哈。下篇演示通过注解实现ORM的思路和源码。
相关文章