目录结构:

package com.frank.leftJoinQuery.entity;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.persistence.*;/*** @author 小石潭记* @date 2020/12/12 18:32* @Description: ${todo} B表*/
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "t_student")
public class Student {@Idprivate Long id;private String name;private String address;private String accountNumber;private String grade;// 同时在B表里添加A表记录的id  默认A表名 + "_id"// 这里感觉就是 Teacher 小写teacher  + "_id"// private Teacher teacher; 应该是根据这里的teacher来的 @OneToMany(mappedBy="teacher")// @JsonIgnoreProperties("teacher")  这里的teacher名字需要保持一致@Column(name = "teacher_id", insertable = false, updatable = false)private Long teacherId;@ManyToOne@JsonIgnoreProperties("studentList") //该注解可防止json转换进入死循环private Teacher teacher;
}
package com.frank.leftJoinQuery.entity;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.persistence.*;
import java.util.List;/*** @author 小石潭记* @date 2020/12/12 18:36* @Description: ${todo} A表*/
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "t_teacher")
public class Teacher {@Id@GeneratedValueprivate Long id;private String name;private String address;private String accountNumber;@OneToMany(mappedBy="teacher")@JsonIgnoreProperties("teacher")  //该注解可防止json转换进入死循环private List<Student> studentList;
}
package com.frank.leftJoinQuery.repository;import com.frank.leftJoinQuery.entity.Teacher;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Component;/*** @author 小石潭记* @date 2020/12/12 14:21* @Description: ${todo}*/
@Component
public interface Teacher1Repository extends PagingAndSortingRepository<Teacher, Integer>, JpaSpecificationExecutor<Teacher> {
}
package com.frank.leftJoinQuery.repository;import com.frank.leftJoinQuery.entity.Student;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Component;/*** @author 小石潭记* @date 2020/12/12 14:21* @Description: ${todo}*/
@Component
public interface TStudent1Repository extends PagingAndSortingRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
}
package com.frank.leftJoinQuery.specification;import com.frank.leftJoinQuery.domain.StudentRequest;
import com.frank.leftJoinQuery.entity.Student;
import com.frank.leftJoinQuery.entity.Teacher;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;/*** @author 小石潭记* @date 2020/12/12 14:27* @Description: ${todo}*/
@Component
public class Student1Specification {/*** root 就是mobile实例  root.get("name") name是属性名 不是数据库字段名* @param* @return* */public Specification<Student> getStudentSpecification(StudentRequest request) {return (root, criteriaQuery, criteriaBuilder) -> {List<Predicate> predicateList = new ArrayList<>();// 主表老师的筛选生效的// 筛选教师名字if (StringUtils.isNotBlank(request.getName())) {Predicate teacherPre = criteriaBuilder.equal(root.get("name"), request.getName());predicateList.add(teacherPre);}// 筛选账户号if (StringUtils.isNotBlank(request.getAccountNumber())) {Predicate teacherPre = criteriaBuilder.equal(root.get("accountNumber"), request.getAccountNumber());predicateList.add(teacherPre);}// 使用左连接查询  注意这里的teacher不能乱起名字的Join<Student, Teacher> teacherJoin = root.join("teacher", JoinType.LEFT);// todo 关联表 学生表的筛选未生效if (StringUtils.isNotBlank(request.getAccountNumber())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("accountNumber"), request.getAccountNumber());predicateList.add(studentPre);}if (StringUtils.isNotBlank(request.getStudentName())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("name"), request.getStudentName());predicateList.add(studentPre);}if (StringUtils.isNotBlank(request.getGrade())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("grade"), request.getGrade());predicateList.add(studentPre);}return criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();};}}
package com.frank.leftJoinQuery.specification;import com.frank.leftJoinQuery.domain.StudentRequest;
import com.frank.leftJoinQuery.entity.Student;
import com.frank.leftJoinQuery.entity.Teacher;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;/*** @author 小石潭记* @date 2020/12/12 14:27* @Description: ${todo}*/
@Component
public class Teacher1Specification {/*** root 就是mobile实例  root.get("name") name是属性名 不是数据库字段名* @param* @return* */public Specification<Teacher> getTeacherSpecification(StudentRequest request) {return (root, criteriaQuery, criteriaBuilder) -> {List<Predicate> predicateList = new ArrayList<>();// 主表老师的筛选生效的// 筛选教师名字if (StringUtils.isNotBlank(request.getName())) {Predicate teacherPre = criteriaBuilder.equal(root.get("name"), request.getName());predicateList.add(teacherPre);}// 筛选账户号if (StringUtils.isNotBlank(request.getAccountNumber())) {Predicate teacherPre = criteriaBuilder.equal(root.get("accountNumber"), request.getAccountNumber());predicateList.add(teacherPre);}// 使用左连接查询  注意这里的teacher不能乱起名字的Join<Teacher, Student> teacherJoin = root.join("studentList", JoinType.LEFT);// todo 关联表 学生表的筛选未生效if (StringUtils.isNotBlank(request.getAccountNumber())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("accountNumber"), request.getAccountNumber());predicateList.add(studentPre);}if (StringUtils.isNotBlank(request.getStudentName())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("name"), request.getStudentName());predicateList.add(studentPre);}if (StringUtils.isNotBlank(request.getGrade())) {Predicate studentPre = criteriaBuilder.equal(teacherJoin.get("grade"), request.getGrade());predicateList.add(studentPre);}criteriaQuery.distinct(true);return criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();};}}
package com.frank.leftJoinQuery.domain;import lombok.Data;/*** @author 小石潭记* @date 2021/4/23 22:49* @Description: ${todo}*/
@Data
public class StudentRequest {private String name;private String accountNumber;private String studentName;private String grade;
}
package com.frank.leftJoinQuery.service;import com.frank.leftJoinQuery.domain.StudentRequest;
import com.frank.leftJoinQuery.entity.Student;
import com.frank.leftJoinQuery.entity.Teacher;
import com.frank.leftJoinQuery.repository.TStudent1Repository;
import com.frank.leftJoinQuery.repository.Teacher1Repository;
import com.frank.leftJoinQuery.specification.Student1Specification;
import com.frank.leftJoinQuery.specification.Teacher1Specification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;/*** @author 小石潭记* @date 2020/12/12 14:22* @Description: ${todo}*/
@Service
public class LeftJoinService {@Autowiredprivate TStudent1Repository studentRepository;@Autowiredprivate Teacher1Repository teacher1Repository;@Autowiredprivate Teacher1Specification teacher1Specification;@Autowiredprivate Student1Specification student1Specification;public Page<Student> getStudentList(StudentRequest request) {PageRequest pageRequest = PageRequest.of(0, 10);return studentRepository.findAll(student1Specification.getStudentSpecification(request), pageRequest);}public Page<Teacher> getTeacherList(StudentRequest request) {PageRequest pageRequest = PageRequest.of(0, 10);return teacher1Repository.findAll(teacher1Specification.getTeacherSpecification(request), pageRequest);}}
package com.frank.leftJoinQuery.controller;import com.frank.leftJoinQuery.domain.StudentRequest;
import com.frank.leftJoinQuery.entity.Student;
import com.frank.leftJoinQuery.entity.Teacher;
import com.frank.leftJoinQuery.service.LeftJoinService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author 小石潭记* @date 2020/12/12 19:02* @Description: ${todo}*/
@RestController
public class LeftJoinController {@Autowiredprivate LeftJoinService leftJoinService;@GetMapping("/student1")public Page<Student> getStudent(StudentRequest request) {return leftJoinService.getStudentList(request);}@GetMapping("/teacher1")public Page<Teacher> getTeacher(StudentRequest request) {return leftJoinService.getTeacherList(request);}}

测试:根据多的一方学生查询,每个学生对应一个老师

根据一对多来查询,每个老师对应多个学生

-- --------------------------------------------------------
-- 主机:                           127.0.0.1
-- 服务器版本:                        5.6.40 - MySQL Community Server (GPL)
-- 服务器操作系统:                      Win64
-- HeidiSQL 版本:                  8.2.0.4675
-- --------------------------------------------------------/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;-- 导出  表 test.t_student 结构
CREATE TABLE IF NOT EXISTS `t_student` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,`address` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,`account_number` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,`grade` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '等级',`teacher_id` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;-- 正在导出表  test.t_student 的数据:~5 rows (大约)
DELETE FROM `t_student`;
/*!40000 ALTER TABLE `t_student` DISABLE KEYS */;
INSERT INTO `t_student` (`id`, `name`, `address`, `account_number`, `grade`, `teacher_id`) VALUES(1, '陈同学', '重庆', '1001', 'A', 1),(2, '谭同学', '丰都', '1001', 'B', 1),(3, '文同学', '涪陵', '1002', 'A', 2),(4, '刘同学', '忠县', '1003', 'C', 3),(5, '肖同学', '万州', '1002', 'A', 2);
/*!40000 ALTER TABLE `t_student` ENABLE KEYS */;-- 导出  表 test.t_teacher 结构
CREATE TABLE IF NOT EXISTS `t_teacher` (`id` int(11) DEFAULT NULL,`name` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,`address` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL,`account_number` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;-- 正在导出表  test.t_teacher 的数据:~3 rows (大约)
DELETE FROM `t_teacher`;
/*!40000 ALTER TABLE `t_teacher` DISABLE KEYS */;
INSERT INTO `t_teacher` (`id`, `name`, `address`, `account_number`) VALUES(1, '小明老师', '四川', '1001'),(2, '小蓝老师', '重庆', '1002'),(3, '小花老师', '北京', '1003');
/*!40000 ALTER TABLE `t_teacher` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

参考文章:

https://blog.csdn.net/xpopi/article/details/83915533

https://blog.csdn.net/lyl614976970/article/details/92794120

public Specification<SwindleAccountEntity> getBlackSwindleAccountSpecification(SwindleBlackRequest request) {return (root, criteriaQuery, criteriaBuilder) -> {List<Predicate> predicateList = new ArrayList<>();predicateList = getBaseSwindleAccountPredicate(request, root, predicateList, criteriaBuilder);predicateList.add(criteriaBuilder.equal(root.get("blackListFlag"), true));String customerNumber = request.getCustomerNumber();if (StringUtils.isNotBlank(customerNumber)) {predicateList.add(criteriaBuilder.equal(root.get("customerNumber"), customerNumber));}// 查询有效期if (request.getPeriodValidityFlag() != null) {// 主表账户表Subquery<SwindleAccountEntity> subQuery = criteriaQuery.subquery(SwindleAccountEntity.class);// 副表事件表Root<SwindlePolicePushEntity> subRoot = subQuery.from(SwindlePolicePushEntity.class);if (request.getPeriodValidityFlag()) {// 这里是子查询的条件,前者是自身的条件,后者是主表的关联条件,当然where方法的参数是个可变参数,可以根据自己需要加条件subQuery.where(criteriaBuilder.greaterThan(subRoot.get("expirationDate").as(LocalDate.class), LocalDate.now()),criteriaBuilder.equal(subRoot.get("pushType"), PolicePushTypeEnum.BLACK_LIST.ordinal()),// 主表和副表相同的字段criteriaBuilder.equal(root.get("accountNumber"), subRoot.get("accountNumber")));} else {subQuery.where(criteriaBuilder.isNotNull(subRoot.get("expirationDate").as(LocalDate.class)),criteriaBuilder.equal(subRoot.get("pushType"), PolicePushTypeEnum.BLACK_LIST.ordinal()),criteriaBuilder.lessThanOrEqualTo(subRoot.get("expirationDate").as(LocalDate.class), LocalDate.now()),criteriaBuilder.equal(root.get("accountNumber"), subRoot.get("accountNumber")));}// 这句话不加会报错,因为他不知道你子查询要查出什么字段subQuery.select(subRoot.get("id"));predicateList.add(criteriaBuilder.exists(subQuery));}return criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();};}

Springboot使用Specification连表多条件查询(完整demo)相关推荐

  1. springDataJpa入门教程(5)-单表动态条件查询+分页

    springDataJpa入门教程 springDataJpa入门教程(1)-基于springBoot的基本增删改查 springDataJpa入门教程(2)-Specification动态条件查询+ ...

  2. jpa多表关联条件查询实现

    通过实体类映射实现多表关联条件查询 jpa对于多表关联可以在实体类中进行关联映射,一对一用@OneToOne,一对多用@OneToMany,多对多用@ManyToMany,多对一用@ManyToOne ...

  3. SpringBoot使用JPA多表关联动态查询指定字段

    SpringBoot使用JPA多表关联动态查询指定字段 目标需求 Maven依赖 项目结构 代码 运行结果 源码下载 目标需求 在SpringBoot中用JPA实现多表关联动态查询,并且只查询指定字段 ...

  4. mongotemplate 多表多条件查询记录

    mongotemplate 多表多条件查询记录 在这里插入代码片

  5. SAP ABAP 动态内表的条件查询(SORT / READ TABLE / LOOP)

    SAP ABAP 动态内表的条件查询(SORT / READ TABLE / LOOP) 简介: 动态内表是动态报表的核心,动态内表的条件操作能有效解决性能问题.这篇文章用于普及动态内表在 SORT ...

  6. Springboot使用Specification连表查询LEFT

    大致目录机构 package com.frank.leftQuery.entity;import lombok.AllArgsConstructor; import lombok.Data; impo ...

  7. Rails中多重子表多条件查询

    在项目创建时为了逻辑上的简单,采用了多级子表嵌套;而且底层子表大多是静态表,即没有用has_one或belongs_to作为相互关系的. 在某个对象的搜索涉及到3个底层子表中的字段的比较,很难用whe ...

  8. jpa多表联查动态_Spring Data JPA 连表动态条件查询

    多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现(使用较为复杂,查询不够灵活),第二种是使用原生sql查询. JPA原生SQL连表查询 @Rep ...

  9. jfinal-layui中如果sql是多表时条件查询写法

    一.如果是一个表 二.如果sql是两个表关联查询

最新文章

  1. 从MyEclipse到IntelliJ IDEA ——让你摆脱鼠标,全键盘操作
  2. 幼儿课外活动游戏_幼儿园户外游戏活动大全
  3. Android第三夜
  4. 16节课搞懂大数据,视频教程限时免费领取
  5. ant 改变表格数据_React ant design表格导出数据为EXCEL表格数据
  6. Java String类的intern()方法
  7. Ubuntu 16.04源码搭建ELK日志分析系统(Elasticsearch+Logstash+Kibana)
  8. 计算机点击右键管理闪退,Win7系统桌面鼠标右键菜单出现闪退解决方法
  9. ads1115应用电路及驱动程序
  10. 机器学习实战-手写识别系统
  11. Live Archive 6657
  12. 667应用题出题点预测
  13. 什么是fail safe IO
  14. 计算机主机核心通常包括,2017年计算机一级复习试题及答案解析
  15. 微社区成为社交电商法宝的原因是什么?
  16. Java SE疯狂涨价!甲骨文改按公司人头收费,用不用Java都要交钱,网友:慢性自杀
  17. 第一章 README
  18. 传统的不确定性量化数值方法
  19. 安卓开发-Android Studio界面介绍
  20. 我们来找茬外挂思路之一

热门文章

  1. ES6 - lterator
  2. maya批量操作mel_MAYA运行单个MEL命令方法图文介绍
  3. IBM V7000存储升级微码
  4. 辩证法三大规律和五大范畴
  5. 手机PUK码和PIN码知识及其查询方式
  6. python批量评论_手把手教你 Python挖掘用户评论典型意见并自动生产报告
  7. 2021 工业信息安全技能大赛 线上赛第一场--隐藏的工程
  8. 安装 - LNMP一键安装包
  9. 斯坦福机器学习笔记(三)—— 高斯判别分析
  10. SSM+老年人社区服务平台 毕业设计-附源码211711