注解是项目中经常用到的技术,常见的有java原生注解,像@overwrite等,还有像spring 中的@RequestMapping()这样的第三方注解,下面说一下自定义注解。理论的我也知之甚少,就不啰嗦,直接贴代码吧。
需求:想实现项hiberate那样通过一个简单的注解,直接生成Sql语句。
一:创建实体类,并加上自定义的注解
package annotation.pojo; import annotation.ann.MyColome; import annotation.ann.MyTable; @MyTable("t_user") public class User { @MyColome("id") private String id; @MyColome("user_name") private String userName; @MyColome("tel") private String tel; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } }此时添加的自定义注解并没有被声明,会报错,不过没关系,下边就创建这两个注解。
二:创建自定义注解
@Target({ElementType.TYPE}) //作用在类或接口上 @Retention(RetentionPolicy.RUNTIME) public @interface MyTable { String value(); }
@Target({ElementType.FIELD}) //作用在字段上 @Retention(RetentionPolicy.RUNTIME) public @interface MyColome { String value(); }
创建注解其实主要的就看两个方面,一是作用域 @Target ,第二是 @Retention 定义注解的保留策略
@Target(ElementType.TYPE)
//
接口、类、枚举、注解
@Target(ElementType.FIELD)
//
字段、枚举的常量
@Target(ElementType.METHOD)
//
方法
@Target(ElementType.PARAMETER)
//
方法参数
@Target(ElementType.CONSTRUCTOR)
//
构造函数
@Target(ElementType.LOCAL_VARIABLE)
//
局部变量
@Target(ElementType.ANNOTATION_TYPE)
//
注解
@Target(ElementType.PACKAGE) /
//
包
@Retention(RetentionPolicy.
SOURCE)
//注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.
CLASS)
// 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME)
// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
三 使用注解,动态生成sql
在此我模拟了三组查询,根据id,name去查用户信息,最后又增加一个学生实体类,验证注解的通用性
实现思路:
1.获取表名:表名我是现在@Mytable("t_user") 通过查询条件获取当前对象的class,通过boolean isExist =c.isAnnotationPresent(MyTable.class);这行代码判断此对象中是否用到这个注解,如果有用到,就可以拿到并实例化这个注解对象,通过这个注解对象就可以拿到注解中定义的值。
2.获取数据库字段名:其实与上边类似,通过该对象的class获取他的所有属性,然后再一次判断属性是否用到注解,
等等等一样的逻辑。
3.获取查询条件的值:拿到所有属性后,就可以通过属性的get方法应用java反射那对对应的属性值,具体见代码。
4.其他的就是把拿到的这些值,拼接到一起
public class UserDao { public static void main(String[] args) { User u1 = new User(); u1.setId("10"); //根据ID查询用户信息 User u2 = new User(); u2.setUserName("nsh"); //根据用户名查询 Student s = new Student(); s.setId("2"); String sql1 =query(u1); String sql2 =query(u2); String sql3 =query(s); System.out.println("sql1="+sql1); System.out.println("sql2="+sql2); System.out.println("sql3="+sql3); } private static String query(Object u) { StringBuffer sb = new StringBuffer(); //1.获取class Class c =u.getClass(); //2.获取tableName //判断是否有table这个注解 boolean isExist =c.isAnnotationPresent(MyTable.class); if(isExist){ //获取到table这个注解,并取得表名 MyTable mt =(MyTable) c.getAnnotation(MyTable.class); String tableName =mt.value(); sb.append("select * from ").append(tableName).append(" where 1=1"); } //3遍历所有字段 Field[] fArray= c.getDeclaredFields(); for(Field f:fArray){ //拿到字段后与实体类中的属性匹配,并得到其get方法,用来获取他的属性值 String getMethodName =""; boolean isCExist =f.isAnnotationPresent(MyColome.class); if(isCExist){ MyColome mc =f.getAnnotation(MyColome.class); String columeName =mc.value(); //字段对应数据库名字 String name =f.getName(); //字段名字 String value=null; //字段值 getMethodName="get"+name.substring(0,1).toUpperCase()+name.substring(1);//拼接属性的get方法 try { Method m =c.getMethod(getMethodName); value =(String)m.invoke(u); //拿到属性的值 if(value == null || "".equals(value)){ //如果属性没值,不拼接sql continue; } else if(value instanceof String){ value ="'"+value+"'"; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } sb.append(" and ").append(columeName).append(" = ").append(value); } } return sb.toString(); } }四:测试