精通 Spring Boot 系列文(9)

程序IT圈

共 19402字,需浏览 39分钟

 · 2020-07-27

阅读全文,约 30 分钟


精通 Spring Boot 系列文(1)
精通 Spring Boot 系列文(2)
精通 Spring Boot 系列文(2)
精通 Spring Boot 系列文(4)
精通 Spring Boot 系列文(5)
精通 Spring Boot 系列文(6)
精通 Spring Boot 系列文(7)
精通 Spring Boot 系列文(8)

案例2:关联查询和 @Query 查询

如果两个对象的查询,有关联关系,则可以在方法名中的添加下划线来标识。

我们就用 学生 和 班级 的关系,来给大家举个例子。

1)编辑 pom.xml 文件(与 CrudRepository 接口案例一样)
2)编辑 application.properties 文件(与 CrudRepository 接口案例一样)
3)创建 Student 和 Clazz 持久化类
// 学生
@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;
    }

    // getXxx 和 setXxx 方法
}
@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 students = new HashSet<>();

    public Clazz() {
    }
    // 班级对象
    public Clazz(String name) {
        this.name = name;
    }
}
4)创建 ClazzRepository 和 StudentRepository 数据访问接口
public interface ClazzRepository extends JpaRepository<ClazzInteger{
}
public interface StudentRepository extends JpaRepository<StudentInteger{

    /**
     * 根据班级名称查询这个班级下所有的学生信息
     * 相当于JPQL语句
     * select s from Student s where s.clazz.name = ?1
     */

    List findByClazz_name(String clazzName);

    /**
     * @Query 写法
     * 根据班级名称查询这个班级下所有的学生信息
     * ?1 此处使用的是参数的位置,代表的是第一个参数
     * 此写法与上面的方法实现的功能完全一致
     * */

    @Query("select s from Student s where s.clazz.name = ?1")
    List findStudentsByClazzName(String clazzName);

    /**
     * 使用 @Query 注解的形式,查询某个班级下所有学生的姓名和性别 
     */

    @Query("select new Map(s.name as name , s.sex as sex) "
            + "from Student s where s.clazz.name = ?1")
    List> findNameAndSexByClazzName(String clazzName);

    /**
     *  使用 @Query 注解的形式,查询某个班级下某种性别的所有学生的姓名
     *  上面方法是用的是参数的位置来查询的,Spring Data JPA中还支持用
     *  名称来匹配查询使用格式 “:参数名称” 引用
     */

    @Query("select s.name from Student s "
            + "where s.clazz.name = :clazzName and s.sex = :sex ")
    List findNameByClazzNameAndSex(@Param("clazzName")String clazzName , @Param("sex")char sex);

    /**
     *  使用 @Query 注解的形式,查询某个学生属于哪个班级
     */

    @Query("select c.name from Clazz c inner join c.students s "
            + "where s.name = ?1 ")
    String findClazzNameByStuName(String stuName);

    /**
     * 执行更新查询,使用 @Query与 @Modifying 可以执行更新操作
     */

    @Modifying
    @Query("delete from Student s where s.name = ?1")
    int deleteStuByStuName(String stuName);
}
5)创建 SchoolService 业务层类
@Service
public class SchoolService {

    // 注入数据访问层接口对象 
    @Resource
    private StudentRepository studentRepository;
    @Resource
    private ClazzRepository clazzRepository;

    @Transactional
    public void saveClazzAll(List clazzs) {
        clazzRepository.saveAll(clazzs);
    }

    @Transactional
    public void saveStudentAll(List students) {
        studentRepository.saveAll(students);
    }

    public List> getStusByClazzName(String clazzName) {

        List students = studentRepository.findByClazz_name(clazzName);
        // List students = studentRepository.findStudentsByClazzName(clazzName);

        List>  results = new ArrayList<>(); 

        // 遍历查询出的学生对象,提取姓名,年龄,性别信息
        for(Student student:students){
            Map stu = new HashMap<>(); 
            stu.put("name", student.getName());
            stu.put("age", student.getAge());
            stu.put("sex", student.getSex());
            results.add(stu);
        }
        return results;
    }

    public List> findNameAndSexByClazzName(String clazzName) {
        return studentRepository.findNameAndSexByClazzName(clazzName);
    }

    public List findNameByClazzNameAndSex(
            String clazzName, char sex)
 
{
        return studentRepository.findNameByClazzNameAndSex(clazzName, sex);
    }

