1、实现功能
我们已经对注解有了基本的认识,知道了如何自定义注解,如何使用和最基本的处理注解。
本篇主要介绍,如何使用运行时级别的注解,配合反射来自动生成建表的sql语句。如下例:
我们有实体类Student,并添加相应的注解 @Table、@Column,最终可以获取到创建对应表的sql语句
@Table(name = "t_student")
public class Student {
@Column(name = "c_name")
public String name;
@Column(name = "c_sex")
public String sex;
...
}
11
1
@Table(name = "t_student")
2
public class Student {
3
4
@Column(name = "c_name")
5
public String name;
6
7
@Column(name = "c_sex")
8
public String sex;
9
10
...
11
}
2、自定义注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
//设置表名
String name();
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
//设置字段名
String name();
}
11
1
@Retention(RetentionPolicy.RUNTIME)
2
public @interface Table {
3
//设置表名
4
String name();
5
}
6
7
@Retention(RetentionPolicy.RUNTIME)
8
public @interface Column {
9
//设置字段名
10
String name();
11
}
3、对实体类使用注解
/**
* 学生类
*/
@Table(name = "t_student")
public class Student {
@Column(name = "c_name")
public String name;
@Column(name = "c_sex")
public String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
28
1
/**
2
* 学生类
3
*/
4
@Table(name = "t_student")
5
public class Student {
6
7
@Column(name = "c_name")
8
public String name;
9
10
@Column(name = "c_sex")
11
public String sex;
12
13
public String getName() {
14
return name;
15
}
16
17
public void setName(String name) {
18
this.name = name;
19
}
20
21
public String getSex() {
22
return sex;
23
}
24
25
public void setSex(String sex) {
26
this.sex = sex;
27
}
28
}
4、运行时获取注解并转化
4.1 获取表名
private static String getTableName(Class<?> clazz) {
String name = null;
//如果有@Table注解
if (clazz.isAnnotationPresent(Table.class)) {
Table table = clazz.getAnnotation(Table.class);
name = table.name();
}
return name;
}
10
1
private static String getTableName(Class<?> clazz) {
2
String name = null;
3
//如果有@Table注解
4
if (clazz.isAnnotationPresent(Table.class)) {
5
Table table = clazz.getAnnotation(Table.class);
6
name = table.name();
7
}
8
9
return name;
10
}
4.2 获取字段名和类型
4.2.1 建立NameAndType类用来封装获取到的字段名和类型
public class NameAndType {
String name;
String type;
public NameAndType(String name, String type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
27
1
public class NameAndType {
2
3
String name;
4
5
String type;
6
7
public NameAndType(String name, String type) {
8
this.name = name;
9
this.type = type;
10
}
11
12
public String getName() {
13
return name;
14
}
15
16
public void setName(String name) {
17
this.name = name;
18
}
19
20
public String getType() {
21
return type;
22
}
23
24
public void setType(String type) {
25
this.type = type;
26
}
27
}
4.2.2 获取字段名和类型
private static List<NameAndType> getColumns(Class<?> clazz) throws Exception {
List<NameAndType> colums = new ArrayList<NameAndType>();
Field[] fields = clazz.getDeclaredFields();
if (fields != null) {
//分析clazz中变量是否需要生成sql字段
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
//生成sql字段的字段名
Column column = field.getAnnotation(Column.class);
String name = column.name();
//生成sql字段的字段类型
String type;
if (int.class.isAssignableFrom(field.getType())) {
type = "integer";
}
else if (String.class.isAssignableFrom(field.getType())) {
type = "text";
}
else {
throw new Exception("unsupported type");
}
colums.add(new NameAndType(name, type));
}
}
}
return colums;
}
28
1
private static List<NameAndType> getColumns(Class<?> clazz) throws Exception {
2
List<NameAndType> colums = new ArrayList<NameAndType>();
3
Field[] fields = clazz.getDeclaredFields();
4
if (fields != null) {
5
//分析clazz中变量是否需要生成sql字段
6
for (Field field : fields) {
7
if (field.isAnnotationPresent(Column.class)) {
8
//生成sql字段的字段名
9
Column column = field.getAnnotation(Column.class);
10
String name = column.name();
11
//生成sql字段的字段类型
12
String type;
13
if (int.class.isAssignableFrom(field.getType())) {
14
type = "integer";
15
}
16
else if (String.class.isAssignableFrom(field.getType())) {
17
type = "text";
18
}
19
else {
20
throw new Exception("unsupported type");
21
}
22
colums.add(new NameAndType(name, type));
23
}
24
}
25
}
26
27
return colums;
28
}
注意Class类的isAssignableFrom方法可以判断两个类是不是存在父子关系。
4.3 生成建表sql
public static String createTable(Class<?> clazz) throws Exception {
String sql = null;
String tableName = getTableName(clazz);
List<NameAndType> columns = getColumns(clazz);
if (tableName != null && !tableName.equals("") && !columns.isEmpty()) {
StringBuffer strBuffer = new StringBuffer("CREATE TABLE " + tableName + "( ");
for (NameAndType column : columns) {
String bean = column.getName() + " " + column.getType() + ", ";
strBuffer.append(bean);
}
//删除最后多余的一个逗号
strBuffer.deleteCharAt(strBuffer.length() - 2);
strBuffer.append(");");
sql = strBuffer.toString();
}
return sql;
}
19
1
public static String createTable(Class<?> clazz) throws Exception {
2
String sql = null;
3
String tableName = getTableName(clazz);
4
List<NameAndType> columns = getColumns(clazz);
5
6
if (tableName != null && !tableName.equals("") && !columns.isEmpty()) {
7
StringBuffer strBuffer = new StringBuffer("CREATE TABLE " + tableName + "( ");
8
for (NameAndType column : columns) {
9
String bean = column.getName() + " " + column.getType() + ", ";
10
strBuffer.append(bean);
11
}
12
//删除最后多余的一个逗号
13
strBuffer.deleteCharAt(strBuffer.length() - 2);
14
strBuffer.append(");");
15
sql = strBuffer.toString();
16
}
17
18
return sql;
19
}
4.4 测试和结果
public class TestAnnotation {
public static void main(String[] args) throws Exception {
String sql = TableAnnotationUtil.createTable(Student.class);
System.out.println(sql);
}
}
//结果输出
CREATE TABLE t_student( c_name text, c_sex text );
x
1
public class TestAnnotation {
2
public static void main(String[] args) throws Exception {
3
String sql = TableAnnotationUtil.createTable(Student.class);
4
System.out.println(sql);
5
}
6
}
7
8
//结果输出
9
CREATE TABLE t_student( c_name text, c_sex text );