博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Data JPA: 实现自定义Repository
阅读量:6622 次
发布时间:2019-06-25

本文共 8114 字,大约阅读时间需要 27 分钟。

一、前言

  由于项目中的 实体(entity)默认都是继承一个父类(包含一些公共的属性,比如创建时间,修改时间,是否删除,主键id)。为了实现逻辑删除,一般会自己实现RepositoryFactoryBean 和 Repository。但是由于多个团队开发的结果,表的结构没有同一,也就是会出现有的表没有基础父类对应的字段,这样就会导致自定义的jpa repository操作这些表就会出错。

二、最开始实现

  默认父类

import java.io.Serializable;import java.sql.Timestamp;import javax.persistence.Column;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.MappedSuperclass;import org.hibernate.annotations.GenericGenerator;@MappedSuperclasspublic abstract class AbsIdEntity implements Serializable {    private static final long serialVersionUID = 7988377299341530426L;    @Id    @GenericGenerator(name="uuid", strategy="uuid")    @GeneratedValue(generator="uuid")    @Column(name="id")    protected String id;    @Column(name = "creationtime")    protected Timestamp creationTimestamp = new Timestamp(System.currentTimeMillis());    @Column(name = "lastmodifiedtime")    protected Timestamp modificationTimestamp = new Timestamp(System.currentTimeMillis());        @Column(name = "dr")    protected int dr;// 是否删除。0:未删除;1:已删除    /**     * 主键,对应id字段     */    public String getId() { return id; }    public void setId(String id) { this.id = id; }    /**     * 创建日期,对应ts_insert字段     */    public Timestamp getCreationTimestamp() { return creationTimestamp; }    public void setCreationTimestamp(Timestamp creationTimestamp) { this.creationTimestamp = creationTimestamp; }    /**     * 修改日期,对应ts_update字段     */    public Timestamp getModificationTimestamp() { return modificationTimestamp; }    public void setModificationTimestamp(Timestamp modificationTimestamp) { this.modificationTimestamp = modificationTimestamp; }    /**     * 是否删除,对应dr字段     * @return     */    public int getDr() {        return dr;    }    public void setDr(int dr) {        this.dr = dr;    }}
View Code

  自定义Repository接口

  • 添加BaseDao接口
  • BaseDao继承了JpaSpecificationExecutor、CrudRepository,这样可以保证所有Repository都有基本的增删改查以及分页等方法。
  • 在BaseDao上添加@NoRepositoryBean标注,这样Spring Data Jpa在启动时就不会去实例化BaseDao这个接口
import java.io.Serializable;import org.springframework.data.jpa.repository.JpaSpecificationExecutor;import org.springframework.data.repository.CrudRepository;import org.springframework.data.repository.NoRepositoryBean;/** * Data Access Object基类,已经包含了常用的增删改查操作。
* 使用时只需要继承接口,不需要实现类,spring自动通过cglib生成实现类 * * @param
* 实体类型 */@NoRepositoryBeanpublic interface BaseDao
extends CrudRepository
/* JpaRepository
*/, JpaSpecificationExecutor
{}
View Code

  然后,使所有Repository接口都继承BaseDao

  实现BaseRepository

  定义好自定义的方法后,我们现在通过一个基本的Repository类来实现该方法:

  首先添加BaseDaoImpl类,继承SimpleJpaRepository类,使其拥有Jpa Repository的基本方法。

  我们发现Repository有两个构造函数:

  • SimpleJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager)
  • SimpleJpaRepository(Class domainClass, EntityManager em)

  这里我们实现第二个构造函数,拿到domainClassEntityManager两个对象。因为我们要实现的是知道某个Repository是否支持某个领域对象的类型,因此在实现构造函数时我们将domainClass的信息保留下来。

