阅读全文,约 18 分钟
这是江帅帅的第013篇原创
案例4:Specification 查询
1)编辑 pom.xml 文件(与 CrudRepository 接口案例一样)
2)编辑 application.properties 文件(与 CrudRepository 接口案例一样)
3)创建 Clazz 和 Student 持久化类
先来看 Clazz 类。
@Entity @Table(name="tb_clazz") public class Clazz implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int code ; private String name ; // 班级与学生是一对多的关联 @OneToMany( fetch=FetchType.LAZY, targetEntity=Student.class, mappedBy="clazz" ) private Set<Student> students = new HashSet<>(); public Clazz() { } // 班级对象 public Clazz(String name) { this.name = name; } // setXxx 和 getXxx 方法 }
再来看看 Student 类。
@Entity @Table(name="tb_student") public class Student implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name ; private String address ; private int age ; private char sex; // 学生与班级是多对一的关系,这里配置的是双向关联 @ManyToOne(fetch=FetchType.LAZY, targetEntity=Clazz.class ) @JoinColumn(name="clazzId",referencedColumnName="code") private Clazz clazz ; public Student() { } public Student(String name, String address, int age, char sex, Clazz clazz) { super(); this.name = name; this.address = address; this.age = age; this.sex = sex; this.clazz = clazz; } // setXxx 和 getXxx 方法 }
4)创建 ClazzRepository 和 StudentRepository 数据访问接口
先看 ClazzRepository 类。
public interface ClazzRepository extends JpaRepository<Clazz, Integer> ,JpaSpecificationExecutor<Clazz>{ }
再看 StudentRepository 类。
public interface StudentRepository extends JpaRepository<Student,Integer>,JpaSpecificationExecutor<Student>{ }
5)创建 ShcoolService 业务层
@Service public class ShcoolService { // 注入数据访问层接口对象 @Resource private StudentRepository studentRepository; @Resource private ClazzRepository clazzRepository; @Transactional public void saveClazzAll(List<Clazz> clazzs) { clazzRepository.saveAll(clazzs); } @Transactional public void saveStudentAll(List<Student> students) { studentRepository.saveAll(students); } /** * 根据性别查询学生信息 */ @SuppressWarnings("serial") public List<Map<String, Object>> getStusBySex(char sex) { List<Student> students = studentRepository.findAll(new Specification<Student>() { @Override public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Predicate p1 = cb.equal(root.get("sex"), sex); return p1; } }); List<Map<String, Object>> results = new ArrayList<>(); for(Student student:students){ Map<String , Object> stu = new HashMap<>(); stu.put("name", student.getName()); stu.put("age", student.getAge()); stu.put("sex", student.getSex()); results.add(stu); } return results; } /** * 动态查询学生信息 * 可以根据学生对象的姓名(模糊匹配) * 地址查询(模糊匹配)、性别、班级查询学生信息 * 如果没有传输参数,默认查询所有的学生信息 */ @SuppressWarnings("serial") public List<Map<String, Object>> getStusByDynamic(Student student) { List<Student> students = studentRepository.findAll(new Specification<Student>() { @Override public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) { // 本集合用于封装查询条件 List<Predicate> predicates = new ArrayList<Predicate>(); if(student!=null){ /** 是否传入了姓名来查询 */ if(!StringUtils.isEmpty(student.getName())){ predicates.add(cb.like(root.<String> get("name"),"%" + student.getName() + "%")); } /** 是否传入了地址来查询 */ if(!StringUtils.isEmpty(student.getAddress())){ predicates.add(cb.like(root.<String> get("address"),"%" + student.getAddress() + "%")); } /** 是否传入了性别来查询 */ if(student.getSex() != '\0'){ predicates.add(cb.equal(root.<String> get("sex"),student.getSex())); } /** 判断是否传入了班级信息来查询 */ if(student.getClazz()!=null && !StringUtils.isEmpty(student.getClazz().getName())){ root.join("clazz", JoinType.INNER); Path<String> clazzName = root.get("clazz").get("name"); predicates.add(cb.equal(clazzName, student.getClazz().getName())); } } return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); } }); List<Map<String, Object>> results = new ArrayList<>(); for(Student stu :students){ Map<String , Object> stuMap = new HashMap<>(); stuMap.put("name", stu.getName()); stuMap.put("age", stu.getAge()); stuMap.put("sex", stu.getSex()); stuMap.put("address", stu.getAddress()); stuMap.put("clazzName", stu.getClazz().getName()); results.add(stuMap); } return results; } /** * 分页查询某个班级的学生信息 */ @SuppressWarnings("serial") public Page<Student> getStusByPage(String clazzName , int pageIndex , int pageSize ) { // 指定排序参数对象:根据id,进行降序查询 Sort sort = new Sort(Sort.Direction.DESC, "id"); // 分页查询学生信息,返回分页实体对象数据 // pages对象中包含了查询出来的数据信息,以及与分页相关的信息 Page<Student> pages = studentRepository.findAll(new Specification<Student>() { @Override public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) { root.join("clazz", JoinType.INNER); Path<String> cn = root.get("clazz").get("name"); Predicate p1 = cb.equal(cn, clazzName); return p1 ; } },PageRequest.of(pageIndex-1, pageSize, sort)); return pages; } }
6)创建分页对象
添加 nx.vo 文件夹,然后创建分页对象,具体如下:
public class PageData { // 定义一个变量用于存放当前页码 private int pageIndex; // 定义一个变量用于保存满足查询条件下用于分页的数据总量 private long totalCount ; // 定义一个变量用于保存当前条件下总共可以分的总页数 private int pageSize ; // 定义一个变量用于保存当前页码查询出的数据总量 private int pageNum; // 定义一个变量用于保存当前查询出来的学生信息 private List<Map<String,Object>> stuDatas = new ArrayList<>(); // setXxx 和 getXxx 方法 }
7)创建 StudentController 控制器类
@RestController @RequestMapping("/student") public class StudentController { // 注入ShcoolService @Resource private ShcoolService shcoolService; @RequestMapping("/save") public String save() { Clazz clazz1 = new Clazz("架构师001班"); Clazz clazz2 = new Clazz("架构师002班"); // 保存班级对象数据 List<Clazz> clazzs = new ArrayList<>(); clazzs.add(clazz1); clazzs.add(clazz2); shcoolService.saveClazzAll(clazzs); Student s1 = new Student("小黄","广州",17,'男',clazz1); Student s2 = new Student("小红","成都",15,'女',clazz1); Student s3 = new Student("小绿","上海",15,'男',clazz1); Student s4 = new Student("小豆","北京",15,'女',clazz2); Student s5 = new Student("小牛","西藏",15,'男',clazz2); Student s6 = new Student("小兰","黑龙江",17,'女',clazz2); List<Student> students = new ArrayList<>(); students.add(s1); students.add(s2); students.add(s3); students.add(s4); students.add(s5); students.add(s6); shcoolService.saveStudentAll(students); return "保存学生成功"; } @RequestMapping("/getStusBySex") public List<Map<String, Object>> getStusBySex(char sex){ return shcoolService.getStusBySex(sex); } // 动态的查询学生信息 @RequestMapping("/getStusByDynamic") public List<Map<String, Object>> getStusByDynamic(Student student) { return shcoolService.getStusByDynamic(student); } // 分页查询某个班级下的学生信息 @RequestMapping("/getStusByPage") public PageData getStusByPage(String clazzName , int pageIndex , int pageSize ) { // 分页查询某个班级的学生信息 Page<Student> page = shcoolService.getStusByPage(clazzName , pageIndex , pageSize); // 对查询出来的结果数据进行分析 List<Student> students = page.getContent(); List<Map<String,Object>> stuDatas = new ArrayList<>(); for(Student stu :students){ Map<String , Object> stuMap = new HashMap<>(); stuMap.put("id", stu.getId()); stuMap.put("name", stu.getName()); stuMap.put("age", stu.getAge()); stuMap.put("sex", stu.getSex()); stuMap.put("address", stu.getAddress()); stuMap.put("clazzName", clazzName); stuDatas.add(stuMap); } // 将分页查询出的结果数据进行分析,然后把数据存入到PageData对象中去保存起来响应给浏览器展示 PageData data = new PageData(); data.setStuDatas(stuDatas); data.setPageIndex(page.getNumber()+1); data.setPageSize(page.getTotalPages()); data.setTotalCount(page.getTotalElements()); data.setPageNum(page.getSize()); return data ; } }
8)测试
http://localhost:8080/student/save