目录

  • 1 概述
  • 2 Spring Data JPA整合
  • 2.1 pom文件
  • 2.2 配置文件
  • 2.3 实体类
  • 2.4 Dao接口
  • 2.5 启动类
  • 2.6 编写测试类
  • 3 Spring Data JPA核心接口
  • 3.1 Repository接口
  • 3.1.1 基于方法名称命名方式查询
  • 3.1.1.1 接口
  • 3.1.1.2 测试代码
  • 3.1.1.3 运行结果
  • 3.1.2 基于@Query注解查询与更新
  • 3.1.2.1 接口
  • 3.1.2.2 测试代码
  • 3.1.2.3 运行结果
  • 3.2 CrudRepository接口
  • 3.2.1 接口
  • 3.2.2 测试代码
  • 3.2.3 运行结果
  • 3.3 PagingAndSortingRepository接口
  • 3.3.1 接口
  • 3.3.2 测试代码
  • 3.3.3 运行结果
  • 3.4 JpaRepository接口
  • 3.4.1 接口
  • 3.4.2 测试代码
  • 3.4.3 运行结果
  • 3.5 JPASpecificationExecutor接口
  • 3.5.1 接口
  • 3.5.2 测试代码
  • 3.5.3 运行结果
  • 4 关联映射操作
  • 4.1 一对多双向关联
  • 4.1.2 User
  • 4.1.2 Role
  • 4.1.3 测试代码
  • 4.1.4 运行结果
  • 4.2 多对多双向关联
  • 4.2.1 Role
  • 4.2.2 Menu
  • 4.2.3 测试代码
  • 4.2.4 运行结果


1 概述

Spring Data:spring提供的操作数据库的框架,Spring Data JPA是Spring Data框架下的一个基于JPA标准操作数据的模块。
Spring Data JPA:基于JPA标准对数据库进行操作,简化持久层的代码操作。只需要编写接口即可。
本章节主要学习Spring Data JPA 核心的五个接口,以及如何实现双向一对多,多对多关联。

2 Spring Data JPA整合

通过自动创建表并插入一条数据实例来演示Spring Data JPA的整合。

2.1 pom文件

<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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.3.RELEASE</version>
	</parent>
	<groupId>com.liulg</groupId>
	<artifactId>12-spring-boot-jpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<java.version>1.7</java.version>
	</properties>
	<dependencies>
	    <!-- web启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		 <!-- spring data jpa启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa </artifactId>
		</dependency>
		 <!-- mysql驱动 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		 <!--连接池-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.16</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
	</dependencies>
</project>

2.2 配置文件

src/main/resources/application.properties
#数据源配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#如果程序启动出现时区异常,需要添加后面的serverTimezone参数
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=truespring.datasource.username=root
spring.datasource.password=123456

#数据库连接池配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 

#jpa配置
#ddl-auto:create----每次运行该程序,没有表格会新建表格,表内有数据会清空
#ddl-auto:create-drop----每次程序结束的时候会清空表
#ddl-auto:update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
#ddl-auto:validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
spring.jpa.hibernate.ddl-auto=update
#显示sql
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.enable_lazy_load_no_trans= true

2.3 实体类

package com.liulg.pojo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="user")
public class User {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id")
	private Integer id;
	 
	@Column(name="name")
	private String name;
	
	@Column(name="age")
	private Integer age;
	
	@Column(name="address")
	private String address;
	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 Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
	}
}

2.4 Dao接口

package com.liulg.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.liulg.pojo.User;
/**
 * 参数-T:当前需要映射的实体
 * 参数-ID:当前映射实体中的ID(主键)的类型 
 *
 */
public interface UserRepository extends JpaRepository<User, Integer> {
 
}

2.5 启动类

package com.liulg;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);

	} 
}

2.6 编写测试类

package com.liulg.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.liulg.Application;
import com.liulg.dao.JPARepository;
import com.liulg.pojo.User;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes= {Application.class })
public class JPARepositoryTest {
	@Autowired
	private JPARepository jpaRepository;
	
