Java后端爱上SpringBoot 第二节:Spring-Data-Jpa应用

何为Spring-Data-Jpa?

首先要明确的是JPA是一个规范,并不是一个框架,Spring-data-jpa就是一群Spring的抠脚大汉写的一个符合JPA规范的一个封装了不易上手的Hibernate的易上手DAO框架。

为什么要用Spring-Data-Jpa?

  • 能大大的简化我们DAO层的开发(这个现如今的DAO层框架都能做到,但是Spring-Data-Jpa做的更多)
  • 可以解放写SQL的工作量
  • 不用做数据库初始化建表语句的管理
  • Jdk生成要实行ORM(现在还没有做到),在DAO层从一大堆SQL转变成关系-对象的模式
  • 有成熟的生态圈
    还有别的一些好处,就在此不在说了,有兴趣的道友可以自己搜一下。

使用JPA的一些思想上的转变

  • 要把传统的在SQL上实现一大堆的业务逻辑分解成多的简单的业务逻辑
    贫道的栗子:在日常开发中,特别是三五年前的项目,有些程序员就是要用一个很大很大的SQL(超过100行的SQL)来做一个复杂的业务逻辑,他写的代码让后人无法可写。

  • 允许添加冗余的字段,以减少关联查询带来的效率问题

  • 在插入数据时尽量多做,在查询数据时尽量少做

一些链接

SpringBoot整合Spring-Data-Jpa

上一节其实都说了,在这里再啰嗦一遍吧。

  1. Maven添加依赖包
    <dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter-data-jpa</artifactId>
   	</dependency>
  1. 添加数据库配置和JPA配置
spring:
###数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/spring?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
    username: hyn
    password: hyn1234
###JPA配置
  jpa:
    properties:
      hibernate:
        hbm2ddl:
          auto: update
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    show-sql: true
    generate-ddl: true
    database: mysql 

Spring-Data-Jpa应用

自动建表功能

创建一个实体SysUser

package com.hyn.spring.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

/**
 * 
 * @Title: SysUser.java
 * @Package com.hyn.spring.domain
 * @Description: TODO
 * @author hyn  
 * @date 2018年12月9日 下午1:38:53
 * @version V1.0  
 */
@Entity
@Table(name = "sys_user")
@EntityListeners(AuditingEntityListener.class)
public class SysUser implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid") // 这个是hibernate的注解/生成32位UUID
	@GeneratedValue(generator = "idGenerator")
	/**
	 *  用户ID
	 */
	@Column(columnDefinition="varchar(36)  not null  comment '用户ID'  ")
	String id;

	/**
	 * 
	 * 用户状态
	 */
	@Column(columnDefinition = "enum('true','false') default  'true' not null comment '用户状态' ")
	String status;

	/**
	 *  邮箱
	 */
	@Column(columnDefinition = "varchar(20)  not null  default '' comment '用户邮箱'" )
	private String email;

	/**
	 *  登录用户名
	 */
	@Column(columnDefinition = "varchar(20)  not null unique default '' comment '登录用户名'" )
	private String loginName;

	/**
	 *  用户名名称
	 */
	@Column(columnDefinition = "varchar(10)  not null  default '' comment '用户名称'" )
	private String userName;

	/**
	 *  密码策略
	 */
	@Column(columnDefinition = "varchar(100)  not null  default '888888' comment '登录密码'" )
	private String password;

	/**
	 *  电话
	 */
	@Column(columnDefinition = "varchar(11)  not null unique default '' comment '手机号码'" )
	private String phone;

	/**
	 *  更新时间
	 */
	@Temporal(TemporalType.TIMESTAMP)    
	@Column(columnDefinition = "timestamp  default current_timestamp on update current_timestamp comment '更新时间'")
	@UpdateTimestamp
	private Date moditime;
	//省略get set

