本次记录的是通过自定义注解实现通过在一个实体类上进行注解自动在数据库生成表。本实例参考《Java编程思想》一书中的注解章节,有本书的同学可以查看第620页得内容。
首先定义第一个注解DBTable,它用来给类进行注解,其中name()代表要生成表得名字
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Huhailong
* generate db table annotation
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable{
public String name() default ""; //table name
}
有了表名我们还需要定义表中字段的一些约束条件,下面这个注解是作用在字段上面的
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author huhailong
* field constraints
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints{
boolean primaryKey() default false; //set field is primary key
boolean allowNull() default true; //set field is allow null, default is null
boolean unique() default false; //set field is unique
}
下面我们定义几个sql类型,name()为这个字段的名称,value()为大小,constraints为约束条件,嵌套的上一个注解,这里为了演示定义了三个类型:varcahr、int、datatime
varchar类型
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Huhailong
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString{
int value() default 0;
public String name() default "";
Constraints constraints() default @Constraints;
}
int类型
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Huhailong
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger{
public String name() default "";
Constraints constraints() default @Constraints;
}
datatime类型
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* sql type for datetime
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDatetime{
public String name() default "";
public Constraints constraints() default @Constraints;
}
上面这些就是我们要用到的注解,其中@Constraints被嵌套在了sql类型注解(@SQLString @SQLInteger @SQLDatetime)中
/**
* Entity Class
* @author Huhailong
*/
@DBTable(name = "MEMBER") //table name
public class Member{
@SQLString(value = 30, name = "FIRST_NAME")
String firstName;
@SQLString(value = 50, name = "LAST_NAME")
String lastName;
@SQLInteger
Integer age;
@SQLDatetime
String born;
@SQLString(value = 30, constraints = @Constraints(primaryKey = true))
String handle;
public String getHandle(){
return handle;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return handle;
}
public Integer getAge(){
return age;
}
}
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* generate db table class
* @author Huhailong
*/
public class TableCreator{
public static void main(String[] args) throws Exception{
String tableCreate = null;
if(args.length<1){
System.out.println("arguments: annotated classes");
System.exit(0);
}
for(String className : args){
Class> cl = Class.forName(className);
DBTable table = cl.getAnnotation(DBTable.class);
if(table == null){
System.out.println("No DBTable annotations in class:"+className);
continue;
}
String tableName = table.name();
//if name is empty. use class name
if(tableName == null){
tableName = cl.getName().toUpperCase();
}
List columnDefs = new ArrayList<>();
for(Field field : cl.getDeclaredFields()){
String columnName = null;
Annotation[]anns = field.getDeclaredAnnotations();
if(anns.length<1){
continue; //No a db table column
}
if(anns[0] instanceof SQLInteger){
SQLInteger sInt = (SQLInteger)anns[0];
//use field name if name not specified
if(sInt.name().length()<1){
columnName = field.getName().toUpperCase();
}else{
columnName = sInt.name();
}
columnDefs.add(columnName+" INT"+getConstraints(sInt.constraints()));
}
if(anns[0] instanceof SQLString){
SQLString sString = (SQLString)anns[0];
//use field name if name not specified
if(sString.name().length()<1){
columnName = field.getName().toUpperCase();
}else{
columnName = sString.name();
}
columnDefs.add(columnName+" VARCHAR("+sString.value()+")"+getConstraints(sString.constraints()));
}
if(anns[0] instanceof SQLDatetime){
SQLDatetime sDatetime = (SQLDatetime)anns[0];
//use field name if name not specified
if(sDatetime.name().length()<1){
columnName = field.getName().toUpperCase();
}else{
columnName = sDatetime.name();
}
columnDefs.add(columnName+" DATETIME"+getConstraints(sDatetime.constraints()));
}
StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName+"(");
for(String columnDef : columnDefs){
createCommand.append("\n "+columnDef+",");
}
//Remove trailing comma - ,
tableCreate = createCommand.substring(0, createCommand.length()-1)+"\n);";
}
System.out.println("Table Creation SQL for "+ className+" is :\n"+tableCreate);
System.out.println("excute sql ....");
createTableByDatabase(tableCreate);
}
}
private static String getConstraints(Constraints constraints){
String result = "";
if(!constraints.allowNull()){
result += " NOT NULL";
}
if(constraints.primaryKey()){
result += " PRIMARY KEY";
}
if(constraints.unique()){
result += " UNIQUE";
}
return result;
}
public static void createTableByDatabase(String sql) throws Exception{
Connection connection = null;
PreparedStatement pStatement = null;
ResultSet resultSet = null;
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";
String userName = "username";
String password = "password";
DaoUtil util = new DaoUtil();
connection = util.getConnection(driver, url, userName, password);
pStatement = connection.prepareStatement(sql);
pStatement.executeUpdate();
util.close(connection,pStatement,resultSet);
}
}
所需要的一个工具类DaoUtil.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* connection database util
* @author Huhailong
*/
public class DaoUtil{
public Connection getConnection(String driver, String url, String userName, String password){
try {
Class.forName(driver);
Connection conn = DriverManager.getConnection(url,userName,password);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void close(Connection connection){
try {
if(connection != null){
connection.close();
}
} catch (Exception e) {
//TODO: handle exception
e.printStackTrace();
}
}
public void close(Connection connection, Statement statement, ResultSet resultSet){
try {
if(connection != null){
connection.close();
}
if(statement != null){
statement.close();
}
if(resultSet != null){
resultSet.close();
}
} catch (Exception e) {
//TODO: handle exception
e.printStackTrace();
}
}
}
运行结果
C:\projectcode\java\基础知识\注解>javac -Djava.ext.dirs=./ TableCreator.java
C:\projectcode\java\基础知识\注解>java -Djava.ext.dirs=./ TableCreator Member
Table Creation SQL for Member is :
CREATE TABLE MEMBER(
FIRST_NAME VARCHAR(30),
LAST_NAME VARCHAR(50),
AGE INT,
BORN DATETIME,
HANDLE VARCHAR(30) PRIMARY KEY
);
excute sql ....
数据库结果