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

问题

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

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

主键不叫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);
		} 
		
	}
	
	
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值