启动项目会生成自动建表语句,如果你没有看到自动建表,请检查你的配置:
在这里插入图片描述
spring.jpa.properties.hibernate.hbm2ddl.auto有几种状态,我这里去贴一下别人的:

  • validate 加载hibernate时,验证创建数据库表结构
  • create 每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
  • create-drop 加载hibernate时创建,退出是删除表结构
  • update 加载hibernate自动更新数据库结构
  • none 不自动建表,也不检查表结构

自动注入时间

细心的道友会发现为什么实体上会加一个 @EntityListeners(AuditingEntityListener.class) 这个注解,在这里解释一下,这个注解是用来自动更新时间用的,比如每个表都应该有一个moditime字段用来记录这条数据最后更新的时间,如果让自己手动去维护这个字段就很麻烦,JPA提供了一个 @UpdateTimestamp注解来自动更新moditime,@EntityListeners 是用来开启这个实体上自动更新时间的。不过除了需要加上这个注解以为,还去要在启动类上加上 @EnableJpaAuditing注解,来开启SpringBoot的Jpa的自动注解功能。

@SpringBootApplication
@EnableJpaAuditing
@EnableSwagger2
public class SpringFirstApplication {

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

单表操作

新增数据

创建DAO层

package com.hyn.spring.repository;

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

import com.hyn.spring.entity.SysUser;

public interface ISysUserRepository extends JpaRepository<SysUser, String>,JpaSpecificationExecutor<SysUser>{

}

单个新增

    @Override
	public String save(SysUserVO sysUserVO) {

		SysUser sysUser = new SysUser();
		sysUser.setEmail(sysUserVO.getEmail());
		sysUser.setLoginName(sysUserVO.getLoginName());
		sysUser.setPassword(sysUserVO.getPassword());
		sysUser.setPhone(sysUserVO.getPhone());
		sysUser.setStatus(sysUserVO.getStatus());
		sysUser.setUserName(sysUserVO.getUserName());
		iSysUserRepository.save(sysUser);
		return "success";
	}

批量新增

    @Override
	@Transactional(rollbackOn=Exception.class)
	public String batchSave(List<SysUserVO> sysUserVOs) {
		List<SysUser> sysUsers = new ArrayList<>(sysUserVOs.size());
		for (SysUserVO sysUserVO : sysUserVOs) {
			SysUser sysUser = new SysUser();
			sysUser.setEmail(sysUserVO.getEmail());
			sysUser.setLoginName(sysUserVO.getLoginName());
			sysUser.setPassword(sysUserVO.getPassword());
			sysUser.setPhone(sysUserVO.getPhone());
			sysUser.setStatus(sysUserVO.getStatus());
			sysUser.setUserName(sysUserVO.getUserName());
			sysUsers.add(sysUser);
		}
		iSysUserRepository.saveAll(sysUsers);
		return "success";

	}

注意进行事务控制,spring-data-jpa默认是开启事务控制的,并且进行手动回滚 @Transactional(rollbackOn=Exception.class)
,这个是个好习惯。

注意这里有坑:Spring-data-jpa自带的批量插入接口,不适合大数据的插入,不是批量提交,是一条一条的INSERT来执行的,因为JPA每次都要检查此条数据在数据库中是否存在,如果存在是进行更新的。效率特别差,提交千条数据以上请使用别的方法。
批量保存 Jpa saveAll() 和 JdbcTemplate batchUpdate()效率对比

删除数据

删除数据只是一行代码,但是不管在那个地方写删除数据是特别谨慎的事情,应该多进行验证和确认。

    @Override
	public String delete(String id) {
		iSysUserRepository.deleteById(id);
		return "success";
	}

注意点:删除数据的时候如果有关联关系,注意删除关联关系,才能删除此条数据。

修改数据

修改数据需要验证数据是否存在,在进行修改,修改数据的时候需要提交实体的所有属性,否则会将实体的属性更新为空!

