1.创建一个BaseRepostory接口
/**
* 自定义一个Repository,它是JpaRepository的功能基础上继承增强
* 在上面添加@NoRepositoryBean标注,这样Spring Data Jpa在启动时就不会去实例化BaseRepository这个接口
* @param <T>
* @param <ID>
*/
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
//根据Query拿到分页对象(分页)
Page findPageByQuery(BaseQuery baseQuery);
//根据Query拿到对应的所有数据(不分页)
List<T> findByQuery(BaseQuery baseQuery);
//根据jpql与对应的参数拿到数据
List findByJpql(String jpql,Object... values);
}
2.实现BaseRepostory接口
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {
private final EntityManager entityManager;
//必需要实现父类的这个构造器
public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
}
@Override
public Page findPageByQuery(BaseQuery baseQuery) {
// 拿到所有高级查询条件
Specification specification = baseQuery.createSpecification();
// 拿到分页对象
Pageable page = baseQuery.createPage();
// 查询数据
return findAll(specification, page);
}
@Override
public List<T> findByQuery(BaseQuery baseQuery) {
// 根据高级查询条件查询数据(不加分页)
return findAll(baseQuery.createSpecification());
}
@Override
public List findByJpql(String jpql, Object... values) {
// 根据传入的jpql创建query对象
Query query = entityManager.createQuery(jpql);
for (int i = 0; i < values.length; i ++){
// 根据传入参数个数给jpql中的?赋值
query.setParameter(i + 1, values[i]);
}
// 返回查询数据(List集合)
return query.getResultList();
}
}
3.子接口直接继承BaseRepository就能获取扩展方法
/**
* JpaRepository<ProductRepository,Long>:拥有CRUD、排序、分页方法
* 泛型一:要进行CRUD的domain
* 泛型二:domain的主键类型
*
* JpaSpecificationExecutor<ProductRepository>:可以将高级查询、排序、分页结合
*/
public interface ProductRepository extends BaseRepository<Product, Long> {
@Query("select o from Product o where name = ?1")
Product checkName(String name);
}
4.使代理类默认继承BaseRepositoryImpl
- 实现JpaRepository接口后,jpa会自动创建一个代理类
- 代理类默认继承SimpleJpaRepository类,SimpleJpaRepository类实现了JpaRepository接口中的所有方法
- 此时代理类中并没有实现我们扩展的方法,所以必须修改代理类默认继承
步骤:
- BaseRepositoryImpl类继承SimpleJpaRepository类,并实现父类构造器
- 创建BaseRepositoryFactoryBean类(固定代码,直接使用即可)
/**
* BaseRepository接口默认实现类继承SimpleJpaRepository类
* 修改默认继承为BaseRepository类
* @param <T>
* @param <S>
* @param <ID>
*/
public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MyRepositoryFactory<T,ID>(entityManager); //注:这里创建是我们的自定义类
}
//继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
private static class MyRepositoryFactory<T,ID extends Serializable> extends JpaRepositoryFactory {
private final EntityManager entityManager;
/**
* Creates a new {@link JpaRepositoryFactory}.
*
* @param entityManager must not be {@literal null}
*/
public MyRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
//这里返回最后的功能对象
@Override
protected Object getTargetRepository(RepositoryInformation information) {
return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
}
//确定功能对象的类型
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return BaseRepositoryImpl.class;
}
}
} - 配置applicationContext.xml
<!--用SpringDataJpa的方案去扫描它
只要发现接口继承了JpaRepository接口,就自动完成CRUD以及分页等功能
-->
<jpa:repositories base-package="cn.meco.aisell.repository"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"
factory-class="cn.meco.aisell.repository.BaseRepositoryFactoryBean"
/> - 子接口直接继承BaseRepository即可
public interface EmployeeRepository extends BaseRepository<Employee, Long> {