import java.io.Serializable;import java.sql.Timestamp;import javax.persistence.EntityManager;import org.springframework.data.jpa.repository.support.JpaEntityInformation;import org.springframework.data.jpa.repository.support.SimpleJpaRepository;import org.springframework.transaction.annotation.Transactional;import com.yyjz.icop.base.dao.BaseDao;@Transactionalpublic class BaseDaoImpl
extends SimpleJpaRepository
implements BaseDao
{ @SuppressWarnings("unused") private final EntityManager entityManager; public BaseDaoImpl(Class
domainClass, EntityManager entityManager) { super(domainClass, entityManager); this.entityManager = entityManager; } public BaseDaoImpl(JpaEntityInformation
information, EntityManager entityManager) { super(information, entityManager); this.entityManager = entityManager; } @Override public
S save(S entity) { entity.setModificationTimestamp(new Timestamp(System.currentTimeMillis())); return super.save(entity); } /** * 只做逻辑删除 */ @Override public void delete(T entity) { entity.setDr(1); save(entity); } @Override public void delete(Serializable id) { T entity = findOne(id); entity.setDr(1); this.save(entity); }}
View Code

  RepositoryFactoryBean 实现

  接下来我们来创建一个自定义的BaseDaoFactoryBean来代替默认的RepositoryFactoryBeanRepositoryFactoryBean负责返回一个RepositoryFactory,Spring Data Jpa 将使用RepositoryFactory来创建Repository具体实现,这里我们用BaseDaoImpl代替SimpleJpaRepository作为Repository接口的实现。这样我们就能够达到为所有Repository添加或修改自定义方法的目的。

import xxx.AbsIdEntity;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;import org.springframework.data.jpa.repository.support.SimpleJpaRepository;import org.springframework.data.repository.core.RepositoryInformation;import org.springframework.data.repository.core.RepositoryMetadata;import org.springframework.data.repository.core.support.RepositoryFactorySupport;import javax.persistence.EntityManager;import java.io.Serializable;public class BaseDaoFactoryBean
, T extends AbsIdEntity> extends JpaRepositoryFactoryBean
{ @Override protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) { return new JpaRepositoryFactory(entityManager) { protected SimpleJpaRepository
getTargetRepository( RepositoryInformation information, EntityManager entityManager) { return new BaseDaoImpl((Class
) information.getDomainType(), entityManager); } @Override protected Class
getRepositoryBaseClass(RepositoryMetadata metadata) { return BaseDaoImpl.class; } }; }}
View Code

  jpa 配置文件

三、改进之后

  由于有的表没有默认父类AbsIdEntity对应的字段,导致生成 Repository 在操作表的时候会报错。需要修改的就是RepositoryFactoryBean的实现逻辑。对于继承了AbsIdEntity的实体类,返回自定义的BaseRepository(也就是BaseDaoImpl),否则就返回SimpleJpaRepository。注意自定义RepositoryFactoryBean的泛型也做了修改。

import xxx.AbsIdEntity;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;import org.springframework.data.jpa.repository.support.SimpleJpaRepository;import org.springframework.data.repository.core.RepositoryInformation;import org.springframework.data.repository.core.RepositoryMetadata;import org.springframework.data.repository.core.support.RepositoryFactorySupport;import javax.persistence.EntityManager;import java.io.Serializable;public class BaseDaoFactoryBean
, T> extends JpaRepositoryFactoryBean
{ @Override protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) { return new JpaRepositoryFactory(entityManager) { protected SimpleJpaRepository
getTargetRepository( RepositoryInformation information, EntityManager entityManager) { Class
domainClass = (Class
) information.getDomainType(); if(AbsIdEntity.class.isAssignableFrom(domainClass)) { return new BaseDaoImpl(domainClass, entityManager); } else { return new SimpleJpaRepository(domainClass, entityManager); } } @Override protected Class
getRepositoryBaseClass(RepositoryMetadata metadata) { return metadata.getDomainType().isAssignableFrom(AbsIdEntity.class) ? BaseDaoImpl.class : SimpleJpaRepository.class; } }; }}
View Code

  至此,完成了适配。

 

 生活不止眼前的bug,还有诗和远方。。。

转载地址:http://injpo.baihongyu.com/

你可能感兴趣的文章
Python---装饰器
查看>>
s17data01
查看>>
kubernetes1.9.1 集群
查看>>
java set and get 用法
查看>>
linux笔记1-1
查看>>
less及编译工具介绍
查看>>
干货满满,腾讯云+社区技术沙龙 Kafka Meetup 深圳站圆满结束
查看>>
IP访问控制列表(ACL)
查看>>
MPLS ×××案例
查看>>
Jmeter-发送JDBC请求
查看>>
LVS DR模式搭建 keepalived + LVS
查看>>
dubbo源码分析-负载均衡
查看>>
OCP 052考试新题库收集整理-第20题
查看>>
决心书
查看>>
一统江湖的大前端(3) DOClever——你的postman有点low
查看>>
Java 初始化执行顺序
查看>>
云栖大会上发布了哪些移动研发新利器?
查看>>
《黑客免杀攻防》读书笔记-软件逆向工程(6) switch-case分支
查看>>
根据自己的应用范围选择合适
查看>>
day6作业--游戏人生完善
查看>>