Spring Data JPA: 实现自定义Repository

一、前言

  由于项目中的 实体(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;@MappedSuperclass
public 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基类,已经包含了常用的增删改查操作。<br>* 使用时只需要继承接口,不需要实现类,spring自动通过cglib生成实现类* * @param <T>*            实体类型*/
@NoRepositoryBean
public interface BaseDao<T extends AbsIdEntity> extendsCrudRepository<T, Serializable>/* JpaRepository<T, Serializable> */, JpaSpecificationExecutor<T> {
}
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;@Transactional
public class BaseDaoImpl<T extends AbsIdEntity> extends SimpleJpaRepository<T, Serializable> implements BaseDao<T> {@SuppressWarnings("unused")private final EntityManager entityManager;public BaseDaoImpl(Class<T> domainClass, EntityManager entityManager) {super(domainClass, entityManager);this.entityManager = entityManager;}public BaseDaoImpl(JpaEntityInformation<T, Serializable> information, EntityManager entityManager) {super(information, entityManager);this.entityManager = entityManager;}@Overridepublic <S extends T> S save(S entity) {entity.setModificationTimestamp(new Timestamp(System.currentTimeMillis()));return super.save(entity);}/*** 只做逻辑删除*/@Overridepublic void delete(T entity) {entity.setDr(1);save(entity);}@Overridepublic 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<R extends JpaRepository<T, Serializable>, T extends AbsIdEntity> extends JpaRepositoryFactoryBean<R, T, Serializable> {@Overrideprotected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {return new JpaRepositoryFactory(entityManager) {protected SimpleJpaRepository<T, Serializable> getTargetRepository(RepositoryInformation information,    EntityManager entityManager) {return new BaseDaoImpl((Class<T>) information.getDomainType(), entityManager);}@Overrideprotected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {return BaseDaoImpl.class;}};}
}
View Code

  jpa 配置文件

<!-- Spring Data Jpa配置 -->
<jpa:repositories base-package="com.xxx"transaction-manager-ref="transactionManager"entity-manager-factory-ref="entityManagerFactory"factory-class="xxx.BaseDaoFactoryBean"><!-- 自定义RepositoryFactoryBean -->
</jpa:repositories>

三、改进之后

  由于有的表没有默认父类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<R extends JpaRepository<T, Serializable>, T> extends JpaRepositoryFactoryBean<R, T, Serializable> {@Overrideprotected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {return new JpaRepositoryFactory(entityManager) {protected SimpleJpaRepository<T, Serializable> getTargetRepository(RepositoryInformation information,    EntityManager entityManager) {Class<T> domainClass = (Class<T>) information.getDomainType();if(AbsIdEntity.class.isAssignableFrom(domainClass)) {return new BaseDaoImpl(domainClass, entityManager);} else { return new SimpleJpaRepository(domainClass, entityManager);}}@Overrideprotected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {return metadata.getDomainType().isAssignableFrom(AbsIdEntity.class) ? BaseDaoImpl.class : SimpleJpaRepository.class;}};}
}
View Code

  至此,完成了适配。

 

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

转载于:https://www.cnblogs.com/hujunzheng/p/6494671.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java json和对象互相装换

java json和对象互相装换 1.com.alibaba.fastjson.JSON 2.com.fasterxml.jackson.databind.ObjectMapper 转载于:https://www.cnblogs.com/hujunzheng/p/6593491.html

js冲刺一下

js中__proto__和prototype的区别和关系 1.对象有属性__proto__,指向该对象的构造函数的原型对象。  2.方法除了有属性__proto__,还有属性prototype&#xff0c;prototype指向该方法的原型对象。 深入浅出妙用 Javascript 中 apply、call、bind ***两道面试题*** 关于js中伪数…

springmvc 源码分析

DispatcherServlet的初始化流程 HandlerMapping - RequestMappingHandlerMapping初始化 DefaultAnnotationHandlerMapping 和RequestMappingHandlerMapping RequestToViewNameTranslator请求到视图名称的转换 (如果没有responsebody&#xff0c;并且没有返回一个view&#xff0…

EntityManager的使用

1、最基础的查询 CriteriaBuilder cb entityManager.getCriteriaBuilder(); CriteriaQuery<User> cq cb.createQuery(User.class); Root<User> root cq.from(User.class); //from User cq.select(root); //select * from User javax.persistence.criteria.Predi…

Jackson序列化实例

参考文章 Jackson使用ContextualSerializer在序列化时获取字段注解的属性 使用BeanSerializerModifier定制jackson的自定义序列化(null值的处理) 关于使用ContextualSerializer的补充 BeanSerializerFactory中有如下代码&#xff0c; 关于设置SerializerModifier&#xff0c;如…

maven自定义脚手架(快速生成项目)

Maven之自定义archetype生成项目骨架 利用脚手架生成 新项目 命令行方式 mvn archetype:generate \ -DarchetypeGroupIdcom.xxx \ -DarchetypeArtifactIdarchetype-spring-boot \ -DarchetypeVersion1.0.0 \ -DgroupIdcom.xxx \ -DartifactIddemo-archetype-generate \ -Dversi…

JSONObject 自定义过滤配置

一、自定义过滤器说明 PropertyPreFilter 根据PropertyName判断是否序列化   PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化   NameFilter 修改Key&#xff0c;如果需要修改Key,process返回值则可   ValueFilter 修改Value   BeforeFilter 序列化时…

springmvc防止重复提交拦截器

一、拦截器实现&#xff0c;ResubmitInterceptorHandler.java import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.Hand…

Mac idea 快捷键

Mac键盘符号和修饰键说明 ⌘ Command⇧ Shift⌥ Option⌃ Control↩︎ Return/Enter⌫ Delete⌦ 向前删除键&#xff08;FnDelete&#xff09;↑ 上箭头↓ 下箭头← 左箭头→ 右箭头⇞ Page Up&#xff08;Fn↑&#xff09;⇟ Page Down&#xff08;Fn↓&#xff09;Home Fn ←…

cas4.2.7实现单点登录

准备前参考&#xff1a;  cas server下载地址 cas client 下载地址 安全cookie setSecure详解 Spring通过构造方法注入的四种方式 cas 学习博文 自定义登录页和登录认证 cas server端的login-webflow详细流程 CAS服务端自定义数据库认证用户 准备工作 1. cas server下载之后解…

log4j之log4j2.xml使用

依赖jar包 log4j-api-2.6.2.jar log4j-core-2.6.2.jar log4j-slf4j-impl-2.6.2.jar slf4j-api-1.7.12.jar 在resources目录下新建log4j2.xml&#xff0c;内容如下。 <?xml version"1.0" encoding"UTF-8"?><!--status : 这个用于设置log4j2自身内…

cas4.2.7与shiro进行整合

准备工作 cas单点登录开始前准备&#xff0c;请参考cas4.2.7实现单点登录。 与shiro进行整合 注&#xff1a;准备工作的基础上&#xff0c;对cas客户端进行如下改进。 引入相关jar包 shiro-cas-1.2.6.jar shiro-core-1.2.6.jar shiro-spring-1.2.6.jar shiro-web-1.2.6.jar web…

命令行fuck神器

文章 thefuck git thefuck 转载于:https://www.cnblogs.com/hujunzheng/p/6935587.html

springmvc配置MappingJackson2HttpMessageConverter实现属性驼峰和下划线的转换

需求 php调用java接口时&#xff0c;因为php那边的属性都是下划线风格&#xff0c;java这边的属性都是驼峰的风格。配置springmvc的json转换&#xff0c;在requestBody的时候&#xff08;调用对象的set 方法&#xff09;将java属性name映射成下划线形式 和 请求的参数匹配&…

springmvc中使用MockMvc测试controller

示例代码 import com.alibaba.fastjson.JSONObject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springfra…

swagger restful api form映射实体对象和body映射实体对象配置

实体Model ModelAttribute一个具有如下三个作用&#xff1a; ①绑定请求参数到命令对象&#xff1a;放在功能处理方法的入参上时&#xff0c;用于将多个请求参数绑定到一个命令对象&#xff0c;从而简化绑定流程&#xff0c;而且自动暴露为模型数据用于视图页面展示时使用&…

程序员的开发文档

Web版&#xff1a; DevDocs API Documentation 桌面版&#xff1a;devdocs-app 转载于:https://www.cnblogs.com/hujunzheng/p/7015947.html

ssh端口转发(之kettle ssh方式连接数据库)

ssh参数解释 格式  ssh [user]host [command] 选项&#xff1a; -1&#xff1a;强制使用ssh协议版本1&#xff1b; -2&#xff1a;强制使用ssh协议版本2&#xff1b; -4&#xff1a;强制使用IPv4地址&#xff1b; -6&#xff1a;强制使用IPv6地址&#xff1b; -A&#xff1a…

ThreadLocal和InheritableThreadLocal使用

InheritableThreadLocal代码 public class InheritableThreadLocal<T> extends ThreadLocal<T> {protected T childValue(T parentValue) {return parentValue;}ThreadLocalMap getMap(Thread t) {return t.inheritableThreadLocals;}void createMap(Thread t, T f…

mybatis generator修改默认生成的sql模板

相关连接&#xff1a; mybatis-generator扩展教程系列 -- 自定义sql xml文件 git项目地址 转载于:https://www.cnblogs.com/hujunzheng/p/7110510.html