`

利用反射和动态代理实现DAO接口的默认CRUD实现(类似Sprng JPA)

 
阅读更多

本文来自 fair-jm.iteye.com 转截请注明出处

 

用了下JPA对于其方便的操作很好奇 通过继承CRUDRepository等接口 DAO不用写实现类就可以在注入后实现基本的增删改查功能

 

搜索到了一些内容:

http://my.oschina.net/xdev/blog/126049 这里有一些实现的原理 比较详细

http://sunting-bcwl.iteye.com/blog/768989 代码实现如何获得泛型等内容

 

 

实现很简单 用了JPA和java的动态代理以及反射

基本的结构

有一个CRUD的接口:

package jdbc;

import java.util.List;

public interface CRUD<T,I> {

	public List<T> query();
	
	public T findOne(I id);
	
	public void delete(I id);
	
	public void add(T t);
	
	public int update(T t);
}

 此接口是所有DAO的接口必须继承的

 

 

 实践中用了两个DAO user和item

 这里以User为例

User的代码如下:

package com.cc.proxy.test.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="user")
public class User {

	@Id
	private int uid;
	private String name;
	private int sex;
	private String description;
	private int age;
	//省略getter和setter
	
}

   UserDao:

package com.cc.proxy.test.dao;

import com.cc.proxy.test.domain.User;

import jdbc.CRUD;

public interface UserDao extends CRUD<User,Integer> {

}

   

通过代理User就可以使用CRUD等方法(我实际上就写了query和add 其他方法在代理的invoke中补充就可以了):

   

 

=================================================================================

=================================================================================

 

接下去是最主要的代理类的代码:

代理类ProxyDao(实现InvocationHandler)的属性如下:

	private String tableName=null; //表名
	
	private Class entity=null;   //实体类
	private Class idType=null;  //id类型
	
	private String id=null;  //id在实体类中的属性名(方便操作)
	//filed<--->column
	private Map<String,String> columMapping=new HashMap<>(); 

 

构造方法:

	public ProxyDao(Class dao) throws Exception{
		if(!check(dao)){
			throw new Exception("not a dao");
		}
	}

 其中check方法是完成DAO的检查

这里的检查主要包括:

  1. DAO是否继承了CRUD接口
  2. CRUD接口上的泛型是否是实体(有无@Entity和@Id)

代码如下:

	private boolean check(Class dao) throws Exception{
		 boolean hasCRUD=false;
		 //检查是否继承了CRUD接口 没有的话就返回false
		 for(Class inter:dao.getInterfaces()){
			 if(inter==CRUD.class){
				 hasCRUD=true;
				 break;
			 }
		 }
		 if(!hasCRUD){
			 return false;
		 }
		 //取得第一个接口的信息 这里也就是CRUD接口
		 Type t=dao.getGenericInterfaces()[0];
		 //获得CRUD的泛型 第一个是对应的实体类 第二个是对应的id类型
		 entity=(Class)((ParameterizedType)t).getActualTypeArguments()[0];
		 idType=(Class)((ParameterizedType)t).getActualTypeArguments()[1];
		 
		 Annotation[] as=entity.getAnnotations();
		 //检查是否有Entity这个annotation没有则退出
		 boolean hasEntity=false;
	       for(Annotation a:as){
	    	  if(a.annotationType()==javax.persistence.Entity.class){
	    		  hasEntity=true;
	    	  }
	    	  if(a.annotationType()==javax.persistence.Table.class){
	    		  tableName=((javax.persistence.Table)a).name();
	    	  }
	       }
	       if(!hasEntity){
	    	   return false;
	       }
	       //如果table的name没有值 那么用实体类的类名就可以了
	       if(tableName==null){
	    	   tableName=entity.getSimpleName();
	       }
	       
	       boolean hasId=false;
			Field[] fs=entity.getDeclaredFields();
			for(Field f:fs){
				if(f.getAnnotation(Id.class)!=null){
					id=f.getName();
					hasId=true;
				}
				//这里建立 属性<-->字段名的映射
				if(f.getAnnotation(Column.class)!=null){
					columMapping.put(f.getName(), f.getAnnotation(Column.class).name());
				}else{
					columMapping.put(f.getName(),f.getName());
				}
			}
	       if(!hasId){
	    	   return false;
	       }
	       return true;
	}

 

最后就是invoke方法了,invoke完成运行方法的指派:

	public static final String QUERY="select * from %s ";
	public static final String ADD="insert into %s(%s) values (%s)";
	public static final String DELETE="delete from %s where %s=?";
	public static final String FIND="select * from %s where %s=?";
	public static final String UPDATE="update %s set %s where %s=?";
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if(method.getName().equals("query")){
			List list=new ArrayList<>();
			try(Connection conn=DBConnection.getConnection()){
				PreparedStatement pst=conn.prepareStatement(String.format(QUERY, tableName));
				ResultSet rs=pst.executeQuery();
				while(rs.next()){
					Object o=entity.newInstance();
					for(Field f:entity.getDeclaredFields()){
						f.setAccessible(true);
						f.set(o, rs.getObject(columMapping.get(f.getName()),f.getType()));
					}
					list.add(o);
				}
			}
			return list;
		}
		
		if(method.getName().equals("add")){
			Object o=args[0];
			StringBuffer arg=new StringBuffer();
			StringBuffer values=new StringBuffer();
			for(Field f:entity.getDeclaredFields()){
				if(f.getName().equals(id)){ //id不用自己插入
					continue;
				}
				f.setAccessible(true);
				if(f.get(o)!=null){
				  arg.append(columMapping.get(f.getName())).append(",");
				  values.append(String.format("'%s'", f.get(o))).append(",");
				}
			}
//			arg.substring(0,arg.length()-1);
//			values.substring(0,values.length()-1);
			try(Connection conn=DBConnection.getConnection()){
				PreparedStatement pst=conn.prepareStatement(String.format(ADD, tableName,arg.substring(0,arg.length()-1),values.substring(0,values.length()-1)));
				  pst.execute();
				}
		}
		
				if(method.getName().equals("delete")){
			Object o=args[0];
			try(Connection conn=DBConnection.getConnection()){
				PreparedStatement pst=conn.prepareStatement(String.format(DELETE, tableName,id));
				pst.setObject(1, o);
				pst.execute();
			}
		}
		
		if(method.getName().equals("findOne")){
			Object o=args[0];
			try(Connection conn=DBConnection.getConnection()){
				PreparedStatement pst=conn.prepareStatement(String.format(FIND, tableName,id));
				pst.setObject(1, o);
				ResultSet rs=pst.executeQuery();
				if(rs.next()){
						Object ob=entity.newInstance();
						for(Field f:entity.getDeclaredFields()){
							f.setAccessible(true);
							f.set(ob, rs.getObject(columMapping.get(f.getName()),f.getType()));
						}
						return ob;
				}else{
					return null;
				}
			}
		}
		
		if(method.getName().equals("update")){
			Object o=args[0];
			Object idNumber=null;
			StringBuffer set=new StringBuffer();
			for(Field f:entity.getDeclaredFields()){
				f.setAccessible(true);
				if(f.getName().equals(id)){
					idNumber=f.get(o);
					continue;
				}
				if(f.get(o)!=null){
				  set.append(columMapping.get(f.getName())+"="+String.format("'%s'", f.get(o))).append(",");
				}
			}
			if(idNumber==null){
				return 0;
			}
			try(Connection conn=DBConnection.getConnection()){
				PreparedStatement pst=conn.prepareStatement(String.format(UPDATE, tableName,set.substring(0,set.length()-1),id));
				pst.setObject(1, idNumber);
				return pst.executeUpdate();
			}
		}
		
		return null;
	}

 不只是这些方法 对于UserDao如果有findOneByName这种方法 完全可以通过invoke方法进行分析和执行相应动作(这里可以用一个判断方法名是findOneBy开头的来 后面的属性放入SQL中就可以了)

 

代码中偷懒直接对属性用Field来取 实际中应该通过getter和setter来取和赋值 自己实验一下就怎么方便怎么写了

 

 

实现起来不是很难 就是一些基本的反射的操作和一些基础的逻辑判断

从前也未思考过动态代理有什么用(最多就是一些AOP的内容) 对于直接用来实现接口 压根就没想过..

写代码这种东西 总是能找到新的乐趣啊....

 

 

此外关于动态代理的其他的用法可以看:

http://www.infoq.com/cn/articles/cf-java-reflection-dynamic-proxy

infoQ里的内容挺不错的~~~

 

 

2013最后一篇博客了~~来年也要玩得开心^_^~~

  • 大小: 39.8 KB
1
2
分享到:
评论

相关推荐

    Spring+jpa实现简单的CRUD

    在本教程中,我们将深入探讨如何使用Spring框架与Java Persistence API (JPA) 实现基本的CRUD(创建、读取、更新、删除)操作。首先,我们需要理解Spring框架是Java开发中的一个核心组件,它提供了多种服务,如依赖...

    基于JPA的CRUD例子

    `EntityManager`是JPA的主要接口,用于执行CRUD操作。通常,我们会在`Persistence`配置文件中定义数据源,并通过`Persistence.createEntityManagerFactory()`创建`EntityManagerFactory`,然后用它来获取`...

    SpringBoot整合Jpa和Thymeleaf实现CRUD

    SpringBoot整合Jpa和Thymeleaf实现CRUD是一个典型的Web开发应用场景,它结合了SpringBoot的便捷性、JPA的数据持久层处理以及Thymeleaf的模板引擎,旨在简化开发流程并提供高效的数据库操作。在这个项目中,我们可以...

    JPA(hibernate) Dao 和 DaoSupport

    在JPA和Hibernate中,DAO通常用于执行CRUD(创建、读取、更新、删除)操作。 **DaoSupport类:** 在Spring框架中,`DaoSupport`是一个抽象类,为DAO实现提供了一些基础支持,比如初始化和关闭数据库资源。继承自`...

    java 基于泛型与反射的通用 DAO

    综上所述,这个项目展示了如何利用Java的泛型和反射技术实现一个通用的DAO,使得数据库操作更加灵活和易于维护。泛型确保了类型安全,而反射则提供了运行时的动态行为。这种设计模式在实际开发中非常常见,尤其是在...

    SpringBoot+JPA+MySQL+Swagger+Redis实现CRUD

    在本项目中,我们利用了SpringBoot框架,联合JPA(Java Persistence API)与MySQL数据库,以及Swagger和Redis,来构建一个完整的CRUD(Create、Read、Update、Delete)应用程序。下面将详细介绍这些技术及其在项目中...

    JAVA反射的实现(使DAO层变得更加简单)

    在本篇文章中,我们将深入探讨如何利用反射机制来简化DAO(数据访问对象)层的设计和实现。 首先,让我们理解什么是DAO层。DAO层是应用程序与数据库交互的一层抽象,它的主要职责是封装SQL查询,处理数据库操作,...

    jpa对表的crud操作

    在JPA中,对表的CRUD操作主要通过`EntityManager`接口来实现,下面我们将详细介绍这些操作。 1. 创建(Create) 在JPA中,创建新记录通常使用`EntityManager`的`persist()`方法。例如,创建一个新的`Person`对象并...

    mybatis基于Dao的crud操作源码

    本项目是基于Mybatis进行DAO(Data Access Object)层的CRUD(Create、Read、Update、Delete)操作的源码实现,结合了Spring框架,便于管理和集成事务。 在Mybatis中,CRUD操作主要通过Mapper接口和对应的XML配置...

    自定义Dao,反射实现

    本篇将深入探讨如何自定义Dao,并利用反射技术来实现这一目标。博客链接:[此处无法提供实际链接,故省略] 首先,了解DAO的基本概念。DAO是应用程序中的一个接口或抽象类,它提供了对数据存储的抽象,使得业务逻辑...

    反射机制反射Dao 反射机制

    在Java编程语言中,反射机制是一项强大的工具,它允许程序在运行时检查和操作类、接口、对象等的内部结构。反射机制的核心在于`java....在设计和实现数据访问层时,反射结合DAO模式可以提供一种高效且灵活的解决方案。

    Springboot和Jpa实现学生CRUD操作代码实例

    Springboot和Jpa实现学生CRUD操作代码实例 Springboot和Jpa是目前非常流行的技术栈,广泛应用于企业级项目中。该篇文章主要介绍了使用Springboot和Jpa实现学生CRUD操作代码实例,通过详细的示例代码,帮助读者快速...

    Springboot+JPA实现分页+crud

    本篇将详细介绍如何使用Spring Boot结合Spring Data JPA实现分页和CRUD(Create、Read、Update、Delete)操作。 首先,我们需要在项目中引入Spring Data JPA的依赖。在`pom.xml`文件中添加如下Maven依赖: ```xml ...

    JPA.rar_JPA 封装DAO

    在DAO(Data Access Object)层的封装中,JPA可以帮助我们创建一组通用的方法,如save、update、delete和findAll,以处理常见的CRUD(Create、Read、Update、Delete)操作。这些方法可以应用于任何实体类,大大提高...

    利用反射创建的CRUD

    利用反射创建的增删改查,保存时只需传入一个对象即可,不需要写配置文件。使用hjz.jar时,首先 Session s = new Session();然后执行数据库操作。

    jpa jsf crud

    在**JPA和JSF集成进行CRUD操作**时,通常会利用JSF的后台Bean(Managed Bean)来处理业务逻辑,而JPA则负责数据库交互。CRUD代表创建(Create)、读取(Retrieve)、更新(Update)和删除(Delete)这四种基本的数据操作。 ...

    SpringDataJpa开发--继承JpaRepository实现简单条件查询

    通过以上步骤,我们可以在Spring Boot应用中利用Spring Data JPA和`JpaRepository`轻松实现对数据库的访问,大大简化了数据访问层的代码。在实际项目中,还可以结合`Pageable`接口进行分页查询,或者使用`...

    封装通用的Spring3+Struts2+JPA的CRUD 通用分页实现

    它结合了Spring框架的依赖注入、Struts2的MVC模式以及JPA(Java Persistence API)的数据持久层处理,来实现数据的创建、读取、更新和删除(CRUD)操作,并提供了通用的分页功能。以下是对这一技术组合的详细解析: ...

    VUE实现静态数据的CRUD功能

    在本案例中,“VUE实现静态数据的CRUD功能”指的是利用Vue.js创建一个能够进行创建(Create)、读取(Retrieve)、更新(Update)和删除(Delete)操作的应用。这种功能通常用于管理数据库中的数据,而在这个特定场景下,...

Global site tag (gtag.js) - Google Analytics