问题
表名与实体类名称不一致,
主键不叫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)的直接超类的 Type Type type = this.getClass().getGenericSuperclass(); // 强制转换为“参数化类型” 【BaseDao<Account>】 ParameterizedType pt = (ParameterizedType) type; // Class类是Type接口的实现类 // 获取参数化类型中,实际类型的定义 【new Type[]{Account.class}】 Type types[] = pt.getActualTypeArguments(); // 获取数据的第一个元素:Accout.class clazz = (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); } } }