在我们平时的工作中,查询列表在我们的系统中基本随处可见,那么我们如何使用jpa进行多条件查询以及查询列表分页呢?下面我将介绍两种多条件查询方式。
1、引入起步依赖
1
|
2
3
4
5
6
7
8
9
10
11
12
|
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
|
2、对thymeleaf和jpa进行配置
打开application.yml,添加以下参数,以下配置在之前的文章中介绍过,此处不做过多说明
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
spring:
thymeleaf:
cache: true
check-template-location: true
content-type: text/html
enabled: true
encoding: utf- 8
mode: HTML5
prefix: classpath:/templates/
suffix: .html
excluded-view-names:
template-resolver-order:
datasource:
driver- class -name: com.mysql.jdbc.Driver
url: jdbc:mysql: //localhost:3306/restful?useUnicode=true&characterEncoding=UTF-8&useSSL=false
username: root
password: root
initialize: true
init-db: true
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
naming:
strategy: org.hibernate.cfg.ImprovedNamingStrategy
|
3、编写实体Bean
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@Entity
@Table (name= "book" )
public class Book {
@Id
@GeneratedValue (strategy = GenerationType.IDENTITY)
@Column (name = "id" , updatable = false )
private Long id;
@Column (nullable = false ,name = "name" )
private String name;
@Column (nullable = false ,name = "isbn" )
private String isbn;
@Column (nullable = false ,name = "author" )
private String author;
public Book (String name,String isbn,String author){
this .name = name;
this .isbn = isbn;
this .author = author;
}
public Book(){
}
//此处省去get、set方法
}
public class BookQuery {
private String name;
private String isbn;
private String author;
//此处省去get、set方法
}
|
4、编写Repository接口
1
|
2
3
4
|
@Repository ( "bookRepository" )
public interface BookRepository extends JpaRepository<Book,Long>
,JpaSpecificationExecutor<Book> {
}
|
此处继承了两个接口,后续会介绍为何会继承这两个接口
5、抽象service层
首先抽象出接口
1
|
2
3
4
|
public interface BookQueryService {
Page<Book> findBookNoCriteria(Integer page,Integer size);
Page<Book> findBookCriteria(Integer page,Integer size,BookQuery bookQuery);
}
|
实现接口
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
@Service (value= " https://my.oschina.net/wangxincj/blog/bookQueryService " )
public class BookQueryServiceImpl implements BookQueryService {
@Resource
BookRepository bookRepository;
@Override
public Page<Book> findBookNoCriteria(Integer page,Integer size) {
Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id" );
return bookRepository.findAll(pageable);
}
@Override
public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {
Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id" );
Page<Book> bookPage = bookRepository.findAll( new Specification<Book>(){
@Override
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<Predicate>();
if ( null !=bookQuery.getName()&&! "" .equals(bookQuery.getName())){
list.add(criteriaBuilder.equal(root.get( "name" ).as(String. class ), bookQuery.getName()));
}
if ( null !=bookQuery.getIsbn()&&! "" .equals(bookQuery.getIsbn())){
list.add(criteriaBuilder.equal(root.get( "isbn" ).as(String. class ), bookQuery.getIsbn()));
}
if ( null !=bookQuery.getAuthor()&&! "" .equals(bookQuery.getAuthor())){
list.add(criteriaBuilder.equal(root.get( "author" ).as(String. class ), bookQuery.getAuthor()));
}
Predicate[] p = new Predicate[list.size()];
return criteriaBuilder.and(list.toArray(p));
}
},pageable);
return bookPage;
}
}
|
此处我定义了两个接口,findBookNoCriteria是不带查询条件的,findBookCriteria是带查询条件的。在此处介绍一下上面提到的自定义Repository继承的两个接口,如果你的查询列表是没有查询条件,只是列表展示和分页,只需继承JpaRepository接口即可,但是如果你的查询列表是带有多个查询条件的话则需要继承JpaSpecificationExecutor接口,这个接口里面定义的多条件查询的方法。当然不管继承哪个接口,当你做分页查询时,都是需要调用findAll方法的,这个方法是jap定义好的分页查询方法。
findBookCriteria方法也可以使用以下方法实现,大家可以自行选择
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Override
public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {
Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id" );
Page<Book> bookPage = bookRepository.findAll( new Specification<Book>(){
@Override
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate p1 = criteriaBuilder.equal(root.get( "name" ).as(String. class ), bookQuery.getName());
Predicate p2 = criteriaBuilder.equal(root.get( "isbn" ).as(String. class ), bookQuery.getIsbn());
Predicate p3 = criteriaBuilder.equal(root.get( "author" ).as(String. class ), bookQuery.getAuthor());
query.where(criteriaBuilder.and(p1,p2,p3));
return query.getRestriction();
}
},pageable);
return bookPage;
}
|
6、编写Controller
针对有查询条件和无查询条件,我们分别编写一个Controller,默认每页显示5条,如下
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Controller
@RequestMapping (value = " https://my.oschina.net/queryBook " )
public class BookController {
@Autowired
BookQueryService bookQueryService;
@RequestMapping ( "/findBookNoQuery" )
public String findBookNoQuery(ModelMap modelMap, @RequestParam (value = " https://my.oschina.net/wangxincj/blog/page " , defaultValue = " https://my.oschina.net/wangxincj/blog/0 " ) Integer page,
@RequestParam (value = " https://my.oschina.net/wangxincj/blog/size " , defaultValue = " https://my.oschina.net/wangxincj/blog/5 " ) Integer size){
Page<Book> datas = bookQueryService.findBookNoCriteria(page, size);
modelMap.addAttribute( "datas" , datas);
return "index1" ;
}
@RequestMapping (value = " https://my.oschina.net/findBookQuery " ,method = {RequestMethod.GET,RequestMethod.POST})
public String findBookQuery(ModelMap modelMap, @RequestParam (value = " https://my.oschina.net/wangxincj/blog/page " , defaultValue = " https://my.oschina.net/wangxincj/blog/0 " ) Integer page,
@RequestParam (value = " https://my.oschina.net/wangxincj/blog/size " , defaultValue = " https://my.oschina.net/wangxincj/blog/5 " ) Integer size, BookQuery bookQuery){
Page<Book> datas = bookQueryService.findBookCriteria(page, size,bookQuery);
modelMap.addAttribute( "datas" , datas);
return "index2" ;
}
}
|
7、编写页面
首先我们编写一个通用的分页页面,新建一个叫page.html的页面
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<!DOCTYPE html>
<html xmlns= " http://www.w3.org/1999/xhtml "
xmlns:th= " http://www.thymeleaf.org "
xmlns:layout= " http://www.ultraq.net.nz/thymeleaf/layout "
layout:decorator= "page" >
<body>
<div th:fragment= "pager" >
<div class = "text-right" th:with= "baseUrl=${#httpServletRequest.getRequestURL().toString()},pars=${#httpServletRequest.getQueryString() eq null ? '' : new String(#httpServletRequest.getQueryString().getBytes('iso8859-1'), 'UTF-8')}" >
<ul style= "margin:0px;" class = "pagination" th:with="newPar=${ new Java.lang.String(pars eq null ? '' : pars).replace( 'page=' +(datas.number), '' )},
curTmpUrl=${baseUrl+ '?' +newPar},
curUrl=${curTmpUrl.endsWith( '&' ) ? curTmpUrl.substring( 0 , curTmpUrl.length()- 1 ):curTmpUrl}" >
<!--<li th:text= "${pars}" ></li>-->
<li><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=0)}" rel= "external nofollow" >首页</a></li>
<li th: if = "${datas.hasPrevious()}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number-1})}" rel= "external nofollow" >上一页</a></li>
<!--总页数小于等于 10 -->
<div th: if = "${(datas.totalPages le 10) and (datas.totalPages gt 0)}" th:remove= "tag" >
<div th:each= "pg : ${#numbers.sequence(0, datas.totalPages - 1)}" th:remove= "tag" >
<span th: if = "${pg eq datas.getNumber()}" th:remove= "tag" >
<li class = "active" ><span class = "current_page line_height" th:text= "${pg+1}" >${pageNumber}</span></li>
</span>
<span th:unless= "${pg eq datas.getNumber()}" th:remove= "tag" >
<li><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${pg})}" rel= "external nofollow" th:text= "${pg+1}" ></a></li>
</span>
</div>
</div>
<!-- 总数数大于 10 时 -->
<div th: if = "${datas.totalPages gt 10}" th:remove= "tag" >
<li th: if = "${datas.number-2 ge 0}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number}-2)}" rel= "external nofollow" th:text= "${datas.number-1}" ></a></li>
<li th: if = "${datas.number-1 ge 0}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number}-1)}" rel= "external nofollow" th:text= "${datas.number}" ></a></li>
<li class = "active" ><span class = "current_page line_height" th:text= "${datas.number+1}" ></span></li>
<li th: if = "${datas.number+1 lt datas.totalPages}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number}+1)}" rel= "external nofollow" th:text= "${datas.number+2}" ></a></li>
<li th: if = "${datas.number+2 lt datas.totalPages}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number}+2)}" rel= "external nofollow" th:text= "${datas.number+3}" ></a></li>
</div>
<li th: if = "${datas.hasNext()}" ><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.number+1})}" rel= "external nofollow" >下一页</a></li>
<!--<li><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/@ {${curUrl}(page=${datas.totalPages-1})}" rel= "external nofollow" >尾页</a></li>-->
<li><a href= " https://my.oschina.net/wangxincj/blog/ #" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" th:href= " https://my.oschina.net/wangxincj/blog/ ${datas.totalPages le 0 ? curUrl+'page=0':curUrl+'&page='+(datas.totalPages-1)}" rel= "external nofollow" >尾页</a></li>
<li><span th:utext= "'共'+${datas.totalPages}+'页 / '+${datas.totalElements}+' 条'" ></span></li>
</ul>
</div>
</div>
</body>
</html>
|
针对无查询条件的接口,创建一个名为index1.html的页面并引入之前写好的分页页面,如下
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<!DOCTYPE html>
<html lang= "en" xmlns:th= " http://www.w3.org/1999/xhtml " >
<head>
<meta charset= "UTF-8" />
<title>Title</title>
<script type= "text/javascript" th:src= " https://my.oschina.net/wangxincj/blog/@ {/jquery-1.12.3.min.js}" ></script>
<script type= "text/javascript" th:src= " https://my.oschina.net/wangxincj/blog/@ {/bootstrap/js/bootstrap.min.js}" ></script>
<link type= "text/css" rel= "stylesheet" th:href= " https://my.oschina.net/wangxincj/blog/@ {/bootstrap/css/bootstrap-theme.min.css}" rel= "external nofollow" rel= "external nofollow" />
<link type= "text/css" rel= "stylesheet" th:href= " https://my.oschina.net/wangxincj/blog/@ {/bootstrap/css/bootstrap.css}" rel= "external nofollow" rel= "external nofollow" />
</head>
<body>
<table class = "table table-hover" >
<thead>
<tr>
<th>ID</th>
<th>name</th>
<th>isbn</th>
<th>author</th>
</tr>
</thead>
<tbody>
<tr th:each= "obj : ${datas}" >
<td th:text= "${obj.id}" >${obj.id}</td>
<td th:text= "${obj.name}" >${obj.name}</td>
<td th:text= "${obj.isbn}" >${obj.isbn}</td>
<td th:text= "${obj.name}" >${obj.author}</td>
</tr>
</tbody>
</table>
<div th:include= "page :: pager" th:remove= "tag" ></div>
</body>
</html>
|
针对有查询条件的接口,创建一个名为index2.html的页面并引入之前写好的分页页面,如下
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
<!DOCTYPE html>
<html lang= "en" xmlns:th= " http://www.w3.org/1999/xhtml " >
<head>
<meta charset= "UTF-8" />
<title>Title</title>
<script type= "text/javascript" th:src= " https://my.oschina.net/wangxincj/blog/@ {/jquery-1.12.3.min.js}" ></script>
<script type= "text/javascript" th:src= " https://my.oschina.net/wangxincj/blog/@ {/bootstrap/js/bootstrap.min.js}" ></script>
<link type= "text/css" rel= "stylesheet" th:href= " https://my.oschina.net/wangxincj/blog/@ {/bootstrap/css/bootstrap-theme.min.css}" rel= "external nofollow" rel= "external nofollow" />
<link type= "text/css" rel= "stylesheet" th:href= "https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap.css}" rel= "external nofollow" rel= "external nofollow" />
</head>
<body>
<form th:action= "@{/queryBook/findBookQuery}" th:object= "${bookQuery}" th:method= "get" >
<div class = "form-group" >
<label class = "col-sm-2 control-label" >name</label>
<div class = "col-sm-4" >
<input type= "text" class = "form-control" id= "name" placeholder= "请输入名称" th:field= "*{name}" />
</div>
<label class = "col-sm-2 control-label" >isbn</label>
<div class = "col-sm-4" >
<input type= "text" class = "form-control" id= "isbn" placeholder= "请输ISBN" th:field= "*{isbn}" />
</div>
</div>
<div class = "form-group" >
<label class = "col-sm-2 control-label" >author</label>
<div class = "col-sm-4" >
<input type= "text" class = "form-control" id= "author" placeholder= "请输author" th:field= "*{author}" />
</div>
<div class = "col-sm-4" >
<button class = "btn btn-default" type= "submit" placeholder= "查询" >查询</button>
</div>
</div>
</form>
<table class = "table table-hover" >
<thead>
<tr>
<th>ID</th>
<th>name</th>
<th>isbn</th>
<th>author</th>
</tr>
</thead>
<tbody>
<tr th:each= "obj : ${datas}" >
<td th:text= "${obj.id}" >${obj.id}</td>
<td th:text= "${obj.name}" >${obj.name}</td>
<td th:text= "${obj.isbn}" >${obj.isbn}</td>
<td th:text= "${obj.name}" >${obj.author}</td>
</tr>
</tbody>
</table>
<div th:include= "page :: pager" th:remove= "tag" ></div>
</body>
</html>
|
ok!代码都已经完成,我们将项目启动起来,看一下效果。大家可以往数据库中批量插入一些数据,访问
http://localhost:8080/queryBook/findBookNoQuery,显示如下页面
访问http://localhost:8080/queryBook/findBookQuery,显示页面如下,可以输入查询条件进行带条件的分页查询:
总结
以上所述是小编给大家介绍的在Spring Boot中使用Spring-data-jpa实现分页查询,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:http://blog.csdn.net/zhengxiangwen/article/details/63815551