	@Override
	public String update(SysUserVO sysUserVO) {
		Optional<SysUser> optional = iSysUserRepository.findById(sysUserVO.getId());
		if (optional.isPresent()) {
			SysUser sysUser = optional.get();
			sysUser.setEmail(sysUserVO.getEmail());
			sysUser.setLoginName(sysUserVO.getLoginName());
			sysUser.setPassword(sysUserVO.getPassword());
			sysUser.setPhone(sysUserVO.getPhone());
			sysUser.setStatus(sysUserVO.getStatus());
			sysUser.setUserName(sysUserVO.getUserName());
			sysUser.setId(sysUserVO.getId());
			iSysUserRepository.save(sysUser);
			return "success";
		} else {
			return "所更新的数据不存在!";
		}
	}

查询数据

普通查询

在ISysUserRepository加入以下方法:

	/**
	 * 根据用户登录名和密码查询
	 * @param loString
	 * @param password
	 */
	Optional<SysUser> findByLoginNameAndPassword(String loginname,String password);

注意:使用Java 8自带的Optional来指示缺省值,以避免空指针。

Distinct查询

	/**
	 * 根据用户名 Distinct 查询用户
	 * @param userName
	 * @return
	 */
	Optional<List<SysUser>> findEmailDistinctByUserName(String userName);

IgnoreCase查询

	/**
	 * 根据用户名 IgnoreCase 查询用户 忽略username大小写
	 * @param userName
	 * @return
	 */
	Optional<List<SysUser>> findByUserNameIgnoreCase(String userName);

生成SQL:

SELECT
	sysuser0_.id AS id1_0_,
	sysuser0_.email AS email2_0_,
	sysuser0_.login_name AS login_na3_0_,
	sysuser0_.moditime AS moditime4_0_,
	sysuser0_.PASSWORD AS password5_0_,
	sysuser0_.phone AS phone6_0_,
	sysuser0_.STATUS AS status7_0_,
	sysuser0_.user_name AS user_nam8_0_ 
FROM
	sys_user sysuser0_ 
WHERE
	upper( sysuser0_.user_name ) = upper( ? )

ORDER BY查询

	/**
	 * 根据用户名 OrderBy moditime 查询用户 
	 * @param userName
	 * @return
	 */
	Optional<List<SysUser>> findByUserNameOrderByModitimeAsc(String userName);

生成SQL:

SELECT
	sysuser0_.id AS id1_0_,
	sysuser0_.email AS email2_0_,
	sysuser0_.login_name AS login_na3_0_,
	sysuser0_.moditime AS moditime4_0_,
	sysuser0_.PASSWORD AS password5_0_,
	sysuser0_.phone AS phone6_0_,
	sysuser0_.STATUS AS status7_0_,
	sysuser0_.user_name AS user_nam8_0_ 
FROM
	sys_user sysuser0_ 
WHERE
	sysuser0_.user_name =? 
ORDER BY
	sysuser0_.moditime ASC

OR查询

	/**
	 * 根据用户名 or登录用户  查询用户 
	 * @param userName
	 * @param userName
	 * @return
	 */
	Optional<List<SysUser>> findByUserNameOrLoginName(String userName,String loginName);

生成SQL:

SELECT
	sysuser0_.id AS id1_0_,
	sysuser0_.email AS email2_0_,
	sysuser0_.login_name AS login_na3_0_,
	sysuser0_.moditime AS moditime4_0_,
	sysuser0_.PASSWORD AS password5_0_,
	sysuser0_.phone AS phone6_0_,
	sysuser0_.STATUS AS status7_0_,
	sysuser0_.user_name AS user_nam8_0_ 
FROM
	sys_user sysuser0_ 
WHERE
	sysuser0_.user_name =? 
	OR sysuser0_.login_name =?

还有Between,LessThan,GreaterThan,和Like表达式就个个举例了,频道有时间会补充的。

特殊参数查询

