Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便。但是Spring Data JPA框架功能更进一步,为我们做了一个数据持久层框架几乎能做的任何事情,本篇主要介绍其强大的条件查询功能。
本次我们采用基于Spring boot的形式讲解Spring Data JPA动态条件查询功能的使用。当前使用的是Spring boot 为2.1.1.RELEASE版本:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.1.RELEASEversion>
<relativePath/>
parent>
搭建完Spring boot项目框架之后,添加如下依赖即可:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
dependencies>
create table tb_label
(
id varchar(20) not null comment '标签ID'
primary key,
labelname varchar(100) null comment '标签名称',
state varchar(1) null comment '状态',
count bigint null comment '使用数量',
recommend varchar(1) null comment '是否推荐',
fans bigint null comment '粉丝数'
)
comment '标签';
执行以上sql脚本后,可以利用Idea强大的JPA映射转换功能生成POJO类:
package cn.lollipop.base.pojo;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
@Entity(name = "tb_label")
public class Label implements Serializable {
@Id
private String id;
private String labelname; //标签名称
private String state; //状态
private Long count; //使用数量
private Long fans; //关注数
setter、getter 略......
}
这里我们只用定义一个带有@Repository注解的接口,并继承JpaRepository和JpaSpecificationExecutor接口,不必写实现类,Spring boot在启动时,将会为我们自动生成实现类并在容器中管理接口对象。
package cn.lollipop.base.dao;
import cn.lollipop.base.pojo.Label;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface LabelDAO extends JpaRepository<Label, String>, JpaSpecificationExecutor<Label> {
}
在JpaRepository接口中传入我们的POJO类的类型和主键类型,在JpaSpecification接口中,我们传入POJO类的类型即可。
本次我们采用JpaSpecification接口提供的findAll(Predicate predicate);方法进行条件查询:
/**
* 根据条件查询全部标签
*
* @param label
* @return
*/
public List<Label> findSearch(Label label) {
return labelDAO.findAll(new Specification<>() {
/**
*
* @param root 根对象,也就是要把条件封装到哪个对象中
* @param criteriaQuery 封装查询关键字
* @param criteriaBuilder 封装条件对象
* @return
*/
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new ArrayList<>();
if (label.getLabelname() != null && !"".equals(label.getLabelname())) {
// where 数据库中labelname列 LIKE '%' + Label.labelname + '%'
predicates.add(criteriaBuilder.like(root.get("labelname"), "%" + label.getLabelname() + "%"));
}
if (label.getState() != null && !"".equals(label.getState())) {
// where 数据库中state列 = Label.state
predicates.add(criteriaBuilder.equal(root.get("state"), label.getState()));
}
Predicate[] pres = new Predicate[predicates.size()];
predicates.toArray(pres);
// and语句
return criteriaBuilder.and(pres);
}
});
}
@RestController
@CrossOrigin
@RequestMapping("/label")
public class LabelController {
private final LabelService labelService;
@Autowired
public LabelController(LabelService labelService) {
this.labelService = labelService;
}
}
@RequestMapping(value = "/search", method = RequestMethod.POST)
public Result findSearch(@RequestBody Label label) {
return new Result(StatusCode.OK, true, "查询成功", labelService.findSearch(label));
}