JPA实体代码生成器

        在JPA项目中,通常实体与数据库之间的映射需要人工去写,容易写错,也比较繁琐,实际上JPA的实体映射方式也就那么几种,与其对着数据库表结构一句一句地去手写,不如用代码生成器去生成一下,本例中不涉及N-N的关系映射(即外键关系),下面贴出代码,希望各位Reader可以完善和点评一下。

项目是基于Maven构建,后期改成普通Java项目。下面是引用到的Jar文件:

工程目录结构:

 

下面贴出所有代码:

[Consts.java]

package com.able.consts;

/**
 * 数据库常量
 * @author	zhanglikun
 * @mail	likun_zhang@yeah.net
 * @date 	2013-6-6
 */
public interface Consts {
	String DB_NAME = "database_name" ;		// 数据库名称
	String DB_HOST = "database_server" ;	// 数据库HOST
	int DB_PORT = 3306 ;					// 数据库端口
	String DB_USER="root" ;					// 用户名
	String DB_PASS="database_password" ;	// 密码
	
	String DB_TABLE_PREFIX = "TBL_" ;		// 表前缀
	
	String TARGET_DIR = "G:/Temps/codes/" ;	// 生成代码存放目录
	
}

 

 

[DBHandler.java]

package com.able.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import com.able.consts.Consts;
/**
 * 创建数据库连接
 * @author	zhanglikun
 * @mail	likun_zhang@yeah.net
 * @date 	2013-6-6
 */
public class DBHandler {
	private static Connection conn ;
	