	/**
	 * 分页查询
	 * @param userName
	 * @param pageable
	 * @return
	 */
	Page<SysUser> findByUserName(String userName,Pageable pageable);

生成SQL:

SELECT
	sysuser0_.id AS id1_0_,
	sysuser0_.email AS email2_0_,
	sysuser0_.login_name AS login_na3_0_,
	sysuser0_.moditime AS moditime4_0_,
	sysuser0_.PASSWORD AS password5_0_,
	sysuser0_.phone AS phone6_0_,
	sysuser0_.STATUS AS status7_0_,
	sysuser0_.user_name AS user_nam8_0_ 
FROM
	sys_user sysuser0_ 
WHERE
	sysuser0_.user_name =? 
ORDER BY
	sysuser0_.moditime DESC 
	LIMIT ?

运用@Query

	/**
	 * @Query 测试
	 * @param userName
	 * @return
	 */
	@Query(value = "select * from sys_user where user_name = ?1", nativeQuery = true)
	Optional<List<SysUser>> findByUserName(String userName);

生成SQL:

select * from sys_user where email_address = ?1

写成 select * 标识一下。

@Query 命名参数

	/**
	 * @Query 测试
	 * @param userName
	 * @return
	 */
	@Query(value = "select * from sys_user where email like :email", nativeQuery = true)
	Optional<List<SysUser>> findByEmail(@Param("email") String email);

生成SQL:

select * from sys_user where email like ?

贴一下官方的代码:

关键词 样品 JPQL代码段

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstnamefindByFirstnameIsfindByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1(附加参数绑定%

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(与前置绑定的参数%

Containing

findByFirstnameContaining

… where x.firstname like ?1(参数绑定包装%

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

多表操作

在日常开发中,一定会有多表的关联关系,不外乎一对一,一对多(多对一),多对对,这几种关联关系,以下依次介绍这几种关联关系的使用方式,来建立一个用户-工位,用户-部门,用户-角色:

一对一关系

以上只建立了用户的实体,而一个用户只能拥有一个工位,因此用户和工位是一对一关系
创建一个工位实体:

package com.hyn.spring.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Entity
@Table(name = "sys_station")
@EntityListeners(AuditingEntityListener.class)
public class SysStation implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid") // 这个是hibernate的注解/生成32位UUID
	@GeneratedValue(generator = "idGenerator")
	/**
	 *  工位ID
	 */
	@Column(columnDefinition="varchar(36)  not null  comment '工位ID'  ")
	String id;
	
	
	/**
	 *  个人电脑编号
	 */
	@Column(columnDefinition = "varchar(10)  not null unique default '' comment '个人电脑编号'" )
	private String pcCode;
	
	
	/**
	 *  pcIP 个人电脑IP
	 */
	@Column(columnDefinition = "varchar(10)  not null unique default '' comment '个人电脑IP'" )
	private String pcIP;
    //省略get set
}

为用户实体和工位实体添加关联关系,这个关联关系是单向的也可以是双向的,我们这里建立一个双向的。
在用户实体中加入:

	@OneToOne(mappedBy="sysUser")
	SysStation sysStation;

在工位实体中加入:

	@OneToOne
	@JoinColumn(name="user_id")
	SysUser sysUser;

@OneToOne表示实体与实体的关联关系
@JoinColumn 定义了与关联实体关联的column字段名
关于关联双向和单向的问题,道友可以参考这篇文章,写的很详细:hibernate的OneToOne映射
在新增工位方法中,添加关联用户的代码

	@Override
	public String save(SysStationVO sysStationVO) {
		SysStation sysStation=new SysStation();
		sysStation.setPcCode(sysStationVO.getPcCode());
		sysStation.setPcIP(sysStationVO.getPcIP());
		//关联用户
		SysUser sysUser=new SysUser();
		sysUser.setId(sysStationVO.getUserId());
		sysStation.setSysUser(sysUser);
		iSysStationRepository.save(sysStation);
		return "success";
	}

新增工位
新增工位时就可以关联用户了

一对多(多对一)关系

多个用户可以对应一个部门,一个部门有多个用户,因此用户-部门是一对多关系。
建立部门实体:

package com.hyn.spring.entity;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;


import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * 
 * @Title::SysOrganization.java 
 * @Package :com.summit.homs.dto.sys 
 * @Description: TODO
 * @author: hyn   
 * @date: 2018年8月28日 下午9:10:40 
 * @version : 1.0
 */
@Entity
@Table(name = "sys_organization")
@EntityListeners(AuditingEntityListener.class)
@ApiModel(value="组织机构")
public class SysOrganization implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid") // 这个是hibernate的注解/生成32位UUID
	@GeneratedValue(generator = "idGenerator")
	/**
	 *  机构ID
	 */
	@Column(length = 36, columnDefinition = "varchar(36) COMMENT '机构ID'")
	String id;

	/**
	 *  机构代码(行政区划码)
	 */
	@Column(columnDefinition = "VARCHAR(6)  not null  default '' COMMENT '机构代码(行政区划码)'")
	private String code;

	/**
	 *  机构名称
	 */
	@Column(columnDefinition = "VARCHAR(20)  unique not null  default '' COMMENT '机构名称'")
	private String name;

	/**
	 *  机构类型
	 */
	@Column(columnDefinition = "VARCHAR(10)  not null COMMENT '机构类型'")
	private String type;

	/**
	 *  机构等级
	 */
	@Column(columnDefinition = "VARCHAR(10)  not null  default '' COMMENT '机构等级'")
	private String level;

	/**
	 *  上级节点ID
	 */
	@Column(columnDefinition = "VARCHAR(36)  not null  default '' COMMENT '机构等级'")
	private String pid;

	/**
	 *  电话
	 */
	@Column(columnDefinition = "VARCHAR(11)  not null  default '' COMMENT '手机号码'")
	private String phone;

	/**
	 *  地址
	 */
	@Column(columnDefinition = "VARCHAR(100)  not null  default '' COMMENT '地址'")
	private String addr;

	/**
	 *  负责人
	 */
	@Column(columnDefinition = "VARCHAR(10)  not null default ''  COMMENT '负责人'")
	private String principal;

	/**
	 *  更新时间
	 */
	@ApiModelProperty(value = "更新时间", name = "moditime", example = "2018-08-27 00:00:00")
	@Temporal(TemporalType.TIMESTAMP)
	@Column(columnDefinition = "timestamp  not null default  current_timestamp comment '更新时间'")
	@UpdateTimestamp
	private Date moditime;

	@OneToMany(mappedBy="sysOrganization")
	List<SysUser> sysUsers;
}

用户中加入关联关系:

	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name="org_id")
	SysOrganization sysOrganization;

建立关联代码:

