一、pom依赖
<!-- SpringBootweb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot测试类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!--SpringDataJPA-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
实体类
@Data
@Entity(name = "fastdfsfile")
public class Fastdfsfile {
@Id
private Integer id;
private String url;
private String name;
}
JPARepository
public interface FastdfsRespsitory extends JpaRepository<Fastdfsfile,Integer>, JpaSpecificationExecutor<Fastdfsfile> {
}
二、条件查询
service代码
/**
* JPA 条件搜索
* @param filename
* @return
*/
public List<Fastdfsfile> search(String filename) {
Specification<Fastdfsfile> Specification = new Specification<Fastdfsfile>() {
/**
* @param root 根对象 : 要把条件封装进哪个对象 目的是将条件封装对象
* @param criteriaQuery 封装查询的关键字:group by,order by等,其实无用!
* @param criteriaBuilder 封装条件对象的 目的是封装条件对象
* @return 如果直接返回null,表示不需要任何条件
*/
@Override
public Predicate toPredicate(Root<Fastdfsfile> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
/**
* like() 模糊查询
* equal() 直接查询
* ------------------------
* root.get("labelname").as(String.class)
* 从封装的条件对象中获得要查询的字段,该字段是String类型
* 参数2 : 具体查询的条件
* 即整体的结果就相当于是
* where labelname like "%张三%"
* ------------------------
* 如果还有需要查询的条件就再来一个criteriaBuilder.like(...);
* 但是该criteriaBuilder.like()返回值是Predicate对象,正是toPredicate的返回值
* 如果多个criteriaBuilderlike()就会返回多个Predicate对象,那该如何返回?
* -------------------------
* criteriaBuilder提供了and(Predicate... p)方法,该方法返回值是Predicate对象
* and()方法的参数是Predicate类型的数组,即有多少查询条件就可以使用criteriaBuilder得当多少
* Predicate对象,然后放入Predicate类型的数组,再放入and()返回.
* 但是不确定有多少查询条件啊?即不确定该Predicate类型的数组的长度啊?
* -------------------------
* 使用集合存储.集合存储所有criteriaBuilder得当的Predicate对象,然后获得集合长度,利用该长度
* 创建数组,然后将该集合中的值传入数组,然后将数组放入and(),最终返回
* -------------------------
* and() 就好比 where name like "%张三%" and age = 1
*/
List<Predicate> list = new ArrayList<>();
root.get("name").as(String.class);
if(filename != null && !"".equals(filename)) {
Predicate predicate = criteriaBuilder.like(root.get("name").as(String.class), "%" + filename + "%");
list.add(predicate);
}
Predicate[] predicates = list.toArray(new Predicate[list.size()]);
return criteriaBuilder.and(predicates);
}
};
List<Fastdfsfile> all = fastdfsRespsitory.findAll(Specification);
return all;
}
测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class JPATest {
@Autowired
FastdfsRespsitory respsitory;
@Autowired
FileService service;
@Test
public void test(){
List<Fastdfsfile> list = service.search("周杰伦");
list.forEach(System.out::println);
}
}
结果
注意: 与Thymeleaf交互
三、条件分页查询
service代码
/**
* JPA 条件+分页 查询
* @param searchname
* @param pageNum
* @param pegeSize
* @return
*
*/
public Page searchAndPage(String searchname, int pageNum, int pegeSize) {
// Pageable是接口,PageRequest是其子类
// jpa的第一页要设置为 0
Pageable pageable = PageRequest.of(pageNum-1,pegeSize);
Specification<Fastdfsfile> specification = new Specification<Fastdfsfile>() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
root.get("name").as(String.class);
if(searchname != null && !"".equals(searchname)) {
Predicate predicate = criteriaBuilder.like(root.get("name").as(String.class), "%" + searchname + "%");
list.add(predicate);
}
Predicate[] predicates = list.toArray(new Predicate[list.size()]);
return criteriaBuilder.and(predicates);
}
};
Page<Fastdfsfile> page = fastdfsRespsitory.findAll(specification, pageable);
return page;
}
页面代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>FastDFS文件服务器</title>
<!-- <link rel="stylesheet" href="../static/css/login.css">-->
<!-- <link rel="stylesheet" type="text/css" th:href="@{static/css/font-awesome.css}">-->
<link rel="stylesheet" href="../static/dist/css/bootstrap.css">
<link rel="stylesheet" href="../static/dist/css/bootstrap.min.css">
<link rel="stylesheet" th:href="@{../static/dist/js/bootstrap.min.js}">
</head>
<body>
<div class="jumbotron">
<h1>文件管理</h1>
<p>文件大小在10M以下,文件越大,速度越慢,请谅解...</p>
<!-- <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>-->
</div>
<!--<form th:action="@{/fastdfs/upload}" enctype="multipart/form-data" method="post" class="form-inline">-->
<!-- <input type="file" name="file" multiple="multiple">-->
<!-- <input type="submit" value="上传">-->
<!--</form>-->
<form class="navbar-form navbar-left" role="search" th:action="@{/fastdfs/upload}" enctype="multipart/form-data" method="post">
<div class="form-group">
<input type="file" class="form-control" name="file" >
</div>
<button type="submit" class="btn btn-default">Upload</button>
</form>
<form class="navbar-form navbar-left" role="search" th:action="@{/fastdfs/searchAndPage}" method="get">
<div class="form-group">
<input type="text" class="form-control" placeholder="文件名" name="searchname" th:value="${searchname}">
</div>
<button type="submit" class="btn btn-default">Search</button>
<a th:href="@{/fastdfs/searchAndPage}"><button type="button" class="btn btn-default">Clear</button></a>
</form>
<br><br>
<table class="table">
<tr>
<td>ID</td>
<td>文件名</td>
<td>URL</td>
<td>操作</td>
</tr>
<tr th:each="fastdfsfile : ${fastdfsfiles}">
<td th:text="${fastdfsfile.id}"> </td>
<td th:text="${fastdfsfile.name}"> </td>
<td th:text="${fastdfsfile.url}"> </td>
<td><a th:href="@{/fastdfs/look(furl=${fastdfsfile.url})}"><span class="glyphicon glyphicon-share-alt" aria-hidden="true"></span></a>
<a th:href="@{/fastdfs/download(fid=${fastdfsfile.url})}"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></a>
<a th:href="@{/fastdfs/delete(fid=${fastdfsfile.id},furl=${fastdfsfile.url})}"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></a></td>
</tr>
</table>
<nav aria-label="Page navigation" class="text-center">
<ul class="pagination pagination-lg">
<li aria-label="Previous">
<a th:href="'/fastdfs/searchAndPage?searchname='+${searchname}+'&pageNum=' + ${pageNo -1}" th:class="${pageNo}-1 le 0 ? 'btn btn-default btn-lg disabled':'' ">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
</li>
<li th:each=" pageNum:${#numbers.sequence(1,totalPages)}" >
<a th:href="'/fastdfs/searchAndPage?searchname='+${searchname}+'&pageNum=' + ${pageNum}" th:text="${pageNum}" th:if="${pageNum} ne ${pageNo}"></a>
<a th:href="'/fastdfs/searchAndPage?searchname='+${searchname}+'&pageNum=' + ${pageNum}" th:text="${pageNum}" th:if="${pageNum} eq ${pageNo}" th:style="'font-weight:bold;background: #84C1FF;'"></a>
</li>
<li aria-label="Next" >
<a th:href="@{/fastdfs/searchAndPage(searchname=${searchname},pageNum=${pageNo} + 1)}" th:class="${pageNo}+1 gt ${totalPages} ? 'btn btn-default btn-lg disabled':'' ">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</li>
</ul>
</nav>
<p th:text="当前页 + ${pageNo}"><p th:text="总页数 + ${totalPages}"><p th:text="总条数 + ${totalElements}">
</body>
</html>
测试:
BUG1
在使用Thymeleaf页面做分页的时候,上一页和下一页的时候
解决方法:
将+1放在大括号外 在相加