	@Test
	public void testSave() {
		User user = new User();
		 user.setName("老大");
		 user.setAge(20);
		 user.setAddress("北京");
		jpaRepository.save(user);
	}
}

3 Spring Data JPA核心接口

3.1 Repository接口

3.1.1 基于方法名称命名方式查询

3.1.1.1 接口
package com.liulg.repository;

import java.util.List;
import org.springframework.data.repository.Repository;
import com.liulg.pojo.User;

public interface UserRepository extends Repository<User, Integer> {
	// 方法的名称必须要遵循驼峰式命名规则。findBy(关键字)+属性名称(首字母大写)+查询条件(首字母大写)
	List<User> findByName(String name);
	List<User> findByNameAndAge(String name, Integer age);
	List<User> findByNameLike(String name);
	// Like通配符在后面:"老%"
	List<User> findByNameStartingWith(String name);
	// Like通配符在前面:"%二"
	List<User> findByNameEndingWith(String name);
}
3.1.1.2 测试代码
/***
	 * Repository接口--方法名称命名查询
	 */
	@Test
	public void testFindByName() {
		List<User> list = userRepository.findByName("老大哥");
		for (User user : list) {
			System.out.println("name属性查询:");
			System.out.println(user);
		}
		
		List<User> list2 = userRepository.findByNameAndAge("老二哥", 20);
		for (User user : list2) {
			System.out.println("name属性和age属性查询:");
			System.out.println(user);
		}
		
		List<User> list3 = userRepository.findByNameStartingWith("老");
		for (User user : list3) {
			System.out.println("StartingWith查询,名字以'老'开头的记录:");
			System.out.println(user);
		}
		
		List<User> list4 = userRepository.findByNameLike("%二%");
		for (User user : list4) {
			System.out.println("通配符查询,名字中包含'二'的记录:");
			System.out.println(user);
		}
		
		List<User> list5 = userRepository.findByNameEndingWith("弟");
		for (User user : list5) {
			System.out.println("EndingWith查询,名字以'弟'结尾的记录:");
			System.out.println(user);
		}
	}
3.1.1.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_List

3.1.2 基于@Query注解查询与更新

3.1.2.1 接口
package com.liulg.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;

import com.liulg.pojo.User;

/***
 * Repository接口使用注解方式进行查询和数据更新
 * @author Administrator
 *
 */
public interface UserRepositoryQueryAnnotation extends Repository<User, Integer > {
		/**
		 * 使用HQL查询,jpa新版本必须在参数匹配符“?”后面添加参数索引,索引从1开始。
		 */
		@Query("from User where name=?1")
		List<User> queryByNameUseHQL(String name);
		
		/**
		 * nativeQuery=true,表示不使用hql查询,使用普通SQL查询
		 */
		@Query(value="select * from user where name=?",nativeQuery=true )
		List<User> queryByName(String name);
		
		
		/**
		 * 进行更新数据库的操作时,必须添加Modifying注解
		 */
		@Query("update User set name=?1 where id=?2")
		@Modifying
		void updateUserNameById(String name,Integer id);
}
3.1.2.2 测试代码
/**
	 * Repository接口注解方式测试--更新数据库操作时,必须添加事务注解。
	 */
	@Test
	@Transactional
	public void testRepositoryAnnotation() {
		List<User> list = userRepositoryQueryAnnotation.queryByNameUseHQL("老大哥");
		for (User user : list) {
			System.out.println(user); 
		}
		List<User> list2 = userRepositoryQueryAnnotation.queryByName("老大哥");
		for (User user : list2) {
			System.out.println(user);
		}
		
		userRepositoryQueryAnnotation.updateUserNameById("老大哥哥", 1);
	}
3.1.2.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_User_02

3.2 CrudRepository接口

CrudRepository接口,主要是完成一些增删改查的操作。
CrudRepository集成了Repository接口。

3.2.1 接口

package com.liulg.repository;

import org.springframework.data.repository.CrudRepository;

import com.liulg.pojo.User;

public interface UserCrudRepository extends CrudRepository<User, Integer> {

}

3.2.2 测试代码