	@Override
	public String save(SysOrganizationVO sysUserVO) {

		SysOrganization sysOrganization = new SysOrganization();
		sysOrganization.setAddr(sysUserVO.getAddr());
		sysOrganization.setCode(sysUserVO.getCode());
		sysOrganization.setLevel(sysUserVO.getLevel());
		sysOrganization.setName(sysUserVO.getName());
		sysOrganization.setPhone(sysUserVO.getPhone());
		sysOrganization.setPid(sysUserVO.getPid());
		sysOrganization.setPrincipal(sysUserVO.getPrincipal());
		sysOrganization.setType(sysUserVO.getType());
		SysOrganization  resultOrganization=	iSysOrganizationRepository.save(sysOrganization);
		
		//用户关联部门结构
		List<String> userIds = sysUserVO.getUserIds();
		if (userIds != null && userIds.size() > 0) {
			for (String userId : userIds) {
				Optional<SysUser> optional=	iSysUserRepository.findById(userId);
				if(optional.isPresent())
				{
					SysUser sysUser=optional.get();
					sysUser.setSysOrganization(resultOrganization);
					iSysUserRepository.saveAndFlush(sysUser);
				}
			}
		}
		
		return "success";
	}

多对多关系

一个用户可以对应多个角色,多个角色也可以被一个用户拥有,因此是多对多关系,建立角色的实体。

package com.hyn.spring.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;


import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
 * 
* @Title: SysRole.java
* @Package com.hyn.spring.entity
* @Description: TODO
* @author hyn  
* @date 2018年12月13日 下午5:38:06
* @version V1.0  
 */
@Entity
@Table(name = "sys_role")
@EntityListeners(AuditingEntityListener.class)
@ApiModel(value="系统角色")
public class SysRole implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GenericGenerator(name = "idGenerator", strategy = "uuid") // 这个是hibernate的注解/生成32位UUID
	@GeneratedValue(generator = "idGenerator")
	/**
	 *  角色ID
	 */
	@Column(columnDefinition="varchar(36)  not null  COMMENT '角色ID'  ")
	private String id;

