写在前面:从2018年底开始学习SpringBoot,也用SpringBoot写过一些项目。现在对学习Springboot的一些知识总结记录一下。如果你也在学习SpringBoot,可以关注我,一起学习,一起进步。相关文章:初识Spring-Data-Jpa
相关文章:
【Springboot系列】Springboot入门到项目实战
目录
编写代码
1、创建持久化类
2、定义数据访问层接口
3、定义业务层类
4、定义控制器类
测试应用
1、测试应用
2、源码下载
依照SpringData的命名规则,对于两个有关联关系的对象的查询,可以通过方法名中“_”下划线类标识,也可以通过Spring-Data-Jpa命名规范查询,同时SpringDataJpa还支持用@Query注解定义在数据访问层接口的方法上实现查询,下面来看一个示例进行理解。
上一篇讲了Spring-Data-Jpa入门,这一篇来看一下Spring-Data-Jpa条件查询(基于上一篇Spring-Data-Jpa入门的项目中写的,配置文件没有任何改动,详情可以参考Spring-Data-Jpa入门)。
在entity包中创建两个持久化类学生类Stu.java和班级类Clazz.java,代码如下
Stu.java类(Stu和Clazz是多对一关系,表关联注解代码中有注释)
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.data.annotation.CreatedBy;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.ManyToOne;
//用于标记持久化类,SpringBoot项目加载后会自动根据持久化类建表
@Entity
//设置表名为tb_stu
@Table(name="tb_stu")
public class Stu {
private Integer id; //主键
private String name; //姓名
private String address; //地址
private Integer age; //年龄
private char sex; //性别
//@JsonIgnore注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉
@JsonIgnore
private Clazz clazz;
/**
* 使用@id指定主键。使用代码@GeneratedValue
* 指定主键的生存策略,mysql默认为自动增长
*/
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
//关联表对应关系,学生与班级的多对一的关系
@ManyToOne
@CreatedBy
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
public Stu() {
}
public Stu(String name, String address, Integer age, char sex, Clazz clazz) {
this.name = name;
this.address = address;
this.age = age;
this.sex = sex;
this.clazz = clazz;
}
}
Class.java类(Clazz和Stu是一对多关系,表关联注解代码中有注释)
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
//用于标记持久化类,SpringBoot项目加载后会自动根据持久化类建表
@Entity
//设置表名为tb_clazz
@Table(name="tb_clazz")
public class Clazz {
private Integer id; //主键
private String name; //班级名称
//@JsonIgnore注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉
@JsonIgnore
private List stuList = new ArrayList<>();
/**
* 使用@id指定主键。使用代码@GeneratedValue(strategy = GenerationType.IDENTITY)
* 指定主键的生存策略,mysql默认为自动增长
*/
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//班级与学生是一对多的关联,mappedBy对应Stu表中clazz字段
@OneToMany(cascade=CascadeType.ALL,mappedBy="clazz")
public List getStuList() {
return stuList;
}
public void setStuList(List stuList) {
this.stuList = stuList;
}
public Clazz(String name) {
this.name = name;
}
public Clazz() {
}
}
从上述代码可以看出,班级与学生是一对多的关系,一个班级可以有多名学生,此处做的是双向关联,即在班级对象中关联了学生对象,在学生对象中也关联了班级对象。
之后在repository包下新建一个接口,命名为StuRepository,该接口继承JpaRepository接口,以持久化对象Stu作为JpaRepository的第一个类型参数,表示当前所操作的持久化对象类型,Integer作为JpaRepository的第二个类型参数,用于指定ID类型,同时创建一个接口名称为ClazzRepository,继承JpaRepository的接口,用于访问班级信息的数据。
ClazzRepository.java接口
import com.mcy.springdatajpa.entity.Clazz;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ClazzRepository extends JpaRepository {
}
StuRepository.java接口(包含了一些关联查询)
import com.mcy.springdatajpa.entity.Stu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Map;
public interface StuRepository extends JpaRepository {
/**
* 根据班级名称查询这个班级所有学生的信息
* 相当于JPQL语句:select s from stu s where s.clazzname = ?1
* @param clazzNam
* @return
*/
List findByClazz_name(String clazzNam);
/**
* 根据班级名称查询这个班级所有学生的信息
* 相当于JPQL语句:select s from stu s where s.clazzname = ?1
* @param clazzNam
* @return
*/
List findByClazzName(String clazzNam);
/**
* @Query方法
* 根据班级名称查询这个班级所有学生的信息
* ?1此处使用的是参数的位置,代表的是第一个参数
* 此写法与findByClazz_name方法实现的功能完全一致
* @param clazzName
* @return
*/
@Query("select s from Stu s where s.clazz.name = ?1")
List findStuByClazzName(String clazzName);
/**
* 使用@Query注解的形式,查询某个班级下所有学生的姓名和性别
* @param clazzName
* @return
*/
@Query("select new Map(s.name, s.sex) from Stu s where s.clazz.name = ?1")
List
在service包下新建一个SchoolService类,代码如下(几个关联查询方法)
import com.mcy.springdatajpa.entity.Clazz;
import com.mcy.springdatajpa.entity.Stu;
import com.mcy.springdatajpa.repository.ClazzRepository;
import com.mcy.springdatajpa.repository.StuRepository;
import com.mcy.springdatajpa.repository.StudentRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SchoolService {
//注入数据访问层接口对象
@Resource
private StuRepository stuRepository;
@Resource
private ClazzRepository clazzRepository;
//事务管理
@Transactional
public void saveClazzAll(List clazzes){
clazzRepository.saveAll(clazzes);
}
@Transactional
public void saveStuAll(List stus){
stuRepository.saveAll(stus);
}
public List> getStusByClazzName(String clazzName){
//使用"-",驼峰式命名和@Query查询方式结果一致
List stus = stuRepository.findByClazz_name(clazzName);
//List stus = stuRepository.findByClazzName(clazzName);
//List stus = stuRepository.findStuByClazzName(clazzName);
List> results = new ArrayList<>();
//遍历查询出的学生对象,提取姓名,年龄,性别信息
for(Stu stu : stus){
Map s = new HashMap<>();
s.put("name", stu.getName());
s.put("age", stu.getAge());
s.put("sex", stu.getSex());
results.add(s);
}
return results;
}
public List> findNameAndSexByClazzName(String clazzName){
return stuRepository.findNameAndSexByClazzName(clazzName);
}
public List findNameByClazzNameAndSex(String clazzName, char sex){
return stuRepository.findNameByClazzNameAndSex(clazzName, sex);
}
public String findClazzNameByStuName(String stuName){
return stuRepository.findClazzNameByStuName(stuName);
}
@Transactional
public Integer deleteStuByStuName(String stuName){
return stuRepository.deleteStuByStuName(stuName);
}
}
在业务层中需要注入数据访问层对象,在上述代码中是通过@Resources注解将StuRepository和ClazzRepository接口对应的实现类对象注入进来的。
在controller包下新建一个StuController类,代码如下(访问方法)。
import com.mcy.springdatajpa.entity.Clazz;
import com.mcy.springdatajpa.entity.Stu;
import com.mcy.springdatajpa.service.SchoolService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/stu")
public class StuController {
//注入ShcoolService
@Resource
private SchoolService schoolService;
//保存,初始化数据
@RequestMapping("/save")
public String save(){
Clazz clazz1 = new Clazz("软件工程1班");
Clazz clazz2 = new Clazz("软件工程2班");
//保存班级对象数据
List clazzs = new ArrayList<>();
clazzs.add(clazz1);
clazzs.add(clazz2);
schoolService.saveClazzAll(clazzs);
Stu stu1 = new Stu("张三", "湖北", 20, '男', clazz1 );
Stu stu2 = new Stu("李四", "湖北", 18, '女', clazz1 );
Stu stu3 = new Stu("王五", "湖北", 17, '男', clazz2 );
List stus = new ArrayList<>();
stus.add(stu1);
stus.add(stu2);
stus.add(stu3);
schoolService.saveStuAll(stus);
return "数据保存成功!";
}
/**
* 查询某个班级所有学生的姓名,年龄,性别
* @param clazzName
* @return
*/
@RequestMapping("/getClazzStus")
public List> getClazzStus(String clazzName){
return schoolService.getStusByClazzName(clazzName);
}
/**
* 查询某个班级所有学生的姓名,性别
* @param clazzName
* @return
*/
@RequestMapping("/findNameAndSexByClazzName")
public List> findNameAndSexByClazzName(String clazzName){
return schoolService.findNameAndSexByClazzName(clazzName);
}
/**
* 查询某个班级某种性别的所有学生的姓名
* @param clazzName
* @param sex
* @return
*/
@RequestMapping("/findNameByClazzNameAndSex")
public List findNameByClazzNameAndSex(String clazzName, Character sex){
return schoolService.findNameByClazzNameAndSex(clazzName, sex);
}
/**
* 查询某个学生属于哪个班级
* @param stuName
* @return
*/
@RequestMapping("/findClazzNameByStuName")
public String findClazzNameByStuName(String stuName){
return schoolService.findClazzNameByStuName(stuName);
}
/**
* 删除某个学生对象
* @param stuName
* @return
*/
@RequestMapping("/deleteStuByStuName")
public String deleteStuByStuName(String stuName){
return "删除数据:"+schoolService.deleteStuByStuName(stuName);
}
}
启动MySQL数据库,在数据库中创建名为jpa的数据库。springboot项目启动后,JPA会在数据库中自动创建持久化类对应的tb_stu和tb_clazz表。
测试添加学生和班级信息,在浏览器中输入http://localhost:8080/stu/save地址,请求会提交给StuController类的save方法进行处理,执行完成返回“数据保存成功!”
查看数据库中的数据如图(StuController类的save方法中数据对应):
测试根据班级名称查询班级的学生信息,在浏览器中输入http://localhost:8080/stu/getClazzStus?clazzName=软件工程1班,请求会提交StuController类的getClazzStus方法进行处理,执行完成后返回查询出的学生姓名和性别,年龄,如图
测试查询某个班级的女学生,在浏览器中输入http://localhost:8080/stu/findNameByClazzNameAndSex?clazzName=软件工程1班&sex=女,请求会提交给StuController类的findNameByClazzNameAndSex方法进行处理,执行完成返回查询出的某个班级的女学生,如图:
测试查询某个学生属于哪个班级,在浏览器中输入http://localhost:8080/stu/findClazzNameByStuName?stuName=张三,请求会提交到StuController类的findClazzNameByStuName方法进行处理,执行完成返回查询出的班级名称,如图
测试删除某个学生对象,在浏览器中输入http://localhost:8080/stu/deleteStuByStuName?stuName=张三,请求会提交给StuController类的deleteStuByStuName方法进行处理,执行完成返回“删除数据:1”,查询数据库如图:
案例代码下载链接:https://github.com/machaoyin/spring-data-jpa