    public String findClazzNameByStuName(String stuName) {
        return studentRepository.findClazzNameByStuName(stuName);
    }

    @Transactional
    public int deleteStuByStuName(String stuName) {
        return studentRepository.deleteStuByStuName(stuName);
    }
}
6)创建 StudentController 控制器类
@RestController
@RequestMapping("/student")
public class StudentController {

    @Resource
    private SchoolService schoolService;
    @RequestMapping("/save")
    public String save() {

        Clazz clazz1 = new Clazz("架构师 001 班");
        Clazz clazz2 = new Clazz("架构师 002 班");

        // 保存班级对象数据
        List clazzs = new ArrayList<>();
        clazzs.add(clazz1);
        clazzs.add(clazz2);
        schoolService.saveClazzAll(clazzs);

        Student s1 = new Student("小黄","广州",18,'男',clazz1);
        Student s2 = new Student("小红","北京",17,'女',clazz1);
        Student s3 = new Student("小绿","成都",15,'男',clazz2);

        List students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);

        schoolService.saveStudentAll(students);

        return "保存学生对象成功";
    }

    /**
     * 查询某个班级下所有的学生姓名,年龄,性别
     */

    @RequestMapping("/getClazzStus")
    public List> getClazzStus(String clazzName){
        return schoolService.getStusByClazzName(clazzName);
    } 

    /**
     * 查询某个班级下所有的学生姓名,性别
     */

    @RequestMapping("/findNameAndSexByClazzName")
    public List> findNameAndSexByClazzName(String clazzName){
        return schoolService.findNameAndSexByClazzName(clazzName);
    } 

    /**
     * 查询某个班级下某种性别的所有学生的姓名
     */

    @RequestMapping("/findNameByClazzNameAndSex")
    public List findNameByClazzNameAndSex(String clazzName ,Character sex){
        return schoolService.findNameByClazzNameAndSex(clazzName ,sex);
    } 

    /**
     * 查询某个学生属于哪个班级
     */

    @RequestMapping("/findClazzNameByStuName")
    public String findClazzNameByStuName(String stuName){
        return schoolService.findClazzNameByStuName(stuName);
    } 

    /**
     * 删除某个学生对象
     */

    @RequestMapping("/deleteStuByStuName")
    public String deleteStuByStuName(String stuName){
        return "删除数据:"+schoolService.deleteStuByStuName(stuName);
    } 
}
7)测试

http://localhost:8080/student/save

案例3:NamedQuery 查询

使用 NameQuery 就是一个名称映射一个查询语句的查询操作。

1)编辑 pom.xml 文件(与 CrudRepository 接口案例一样)
2)创建 Student 和 Clazz 持久化类

先看 Student 类。

@Entity
@Table(name="tb_student")
// 查询班级下的学生
@NamedQuery(name="Student.findStudentsByClazzName",query="select s from Student s where s.clazz.name = ?1")
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 方法
}

再来看看 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 students = new HashSet<>();

    public Clazz() {

    }
    // 班级对象
    public Clazz(String name) {
        this.name = name;
    }

    // setXxx 和 getXxx 方法
}
3)创建 StudentRepository 和 ClazzRepository 数据访问接口

先看 StudentRepository 类。

public interface StudentRepository extends JpaRepository<StudentInteger{
    /**
     * 查询班级下的所有学生
     */

    List findStudentsByClazzName(String clazzName);
}

再看 ClazzRepository 类。

public interface ClazzRepository extends JpaRepository<ClazzInteger{    
}
4)创建 ShcoolService 业务层
@Service
public class ShcoolService {
    // 注入数据访问层接口对象 
    @Resource
    private StudentRepository studentRepository;
    @Resource
    private ClazzRepository clazzRepository;

    @Transactional
    public void saveClazzAll(List clazzs) {
        clazzRepository.saveAll(clazzs);
    }
    @Transactional
    public void saveStudentAll(List students) {
        studentRepository.saveAll(students);
    }