	/**
	 *  角色名称
	 */
	@Column(columnDefinition="varchar(20)  not null unique COMMENT '角色名称'  default ''")
	private String name;
	
	/**
	 *  角色描述
	 */
	@Column(columnDefinition="varchar(50)  not null COMMENT '角色描述'  default ''")
	private String comments;
	

	/**
	 *  更新时间
	 */
	@ApiModelProperty(value = "更新时间", name = "moditime", example = "新增,修改,无此字段")
	@Temporal(TemporalType.TIMESTAMP)    
	@Column(columnDefinition = "TIMESTAMP  not null default  CURRENT_TIMESTAMP COMMENT '更新时间'")
	@UpdateTimestamp
	private Date moditime;
    //省略get set
}

添加用户-角色的关联关系,在用户中添加:

	/**
	 * 用户-角色列表 (多对多)
	 * @return 
	 */
	@ManyToMany(mappedBy="sysUsers")
	private List<SysRole> sysRoles;

在角色中添加:

	@ManyToMany(fetch = FetchType.EAGER,cascade=CascadeType.DETACH)
    @JoinTable(name = "sys_user_role_r",joinColumns = @JoinColumn(name="user_id",referencedColumnName = "id"),inverseJoinColumns = @JoinColumn(name = "role_id",referencedColumnName = "id"))
	List<SysUser> sysUsers;

建立关联关系,在保存角色中关联对应用户:

	@Override
	public String save(SysRoleVO sysRoleVO) {
		SysRole sysRole = new SysRole();
		sysRole.setComments(sysRoleVO.getComments());
		sysRole.setName(sysRoleVO.getName());
		List<String> userIds = sysRoleVO.getUserIds();
		if (userIds != null && userIds.size() > 0) {
			List<SysUser> users = new ArrayList<>(userIds.size());
			for (String userId : userIds) {
				SysUser user = new SysUser();
				user.setId(userId);
				users.add(user);
			}
			sysRole.setSysUsers(users);
		}
		iSysRoleRepository.save(sysRole);
		return "success";
	}

测试:
在这里插入图片描述

自定义动态条件拼接

根据用户名查询用户:

	/**
	 * 构造断言
	 * 
	 * @param userName
	 * @return
	 */
	private Specification<SysUser> getWhereClause(String userName) {
		return new Specification<SysUser>() {

			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				Predicate predicate = criteriaBuilder.conjunction();

				if (StringUtils.isEmpty(userName)) {
					predicate.getExpressions()
							.add(criteriaBuilder.like(root.<String>get("userName"), "%" + userName + "%"));
				}
				return predicate;
			}
		};
	}

注意:CriteriaBuilder 类中可以拼接很多查询条件,道友们可以自行研究,贫道再此就不一一解释了,有问题的可以留言。

自定义动态SQL查询

	@PersistenceContext
	private EntityManager entityManager;
    ...
	@Override
	public List<SysUserVO> listSysUser(String userName) {

		StringBuffer sqlBuffer = new StringBuffer();
		sqlBuffer.append("select id from sys_user where user_name = ?1");

		String sql = sqlBuffer.toString();
		Query query = entityManager.createNativeQuery(sql);
		query.setParameter(1, userName);
	
		List<String> sysUsers= query.getResultList();
		System.out.println(sysUsers);
		return null;
	}

这个和Hibernate的Query 差不多,有兴趣的道友可以自行学习。

猜你喜欢

转载自blog.csdn.net/baidu_37307156/article/details/84958337
今日推荐