/**
	 * CrudRepository接口测试,该接口提供的save方法用来实现保存和更新两个功能。
	 * 保存记录前,会通过主键ID判断记录是否存在,如果存在就执行更新操作,如果不存在就执行保存操作。
	 */
	@Test
	public void testCrudRepository() {
		//添加用户信息
		 User user = new User();
		 user.setName("老五弟");
		 user.setAge(20);
		 user.setAddress("山西");
		 userCrudRepository.save(user);
		
		 //通过主键查询
		Optional<User> optional = this.userCrudRepository.findById(4);
		User u1 = optional.get();
		System.out.println(u1);
		
		//查询所有的记录
		 List<User> list =(List<User>) this.userCrudRepository.findAll();
		 for (User user2: list) {
			System.out.println(user2);
		}
		 
		//根据主键ID删除记录
		 this.userCrudRepository.deleteById(7);
	}

3.2.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_spring_03

3.3 PagingAndSortingRepository接口

该接口用来进行分页和排序操作,该接口继承了CrudRepository接口。

3.3.1 接口

package com.liulg.repository;

import org.springframework.data.repository.PagingAndSortingRepository;

import com.liulg.pojo.User;

public interface UserPagingAndSortingRepository extends PagingAndSortingRepository<User, Integer > {

}

3.3.2 测试代码

@Test
	public void testPagingAndSortingRepository() {
		/***排序查询**/
		//Order 定义了排序规则
		Order order = new Order(Direction.DESC,"id");
		Sort sort = new Sort(order);
		//Sort对象封装了排序规则
		List <User> list =(List<User>) userPagingAndSortingRepository.findAll(sort); 
		System.out.println("排序查询:**********************************");
		for (User user : list) {
			System.out.println(user);
		}
		/***分页查询**/
		//page :第几页,从0开始
		//size:每页查询多少条
		int page = 1;
		int size = 2;
		Pageable pageable = new PageRequest (page,size);
		Page <User> pageU =userPagingAndSortingRepository.findAll(pageable); 
		System.out.println("分页查询:**********************************");
		System.out.println("总条数:"+pageU.getTotalElements());
		System.out.println("总页数:"+pageU.getTotalPages());
		List<User> content = pageU.getContent();
		for (User user : content) {
			System.out.println(user);
		}
		/***排序+分页**/
		Sort sort2 = new Sort(new Order(Direction.DESC,"id"));
		int page2 = 1;
		int size2 = 2;
		Pageable pageable2 = new PageRequest (page2,size2,sort2);
		Page <User> pageU2 =userPagingAndSortingRepository.findAll(pageable2); 
		System.out.println("分页+排序:**********************************");
		System.out.println("总条数:"+pageU2.getTotalElements());
		System.out.println("总页数:"+pageU2.getTotalPages());
		List<User> content2 = pageU2.getContent();
		for (User user : content2) {
			System.out.println(user);
		}

	}

3.3.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_List_04

3.4 JpaRepository接口

该接口继承了PagingAndSortingRepository接口。对继承的父接口中的方法的返回值进行适配,例如在PagingAndSortingRepository接口中的findAll方法,返回值是Iterable,需要进行强制转换,在JpaRepository中就能够直接返回List类型进行使用。

3.4.1 接口

package com.liulg.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.liulg.pojo.User;


/**
 * 参数-T:当前需要映射的实体
 * 参数-ID:当前映射实体中的ID(主键)的类型
 *
 */
public interface JPARepository extends JpaRepository<User, Integer> {
 
}

3.4.2 测试代码

@Test
	public void testJpaRepository() {
		Order order = new Order(Direction.DESC,"id");
		Sort sort = new Sort(order);
		List<User> list = jpaRepository.findAll(sort);
		for (User user : list) {
			System.out.println(user);
		}
	}

3.4.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_List_05

3.5 JPASpecificationExecutor接口

该接口主要用来进行多条件的查询操作,并且能够在查询中添加分页与排序。JPASpecificationExecutor接口是单独存在的,没有继承上述章节的接口。JPASpecificationExecutor接口使用时一般和JpaRepository组合使用,否则Spring在注入该对象时会报错。

