(2)一对多的关联关系
上一节,通过用户和角色来学习了一对一的关联关系。这一节我们还是通过用户与角色来学习一对多的关联关系。
需求:一个用户可以对应多个角色,但是一个角色可以对应多个用户。
这是从角色到用户的一对多的关系,或者说是从用户到角色的多对一的关联关系。
角色是一方,用户是多方。
先把之前学习一对一关联关系的Roles和Users实体拿来,然后把里面的@OneToOne等一对一的相关的注解给删掉。然后重新编写一对一的关联关系的相关的注解和配置。
Roles
package com.haiexijun.pojo; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "t_roles") public class Roles { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "roleid") private Integer roleId; @Column(name = "rolename") private String roleName; @OneToMany(mappedBy = "roles") private Set<Users> users=new HashSet<>(); public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Set<Users> getUsers() { return users; } public void setUsers(Set<Users> users) { this.users = users; } }
Users
package com.haiexijun.pojo; import javax.persistence.*; import java.io.Serializable; @Entity @Table(name = "t_users") public class Users implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY)//自增 @Column(name = "userid") private Integer userId; @Column(name = "username") private String userName; @Column(name = "userage") private Integer userAge; @ManyToOne(cascade =CascadeType.PERSIST) @JoinColumn(name = "roleid") private Roles roles; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } public Roles getRoles() { return roles; } public void setRoles(Roles roles) { this.roles = roles; } @Override public String toString() { return "Users{" + "userId=" + userId + ", userName='" + userName + '\'' + ", userAge=" + userAge + ", roles=" + roles + '}'; } }
上面注意了,要把一的一方的toString()方法给去掉,负责一对多的查询操作会报错。
下面编写测试方式来学习:
/** * 测试一对多的关联操作 * * 添加用户,同时添加角色 */ @Test @Transactional @Rollback(value = false) public void test24(){ //创建角色 Roles roles=new Roles(); roles.setRoleName("普通用户"); //创建用户 Users users=new Users(); users.setUserAge(50); users.setUserName("黄晓明"); //建立关系 roles.getUsers().add(users); users.setRoles(roles); //保存数据 usersDao.save(users); } }
下面再来编写代码学习一下一对多的关联查询:
@Test @Transactional @Rollback(value = false) public void test25(){ Users users= usersDao.findByUserName("黄晓明"); System.out.println(users); Roles roles=users.getRoles(); System.out.println(roles); }
(3)多对多的关联操作
需求:一个角色可以拥有多个菜单,一个菜单可以分配给多个角色。
角色是多方,菜也是多方。
我们需要用到之前的Roles的实体以及新创建一个Menus实体
Roles
package com.haiexijun.pojo; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "t_roles") public class Roles { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "roleid") private Integer roleId; @Column(name = "rolename") private String roleName; @ManyToMany //JoinTable的作用: //它可以写在任一的多对多关系的实体中,配置中间表 //joinColumns作用:建立当前表在中间表中的外键字段 @JoinTable(name = "t_roles_menus",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name ="menu_id")) private Set<Menus> menus=new HashSet<>(); public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Set<Menus> getMenus() { return menus; } public void setMenus(Set<Menus> menus) { this.menus = menus; } }
Menus
package com.haiexijun.pojo; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Table(name = "t_nemus") public class Menus { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "menuid") private Integer menuId; @Column(name = "menuname") private String menuName; @Column(name = "namuurl") private String menuUrl; @Column(name = "menuid") private Integer fatherId; @ManyToMany(mappedBy ="menus" ) private Set<Roles> roles=new HashSet<>(); public Integer getMenuId() { return menuId; } public void setMenuId(Integer menuId) { this.menuId = menuId; } public String getMenuName() { return menuName; } public void setMenuName(String menuName) { this.menuName = menuName; } public String getMenuUrl() { return menuUrl; } public void setMenuUrl(String menuUrl) { this.menuUrl = menuUrl; } public Integer getFatherId() { return fatherId; } public void setFatherId(Integer fatherId) { this.fatherId = fatherId; } public Set<Roles> getRoles() { return roles; } public void setRoles(Set<Roles> roles) { this.roles = roles; } @Override public String toString() { return "Menus{" + "menuId=" + menuId + ", menuName='" + menuName + '\'' + ", menuUrl='" + menuUrl + '\'' + ", fatherId=" + fatherId + ", roles=" + roles + '}'; } }
下面编写测试代码来演示相关的操作:
/** * 多对多关联操作 * * 添加角色同时添加菜单 */ @Test @Transactional @Rollback(value = false) public void test26(){ //创建角色对象 Roles roles=new Roles(); roles.setRoleName("超级管理员"); //创建菜单对象 //比如xxx管理平台,他下面会有用户管理等 Menus menus1=new Menus(); menus1.setMenuName("xxx管理平台"); menus1.setFatherId(-1); menus1.setMenuUrl(null); Menus menus2=new Menus(); menus2.setMenuName("用户管理"); menus2.setFatherId(1); menus2.setMenuUrl(null); //建立关系 roles.getMenus().add(menus1); roles.getMenus().add(menus2); menus1.getRoles().add(roles); menus2.getRoles().add(roles); //保存数据 usersDao.save(roles); }
二.SpringBoot整合使用Spring Data Jpa
1.创建springboot的项目:
2.然后对项目的配置文件进行配置:
#数据库的配置 ##指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建 spring.jpa.hibernate.ddl-auto=update spring.jpa.database=mysql #指定jpa的自动表生成策略,驼峰自动映射为下划线格式 spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=zc20020106 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #是否显示sql在控制台 spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto
create:
每次应用启动的时候会重新根据实体建立表,之前的表和数据都会被删除。
create-drop:
和上面的功能一样,但是多了一样,就是在应用关闭的时候,也就是sessionFactory一关闭,会把表删除。
update:
最常用的,第一次启动根据实体建立表结构,之后启动会根据实体的改变更新表结构,之前的数据都在。
validate:
会验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值,运行程序会校验实体字段与数据库已有的表的字段类型是否相同,不同会报错
然后创建一个pojo包,里面创建一个实体类,具体代码如下:
package com.example.springbootjpa.pojo; import javax.persistence.*; //@Entity注解标注实体类,必需 @Entity //@Table注解:对应数据库中的表, 必须, name=表名, Indexes是声明表里的索引, columnList是索引的列, 同时声明此索引列是否唯一, 默认false @Table(name="student",indexes = {@Index(name="id",columnList = "id",unique = true),@Index(name = "name",columnList = "name",unique = true)}) public class Student { @Id //id用于指明主键 //@GeneratedValue: 表明是否自动生成, 必须, strategy也是必写, 指明主键生成策略, 默认是Oracle @GeneratedValue(strategy = GenerationType.IDENTITY) // @Column: 对应数据库列名 @Column(name = "id") private Long id; @Column(name = "name") private String name; @Column(name = "password") private String password; @Column(name = "email") private String email; @Column(name = "age") private Integer age; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; } }
3 然后编写一个StudentDao并继承自JpaRepository,由此我们已经继承了大部分可用的CRUD操作,针对基础操作,DAO完全不用写任何方法。
package com.example.springbootjpa.dao; import com.example.springbootjpa.pojo.Student; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface StudentDao extends JpaRepository<Student,Long> { }
4.接着编写一个服务接口,添加学生的保存、删除、查询全部和分页查询等的方法。
package com.example.springbootjpa.service; import com.example.springbootjpa.pojo.Student; import org.springframework.data.domain.Pageable; public interface StudentService { //保存学生 public void save(Student student); //删除学生 public void delete(Student student); //查询分页数据 public Object findPage(Pageable pageable); }
5.继续编写服务实现类并调用DAO实现相应功能
package com.example.springbootjpa.service.impl; import com.example.springbootjpa.dao.StudentDao; import com.example.springbootjpa.pojo.Student; import com.example.springbootjpa.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @Service public class StudentServiceImpl implements StudentService { @Autowired private StudentDao studentDao; @Override public void save(Student student) { studentDao.save(student); } @Override public void delete(Student student) { studentDao.delete(student); } @Override public Object findPage(Integer PageNum,Integer pageSize) { Pageable pageable= PageRequest.of(PageNum,pageSize); return studentDao.findAll(pageable); } }
6.接着编写一个学生控制器,调用服务接口实现对应功能。
package com.example.springbootjpa.controller; import com.example.springbootjpa.pojo.Student; import com.example.springbootjpa.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/student") public class StudentController { @Autowired private StudentService studentService; @PostMapping("/save") public void save(@RequestBody Student student){ studentService.save(student); } @PostMapping("/delete") public void delete(@RequestBody Student student){ studentService.delete(student); } @GetMapping("/findAll") public Object findAll(){ return studentService.findAll(); } @GetMapping("/findPage") public Object findPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){ return studentService.findPage(pageNum,pageSize); } }
到这里基本的整合与使用都介绍完了。如果以后我遇到其他的用法和知识点我再回来添加。