使用Java注解开发自动生成SQL
使用注解开发的好处就是减少配置文件的使用。在实际过程中,随着项目越来越复杂,功能越来越多,会产生非常多的配置文件。但是,当配置文件过多,实际维护过程中产生的问题就不容易定位,这样就会徒劳的增加工作量。而使用注解开发,可以减少配置文件的使用,方便代码的维护,同时,在开发速度上也有大幅提升,因此,学会使用注解开发,是有必要掌握的一项技能。
下面为各位展示下使用注解开发自动生成 SQL 语句的过程。
首先先定义一个实体类,用于和数据库字段进行映射,为了方便,数据库字段名称和实体类变量名称保持一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.huawei.andrid.net.annotation; @Table ( "person" ) public class Person { @Column ( "name" ) private String name; @Column ( "sex" ) private String sex; @Column ( "id" ) private int id; @Column ( "age" ) private int age; 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; } public int getId() { return id; } public void setId( int id) { this .id = id; } public int getAge() { return age; } public void setAge( int age) { this .age = age; } } |
下面我们要为这个实体类定义注解,包含 @Table 和 @Column 两个注解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.huawei.andrid.net.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Documented @Retention (RUNTIME) @Target (TYPE) public @interface Table { public String value(); } |
元注解:
@Documented 生成 javadoc 时,支持注解
@Retention(RUNTIME) 注解的生命周期
@Target(TYPE) 注解的在类上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.huawei.andrid.net.annotation; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Documented @Retention (RUNTIME) @Target (FIELD) public @interface Column { public String value(); } |
最后,我们需要解析注解,使用 java 的反射机制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | private static String query(Object p) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { StringBuilder str = new StringBuilder(); //通过反射获取Class对象,以便获取注解的值 Class<? extends Object> obj = p.getClass(); //判断该对象的类上有没有注解@Table boolean isExistsTable = obj.isAnnotationPresent(Table. class ); if (!isExistsTable) { return null ; } //获取Table注解,并获取注解的值,即表名 Table table = (Table) obj.getAnnotation(Table. class ); String tableName = table.value(); //拼装sql str.append( "select * from " ).append(tableName).append( " where 1=1 " ); //获取所有的成员变量,并遍历出来成员变量上的注解值 Field[] fields = obj.getDeclaredFields(); for (Field field : fields) { Boolean isExistColumn = field.isAnnotationPresent(Column. class ); if (!isExistColumn) { continue ; } //获取成员变量上的注解值 Column column = field.getAnnotation(Column. class ); String columnName = column.value(); //获取成员变量的get方法名 String methodName = "get" + columnName.substring( 0 , 1 ).toUpperCase() + columnName.substring( 1 ); //获取成员变量的get方法 Method method = obj.getMethod(methodName); //执行成员变量的get方法,参数为该对象 Object value = method.invoke(p); //过滤掉成员变量中的null值,以及0 if ( null == value || (value instanceof Integer && (Integer) value == 0 )) { continue ; } str.append( " and " ).append(columnName).append( "=" ).append(value); } return str.toString(); } |
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static void main(String[] args) { Person p = new Person(); p.setName( "wanglu" ); p.setAge( 25 ); String querySQL = null ; try { querySQL = query(p); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } System.out.println(querySQL); } |