-
Notifications
You must be signed in to change notification settings - Fork 626
Spring Data JPA(一)
在Spring Boot中使用JPA,需要引入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
现在对本项目中使用到的JPA相关的知识点做一个梳理。
本项目中的DAO层放在com.imooc.repository包下。以我们的ProductCategoryRepository这个DAO为例,先看它的接口定义:
public interface ProductCategoryRepository extends JpaRepository<ProductCategory,Integer> {
List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList);
}
可以看到它继承自JpaRepository,其实我们这里所有的DAO都继承之JpaRepository接口。现在我们来研究一下JpaRepository接口。下面是一个继承关系图。
可以看到JpaRepository接口间接继承自CrudRepository,而CrudRepository大致方法如下:
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
// … more functionality omitted.
}
它定义了一些CRUD方法,所以继承自的类可以直接获得这些对数据库操作的CRUD方法。
从图中还可以看到JpaRepository继承自PagingAndSortingRepository,它是一个Spring Data JPA中实现分页的接口,它的定义如下:
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
着重看Page<T> findAll(Pageable pageable);
这个方法,它就是与分页有关的,它的参数是一个接口,我们使用时传入一个PageRequest。如下是Controller层的一个使用:
@GetMapping("/list")
public ModelAndView list(@RequestParam(value = "page" ,defaultValue="1") Integer page,
@RequestParam(value = "size",defaultValue = "10") Integer size,
Map<String,Object> map){
PageRequest request=new PageRequest(page-1,size);
Page<ProductInfo> productInfoPage=productService.findAll(request);
map.put("productInfoPage",productInfoPage);
map.put("currentPage",page);
map.put("size",size);
return new ModelAndView("product/list",map);
}
它调用的Service层如下:
@Override
public Page<ProductInfo> findAll(Pageable pageable) {
return repository.findAll(pageable);
}
DAO层更简单,没有任何方法,它的CRUD方法和分页方法都继承与父接口。并且它指定了两个泛型参数<ProductInfo,String>,第一个参数是操作的实体类,第二个参数是主键类型。
public interface ProductInfoRepository extends JpaRepository<ProductInfo,String>{
}
对于Controller层返回的Page<ProductInfo> productInfoPage
对象,在视图层我们使用的是freemarker模板引擎,分页的使用方式如下:
<div class="col-md-12 column">
<ul class="pagination pull-right">
<#if currentPage lte 1>
<li class="disabled"><a href="#">上一页</a></li>
<#else>
<li><a href="/sell/seller/product/list?page=${currentPage - 1}&size=${size}">上一页</a></li>
</#if>
<#list 1..productInfoPage.getTotalPages() as index>
<#if currentPage == index>
<li class="disabled"><a href="#">${index}</a></li>
<#else>
<li><a href="/sell/seller/product/list?page=${index}&size=${size}">${index}</a></li>
</#if>
</#list>
<#if currentPage gte productInfoPage.getTotalPages()>
<li class="disabled"><a href="#">下一页</a></li>
<#else>
<li><a href="/sell/seller/product/list?page=${currentPage + 1}&size=${size}">下一页</a></li>
</#if>
</ul>
</div>
观察一下,可以看到JpaRepository,PagingAndSortingRepository这些接口都有一个@NoRepositoryBean注解,用官方的话说就是一个intermediate Repository,它会告诉Spring Data不会为这个接口创建代理bean,因为我们JpaRepository这些Repo都是为了来扩展功能的,是用来被继承的,而我们的ProductInfoRepository没有使用这个注解,Spring Data都会为它生成一个代理,并实现里面的方法。
该问题可以参考Stackoverflow上的的解答:Understanding the Spring Data JPA @NoRepositoryBean interface
目录