	public static final Connection createConnection() {
		try {
			Class.forName("com.mysql.jdbc.Driver") ;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		try {
			conn = DriverManager.getConnection("jdbc:mysql://" + Consts.DB_HOST + ":" + Consts.DB_PORT + "/" + Consts.DB_NAME, Consts.DB_USER ,Consts.DB_PASS) ;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn ;
	}
	
	public static final void close() {
		if(conn != null) {
			try {
				conn.close() ;
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
}

 

[AnalysisDB.java]

package com.able.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.able.consts.Consts;
import com.able.model.ColumnMeta;
import com.able.model.TableMeta;
/**
 * 解析表结构
 * @author	zhanglikun
 * @mail	likun_zhang@yeah.net
 * @date 	2013-6-6
 */
public class AnalysisDB {
	
	/**
	 * 读取表列表
	 * @return
	 */
	public static final List<TableMeta> readDB() {
		List<TableMeta> list = new ArrayList<TableMeta>();
		String sql = "SELECT TABLE_NAME ,TABLE_COMMENT FROM information_schema.tables "
				+ " WHERE table_schema ='"+Consts.DB_NAME+"'";
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = DBHandler.createConnection().prepareStatement(sql);
			rs = ps.executeQuery();
			while (rs.next()) {
				TableMeta tm = new TableMeta() ;
				tm.setSchemaName(Consts.DB_NAME) ;
				tm.setTableName(rs.getString("TABLE_NAME")) ;
				tm.setComment(rs.getString("TABLE_COMMENT")) ;
				list.add(tm) ;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				rs.close();
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
	
	/**
	 * 填充字段信息
	 * @param tables
	 */
	public static final void readTables(List<TableMeta> tables) {
		if(tables != null) {
			for(TableMeta tm : tables) {
				readTable(tm) ;
			}
		}
		DBHandler.close() ;
	}
	
	/**
	 * 读取表结构
	 * @param table
	 */
	private static final void readTable(TableMeta table) {
		List<ColumnMeta> list = new ArrayList<ColumnMeta>() ;
		String sql = "SELECT COLUMN_NAME ,ORDINAL_POSITION ,IS_NULLABLE ,COLUMN_DEFAULT ,COLUMN_TYPE ,COLUMN_KEY ,EXTRA ,COLUMN_COMMENT "
		+ " FROM information_schema.columns WHERE table_schema ='" + Consts.DB_NAME + "' AND table_name = '" + table.getTableName() + "'";
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = DBHandler.createConnection().prepareStatement(sql);
			rs = ps.executeQuery();
			while (rs.next()) {
				ColumnMeta fm = new ColumnMeta() ;
				
				fm.setColumnName(rs.getString("COLUMN_NAME")) ;
				fm.setOrdinalPosition(rs.getString("ORDINAL_POSITION")) ;
				fm.setIsNullable(rs.getString("IS_NULLABLE")) ;
				fm.setColumnDefault(rs.getString("COLUMN_DEFAULT")) ;
				fm.setColumnType(rs.getString("COLUMN_TYPE")) ;
				fm.setColumnKey(rs.getString("COLUMN_KEY")) ;
				fm.setExtra(rs.getString("EXTRA")) ;
				fm.setColumnComment(rs.getString("COLUMN_COMMENT")) ;
				
				list.add(fm) ;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				rs.close();
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		table.setColumns(list) ;
	}
	
}

 

[ColumnMeta.java]

package com.able.model;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
/**
 * 字段结构
 * @author	zhanglikun
 * @mail	likun_zhang@yeah.net
 * @date 	2013-6-6
 */
public class ColumnMeta {
	private String columnName ;
	private String ordinalPosition ; 
	private String isNullable ;
	private String columnDefault ;
	private String columnType ;
	private String columnKey ;
	private String extra ;
	private String columnComment ;		
	private int columnSize ;				// 字段长度,将在计算属性类型时赋值
	
	public String getColumnName() {
		return columnName;
	}
	public void setColumnName(String columnName) {
		this.columnName = columnName;
	}
	public String getOrdinalPosition() {
		return ordinalPosition;
	}
	public void setOrdinalPosition(String ordinalPosition) {
		this.ordinalPosition = ordinalPosition;
	}
	public String getIsNullable() {
		return isNullable;
	}
	public void setIsNullable(String isNullable) {
		this.isNullable = isNullable;
	}
	public String getColumnDefault() {
		return columnDefault;
	}
	public void setColumnDefault(String columnDefault) {
		this.columnDefault = columnDefault;
	}
	public String getColumnType() {
		return columnType;
	}
	public void setColumnType(String columnType) {
		this.columnType = columnType;
	}
	public String getColumnKey() {
		return columnKey;
	}
	public void setColumnKey(String columnKey) {
		this.columnKey = columnKey;
	}
	public String getExtra() {
		return extra;
	}
	public void setExtra(String extra) {
		this.extra = extra;
	}
	public String getColumnComment() {
		return columnComment;
	}
	public void setColumnComment(String columnComment) {
		this.columnComment = columnComment;
	}
	/**
	 * 获取属性名称
	 * @return
	 */
	public String getPropertyName() {
		StringBuffer propertyName = new StringBuffer() ;
		String [] names = StringUtils.split(columnName.toLowerCase(), "_") ;
		propertyName.append(names[0]) ;	// 第一个单词全小写
		for(int i = 1 ,len = names.length ; i < len ; i ++) {
			propertyName.append(names[i].substring(0, 1).toUpperCase() + names[i].substring(1)) ;
		}
		return propertyName.toString() ;
	}
	/**
	 * 获取属性类型
	 * @return
	 */
	public String getPropertyType() {
		String type = columnType.toLowerCase() ;
		String propertyType = null ;
		if(StringUtils.startsWith(type, "int")) {				// int/long
			columnSize = NumberUtils.toInt(StringUtils.substring(type, StringUtils.indexOf(type, "(") + 1 ,StringUtils.indexOf(type, ")"))) ;
			if(columnSize <= 4)propertyType = "Integer" ;
			else propertyType = "Long" ;
		} else if(StringUtils.startsWith(type, "bigint")) {		// long 
			propertyType = "Long" ;
		} else if(StringUtils.startsWith(type, "double")) {		// double
			propertyType = "Double" ;
		} else if(StringUtils.startsWith(type, "float")) {		// float
			propertyType = "Float" ;
		} else if(StringUtils.startsWith(type, "varchar")) {	// String
			columnSize = NumberUtils.toInt(StringUtils.substring(type, StringUtils.indexOf(type, "(") + 1 ,StringUtils.indexOf(type, ")"))) ;
			propertyType = "String" ;
		} else if(StringUtils.startsWith(type, "char")) {		// String
			columnSize = NumberUtils.toInt(StringUtils.substring(type, StringUtils.indexOf(type, "(") + 1 ,StringUtils.indexOf(type, ")"))) ;
			propertyType = "String" ;
		} else if(StringUtils.startsWith(type, "text")) {		// String
			propertyType = "String" ;
		} else if(StringUtils.startsWith(type, "date")) {		// date
			propertyType = "java.util.Date" ;
		} else if(StringUtils.startsWith(type, "datetime")) {	// date
			propertyType = "java.util.Date" ;
		} else if(StringUtils.startsWith(type, "timestamp")) {	// date 
			propertyType = "java.util.Date" ;
			
		} else {
			System.out.println("==类型[" + type + "]解析尚不支持==");
		}
		return propertyType ;
	}
	public int getColumnSize() {
		return columnSize;
	}
	
}

 

[TableMeta.java]

package com.able.model;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.able.consts.Consts;
/**
 * 表结构信息
 * @author	zhanglikun
 * @mail	likun_zhang@yeah.net
 * @date 	2013-6-6
 */
public class TableMeta {
	private String schemaName ;
	private String tableName ;
	private String comment ;
	private List<ColumnMeta> columns ; 
	
	public String getTableName() {
		return tableName;
	}
	public void setTableName(String tableName) {
		this.tableName = tableName;
	}
	public String getComment() {
		return comment;
	}
	public void setComment(String comment) {
		this.comment = comment;
	}
	public List<ColumnMeta> getColumns() {
		return columns;
	}
	public void setColumns(List<ColumnMeta> columns) {
		this.columns = columns;
	}
	public String getClassName() {
		if(tableName == null) return "" ;
		StringBuffer className = new StringBuffer() ;
		if(StringUtils.startsWith(tableName, Consts.DB_TABLE_PREFIX)) {
			String newName = StringUtils.substring(tableName, Consts.DB_TABLE_PREFIX.length()) ;
			String [] names = StringUtils.split(newName.toLowerCase(), "_") ;
			for(int i = 0 ,len = names.length ; i < len ; i ++) {
				className.append(names[i].substring(0, 1).toUpperCase() + names[i].substring(1)) ;
			}
		} else {
			System.out.println("==不支持的表前缀==");
		}
		return className.toString() ;
	}
	public String getSchemaName() {
		return schemaName;
	}
	public void setSchemaName(String schemaName) {
		this.schemaName = schemaName;
	}
	
}

 

[GenerateMain.java]

package com.able;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.able.consts.Consts;
import com.able.db.AnalysisDB;
import com.able.model.TableMeta;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
 * 生成代码入口
 * @author	zhanglikun
 * @date	2013-7-17
 * @desc	XXX
 */
public class GenerateMain {
	public static void main(String[] args) throws IOException, TemplateException {
		
		List<TableMeta> tableList ;
		Writer out = null ;
		String targetDir = Consts.TARGET_DIR ;
		
		tableList = AnalysisDB.readDB() ;
		AnalysisDB.readTables(tableList) ;
		// 输出到文件
		File dir = new File(targetDir) ;
		if(!dir.isDirectory()) {
			dir.mkdirs() ;
		}
		
		Configuration cfg = new Configuration() ;
		cfg.setDirectoryForTemplateLoading(new File("src/main/tpl")) ;
		cfg.setObjectWrapper(new DefaultObjectWrapper()); 
		Template tpl = cfg.getTemplate("model.ftl") ;
		if(tableList != null) {
			for(TableMeta tm : tableList) {
				if(StringUtils.isBlank(tm.getClassName()))continue ;
				out = new FileWriter(new File(targetDir + tm.getClassName() + ".java")) ;
				tpl.process(tm, out) ;
				System.out.println("===文件 " + tm.getClassName() + ".java" + " 生成成功===");
			}
		}
		
		out.flush() ;
		out.close() ;		
		
	}
	
}

 

[model.ftl]

<#-- TODO 改为实际使用的包名 -->
package com.able.model ;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import com.able.consts.UCCConsts;
/**
 * ${comment!""}
 * @desc	使用代码生成器生成.
 * @date 	${.now?string("yyyy/MM/dd")}
 */
@Entity
@Table(name = "${tableName}" ,catalog = UCCConsts.APP_SCHEMA)
public class ${className} extends IDEntity {
	<#list columns as column>
	<#assign autograph = "private " + column.propertyType + " " + column.propertyName + " ;">
	<#if column.propertyName != "id">
	${autograph}<#if (column.columnComment?? && column.columnComment?length > 0)><#if (autograph?length < 4)>${"\t\t\t\t\t\t\t\t\t\t"}<#elseif (autograph?length < 8)>${"\t\t\t\t\t\t\t\t\t"}<#elseif (autograph?length < 12)>${"\t\t\t\t\t\t\t\t"}<#elseif (autograph?length < 16)>${"\t\t\t\t\t\t\t"}<#elseif (autograph?length < 20)>${"\t\t\t\t\t\t"}<#elseif (autograph?length < 24)>${"\t\t\t\t\t"}<#elseif (autograph?length < 28)>${"\t\t\t\t"}<#elseif (autograph?length < 32)>${"\t\t\t"}<#elseif (autograph?length < 36)>${"\t\t"}<#else>${"\t"}</#if>// ${column.columnComment}</#if>
	</#if>
	</#list>	
	<#list columns as column>
	<#if column.propertyName != "id">
	public void set${column.propertyName?cap_first} (${column.propertyType} ${column.propertyName}){
		this.${column.propertyName} = ${column.propertyName} ;
	}
	<#if column.propertyType == "java.util.Date">@javax.persistence.Temporal(javax.persistence.TemporalType<#if column.columnType == "DATE" || column.columnType == "date">.DATE<#else>.TIMESTAMP</#if>)</#if>
	@Column(name = "${column.columnName}"<#if column.columnSize != 0> ,length = ${column.columnSize}</#if><#if column.isNullable == "NO"> ,nullable = false</#if><#if column.columnKey == "UNI"> ,unique = true</#if>)	
	public ${column.propertyType} get${column.propertyName?cap_first} (){
		return this.${column.propertyName} ;
	}
	
	</#if>
	</#list>	
}

运行:GenerateMain即可生成代码,生成代码配置在Consts中完成。

注:本项目仅适用于MySQL数据库。

 

其中的IDEntity可自行编写,下面是我的,当然未必需要对ID做统一映射:

package com.able.model;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
/**
 * 公共主键映射
 * @author	ZhangLiKun
 * @title	IDEntity
 * @date	2013-6-6
 */
@MappedSuperclass
public class IDEntity {
	
	private Long id ;
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "ID")
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	
}

 

下面贴出的是一个生成后的Model代码:

package com.able.model ;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
 * 推课表
 * @desc	使用代码生成器生成.
 * @date 	2013/07/17
 */
@Entity
@Table(name = "TBL_RECOMMEND" ,catalog = "COURSE_CENTER")
public class Recommend extends IDEntity {
	private Long parentId ;					// 父ID
	private Long recommendCourseId ;		// 推课ID
	private Long userId ;					// 用户ID
	private String reason ;					// 推课理由
	private java.util.Date createdTime ;	// 推课时间
	public void setParentId (Long parentId){
		this.parentId = parentId ;
	}
	
	@Column(name = "PARENT_ID" ,length = 11 ,nullable = false)	
	public Long getParentId (){
		return this.parentId ;
	}
	
	public void setRecommendCourseId (Long recommendCourseId){
		this.recommendCourseId = recommendCourseId ;
	}
	
	@Column(name = "RECOMMEND_COURSE_ID" ,length = 11 ,nullable = false)	
	public Long getRecommendCourseId (){
		return this.recommendCourseId ;
	}
	
	public void setUserId (Long userId){
		this.userId = userId ;
	}
	
	@Column(name = "USER_ID" ,length = 11 ,nullable = false)	
	public Long getUserId (){
		return this.userId ;
	}
	
	public void setReason (String reason){
		this.reason = reason ;
	}
	
	@Column(name = "REASON" ,length = 500)	
	public String getReason (){
		return this.reason ;
	}
	
	public void setCreatedTime (java.util.Date createdTime){
		this.createdTime = createdTime ;
	}
	@javax.persistence.Temporal(javax.persistence.TemporalType.TIMESTAMP)
	@Column(name = "CREATED_TIME" ,nullable = false)	
	public java.util.Date getCreatedTime (){
		return this.createdTime ;
	}
	
}

 

转载于:https://my.oschina.net/zhanglikun/blog/148633

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值