Spring Data JPA: 为所有Repository添加自定义方法

16 篇文章 0 订阅

Spring Data JPA中的Repository是接口,是JPA根据方法名帮我们自动生成的。但很多时候,我们需要为Repository提供一些自定义的实现。今天我们看看如何为Repository添加自定义的方法。

自定义Repository接口

首先我们来添加一个自定义的接口:

  • 添加BaseRepository接口
  • BaseRepository继承了PagingAndSortingRepository,这样可以保证所有Repository都有基本的增删改查以及分页等方法。
  • BaseRepository上添加@NoRepositoryBean标注,这样Spring Data Jpa在启动时就不会去实例化BaseRepository这个接口
  • 添加support(String modelType)方法,表示该Repository的领域对象是否为modelType类型

@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> 
    extends PagingAndSortingRepository<T, ID> {

    boolean support(String modelType);

}

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

实现BaseRepository接口

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

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

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

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

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

最后实现support方法,其参数是领域对象的类型,将其和domainClass对比,如果相等,则该Repository支持该类型的领域对象:

public class BaseRepositoryImpl<T, ID extends Serializable> 
    extends SimpleJpaRepository<T, ID> 
    implements BaseRepository<T, ID> {

    private final Class<T> domainClass;

    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.domainClass = domainClass;
    }

    @Override
    public boolean support(String modelType) {
        return domainClass.getName().equals(modelType);
    }

}

创建自定义RepositoryFactoryBean

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

public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> 
    extends JpaRepositoryFactoryBean<R, T, I> {

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
        return new MyRepositoryFactory(em);
    }

    private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

        private final EntityManager em;

        public MyRepositoryFactory(EntityManager em) {
            super(em);
            this.em = em;
        }

        @Override
        protected Object getTargetRepository(RepositoryMetadata metadata) {
            return new BaseRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), em);
        }

        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

配置Jpa factory class

最后,我们需要配置Jpa使用我们自定义的BaseRepositoryFactoryBean。Spring支持使用标注进行配置,我们在com.tmy.App中添加标注@EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class)

@SpringBootApplication
@EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class)
public class App {

    public static void main( String[] args ){
        SpringApplication.run(App.class, args);
    }
}

这样我们就为所有Repository添加了自定义的方法。

测试

我们添加了一个TestController进行测试。进入根目录,执行mvn spring-boot:run可以运行我们的应用。

应用启动后,分别访问http://localhost:8080/test?type=blog&id=1http://localhost:8080/test?type=article&id=1,我们将看到article和blog两个不同的对象。

TestController中,我们通过依赖式注入获取到所有Repository的列表。当用户访问/test,系统将根据传进来的type遍历所有Repository,找到对应的Repository,再调用findOne(id)方法找到对应的对象。这样我们就不需要一个一个的去获取Repository实例,当领域对象越来越多时,通过这种方式是一种更加高效的对象管理方法。

@RestController
public class TestController {

    @Autowired
    private List<BaseRepository> repositories;

    @RequestMapping(value = "/test", method=RequestMethod.GET)
    public Object getEntry(@RequestParam(value="type", required = true) String type,
            @RequestParam(value="id", required=true) Integer id){
        if(type.equals("article")){
            type = Article.class.getName();
        }else if (type.equals("blog")) {
            type = Blog.class.getName();
        }
        for (BaseRepository baseRepository : repositories) {
            if(baseRepository.support(type)){
                return baseRepository.findOne(id);
            }
        }
        return null;
    }

}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值