本文来自 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的检查
这里的检查主要包括:
- DAO是否继承了CRUD接口
- 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最后一篇博客了~~来年也要玩得开心^_^~~
相关推荐
在本教程中,我们将深入探讨如何使用Spring框架与Java Persistence API (JPA) 实现基本的CRUD(创建、读取、更新、删除)操作。首先,我们需要理解Spring框架是Java开发中的一个核心组件,它提供了多种服务,如依赖...
`EntityManager`是JPA的主要接口,用于执行CRUD操作。通常,我们会在`Persistence`配置文件中定义数据源,并通过`Persistence.createEntityManagerFactory()`创建`EntityManagerFactory`,然后用它来获取`...
SpringBoot整合Jpa和Thymeleaf实现CRUD是一个典型的Web开发应用场景,它结合了SpringBoot的便捷性、JPA的数据持久层处理以及Thymeleaf的模板引擎,旨在简化开发流程并提供高效的数据库操作。在这个项目中,我们可以...
在JPA和Hibernate中,DAO通常用于执行CRUD(创建、读取、更新、删除)操作。 **DaoSupport类:** 在Spring框架中,`DaoSupport`是一个抽象类,为DAO实现提供了一些基础支持,比如初始化和关闭数据库资源。继承自`...
综上所述,这个项目展示了如何利用Java的泛型和反射技术实现一个通用的DAO,使得数据库操作更加灵活和易于维护。泛型确保了类型安全,而反射则提供了运行时的动态行为。这种设计模式在实际开发中非常常见,尤其是在...
在本项目中,我们利用了SpringBoot框架,联合JPA(Java Persistence API)与MySQL数据库,以及Swagger和Redis,来构建一个完整的CRUD(Create、Read、Update、Delete)应用程序。下面将详细介绍这些技术及其在项目中...
在本篇文章中,我们将深入探讨如何利用反射机制来简化DAO(数据访问对象)层的设计和实现。 首先,让我们理解什么是DAO层。DAO层是应用程序与数据库交互的一层抽象,它的主要职责是封装SQL查询,处理数据库操作,...
在JPA中,对表的CRUD操作主要通过`EntityManager`接口来实现,下面我们将详细介绍这些操作。 1. 创建(Create) 在JPA中,创建新记录通常使用`EntityManager`的`persist()`方法。例如,创建一个新的`Person`对象并...
本项目是基于Mybatis进行DAO(Data Access Object)层的CRUD(Create、Read、Update、Delete)操作的源码实现,结合了Spring框架,便于管理和集成事务。 在Mybatis中,CRUD操作主要通过Mapper接口和对应的XML配置...
本篇将深入探讨如何自定义Dao,并利用反射技术来实现这一目标。博客链接:[此处无法提供实际链接,故省略] 首先,了解DAO的基本概念。DAO是应用程序中的一个接口或抽象类,它提供了对数据存储的抽象,使得业务逻辑...
在Java编程语言中,反射机制是一项强大的工具,它允许程序在运行时检查和操作类、接口、对象等的内部结构。反射机制的核心在于`java....在设计和实现数据访问层时,反射结合DAO模式可以提供一种高效且灵活的解决方案。
Springboot和Jpa实现学生CRUD操作代码实例 Springboot和Jpa是目前非常流行的技术栈,广泛应用于企业级项目中。该篇文章主要介绍了使用Springboot和Jpa实现学生CRUD操作代码实例,通过详细的示例代码,帮助读者快速...
本篇将详细介绍如何使用Spring Boot结合Spring Data JPA实现分页和CRUD(Create、Read、Update、Delete)操作。 首先,我们需要在项目中引入Spring Data JPA的依赖。在`pom.xml`文件中添加如下Maven依赖: ```xml ...
在DAO(Data Access Object)层的封装中,JPA可以帮助我们创建一组通用的方法,如save、update、delete和findAll,以处理常见的CRUD(Create、Read、Update、Delete)操作。这些方法可以应用于任何实体类,大大提高...
利用反射创建的增删改查,保存时只需传入一个对象即可,不需要写配置文件。使用hjz.jar时,首先 Session s = new Session();然后执行数据库操作。
在**JPA和JSF集成进行CRUD操作**时,通常会利用JSF的后台Bean(Managed Bean)来处理业务逻辑,而JPA则负责数据库交互。CRUD代表创建(Create)、读取(Retrieve)、更新(Update)和删除(Delete)这四种基本的数据操作。 ...
通过以上步骤,我们可以在Spring Boot应用中利用Spring Data JPA和`JpaRepository`轻松实现对数据库的访问,大大简化了数据访问层的代码。在实际项目中,还可以结合`Pageable`接口进行分页查询,或者使用`...
它结合了Spring框架的依赖注入、Struts2的MVC模式以及JPA(Java Persistence API)的数据持久层处理,来实现数据的创建、读取、更新和删除(CRUD)操作,并提供了通用的分页功能。以下是对这一技术组合的详细解析: ...
在本案例中,“VUE实现静态数据的CRUD功能”指的是利用Vue.js创建一个能够进行创建(Create)、读取(Retrieve)、更新(Update)和删除(Delete)操作的应用。这种功能通常用于管理数据库中的数据,而在这个特定场景下,...