简述:
《Java 编程思想第四版 》 第20章注解使用笔记
目标: 使用注解生成SQL建表文件
步骤及说明:
1. 项目结构:
2. 声明几种注解
1) table
DBTable.java
package com.anialy.test.annotation.dbautomaker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据表注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @ interface DBTable {
public String name() default "";
}
2) SQLInteger
SQLInteger.java
package com.anialy.test.annotation.dbautomaker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
3) SQLString
SQLString.java
package com.anialy.test.annotation.dbautomaker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}
4) Constraints
Constraints.java
package com.anialy.test.annotation.dbautomaker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 约束条件
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean unique() default false;
}
3. 绑定Table 实体类Entity
User.java
package com.anialy.test.annotation.dbautomaker.domain;
import com.anialy.test.annotation.dbautomaker.Constraints;
import com.anialy.test.annotation.dbautomaker.DBTable;
import com.anialy.test.annotation.dbautomaker.SQLInteger;
import com.anialy.test.annotation.dbautomaker.SQLString;
@DBTable(name="t_user")
public class User {
@SQLString(value=36, constraints = @Constraints(primaryKey=true))
private String id;
// 学号
@SQLString(value=10, constraints = @Constraints(unique=true))
private String sn;
// 姓名
@SQLString(value=30)
private String name;
// 年龄
@SQLInteger
private int age;
public String getId() {
return id;
}
public String getSn() {
return sn;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setId(String id) {
this.id = id;
}
public void setSn(String sn) {
this.sn = sn;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
4. SQL Factory 生成sql脚本
SQLFactory.java
package com.anialy.test.annotation.dbautomaker.sqlfactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import com.anialy.test.annotation.dbautomaker.Constraints;
import com.anialy.test.annotation.dbautomaker.DBTable;
import com.anialy.test.annotation.dbautomaker.SQLInteger;
import com.anialy.test.annotation.dbautomaker.SQLString;
public class SQLFactory {
public SQLFactory(final String className) {
this.className = className;
}
/**
* 类名
*/
private String className;
/**
* 表名
*/
private String tableName;
/**
* 数据表成员变量的SQL列表
*/
private List<String> columnsDefs = new ArrayList<String>();
private String genSQLOfClass()
throws ClassNotFoundException{
Class<?> clazz = Class.forName(className);
DBTable dbTable = clazz.getAnnotation(DBTable.class);
if(dbTable == null){
System.out.printf("no such class: %s", className);
return "";
}
tableName = dbTable.name();
// If the tableName is empty, then use the class name instead
if(tableName == null || "".equals(tableName)){
String fullClassNamePath = clazz.getName().toUpperCase();
int lastCommaIndex = fullClassNamePath.lastIndexOf(".");
tableName = fullClassNamePath.substring(lastCommaIndex + 1);
}
for(Field field : clazz.getDeclaredFields()){
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations();
Annotation curAnno = anns[0];
if(curAnno == null) // no annotation on this field, then continue
continue;
else if(curAnno instanceof SQLString){
SQLString annoString = (SQLString) curAnno;
columnName = annoString.name();
if(columnName == null || "".equals(columnName)){
columnName = field.getName().toUpperCase();
}
columnsDefs.add(columnName
+ " VARCHAR(" + annoString.value() + ") "
+ getConstraints(annoString.constraints())
);
}else if(curAnno instanceof SQLInteger){
SQLInteger annoInt = (SQLInteger)curAnno;
columnName = annoInt.name();
if(columnName == null || "".equals(columnName)){
columnName = field.getName();
}
columnsDefs.add(columnName
+ " INT "
+ getConstraints(annoInt.constraints())
);
}
}
StringBuilder sbd = new StringBuilder();
sbd.append("CREATE TABLE " + tableName + " (\n");
for(String columnRow : columnsDefs){
sbd.append("\t" + columnRow + ",\n");
}
// remove trailing comma
String tbCreate = sbd.substring(0, sbd.length() - 2);
tbCreate += "\n);\n\n";
return tbCreate;
}
/**
* definition of constraints
* @param constraints
* @return
*/
private String getConstraints(Constraints constraints) {
String constraintsStr = "";
if(constraints.primaryKey()){
constraintsStr += "PRIMARY KEY";
}
if(constraints.unique()){
constraintsStr += "UNIQUE";
}
return constraintsStr;
}
public void outputSQL() throws ClassNotFoundException{
String createTbSQL = genSQLOfClass();
if(createTbSQL == null || "".equals(createTbSQL))
return;
File file = new File(tableName + ".sql");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(createTbSQL.getBytes("utf-8"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fos != null){
try {
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5. 测试类
Test.java
package com.anialy.test.annotation.dbautomaker.test;
import com.anialy.test.annotation.dbautomaker.sqlfactory.SQLFactory;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
new SQLFactory("com.anialy.test.annotation.dbautomaker.domain.User").outputSQL();
}
}
输出:
附录:
如果使用nio输出,output部分可以这么写
public void outputSQL() throws IOException, ClassNotFoundException{
String createTbSQL = genSQLOfClass();
if(createTbSQL == null || "".equals(createTbSQL))
return;
FileChannel fc = new RandomAccessFile(tableName + ".sql", "rw")
.getChannel();
byte[] outputBytes = createTbSQL.getBytes();
int bytesNum = outputBytes.length;
ByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, bytesNum);
bb.put(outputBytes);
fc.close();
}