使用注解反射实现BaseDao(代替XML配置)

来源:互联网 发布:四川话发音软件 编辑:程序博客网 时间:2024/06/05 19:26

问题

表名与实体类名称不一致,

表中字段与实体类中的属性名称不一致,

主键不叫id时,

上面的BaseDao不能用!

 

解决方案1:通过配置文件(XML) 解决

XML:便于维护!但需要写读取代码!

解决方案2:通过注解的方式

优点:

无需XML配置,需要的信息在java源代码级别

缺点:

不便于维护:例如修改字段名,要重新编译。

需要自己来处理表和实体类之间的映射关系。
package dao;import java.lang.reflect.Field;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.sql.ResultSet;import java.sql.SQLException;import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.dbutils.ResultSetHandler;import anno.Column;import anno.PrimaryKey;import anno.Table;import util.*;/** * 所有dao的公用的方法,都在这里实现 * 使用注解来保存信息 *  */public class BaseDao<T> {// 保存当前运行类的参数化类型中的实际的类型private Class<T> clazz;// 表名 这里就不需要约定表名就是实体类名了 -- 在C#的BaseDAL中,是通过Lamda表达式传入表名的private String tableName;private String primaryKey;// 构造函数: 1. 获取当前运行类的参数化类型;// 2. 获取参数化类型中实际类型的定义(class)public BaseDao() {// this 表示当前运行类 (AccountDao/AdminDao)// this.getClass() 当前运行类的字节码对象(AccountDao.class/AdminDao.class)// this.getClass().getGenericSuperclass(); 当前运行类的父类,即为BaseDao<Account>// 其实就是“参数化类型”, ParameterizedType//返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 TypeType type = this.getClass().getGenericSuperclass();// 强制转换为“参数化类型” 【BaseDao<Account>】ParameterizedType pt = (ParameterizedType) type;// Class类是Type接口的实现类// 获取参数化类型中,实际类型的定义 【new Type[]{Account.class}】Type types[] = pt.getActualTypeArguments();// 获取数据的第一个元素:Accout.classclazz = (Class<T>) types[0];//现在 拿到了Account.class//获取表名Table table = clazz.getAnnotation(Table.class);tableName = table.tableName();//获取主键字段Field[] declaredFields = clazz.getDeclaredFields();for (Field field : declaredFields) {field.setAccessible(true);PrimaryKey pKey = field.getAnnotation(PrimaryKey.class);if(pKey!=null){Column column = field.getAnnotation(Column.class);primaryKey = column.columnName();break;}}}/** * 主键查询 *  * @param id *            主键值 * @return 返回封装后的对象 */@SuppressWarnings({"unchecked"})public T findById(int id) {/* * 1. 知道封装的对象的类型 2. 表名【表名与对象名称一样, 且主键都为id】 *  * 即,得到当前运行类继承的父类 BaseDao<Account> ----》 得到Account.class */String sql = "select * from " + tableName + " where id=? ";try {//这个时候由于数据库表和实体不是一一对应的,//import org.apache.commons.dbutils.handlers.BeanHandler;就不能使用了//需要自己处理映射关系return JdbcUtils.getQuerrRunner().query(sql,new MyBeanHandler<T>(clazz), id);} catch (SQLException e) {throw new RuntimeException(e);}}}/** * DbUtils组件的ResultSetHandler接口作用 * convert resultSets into Objects 表到对象的映射 * @author bellychang * * @param <T> */class MyBeanHandler<T> implements ResultSetHandler<T>{private Class<T> clazz;public MyBeanHandler(Class<T> clazz){this.clazz = clazz;}public T handle(ResultSet rSet) throws SQLException {try {T t = clazz.newInstance();if (rSet.next()) {Field[] fields = clazz.getDeclaredFields();//遍历 需要获得属性名 属性值 和 对象for (Field field : fields) {//获得属性名String fieldName = field.getName();//获得属性值 需要先获得字段值//获得Field上的注解Column column = field.getAnnotation(Column.class);//获得字段名String columnName = column.columnName();//获得字段值 即属性值Object columnValue = rSet.getObject(columnName);//对象属性的拷贝 使用BeanUtil组件的copyProperty()方法//Copy the specified property value //to the specified destination bean, //performing any type conversion that is required.BeanUtils.copyProperty(t, fieldName, columnValue);}}return t;} catch (Exception e) {throw new RuntimeException(e);} }}


0 0
原创粉丝点击