注解_通用BaseDao优化

本文介绍了一种通过使用注解来优化通用DAO的方法,解决了数据库表名与类名不一致、字段与属性不匹配等问题,并提供了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用注解优化通用Dao

待解决问题

    1. 当数据库表名与类名不一致
    2. 字段与属性不一样
    3. 主键不叫id

使用注解

    好处:简化XML配置,程序处理方便。
    缺点:不便于维护,例如修改字段名,就要修改注解,需要重新编译。服务器发布成本大。

使用XML

    好处:便于维护
    缺点:读取麻烦

优化

使用的工具

BeanUtils组件( 引入BeanUtils包commons-beanutils-1.8.3.jar点击打开链接 引入日志支持包commons-logging-1.1.3.jar点击打开链接)  DbUtils组件( 引入jar文件 :  commons-dbutils-1.6.jar点击打开链接

数据库表如下


 实体类

   
  1. package com.cn.generic_reflect;
  2. /**
  3. * 实体类:对应数据库中的accout表
  4. * 表名 account
  5. * 字段 id(主键) accountName money
  6. *
  7. * @author liuzhiyong
  8. *
  9. */
  10. @Table(tableName = "account")
  11. public class Entity_Account {
  12. @Id
  13. @Column(columnName="id")
  14. private int aId;
  15. @Column(columnName="accountName")
  16. private String aName;
  17. @Column(columnName="money")
  18. private double aMoney;
  19. public int getaId() {
  20. return aId;
  21. }
  22. public void setaId(int aId) {
  23. this.aId = aId;
  24. }
  25. public String getaName() {
  26. return aName;
  27. }
  28. public void setaName(String aName) {
  29. this.aName = aName;
  30. }
  31. public double getaMoney() {
  32. return aMoney;
  33. }
  34. public void setaMoney(double aMoney) {
  35. this.aMoney = aMoney;
  36. }
  37. @Override
  38. public String toString() {
  39. return "Entity_Account [aId=" + aId + ", aName=" + aName + ", aMoney="
  40. + aMoney + "]";
  41. }
  42. }

描述表名的注解Table

   
  1. package com.cn.generic_reflect;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. import javax.persistence.EnumType;
  7. /**
  8. * 注解:描述表的名称
  9. * @author liuzhiyong
  10. *
  11. */
  12. @Target(ElementType.TYPE)//指定注解的作用域,只能作用在类上
  13. @Retention(RetentionPolicy.RUNTIME)//指定注解在运行时有效,反射时必须这么做
  14. public @interface Table {
  15. /**
  16. * 表名
  17. * @return
  18. */
  19. public abstract String tableName();
  20. }

描述表字段的注解

   
  1. package com.cn.generic_reflect;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /**
  7. * 注解:描述表的字段
  8. * @author liuzhiyong
  9. *
  10. */
  11. @Target(ElementType.FIELD)//指定注解的作用域,只能作用在属性Field上
  12. @Retention(RetentionPolicy.RUNTIME)//指定注解运行时有效
  13. public @interface Column {
  14. public abstract String columnName();
  15. }

描述主键的注解

    
  1. package com.cn.generic_reflect;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. import javax.persistence.EnumType;
  7. /**
  8. * 注解:描述表的主键id
  9. * @author liuzhiyong
  10. *
  11. */
  12. @Target(ElementType.FIELD)//指定注解的作用域,只能作用在属性Field上
  13. @Retention(RetentionPolicy.RUNTIME)//指定注解运行时有效
  14. public @interface Id {
  15. }

通用BaseDao

   
  1. package com.cn.generic_reflect;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.ParameterizedType;
  4. import java.lang.reflect.Type;
  5. import java.util.List;
  6. import com.cn.Util.JdbcUtils;
  7. /**
  8. * 通用Dao设计
  9. *
  10. * 解决优化的问题:
  11. * 1. 当数据库表名与类名不一致
  12. * 2. 字段与属性不一样
  13. * 3. 主键不叫id
  14. * @author liuzhiyong
  15. *
  16. * @param <T>
  17. */
  18. public class BaseDao<T> {
  19. //保存当前运行类要操作实体对象的字节码对象
  20. private Class<T> clazz = null;
  21. //保存当前操作实体类对象对应的表的表名
  22. private String tableName;
  23. //保存当前操作实体类对象对应的表的主键id
  24. private String idName;
  25. public BaseDao() {
  26. //获取当前运行类的字节码对象(例如AccountDao.class)
  27. Class currentClazz = this.getClass();
  28. //获取此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。 (例如:BaseDao<Entity_Account>)
  29. ParameterizedType pt = (ParameterizedType)currentClazz.getGenericSuperclass();//参数化的类型
  30. Type[] types = pt.getActualTypeArguments();//获取参数化类型的参数类型数组
  31. clazz = (Class<T>) types[0];//获取参数化类型的实参类型(例如:Entity_Account.class)
  32. /**
  33. * 1. 获取表名
  34. */
  35. Table table = clazz.getAnnotation(Table.class);//获取类上的Table注解
  36. tableName = table.tableName();
  37. /**
  38. * 2. 获取表的主键id
  39. */
  40. //获取所有的属性Filed
  41. Field[] fs = clazz.getDeclaredFields();
  42. //遍历Filed数组,获取每一个属性Filed上的Id注解,判断是否存在Id的注解
  43. for(Field f : fs){
  44. Id id = f.getAnnotation(Id.class);//获取Id注解
  45. if(id != null){//如果注解Id不为空,说明该属性Field为主键id属性
  46. Column column = f.getAnnotation(Column.class);//获取该属性Field上的Column注解
  47. idName = column.columnName();//获取该注解中的columnName属性值,即为表的主键id字段名
  48. //跳出循环
  49. break;
  50. }
  51. }
  52. }
  53. /**
  54. * 根据主键id查询
  55. * @param id
  56. * @return
  57. */
  58. public T findById(int id){
  59. try{
  60. String sql = "select * from " + tableName + " where " + idName + " = ?";
  61. return JdbcUtils.getQueryRunner().query(sql, new MyBeanHandler<T>(clazz), id);
  62. }catch(Exception e){
  63. throw new RuntimeException(e);
  64. }
  65. }
  66. /**
  67. * 查询全部
  68. * @return
  69. */
  70. public List<T> getAll(){
  71. try{
  72. String sql = "select * from " + tableName;
  73. return JdbcUtils.getQueryRunner().query(sql, new MyBeanListHandler<T>(clazz));
  74. }catch(Exception e){
  75. throw new RuntimeException(e);
  76. }
  77. }
  78. }
自定义结果集MyBeanHandler
    
  1. package com.cn.generic_reflect;
  2. import java.lang.reflect.Field;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import org.apache.commons.beanutils.BeanUtils;
  6. import org.apache.commons.dbutils.ResultSetHandler;
  7. public class MyBeanHandler<T> implements ResultSetHandler<T> {
  8. //保存需要封装成的对象的Class字节码
  9. private Class<T> clazz;
  10. public MyBeanHandler(Class<T> clazz1) {
  11. this.clazz = clazz1;
  12. }
  13. @Override
  14. public T handle(ResultSet rs) throws SQLException {
  15. try {
  16. //创建要封装的对象
  17. T t = (T) clazz.newInstance();
  18. //向下读取一行
  19. if(rs.next()){
  20. //获取所有的Field属性数组
  21. Field[] fs = clazz.getDeclaredFields();
  22. //遍历Field属性数组,得到每一个字段类型Field
  23. for(Field f : fs){
  24. //得到属性名,即对象属性名
  25. String fieldName = f.getName();
  26. //得到该Field属性的Column注解
  27. Column column = f.getAnnotation(Column.class);
  28. //获取Column注解的columnName属性值,即字段名
  29. String columnName = column.columnName();
  30. //获取该字段对应的值
  31. Object objValue = rs.getObject(columnName);
  32. //封装属性值到对象属性中
  33. BeanUtils.copyProperty(t, fieldName, objValue);
  34. }
  35. }
  36. return t;
  37. } catch (Exception e) {
  38. throw new RuntimeException(e);
  39. }
  40. }
  41. }
自定义结果集MyBeanListHandler
     
  1. package com.cn.generic_reflect;
  2. import java.lang.reflect.Field;
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import org.apache.commons.beanutils.BeanUtils;
  8. import org.apache.commons.dbutils.ResultSetHandler;
  9. /**
  10. * 自定义结果集封装数据
  11. * @author liuzhiyong
  12. *
  13. * @param <T>
  14. */
  15. public class MyBeanListHandler<T> implements ResultSetHandler<List<T>> {
  16. //保存需要封装对象的字节码
  17. private Class<T> clazz;
  18. public MyBeanListHandler(Class<T> clazz1) {
  19. this.clazz = clazz1;
  20. }
  21. @Override
  22. public List<T> handle(ResultSet rs) throws SQLException {
  23. //创建集合,封装结果集
  24. List<T> list = new ArrayList<T>();
  25. try{
  26. //遍历结果集
  27. while(rs.next()){
  28. //获取所有的Field属性数组
  29. Field[] fs = clazz.getDeclaredFields();
  30. //创建要封装的对象
  31. T t = clazz.newInstance();
  32. //遍历Field属性数组,得到每一个字段类型Field
  33. for(Field f : fs){
  34. //得到属性名,即对象属性名
  35. String fieldName = f.getName();
  36. //得到该Field属性的Column注解
  37. Column column = f.getAnnotation(Column.class);
  38. //获取Column注解的columnName属性值,即字段名
  39. String columnName = column.columnName();
  40. //获取该字段对应的值
  41. Object objValue = rs.getObject(columnName);
  42. //封装属性值到对象属性中
  43. BeanUtils.copyProperty(t, fieldName, objValue);
  44. }
  45. list.add(t);
  46. }
  47. return list;
  48. }catch(Exception e){
  49. throw new RuntimeException(e);
  50. }
  51. }
  52. }

AccountDao调用通用BaseDao

      
  1. package com.cn.generic_reflect;
  2. /**
  3. * dao实现,继承BaseDao
  4. * @author liuzhiyong
  5. *
  6. */
  7. public class AccountDao extends BaseDao<Entity_Account>{
  8. }

测试

       
  1. package com.cn.generic_reflect;
  2. import java.util.List;
  3. public class Test {
  4. @org.junit.Test
  5. public void testDao() throws Exception {
  6. //调用dao
  7. AccountDao accountDao = new AccountDao();
  8. Entity_Account account = accountDao.findById(2);
  9. System.out.println(account.toString());
  10. List<Entity_Account> accountList = accountDao.getAll();
  11. System.out.println(accountList);
  12. }
  13. }

测试结果


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值