TDEngine整合springboot springboot整合springdatajpa_List_06

3.5.1 接口

package com.liulg.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import com.liulg.pojo.User;

public interface UserJPASpecificationExecutor extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User> {

}

3.5.2 测试代码

@Test
	public void testJpaSpecificationExecutor() {
		/**
		 * 单条件查询
		 * Specification用来封装查询条件
		 */
		System.out.println("单条件查询:**************************************");
		Specification< User> spec = new Specification<User>() {
			
			//Predicate封装了单个的查询条件
			/**
			 * Root:查询对象属性的封装
			 * CriteriaQuery:封装SQL中的各个部分信息,select order
			 * CriteriaBuilder:查询条件构造器。定义构造不同的查询条件
			 */
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// where name ="老二哥"
				/**
				 * arg0:查询条件的属性
				 * arg1:查询的值
				 */
				Predicate predicate = cb.equal(root.get("name"), "老二哥");
				return predicate;
			}
		};
		List<User> findAll = userJPASpecificationExecutor.findAll(spec);
		for (User user : findAll) {
			System.out.println(user);
		}
		/**
		 * 多条件查询,第一种方式
		 */
		System.out.println("多条件查询,第一种方式:**************************************");
		Specification< User> spec2 = new Specification<User>() {
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// where name ="老二哥" and age=20
				List<Predicate> list = new ArrayList<Predicate>();
				list.add(cb.equal(root.get("name"), "老二哥"));
				list.add(cb.equal(root.get("age"), 20));
				Predicate [] array = new Predicate[list.size()];
				return cb.and(list.toArray(array));
			}
		};
		List<User> findAll2 = userJPASpecificationExecutor.findAll(spec2);
		for (User user : findAll2) {
			System.out.println(user);
		}
		/**
		 * 多条件查询+排序,第二种方式
		 */
		System.out.println("多条件查询,第二种方式:**************************************");
		Specification< User> spec3 = new Specification<User>() {
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// where (name ="老二哥" and age=20) or id=1
				Predicate p = cb.or(cb.and(cb.equal(root.get("name"), "老二哥"), cb.equal(root.get("age"), 20)),cb.equal(root.get("id"), 1));
				return cb.and(p);
			}
		};
		List<User> findAll3= userJPASpecificationExecutor.findAll(spec3,new Sort(new Order(Direction.DESC,"id")));
		for (User user : findAll3) {
			System.out.println(user);
		}
	}

3.5.3 运行结果

TDEngine整合springboot springboot整合springdatajpa_spring_07

4 关联映射操作

4.1 一对多双向关联

场景需求:
角色(一):一个角色可以分配给多个用户
用户(多):一个用户只可以有一个角色

4.1.2 User

package com.liulg.pojo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="user")
public class User {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id")
	private Integer id;
	
	@Column(name="name")
	private String name;
	
	@Column(name="age")
	private Integer age;
	
	@Column(name="address")
	private String address;
	
	@ManyToOne
	@JoinColumn(name="role_id")
	private Role role;
	
	public Role getRole() {
		return role;
	}
	public void setRole(Role role) {
		this.role = role;
	}
	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 Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
	}
}

4.1.2 Role

