在Spring Data JPA中使用@ManyToMany来注解多对多的映射关系,由一个关联表来维护。关联表的表名默认是:主表名+下划线+从表名(主表是指关系维护端对应的表,从表是指关系被维护端对应的表)。关联表只有两个外键字段,分别指向主表ID和从表ID。字段的名称默认为:主表名+下划线+主表中的主键列名,从表名+下划线+从表中的主键列名。需要注意的是,多对多关系中一般不设置级联保存、级联删除、级联更新等操作。
具体实现步骤如下。 1)创建持久化实体类 2)创建数据访问层 3)创建业务层 4)创建控制器类 5)运行
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.manytomany</groupId> <artifactId>SpringBootManytoMany</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <!-- 声明项目配置依赖编码格式为 utf-8 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <fastjson.version>1.2.24</fastjson.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 添加MySQL依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.13</version><!--$NO-MVN-MAN-VER$ --> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
server.port=8089 server.servlet.context-path=/ch6_2 spring.datasource.url=jdbc:mysql://localhost:3306/springbootjpa?serverTimezone=UTC&autoReconnect=true spring.datasource.username=root spring.datasource.password=admin spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.database=MYSQL spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jackson.serialization.indent-output=true
package com.ch.ch6_2.entity; import java.io.Serializable; import java.util.List; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "user") @JsonIgnoreProperties(value = { "hibernateLazyInitializer" }) public class User implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String username; private String password; @ManyToMany @JoinTable(name = "user_authority", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "authority_id")) /** * 1、关系维护端,负责多对多关系的绑定和解除 * 2、@JoinTable注解的name属性指定关联表的名字,joinColumns指定外键的名字,关联到关系维护端(User) * 3、inverseJoinColumns指定外键的名字,要关联的关系被维护端(Authority) * 4、其实可以不使用@JoinTable注解,默认生成的关联表名称为主表表名+下划线+从表表名, 即表名为user_authority * 关联到主表的外键名:主表名+下划线+主表中的主键列名,即user_id * 关联到从表的外键名:主表中用于关联的属性名+下划线+从表的主键列名,即authority_id 主表就是关系维护端对应的表,从表就是关系被维护端对应的表 */ private List<Authority> authorityList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public List<Authority> getAuthorityList() { return authorityList; } public void setAuthorityList(List<Authority> authorityList) { this.authorityList = authorityList; } }
package com.ch.ch6_2.entity; import java.io.Serializable; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToMany; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "authority") @JsonIgnoreProperties(value = { "hibernateLazyInitializer" }) public class Authority implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(nullable = false) private String name; @ManyToMany(mappedBy = "authorityList") @JsonIgnore private List<User> userList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } }
2)创建数据访问层
在com.ch.ch6_2.repository包中,创建名为UserRepository和AuthorityRepository的接口。
package com.ch.ch6_2.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.ch.ch6_2.entity.User; public interface UserRepository extends JpaRepository<User, Integer> { /** * 根据权限id查询拥有该权限的用户(关联查询) 相当于JPQL语句:select u from User u inner join * u.authorityList a where a.id = ?1 */ public List<User> findByAuthorityList_id(int id); /** * 根据权限名查询拥有该权限的用户(关联查询) 相当于JPQL语句:select u from User u inner join * u.authorityList a where a.name = ?1 */ public List<User> findByAuthorityList_name(String name); }
package com.ch.ch6_2.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import com.ch.ch6_2.entity.Authority; public interface AuthorityRepository extends JpaRepository<Authority, Integer> { /** * 根据用户id查询用户所拥有的权限(关联查询) 相当于JPQL语句:select a from Authority a inner join * a.userList u where u.id = ?1 */ public List<Authority> findByUserList_id(int id); /** * 根据用户名查询用户所拥有的权限(关联查询) 相当于JPQL语句:select a from Authority a inner join * a.userList u where u.username = ?1 */ public List<Authority> findByUserList_Username(String username); /** * 根据用户名查询用户所拥有的权限(关联查询) */ @Query("select a from Authority a inner join a.userList u where u.username = ?1") public List<Authority> findByUserListUsername(String username); }
3)创建业务层
在com.ch.ch6_2.service包中,创建名为UserAndAuthorityService的接口和接口实现类UserAndAuthorityServiceImpl。
package com.ch.ch6_2.service; import java.util.List; import com.ch.ch6_2.entity.Authority; import com.ch.ch6_2.entity.User; public interface UserAndAuthorityService { public void saveAll(); public List<User> findByAuthorityList_id(int id); public List<User> findByAuthorityList_name(String name); public List<Authority> findByUserList_id(int id); public List<Authority> findByUserList_Username(String username); public List<Authority> findByUserListUsername(String username); }
package com.ch.ch6_2.service; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ch.ch6_2.entity.Authority; import com.ch.ch6_2.entity.User; import com.ch.ch6_2.repository.AuthorityRepository; import com.ch.ch6_2.repository.UserRepository; @Service public class UserAndAuthorityServiceImpl implements UserAndAuthorityService { @Autowired private AuthorityRepository authorityRepository; @Autowired private UserRepository userRepository; @Override public void saveAll() { // 添加权限1 Authority at1 = new Authority(); at1.setName("增加"); authorityRepository.save(at1); // 添加权限2 Authority at2 = new Authority(); at2.setName("修改"); authorityRepository.save(at2); // 添加权限3 Authority at3 = new Authority(); at3.setName("删除"); authorityRepository.save(at3); // 添加权限4 Authority at4 = new Authority(); at4.setName("查询"); authorityRepository.save(at4); // 添加用户1 User u1 = new User(); u1.setUsername("陈恒1"); u1.setPassword("123"); ArrayList<Authority> authorityList1 = new ArrayList<Authority>(); authorityList1.add(at1); authorityList1.add(at2); authorityList1.add(at3); u1.setAuthorityList(authorityList1); userRepository.save(u1); // 添加用户2 User u2 = new User(); u2.setUsername("陈恒2"); u2.setPassword("234"); ArrayList<Authority> authorityList2 = new ArrayList<Authority>(); authorityList2.add(at2); authorityList2.add(at3); authorityList2.add(at4); u2.setAuthorityList(authorityList2); userRepository.save(u2); } @Override public List<User> findByAuthorityList_id(int id) { return userRepository.findByAuthorityList_id(id); } @Override public List<User> findByAuthorityList_name(String name) { return userRepository.findByAuthorityList_name(name); } @Override public List<Authority> findByUserList_id(int id) { return authorityRepository.findByUserList_id(id); } @Override public List<Authority> findByUserList_Username(String username) { return authorityRepository.findByUserList_Username(username); } @Override public List<Authority> findByUserListUsername(String username) { return authorityRepository.findByUserListUsername(username); } }
4)创建控制器类
在com.ch.ch6_2.controller包中,创建名为TestManyToManyController的控制器类。
package com.ch.ch6_2.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ch.ch6_2.entity.Authority; import com.ch.ch6_2.entity.User; import com.ch.ch6_2.service.UserAndAuthorityService; @RestController public class TestManyToManyController { @Autowired private UserAndAuthorityService userAndAuthorityService; @RequestMapping("/saveManyToMany") public String save() { userAndAuthorityService.saveAll(); return "权限和用户保存成功!"; } @RequestMapping("/findByAuthorityList_id") public List<User> findByAuthorityList_id(int id) { return userAndAuthorityService.findByAuthorityList_id(id); } @RequestMapping("/findByAuthorityList_name") public List<User> findByAuthorityList_name(String name) { return userAndAuthorityService.findByAuthorityList_name(name); } @RequestMapping("/findByUserList_id") public List<Authority> findByUserList_id(int id) { return userAndAuthorityService.findByUserList_id(id); } @RequestMapping("/findByUserList_Username") public List<Authority> findByUserList_Username(String username) { return userAndAuthorityService.findByUserList_Username(username); } @RequestMapping("/findByUserListUsername") public List<Authority> findByUserListUsername(String username) { return userAndAuthorityService.findByUserListUsername(username); } }
5)运行 首先,运行Ch62Application主类。然后,访问“http://localhost:8080/ch6_2/saveManyToMany/”。