何为注解
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。而这些功能则可以使得我们在程序中能够快速简洁的配置程序的信息。
就比如现在,可以利用注解里面的配置信息来配置来为程序快速的建立数据库当中的表的信息
注解
注解的语法为
public @interface annotation{
String stringValue();
Integer intValue();
......
}
和接口是十分相似的,不过在注解当中,他只支持使用原子类型与String类型,其他的类型是不允许使用的,同时,我们可以使用一些注解来为这个注解的使用模式进行限定
@Retention(RetentionPolicy.RUNTIME) //表示在运行时使用,可以通过反射来进行获取
@Target(ElementType.TYPE) //使用在类型,枚举等地方
@Documented //会在生成文档的时候生成
@Inherited //允许这个注释被继承
public @interface Table {
String value();
}
当然,@Rentention
与@Target
都有不少的属性
@Target表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
@Rentention表示需要在什么级别保存该注解信息,可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃,(只在源码当中给程序员当提示使用)
CLASS:注解在class文件中可用,但会被VM丢弃,也就是说不会被加载到程序当中,自然无法通过反射获取
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
使用注解获取建立SQL语句
既然RUNTIME的注解能够在运行时可以给我们提供信息,那么我们自然可以利用注解来进行一些事情了,现在就以注解来进行快速的建立SQL语句
首先,由于SQL语句的语法是固定的,因此,有变化的仅仅是表名,列名以及where当中的搜索条件,因此,使用注解来为实体类建立与数据库表的映射关系是一种比较方便的方式
步骤
1,首先我们要对实体类进行加载,使用反射的方式,从而,能够获取类当中的注解。
2,判断注解的内容,若是数据库的实体类则进行后续的加载
3,根据实体类的注解获取表名与列名
4,构建SQL语句
从步骤来说是比较简单的,我们现在来看看代码的实现吧
首先是注解的建立,
实体类的标志
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Entity {
}
表名的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Table {
String value();
}
列名的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface Column {
String value();
}
然后是select语句的实现
public String find(T entity) {
//SQL语句
StringBuilder sqlQuery = new StringBuilder();
//加载类
Class c = loadClass(entity);
//若不是对应的类,则退出
if (c == null || !c.isAnnotationPresent(Entity.class) || !c.isAnnotationPresent(Table.class)) {
return null;
}
//获取表名
sqlQuery.append("select * from ").append(getTableNameStr(c));
//获取列名与对应的数值
ColumnAndValue columnAndValue = getColumnAndValue(c, entity);
//解析获取出来的数据
String[] columnValueStr = columnAndValue.getColumnValue().split(",");
String[] tableColumnStr = columnAndValue.getColumnName().split(",");
//建立SQL语句
if(TextUtils.isEmpty(columnValueStr[0]) || TextUtils.isEmpty(tableColumnStr[0])){
return sqlQuery.toString();
}
sqlQuery.append(" where ");
for (int i = 0; i < columnValueStr.length; i++) {
sqlQuery.append(tableColumnStr[i])
.append("=")
.append(columnValueStr[i]);
if(i != columnValueStr.length - 1){
sqlQuery.append(" and ");
}
}
return removeStrEnd(sqlQuery.toString());
}
获取表名的方法,实际上就是利用反射进行加载
private Class<?> loadClass(T entity) {
try {
return Class.forName(entity.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
获取表名的方法,由于表名是放在Type上的,因此可以直接从类当中获取
private String getTableNameStr(Class<?> clazz) {
Table table = clazz.getAnnotation(Table.class);
return table.value();
}
获取列与数据的方法,获取列与数据的话,由于列与数据都是在方法与变量的层级上的,因此,要获取列名的话就需要获取其中的变量名,而变量的数值则是需要获取其中的get方法(此处要求实体类一定要有相应的get方法)
@NotNull
private ColumnAndValue getColumnAndValue(Class<?> c, T entity) {
StringBuilder sqlTableColumn = new StringBuilder();
StringBuilder sqlColumnValue = new StringBuilder();
//获取所有的变量
Field[] fields = c.getDeclaredFields();
//获取每一个变量的列与其数值
for (Field field : fields) {
if (!field.isAnnotationPresent(Column.class)) {
continue;
}
//获取列名
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
//获取get方法
String filedName = field.getName();
String getMethodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
//使用get方法获取变量
Object filedValue = null;
try {
Method getMethod = c.getMethod(getMethodName);
if (getMethod != null) {
filedValue = getMethod.invoke(entity);
}
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
//存在变量则构建sql语句
if (filedValue != null) {
if (filedValue instanceof String) {
sqlColumnValue.append("'")
.append(filedValue.toString())
.append("'")
.append(",");
} else {
sqlColumnValue.append(filedValue.toString()).append(",");
}
sqlTableColumn.append(columnName).append(",");
}
}
String columnValue = sqlColumnValue.toString();
String tableColumn = sqlTableColumn.toString();
columnValue = removeStrEnd(columnValue);
tableColumn = removeStrEnd(tableColumn);
//返回列与其变量
return new ColumnAndValue(tableColumn, columnValue);
}
//列与变量的存储的类
public class ColumnAndValue {
private String columnName;
private String columnValue;
public ColumnAndValue(){
}
public ColumnAndValue(String columnName, String columnValue) {
this.columnName = columnName;
this.columnValue = columnValue;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getColumnValue() {
return columnValue;
}
public void setColumnValue(String columnValue) {
this.columnValue = columnValue;
}
}
同样的insert语句也是一样的
public String save(T entity) {
StringBuilder sqlQuery = new StringBuilder();
Class c = loadClass(entity);
if (c == null || !c.isAnnotationPresent(Entity.class) || !c.isAnnotationPresent(Table.class)) {
return null;
}
sqlQuery.append("insert into ").append(getTableNameStr(c));
ColumnAndValue columnAndValue = getColumnAndValue(c, entity);
String columnValue = columnAndValue.getColumnValue();
String tableColumn = columnAndValue.getColumnName();
return sqlQuery.append("(")
.append(tableColumn)
.append(") ")
.append("values(")
.append(columnValue)
.append(")").toString();
}
有了这个基本的思路,update,delete语句也是可以使用一样的方式建立的
这里我就只建立了两种SQL语句
以下是类的全部代码
public class QueryHelper<T> {
public String find(T entity) {
StringBuilder sqlQuery = new StringBuilder();
Class c = loadClass(entity);
if (c == null || !c.isAnnotationPresent(Entity.class) || !c.isAnnotationPresent(Table.class)) {
return null;
}
sqlQuery.append("select * from ").append(getTableNameStr(c));
ColumnAndValue columnAndValue = getColumnAndValue(c, entity);
String[] columnValueStr = columnAndValue.getColumnValue().split(",");
String[] tableColumnStr = columnAndValue.getColumnName().split(",");
if(TextUtils.isEmpty(columnValueStr[0]) || TextUtils.isEmpty(tableColumnStr[0])){
return sqlQuery.toString();
}
sqlQuery.append(" where ");
for (int i = 0; i < columnValueStr.length; i++) {
sqlQuery.append(tableColumnStr[i])
.append("=")
.append(columnValueStr[i]);
if(i != columnValueStr.length - 1){
sqlQuery.append(" and ");
}
}
return removeStrEnd(sqlQuery.toString());
}
public String save(T entity) {
StringBuilder sqlQuery = new StringBuilder();
Class c = loadClass(entity);
if (c == null || !c.isAnnotationPresent(Entity.class) || !c.isAnnotationPresent(Table.class)) {
return null;
}
sqlQuery.append("insert into ").append(getTableNameStr(c));
ColumnAndValue columnAndValue = getColumnAndValue(c, entity);
String columnValue = columnAndValue.getColumnValue();
String tableColumn = columnAndValue.getColumnName();
return sqlQuery.append("(")
.append(tableColumn)
.append(") ")
.append("values(")
.append(columnValue)
.append(")").toString();
}
private Class<?> loadClass(T entity) {
try {
return Class.forName(entity.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@NotNull
private ColumnAndValue getColumnAndValue(Class<?> c, T entity) {
StringBuilder sqlTableColumn = new StringBuilder();
StringBuilder sqlColumnValue = new StringBuilder();
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Column.class)) {
continue;
}
Column column = field.getAnnotation(Column.class);
String columnName = column.value();
String filedName = field.getName();
String getMethodName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
Object filedValue = null;
try {
Method getMethod = c.getMethod(getMethodName);
if (getMethod != null) {
filedValue = getMethod.invoke(entity);
}
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
if (filedValue != null) {
if (filedValue instanceof String) {
sqlColumnValue.append("'")
.append(filedValue.toString())
.append("'")
.append(",");
} else {
sqlColumnValue.append(filedValue.toString()).append(",");
}
sqlTableColumn.append(columnName).append(",");
}
}
String columnValue = sqlColumnValue.toString();
String tableColumn = sqlTableColumn.toString();
columnValue = removeStrEnd(columnValue);
tableColumn = removeStrEnd(tableColumn);
return new ColumnAndValue(tableColumn, columnValue);
}
private String getTableNameStr(Class<?> clazz) {
Table table = clazz.getAnnotation(Table.class);
return table.value();
}
private String removeStrEnd(String str) {
return str.substring(0, str.length() - 1 > 0 ? str.length() - 1 : 0);
}
}
运行结果
insert into ray_msg(id,div_name,ir_key) values(1,'2','3')
select * from ray_msg where id=1 and div_name='2' and ir_key='3'
Process finished with exit code 0