package com.liulg.pojo;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "role")
public class Role {
	/*
	 * TABLE:使用一个特定的数据库表格来保存主键。
	 *  SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
	 * IDENTITY:主键由数据库自动生成(主要是自动增长型) 
	 * AUTO:主键由程序控制。
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="id")
	private Integer id;

	@Column(name = "role_name")
	private String roleName;
	
	//mappedBy双向关联时用到的属性,表示当前角色关联的用户必须是roleID相等的。
	@OneToMany(mappedBy="role")
	private Set<User> user = new HashSet<User>() ;

	public Set<User> getUser() {
		return user;
	}

	public void setUser(Set<User> user) {
		this.user = user;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getRoleName() {
		return roleName;
	}

	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}

	@Override
	public String toString() {
		return "Role [id=" + id + ", roleName=" + roleName + "]";
	}
}

4.1.3 测试代码

执行查询操作时,如果出现no session异常,在application.properties文件中添加spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true配置

package com.liulg.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.liulg.Application;
import com.liulg.dao.JPARepository;
import com.liulg.pojo.Role;
import com.liulg.pojo.User;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { Application.class })
public class OneToManyTest {
	@Autowired
	private JPARepository jpaRepository;

	@Test
	public void testSave() {
		User u = new User();
		u.setName("老五弟");
		u.setAge(70);
		u.setAddress("广州");
		Role role = new Role();
		role.setRoleName("管理员");
		u.setRole(role);
		jpaRepository.save(u);
	}
	
	@Test
	public void testFindUser() {
		User user = jpaRepository.getOne(9);
		System.out.println(user);
		System.out.println(user.getRole());
	}
}

4.1.4 运行结果

TDEngine整合springboot springboot整合springdatajpa_List_08

4.2 多对多双向关联

场景需求:
角色:多个角色可以拥有多个资源。
资源:多个资源也可以对应多个角色

4.2.1 Role

package com.liulg.pojo;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
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.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "role")
public class Role {
	/*
	 * TABLE:使用一个特定的数据库表格来保存主键。
	 *  SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
	 * IDENTITY:主键由数据库自动生成(主要是自动增长型) 
	 * AUTO:主键由程序控制。
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="id")
	private Integer id;

	@Column(name = "role_name")
	private String roleName;
	
	//mappedBy双向关联时用到的属性,表示当前角色关联的用户必须是roleID相等的。
	@OneToMany(mappedBy="role")
	private Set<User> user = new HashSet<User>() ;
	
	//JoinTable:映射中间表信息
	//joincolums:当前表中的主键所关联的中间表中的外键字段
	@ManyToMany
	@JoinTable(name="menu_role",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="menu_id"))
	private Set<Menu> menu = new HashSet<Menu>();
	
	
	public Set<Menu> getMenu() {
		return menu;
	}

	public void setMenu(Set<Menu> menu) {
		this.menu = menu;
	}

	public Set<User> getUser() {
		return user;
	}

	public void setUser(Set<User> user) {
		this.user = user;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getRoleName() {
		return roleName;
	}

	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}

	@Override
	public String toString() {
		return "Role [id=" + id + ", roleName=" + roleName + "]";
	}
}

4.2.2 Menu

package com.liulg.pojo;

import java.util.HashSet;
import java.util.Set;

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;

@Entity
@Table(name = "menu")
public class Menu {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer menuId;
	@Column(name = "menu_name")
	private String menuName;
	@Column(name = "menu_url")
	private String menuUrl;
	@Column(name = "parent_id")
	private Integer parentId;
	
	@ManyToMany(mappedBy="menu")
	private Set<Role> roles = new HashSet<Role>();
	
	
	public Set<Role> getRoles() {
		return roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

	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 getParentId() {
		return parentId;
	}

	public void setParentId(Integer parentId) {
		this.parentId = parentId;
	}

}

4.2.3 测试代码

package com.liulg.test;

import java.util.Set;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.liulg.Application;
import com.liulg.pojo.Menu;
import com.liulg.pojo.Role;
import com.liulg.repository.RoleRepository;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { Application.class })
public class ManyToManyTest {
	@Autowired
	private RoleRepository roleRepository; 
	
	@Test
	public void testSave() {
		Role role = new Role();
		role.setRoleName("项目经理");
		

		Menu menu = new Menu();
		menu.setMenuName("项目管理");
		menu.setParentId(0);
		
		Menu menu2 = new Menu();
		menu2.setMenuName("人员管理");
		menu2.setParentId(0);
       
		role.getMenu().add(menu);
		role.getMenu().add(menu2);
		
		menu.getRoles().add(role);
		menu2.getRoles().add(role);

		roleRepository.save(role);
		
	}
	
	@Test
	public void testFind() {
		Role role = roleRepository.getOne(6);
		System.out.println(role);
		Set<Menu> menu = role.getMenu();
		for (Menu menu2 : menu) {
			System.out.println(menu2);
		}
	}
}

4.2.4 运行结果

TDEngine整合springboot springboot整合springdatajpa_User_09