SpringData JPA之增删改查操作
SpringData JPA
1、SpringData JPA简介
SpringData JPA是Spring Data家族的一个成员,是SpringData对JPA 封装之后的产物,目的在于简化基于JPA的数据访问技术。使用SpringData JPA技术之后,开发者只需要声明Dao层的接口,不必再写实现类或其它代码,剩下的一切交给SpringData JPA来搞定。
2、SpringData JPA入门
2.1 目标
搭建SpringData JPA环境,并实现一条数据的增删改查。
2.2 准备数据环境
下面的操作让JPA自动生成表结构
2.3 创建java工程,导入坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.9</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>jpaTest1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jpaTest1</name>
<description>jpaTest1</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--JPA相关库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--thymeleaf相关库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--启动库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--devtools插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--mysql插件-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombook插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.4 创建实体类
package com.example.jpaTest1.domain;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
//表示这是一个实体类
@Entity
//使用注解建立实体类和数据表之间的关系
//@Table建立了实体类和数据表的关系 name指向表名
@Table(name = "article")
@Data
public class Article implements Serializable {
/*对照的数据库表
CREATE TABLE 'article'(
'aid' int(11) NOT NULL auto_increment COMMENT '主键',
'author' varchar(255) default NULL COMMENT '作者',
'create_time' datetime default NULL COMMENT '创建时间',
'title' varchar(255) default NULL COMMENT '标题',
PRIMARY KEY ('aid')
);
*/
//标识这是主键字段
@Id
//指定主键生成策略,GenerationType.IDENTITY就是对应到mysql中的数据自增策略
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
//使用@Column映射类的属性和数据表的字段关系 name指定表中的字段名
//当类的属性名和数据表的字段名一致时,此注解可以省略
private String author;
private Date createTime;
private String title;
}
2.5 编写dao接口
使用Spring Data JPA 操作数据库,只需要按照框架的规范提供dao接口,不需要提供在接口中定义方法,也不需要为接口提供实现类就能完成基本的数据库的增删改查等功能。
(1)创建一个Dao层接口,并实现JpaRepository 和 JpaSpecificationExecutor
(2)提供相应的泛型
Dao层接口
package com.example.jpaTest1.dao;
import com.example.jpaTest1.domain.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
//自定义接口需要继承JpaRepository<实体类的类型,实体类中的主键的类型>, JpaSpecificationExecutor<实体类的类型>
@Repository
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
}
测试类
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@SpringBootTest
class JpaTest1ApplicationTests {
@Autowired
private ArticleDao articleDao;
//保存
@Test
public void testSave(){
Article article = new Article();
article.setTitle("熊大");
article.setAuthor("熊凯瑞");
article.setCreateTime(new Date());
articleDao.save(article);
}
//查询主键
@Test
public void testFindByAid(){
Optional<Article> optional = articleDao.findById(1);
System.out.println(optional.get());
}
//查询所有
@Test
public void testFindAll(){
List<Article> articles = articleDao.findAll();
for(Article article : articles){
System.out.println(article);
}
}
//修改
@Test
public void testUpdate(){
Article article = new Article();
article.setAuthor("熊破虏");
article.setAid(2);
//springdata Jpa的保存和修改使用的都是save方法
//关键来看传入的实体是否有主键
//---如果有主键,代表要修改
//---如果没有主键,代表要保存
articleDao.save(article);
}
//删除方法
@Test
public void testDelete(){
articleDao.deleteById(2);
}
}
2.6 SpringDataJpa原理分析之常见接口
Repository (标记接口、做标记、Repository接口的子接口的实现类对象可以自动被SpringIOC容器所识别,此接口的子接口中可以定义一些指定规范的方法)
||
CrudRepository (定义了一些基本的CRUD方法)
||
PagingAndSortingRepository (定义了排序和分页相关的查询方法)
||
JpaRepository (重写了一些基本测CRUD方法)
||
ArticleDao (自己定义的接口)
3、SpringData Jpa保存删除操作
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@SpringBootTest
public class SpringDataJpaCUDTest {
@Autowired
private ArticleDao articleDao;
//保存
@Test
public void testSave(){
Article article = new Article();
article.setTitle("熊二");
article.setAuthor("熊凯瑞");
article.setCreateTime(new Date());
//保存一个实体
articleDao.save(article);
//保存一个实体,并且立即刷新
articleDao.saveAndFlush(article);
}
//保存多个
@Test
public void testSaveAll(){
Article article1 = new Article();
article1.setTitle("张三");
article1.setAuthor("春田花花幼儿园1");
article1.setCreateTime(new Date());
Article article2 = new Article();
article2.setTitle("李四");
article2.setAuthor("春田花花幼儿园2");
article2.setCreateTime(new Date());
Article article3 = new Article();
article3.setTitle("王老五");
article3.setAuthor("春田花花幼儿园3");
article3.setCreateTime(new Date());
List list = new ArrayList();
list.add(article1);
list.add(article2);
list.add(article3);
//保存多个实体
articleDao.saveAll(list);
}
//删除
@Test
public void testDeleteOne(){
//1、根据主键删除
articleDao.deleteById(13);
//2、根据实体删除,但这个实体必须要有主键
Article article = new Article();
article.setAid(13);
articleDao.delete(article);
}
//删除
@Test
public void testDeleteAll(){
//1、删除所有 先查询--再一条条地删除
articleDao.deleteAll();
//2、删除所有 一下子删除所有记录
articleDao.deleteAllInBatch();
Article article1 = new Article();
article1.setAid(19);
Article article2 = new Article();
article2.setAid(20);
List list = new ArrayList();
list.add(article1);
list.add(article2);
//批量删除指定数据 一条语句搞定
articleDao.deleteInBatch(list);
//先一条条地查,然后一条条地删除
articleDao.deleteAll(list);
}
}
4、SpringDataJpa查询方式
4.1 父接口方法查询
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@SpringBootTest
public class Query1Test {
@Autowired
private ArticleDao articleDao;
//根据主键查询
@Test
public void testFindById() {
//根据一个主键查询
Optional<Article> optional = articleDao.findById(11);
System.out.println(optional.get());
//根据多个主键查询
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(11);
list.add(12);
List<Article> articles = articleDao.findAllById(list);
for (Article article : articles) {
System.out.println(article);
}
}
//查询所有
@Test
public void testFindAll() {
List<Article> articles = articleDao.findAll();
for (Article article : articles) {
System.out.println(article);
}
}
//查询所有---排序
@Test
public void testFindAllWithSort() {
//按照aid倒序排列
Sort sort = Sort.by(Sort.Order.desc("aid"));
List<Article> articles = articleDao.findAll(sort);
for (Article article : articles) {
System.out.println(article);
}
}
//查询所有--分页--排序
@Test
public void testFindAllWithPage() {
//按照aid倒序排列
Sort sort = Sort.by(Sort.Order.desc("aid"));
//处理分页条件
//page 当前是第几页 size 每页大小
Pageable pageable = PageRequest.of(1, 2, sort);
Page<Article> page = articleDao.findAll(pageable);
//总记录数 总页数 每页多少
System.out.println("总记录数" + page.getTotalElements());
System.out.println("总页数" + page.getTotalPages());
System.out.println("每页多少" + page.getSize());
//当前页的元素
List<Article> content = page.getContent();
for (Article article : content) {
System.out.println(article);
}
}
}
4.2 方法命名规则查询
4.2.1 定义
根据方法的名字,创建查询。SpringData JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询。
4.2.2 注意
按照SpringData JPA定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,首先条件属性首字母需大写,框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩余部分进行解析。
4.2.3 代码示例
(1)Dao类
package com.example.jpaTest1.dao;
import com.example.jpaTest1.domain.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
//自定义接口需要继承JpaRepository<实体类的类型,实体类中的主键的类型>, JpaSpecificationExecutor<实体类的类型>
@Repository
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//根据标题查询
List<Article> findByTitle(String title);
//根据标题模糊查询
List<Article> findByTitleLike(String title);
//根据标题和作者查询
List<Article> findByTitleAndAuthor(String title, String author);
//根据ID范围查询
List<Article> findByAidIsLessThan(Integer aid);
List<Article> findByAidBetween(Integer startAid, Integer endAid);
List<Article> findByAidIn(List<Integer> aids);
//根据创建时间之后查询
List<Article> findByCreateTimeAfter(Date createTime);
}
(2)测试类
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@SpringBootTest
public class Query2Test {
@Autowired
private ArticleDao articleDao;
//根据标题查询
@Test
public void testFindByTitle() {
List<Article> articles = articleDao.findByTitle("李四");
for (Article article : articles) {
System.out.println(article);
}
}
//根据标题进行模糊查询
@Test
public void testFindByTitleLike() {
List<Article> articles = articleDao.findByTitleLike("%张%");
for (Article article : articles) {
System.out.println(article);
}
}
//根据标题和作者查询
@Test
public void testFindByTitleAndAuthor() {
List<Article> articles = articleDao.findByTitleAndAuthor("熊凯瑞", "玛莎拉");
for (Article article : articles) {
System.out.println(article);
}
}
//根据Aid范围查询
@Test
public void testFindByAidIsLessThan() {
List<Article> articles = articleDao.findByAidIsLessThan(21);
for (Article article : articles) {
System.out.println(article);
}
}
@Test
public void testFindByAidBetween() {
List<Article> articles = articleDao.findByAidBetween(5, 15);
for (Article article : articles) {
System.out.println(article);
}
}
@Test
public void testFindByAidIn() {
ArrayList<Integer> list = new ArrayList<>();
list.add(11);
list.add(12);
List<Article> articles = articleDao.findByAidIn(list);
for (Article article : articles) {
System.out.println(article);
}
}
//根据当前时间之后取值
@Test
public void testFindByCreateTimeAfter() {
List<Article> articles = articleDao.findByCreateTimeAfter(new Date());
for (Article article : articles) {
System.out.println(article);
}
}
}
4.3 JPQL查询
4.3.1 定义
JPQL,全称是JAVA 持久化查询语言,JPQL语句是JPA中定义的一种查询语言,此种语言的用意是让开发者忽略数据库表和表中的字段,而关注实体类及实体类中的属性。写法十分类似于SQL语句的写法,但是要把查询的表名换成实体类的名称,把表中的字段名换成实体类的属性名称。也就是说要使用实体类名代替表名,使用属性名代替字段名[面向对象查询]
4.3.2 代码示例
(1)Dao类
package com.example.jpaTest1.dao;
import com.example.jpaTest1.domain.Article;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
//自定义接口需要继承JpaRepository<实体类的类型,实体类中的主键的类型>, JpaSpecificationExecutor<实体类的类型>
@Repository
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//JPQL:类似于SQL语句,但是要使用实体类名代替表名,使用属性名代替字段名[面向对象查询]
//展示位置参数绑定[按照title和author查询]
//占位符从1开始
@Query("from Article a where a.title = ?1 and a.author = ?2 ")
List<Article> findByCondition1(String title, String author);
//展示名字参数绑定
@Query("from Article a where a.title = :title and a.author = :authors ")
List<Article> findByCondition2(@Param("title") String title, @Param("authors") String author);
//展示like模糊查询
@Query("from Article a where a.title like %:title%")
List<Article> findByCondition3(@Param("title") String title);
//展示排序查询
@Query("from Article a where a.title like %:title% order by a.aid desc")
List<Article> findByCondition4(@Param("title") String title);
//展示分页查询
@Query("from Article a where a.title like %:title%")
List<Article> findByCondition5(Pageable pageable , @Param("title") String title);
//展示传入集合参数查询
@Query("from Article a where a.aid in :aids ")
List<Article> findByCondition6(@Param("aids") List<Integer> aids);
//展示传入Bean进行查询(SPEL表达式查询)
@Query("from Article a where a.title = :#{#article.title} and a.author = :#{#article.author} ")
List<Article> findByCondition7(@Param("article") Article article);
}
(2)测试类
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@SpringBootTest
public class Query3Test {
@Autowired
private ArticleDao articleDao;
//展示位置参数绑定
@Test
public void testFindByCondition1() {
List<Article> articles = articleDao.findByCondition1("熊凯瑞","玛莎拉");
for (Article article : articles) {
System.out.println(article);
}
}
//展示名字参数绑定
@Test
public void testFindByCondition2() {
List<Article> articles = articleDao.findByCondition2("熊凯瑞","玛莎拉");
for (Article article : articles) {
System.out.println(article);
}
}
//展示like模糊查询
@Test
public void testFindByCondition3() {
List<Article> articles = articleDao.findByCondition3("熊");
for (Article article : articles) {
System.out.println(article);
}
}
//展示排序查询
@Test
public void testFindByCondition4() {
List<Article> articles = articleDao.findByCondition4("熊");
for (Article article : articles) {
System.out.println(article);
}
}
//展示分页查询
@Test
public void testFindByCondition5() {
Pageable pageable = PageRequest.of(0,3);
List<Article> articles = articleDao.findByCondition5( pageable ,"熊");
for (Article article : articles) {
System.out.println(article);
}
}
//展示传入集合参数查询
@Test
public void testFindByCondition6() {
List<Integer> list = new ArrayList<>();
list.add(11);
list.add(12);
List<Article> articles = articleDao.findByCondition6( list);
for (Article article : articles) {
System.out.println(article);
}
}
//展示传入Bean进行查询(SPEL表达式查询)
@Test
public void testFindByCondition7() {
Article articleParam = new Article();
articleParam.setTitle("李四");
articleParam.setAuthor("春田花花幼儿园2");
List<Article> articles = articleDao.findByCondition7(articleParam);
for (Article article : articles) {
System.out.println(article);
}
}
}
4.4 本地SQL查询
4.4.1 定义
nativeQuery = true 表示使用本地SQL查询
基本不会使用,除非是出现非常复杂的业务情况导致SQL非常复杂,JPQL搞不定的时候
(1)Dao类
package com.example.jpaTest1.dao;
import com.example.jpaTest1.domain.Article;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
//自定义接口需要继承JpaRepository<实体类的类型,实体类中的主键的类型>, JpaSpecificationExecutor<实体类的类型>
@Repository
public interface ArticleDao extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
//本地SQL查询
@Query(value = "select * from article a where a.title = ?1 and a.author = ?2", nativeQuery = true)
List<Article> findByCondition8(String title, String author);
}
(2)测试类
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@SpringBootTest
public class Query3Test {
@Autowired
private ArticleDao articleDao;
//本地SQL查询
@Test
public void testFindByCondition8() {
List<Article> articles = articleDao.findByCondition8("熊凯瑞","玛莎拉");
for (Article article : articles) {
System.out.println(article);
}
}
}
4.5 Specifications动态查询
4.5.1 定义
有时在查询的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在SpringData JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加地面向对象。
4.5.2 测试类代码
package com.example.jpaTest1;
import com.example.jpaTest1.dao.ArticleDao;
import com.example.jpaTest1.domain.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.thymeleaf.util.StringUtils;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
public class Query4Test {
@Autowired
private ArticleDao articleDao;
//动态SQL查询
//按照标题和作者进行查询,以不为空的属性作为查询条件
@Test
public void testFindAll(){
//模拟从外边传入的变量
String title = "";
String author = "";
List<Article> articles = articleDao.findAll(new Specification<Article>() {
/**
*
* @param root 代表实体对象,可以通过它获取属性值
* @param cq 用于生成SQL语句
* @param cb 用于拼接查询条件
* @return
*/
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if(!StringUtils.isEmpty(title)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class),title);
list.add(predicate);
}
if(!StringUtils.isEmpty(author)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class),author);
list.add(predicate);
}
Predicate predicate = cb.and(list.toArray(new Predicate[]{}));
return predicate;
}
});
for (Article article : articles) {
System.out.println(article);
}
}
//动态SQL查询+分页查询
@Test
public void testFindAllWithPage(){
//模拟从外边传入的变量
String title = "";
String author = "";
//分页
Pageable pageable = PageRequest.of(0,3);
Page<Article> page = articleDao.findAll(new Specification<Article>() {
/**
*
* @param root 代表实体对象,可以通过它获取属性值
* @param cq 用于生成SQL语句
* @param cb 用于拼接查询条件
* @return
*/
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if(!StringUtils.isEmpty(title)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class),title);
list.add(predicate);
}
if(!StringUtils.isEmpty(author)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class),author);
list.add(predicate);
}
Predicate predicate = cb.and(list.toArray(new Predicate[]{}));
return predicate;
}
}, pageable);
for (Article article : page.getContent()) {
System.out.println(article);
}
}
//动态SQL查询+分页查询+排序(倒序)
@Test
public void testFindAllWithPageAndSort(){
//模拟从外边传入的变量
String title = "";
String author = "";
//分页
Pageable pageable = PageRequest.of(0,3, Sort.by(Sort.Order.desc("aid")));
Page<Article> page = articleDao.findAll(new Specification<Article>() {
/**
*
* @param root 代表实体对象,可以通过它获取属性值
* @param cq 用于生成SQL语句
* @param cb 用于拼接查询条件
* @return
*/
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if(!StringUtils.isEmpty(title)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("title").as(String.class),title);
list.add(predicate);
}
if(!StringUtils.isEmpty(author)){
//拼接作为查询条件
Predicate predicate = cb.equal(root.get("author").as(String.class),author);
list.add(predicate);
}
Predicate predicate = cb.and(list.toArray(new Predicate[]{}));
return predicate;
}
}, pageable);
for (Article article : page.getContent()) {
System.out.println(article);
}
}
}