    public List> getStusByClazzName(String clazzName) {
        // 查询班级下的所有学生
        List students = studentRepository.findStudentsByClazzName(clazzName);
        List>  results = new ArrayList<>(); 
        // 遍历查询出的学生对象,提取姓名,年龄,性别信息
        for(Student student:students){
            Map stu = new HashMap<>(); 
            stu.put("name", student.getName());
            stu.put("age", student.getAge());
            stu.put("sex", student.getSex());
            results.add(stu);
        }
        return results;
    }
}
5)创建 StudentController 控制器类
@RestController
@RequestMapping("/student")
public class StudentController {
    @Resource
    private ShcoolService shcoolService;
    @RequestMapping("/save")
    public String save() {

        Clazz clazz1 = new Clazz("架构师001班");
        Clazz clazz2 = new Clazz("架构师002班");
        // 保存班级对象数据
        List clazzs = new ArrayList<>();
        clazzs.add(clazz1);
        clazzs.add(clazz2);
        shcoolService.saveClazzAll(clazzs);

        Student s1 = new Student("帅帅","广州",18,'男',clazz1);
        Student s2 = new Student("小黄","广州",17,'女',clazz1);
        Student s3 = new Student("小红","广州",15,'男',clazz2);

        List students = new ArrayList<>();
        students.add(s1);
        students.add(s2);
        students.add(s3);
        shcoolService.saveStudentAll(students);
        return "保存学生成功";
    }
    /**
     * 查询某个班级下所有的学生姓名,年龄,性别
     */

    @RequestMapping("/getClazzStus")
    public List> getClazzStus(String clazzName){
        return shcoolService.getStusByClazzName(clazzName);
    } 
}
6)测试

http://localhost:8080/student/save

案例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 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<ClazzInteger> ,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 clazzs) {
        clazzRepository.saveAll(clazzs);
    }
    @Transactional
    public void saveStudentAll(List students) {
        studentRepository.saveAll(students);
    }

    /**
     * 根据性别查询学生信息
     */

    @SuppressWarnings("serial")
    public List> getStusBySex(char sex) {
        List students = studentRepository.findAll(new Specification() {

            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query,
                    CriteriaBuilder cb)
 
{
               Predicate p1 = cb.equal(root.get("sex"), sex);
               return p1;
            }
        });
        List>  results = new ArrayList<>(); 

        for(Student student:students){
            Map 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> getStusByDynamic(Student student) {
        List students = studentRepository.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query,
                    CriteriaBuilder cb)
 
{
                // 本集合用于封装查询条件
                List predicates = new ArrayList();  
                if(student!=null){
                    /** 是否传入了姓名来查询  */
                    if(!StringUtils.isEmpty(student.getName())){
                        predicates.add(cb.like(root. get("name"),"%" + student.getName() + "%"));
                    }
                    /** 是否传入了地址来查询  */
                    if(!StringUtils.isEmpty(student.getAddress())){
                        predicates.add(cb.like(root. get("address"),"%" + student.getAddress() + "%"));
                    }
                    /** 是否传入了性别来查询 */
                    if(student.getSex() != '\0'){
                        predicates.add(cb.equal(root. get("sex"),student.getSex()));
                    }
                    /** 判断是否传入了班级信息来查询 */
                    if(student.getClazz()!=null && !StringUtils.isEmpty(student.getClazz().getName())){
                        root.join("clazz", JoinType.INNER);
                        Path 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>  results = new ArrayList<>(); 

        for(Student stu :students){
            Map 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 getStusByPage(String clazzName , int pageIndex , int pageSize ) {
        // 指定排序参数对象:根据id,进行降序查询
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        // 分页查询学生信息,返回分页实体对象数据
        // pages对象中包含了查询出来的数据信息,以及与分页相关的信息
        Page pages = studentRepository.findAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query,
                    CriteriaBuilder cb)
 
{
                root.join("clazz", JoinType.INNER);
                Path 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> 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 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 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> getStusBySex(char sex){
        return shcoolService.getStusBySex(sex);
    } 

    // 动态的查询学生信息 
    @RequestMapping("/getStusByDynamic")
    public List> getStusByDynamic(Student student) {
        return shcoolService.getStusByDynamic(student);
    }

    // 分页查询某个班级下的学生信息
    @RequestMapping("/getStusByPage")
    public PageData getStusByPage(String clazzName , int pageIndex , int pageSize ) {
        // 分页查询某个班级的学生信息
        Page page = shcoolService.getStusByPage(clazzName , pageIndex , pageSize);
        // 对查询出来的结果数据进行分析
        List students = page.getContent();
        List> stuDatas = new ArrayList<>();
        for(Student stu :students){
            Map 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

未完待续,等我下一篇 ~~~


Java后端编程

更多Java推文,关注公众号

浏览 29
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报