# jpa
**Repository Path**: tangcco/jpa
## Basic Information
- **Project Name**: jpa
- **Description**: spring data jpa 与springmvc 和 springboot整合
demo01 maven项目 基本CRUD
demo02 maven项目基本JPQL查询
demo03 整合springmvc 基本CRUD 和 JPQL
demo04 整合springmvc 多表操作 解决json'循环引用引发的堆栈异常
demo05 整合springboot
以上demo已全部完结springboot擦拭代码为demo03和demo05的整合故没有编写笔记
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-01-11
- **Last Updated**: 2022-06-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
---
typora-copy-images-to: img
---
# JPA 从入门到精通
### orm思想和hibernate以及jpa的概述
> 1. orm思想
> 主要目的:操作实体类就相当于操作数据库表
> 建立两个映射关系:
> 实体类和表的映射关系
> 实体类中属性和表中字段的映射关系
> 不再重点关注:具体的sql语句
>
> 实现了ORM思想的框架:mybatis,hibernate
>
> 2. hibernate框架介绍
> Hibernate是一个开放源代码的对象关系映射框架,
> 它对JDBC进行了封装,
> 它将POJO与数据库表建立映射关系,是一个全自动的orm框架
>
> 3. JPA规范
> JPA的全称是Java Persistence API,jpa是一套基于ORM的规范,内部是由接口和抽象类组成。
>
> 
### springDataJpa的概述
> Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,**推荐使用Spring Data JPA + ORM(如:hibernate)完成操作**,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作
>
> 更加简单,方便解耦。
>
> SpringData Jpa 极大简化了数据库访问层代码。 如何简化的呢? **使用了SpringDataJpa,我们的dao层中只需要写接口**,就自动具有了增删改查、分页查询等方法。
### Spring Data JPA 与 JPA和hibernate之间的关系
> Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。
>
> JPA是一套规范,内部是有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式。
>
> 
### [01.jpa入门案例](demo01)
#### 1.1 需求介绍
本章节我们是实现的功能是数据库表基本CRUD。
#### 1.2 开发包介绍
> 由于JPA是sun公司制定的API规范,所以我们不需要导入额外的JPA相关的jar包,只需要导入JPA的提供商的jar包。我们选择Hibernate作为JPA的提供商,所以需要通过Maven导入Hibernate的相关jar包。
>
> https://sourceforge.net/projects/hibernate/files/hibernate-orm/
>
> 
>
#### 1.3 搭建开发环境
创建的数据库表(存储毒鸡汤)
```sql
DROP TABLE IF EXISTS `dujitang`;
CREATE TABLE `dujitang` (
`id` int NOT NULL AUTO_INCREMENT,
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```
> 搭建环境的过程
> 1.创建maven工程导入坐标
> 2.需要配置jpa的核心配置文件
> 位置:配置到类路径下的一个叫做 META-INF 的文件夹下
> 命名:persistence.xml
> 3.编写客户的实体类
> 4.配置实体类和表,类中属性和表中字段的映射关系
> 5.保存客户到数据库中
##### 1.3.1 maven工程导入坐标
```xml
15
15
5.7.0
5.4.27.Final
1.18.16
1.2.75
8.0.22
2.14.0
org.junit.jupiter
junit-jupiter-api
${junit.version}
test
org.junit.jupiter
junit-jupiter-engine
${junit.version}
test
org.hibernate
hibernate-entitymanager
${hibernate.version}
org.hibernate
hibernate-c3p0
${hibernate.version}
mysql
mysql-connector-java
${mysql-connector.version}
org.apache.logging.log4j
log4j-core
${log4j-core.version}
org.projectlombok
lombok
${lombok.version}
provided
com.alibaba
fastjson
${fastjson.version}
```
##### 1.3.2 需要配置jpa的核心配置文件
maven项目的resources目录下新建一个Directory
```
META-INF
```
在resources/META-INF目录下新建一个XML配置文件
```
persistence.xml
```
```xml
org.hibernate.jpa.HibernatePersistenceProvider
```
##### 1.3.3 编写实体类和数据库表的映射配置
在实体类上使用JPA注解的形式配置映射关系
```java
package cn.kgc.tangcco.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/12/29 14:34
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Entity
@Table(name = "dujitang")
public class Dujitang implements Serializable {
private static final long serialVersionUID = 2566271842043865021L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "text")
private String Text;
public Dujitang(String text) {
Text = text;
}
}
```
##### 1.3.4 实现CRUD基本操作
在src/test/java 目录下新建一个Class
> cn.kgc.tangcc.jpa.DujitangTest
>
```java
package cn.kgc.tangcc.jpa;
import cn.kgc.tangcco.pojo.Dujitang;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.HashMap;
/**
* @author 李昊哲
* @Description
* @create 2021/1/11 12:14
* 1、加载配置文件创建工厂
* 2、通过实体管理器工厂获取实体管理器
* 3、获取事务对象并开启事务
* 4、完成CRUD操作
* 5、提交事务
* 6、释放资源
*/
public class DujitangTest {
@Test
public void selectOne() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
// Dujitang dujitang = manager.find(Dujitang.class, 1158);
Dujitang dujitang = manager.getReference(Dujitang.class, 1158);
if (dujitang != null) {
System.out.printf(JSON.toJSONString(dujitang));
}else{
System.out.printf("没有查询到结果");
}
manager.close();
factory.close();
}
@Test
public void insert() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang("桃李不言下自成蹊");
try {
// 4、保存对象
manager.persist(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
factory.close();
}
}
@Test
public void update() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang(1159,"你是我疲惫满身突然的轻松");
try {
// 4、更新对象
manager.merge(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
factory.close();
}
}
@Test
public void delete() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang();
dujitang.setId(1159);
try {
// 4、更新对象
manager.remove(manager.merge(dujitang));
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
factory.close();
}
}
}
```
#### 1.4 JPA中的主键生成策略
> 通过annotation(注解)来映射hibernate实体的,基于annotation的hibernate主键标识为@Id, 其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法。
**IDENTITY:** 主键由数据库自动生成(主要是自动增长型) mysql
```java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
```
**SEQUENCE**:根据底层数据库的序列来生成主键,条件是数据库支持序列。 oracle
**AUTO**: 主键由程序控制
**TABLE**: 使用一个特定的数据库表格来保存主键
#### 1.5 JPA的API介绍
##### 1.5.1 Persistence对象
> **Persistence对象**主要作用是**用于获取EntityManagerFactory对象**的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。
```java
//1.加载配置文件创建(实体管理器)工厂对象
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJpa");
```
##### 1.5.2 EntityManagerFactory
> EntityManagerFactory 接口主要用来创建 EntityManager 实例
```java
//创建实体管理类
EntityManager em = factory.createEntityManager();
```
> 由于EntityManagerFactory 是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory 对象不会有线程安全问题),并且EntityManagerFactory 的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory 的创建进行优化,只需**要做到一个工程只存在一个EntityManagerFactory 即可。**
##### 1.5.3 EntityManager
> 我们可以通过调用EntityManager的方法完成获取**事务**,以及**持久化数据库**的操作
方法说明:
- getTransaction : 获取事务对象
- persist : 保存操作
- merge : 更新操作
- remove : 删除操作
- find/getReference : 根据id查询
##### 1.5.4 EntityTransaction
> 在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单。
- begin:开启事务
- commit:提交事务
- rollback:回滚事务
```
jpa操作的操作步骤
1.加载配置文件创建实体管理器工厂
Persisitence:静态方法(根据持久化单元名称创建实体管理器工厂)
createEntityMnagerFactory(持久化单元名称)
作用:创建实体管理器工厂
2.根据实体管理器工厂,创建实体管理器
EntityManagerFactory :获取EntityManager对象
方法:createEntityManager
* 内部维护的很多的内容
内部维护了数据库信息,
维护了缓存信息
维护了所有的实体管理器对象
再创建EntityManagerFactory的过程中会根据配置创建数据库表
* EntityManagerFactory的创建过程比较浪费资源
特点:线程安全的对象
多个线程访问同一个EntityManagerFactory不会有线程安全问题
* 如何解决EntityManagerFactory的创建过程浪费资源(耗时)的问题?
思路:创建一个公共的EntityManagerFactory的对象
* 静态代码块的形式创建EntityManagerFactory
3.创建事务对象,开启事务
EntityManager对象:实体类管理器
beginTransaction : 创建事务对象
presist : 保存
merge : 更新
remove : 删除
find/getRefrence : 根据id查询
Transaction 对象 : 事务
begin:开启事务
commit:提交事务
rollback:回滚
4.增删改查操作
5.提交事务
6.释放资源
```
#### 1.6-抽取jpaUtils工具类
```java
package cn.kgc.tangcco.uitls.jpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* @author 李昊哲
* @Description
* @create 2021/1/11 13:26
* 解决实体管理器工厂的浪费资源和耗时问题
* 通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
*
* 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
* 第二次方法getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
*/
public abstract class BaseJpaUtil {
private static EntityManagerFactory entityManagerFactory;
static {
entityManagerFactory = Persistence.createEntityManagerFactory("kgcJPA");
}
/**
* 获取EntityManager对象
*/
public static EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
}
```
测试工具类的使用
```java
package cn.kgc.tangcc.jpa;
import cn.kgc.tangcco.pojo.Dujitang;
import cn.kgc.tangcco.uitls.jpa.BaseJpaUtil;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
/**
* @author 李昊哲
* @Description
* @create 2021/1/11 13:31
* JPA 中 find() 和 getReference() 的区别
* 在查询的时候有两个方法:find()和getReference(),这两个方法的参数以及调用方式都相同。那么这两个方法有什么不一样的呢?
* find()称为 立即加载,顾名思义就是在调用的时候立即执行查询语句。
* getReference()称为 延迟加载 或者 懒加载,它在调用的时候不会立即执行查询语句,而是在使用到查询对象的时候才会执行查询语句。
*
* 具体如下:
*
* 使用finde方法查询:
* 查询的对象就是当前对象本身
* 在调用find方法的时候,就会执行sql语句查询数据库
* 使用getReference方法查询:
* 查询到的对象是一个动态代理对象,并不是对象本身
* 在调用getReference方法的时候,不会执行sql语句查询数据库。当调用查询结果对象的时候,才会执行查询sql语句(什么时候用什么时候执行sql语句)
*/
public class BaseJpaUtilTest {
@Test
public void find() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
Dujitang dujitang = manager.find(Dujitang.class, 1158);
if (dujitang != null) {
System.out.printf(JSON.toJSONString(dujitang));
} else {
System.out.printf("没有查询到结果");
}
manager.close();
}
@Test
public void reference() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
Dujitang dujitang = manager.getReference(Dujitang.class, 1158);
if (dujitang != null) {
System.out.printf(JSON.toJSONString(dujitang));
} else {
System.out.printf("没有查询到结果");
}
manager.close();
}
@Test
public void insert() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = BaseJpaUtil.getEntityManagerFactory();
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang("桃李不言下自成蹊");
try {
// 4、保存对象
manager.persist(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
}
}
@Test
public void update() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang(1159, "你是我疲惫满身突然的轻松");
try {
// 4、更新对象
manager.merge(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
}
}
@Test
public void delete() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
// 从数据库中查询该条记录
Dujitang dujitang = manager.find(Dujitang.class, 1160);
if (dujitang != null) {
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
try {
// 4、更新对象
manager.remove(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
}
} else {
System.out.printf("欲被删除的记录不存在");
}
}
}
```
#### 1.7 find方法:根据id查询
```java
/**
* 根据id查询
* 使用find方法查询:
* 1.查询的对象就是当前对象本身
* 2.在调用find方法的时候,就会发送sql语句查询数据库
*
* 立即加载
*
*/
@Test
public void find() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
Dujitang dujitang = manager.find(Dujitang.class, 1158);
if (dujitang != null) {
System.out.printf(JSON.toJSONString(dujitang));
} else {
System.out.printf("没有查询到结果");
}
manager.close();
}
```
#### 1.8 延迟加载与立即加载
```java
/**
* 根据id查询客户
* getReference方法
* 1.获取的对象是一个动态代理对象
* 2.调用getReference方法不会立即发送sql语句查询数据库
* * 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库
*
* 延迟加载(懒加载)
* * 得到的是一个动态代理对象
* * 什么时候用,什么使用才会查询
*/
@Test
public void reference() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
try {
Dujitang dujitang = manager.getReference(Dujitang.class, 2000);
System.out.printf(JSON.toJSONString(dujitang));
}catch (Exception e){
System.out.printf("没有查询到结果");
}finally {
manager.close();
}
}
```
#### 1.9 根据id删除
```java
@Test
public void delete() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
// 从数据库中查询该条记录
Dujitang dujitang = manager.find(Dujitang.class, 1160);
if (dujitang != null) {
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
try {
// 4、更新对象
manager.remove(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
}
} else {
System.out.printf("欲被删除的记录不存在");
}
}
```
#### 1.10 更新操作
```java
@Test
public void update() {
// 1、加载配置文件创建工厂
// EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = BaseJpaUtil.getEntityManager();
// 3、获取事务对象并开启事务
EntityTransaction transaction = manager.getTransaction();
// 开启事务
transaction.begin();
// 创建实体对象
Dujitang dujitang = new Dujitang(1159, "你是我疲惫满身突然的轻松");
try {
// 4、更新对象
manager.merge(dujitang);
// 5、提交事务
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
// 6、释放资源
manager.close();
}
}
```
#### 以上部分有关Jpa的小结:
```
完成基本CRUD案例
persist: 保存
merge: 更新
remove: 删除(注意删除的时候应当为merge状态)
find/getRefrence: 根据id查询
```
------
### [02.JPQL查询](demo02)
#### 2.1 需求介绍
本章节我们是实现的功能是使用 JPA JPQL 数据库表基本查询。
```
jpql查询
sql:查询的是表和表中的字段
jpql:查询的是实体类和类中的属性
* jpql和sql语句的语法相似
1.查询全部
2.分页查询
3.统计查询
4.条件查询
5.排序
```
#### 2.2 开发包介绍
> [开发包介绍](#1.2 开发包介绍)
#### 2.3 搭建开发环境
创建的数据库表(存储信息)
```sql
DROP TABLE IF EXISTS `clazz`;
CREATE TABLE `clazz` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '班级主键',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '班级名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`uuid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '系统唯一标识符',
`id_card` varchar(18) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '中国身份证号',
`first_name` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '曾用名同身份证姓名',
`last_name` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '现用名 生活中的名字',
`mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '中国手机号码',
`auth_text` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码 DES加密',
`cid` int DEFAULT NULL COMMENT '所在班级编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
> 搭建环境的过程
> 1.创建maven工程导入坐标
> 2.需要配置jpa的核心配置文件
> 位置:配置到类路径下的一个叫做 META-INF 的文件夹下
> 命名:persistence.xml
> 3.编写客户的实体类
> 4.配置实体类和表,类中属性和表中字段的映射关系
> 5.保存客户到数据库中
##### 2.3.1 maven工程导入坐标
> [maven工程导入坐标](#1.3.1 maven工程导入坐标 )
##### 2.3.2 需要配置jpa的核心配置文件
> [需要配置jpa的核心配置文件](#1.3.2 需要配置jpa的核心配置文件 )
##### 2.3.3 编写实体类和数据库表的映射配置
在实体类上使用JPA注解的形式配置映射关系
```java
package cn.kgc.tangcco.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 9:23
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Accessors(chain = true)
@Table(name = "student")
@Entity
public class Student implements Serializable {
private static final long serialVersionUID = 7938491898853912340L;
/**
* 学生编号
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
/**
* 学生唯一标志
*/
@Column(name = "uuid")
private String uuid;
/**
* 学生曾用名
*/
@Column(name = "first_name")
private String firstName;
/**
* 学生现用名
*/
@Column(name = "last_name")
private String lastName;
/**
* 学生身份证
*/
@Column(name = "id_card")
private String idCard;
/**
* 学生手机号
*/
@Column(name = "mobile")
private String mobile;
/**
* 密码
*/
@Column(name = "auth_text")
private String authText;
/**
* 学生所在班级编号
*/
@Column(name = "cid")
private Integer cid;
/**
* 学生所在班级信息
*/
// private Clazz clazz;
public Student(String uuid, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.idCard = idCard;
this.mobile = mobile;
this.authText = authText;
this.cid = cid;
}
}
```
```java
package cn.kgc.tangcco.pojo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 9:19
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Accessors(chain = true)
@Table(name = "clazz")
@Entity
public class Clazz implements Serializable {
private static final long serialVersionUID = -5611362264083468063L;
/**
* 班级编号
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
/**
* 班级名称
*/
@Column(name = "name")
private String name;
}
```
##### 2.3.4 jpql查询:
在src/test/java 目录下新建一个Class
> cn.kgc.tangcco.jpa.JpqlTest
```java
package cn.kgc.tangcco.jpa;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.pojo.Student;
import cn.kgc.tangcco.utils.jpa.BaseJpaUtil;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/11 14:35
*/
public class JpqlTest {
@Test
public void selectAll() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Clazz";
Query query = manager.createQuery(jpql, Clazz.class);
List list = query.getResultList();
manager.close();
list.forEach(clazz -> System.out.println(JSON.toJSONString(clazz)));
System.out.println("查询结束");
}
@Test
public void selectOrder() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Clazz order by id desc";
Query query = manager.createQuery(jpql, Clazz.class);
List list = query.getResultList();
manager.close();
list.forEach(clazz -> System.out.println(JSON.toJSONString(clazz)));
System.out.println("查询结束");
}
@Test
public void selectCount() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "count(id) from Clazz";
Query query = manager.createQuery(jpql, Clazz.class);
Object count = query.getSingleResult();
manager.close();
System.out.println("count >>> " + count);
System.out.println("查询结束");
}
@Test
public void selectPage() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Student order by id desc";
Query query = manager.createQuery(jpql, Student.class);
// 起始索引
query.setFirstResult(0);
// 每页记录数
query.setMaxResults(5);
List list = query.getResultList();
manager.close();
list.forEach(student -> System.out.println(JSON.toJSONString(student)));
System.out.println("查询结束");
}
@Test
public void selectLike() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Student where firstName like ?1 or lastName like ?2";
Query query = manager.createQuery(jpql);
// 对占位符赋值
query.setParameter(1, "%孙%");
query.setParameter(2, "%孙%");
// 起始索引
query.setFirstResult(0);
// 每页记录数
query.setMaxResults(10);
List list = query.getResultList();
manager.close();
list.forEach(student -> System.out.println(JSON.toJSONString(student)));
System.out.println("查询结束");
}
}
```
#### 2.4 jpql查询: 全部
```java
@Test
public void selectAll() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Clazz";
Query query = manager.createQuery(jpql, Clazz.class);
List list = query.getResultList();
manager.close();
list.forEach(clazz -> System.out.println(JSON.toJSONString(clazz)));
System.out.println("查询结束");
}
```
#### 2.5 jpql查询: 倒序
```java
@Test
public void selectOrder() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Clazz order by id desc";
Query query = manager.createQuery(jpql, Clazz.class);
List list = query.getResultList();
manager.close();
list.forEach(clazz -> System.out.println(JSON.toJSONString(clazz)));
System.out.println("查询结束");
}
```
#### 2.6 jpql查询: 统计查询
```java
@Test
public void selectCount() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "count(id) from Clazz";
Query query = manager.createQuery(jpql, Clazz.class);
Object count = query.getSingleResult();
manager.close();
System.out.println("count >>> " + count);
System.out.println("查询结束");
}
```
#### 2.7 jpql查询: 分页查询
```java
@Test
public void selectPage() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Student order by id desc";
Query query = manager.createQuery(jpql, Student.class);
// 起始索引
query.setFirstResult(0);
// 每页记录数
query.setMaxResults(5);
List list = query.getResultList();
manager.close();
list.forEach(student -> System.out.println(JSON.toJSONString(student)));
System.out.println("查询结束");
}
```
#### 2.8 jpql查询: 模糊条件查询
```java
@Test
public void selectLike() {
// 1、加载配置文件创建工厂
EntityManagerFactory factory = Persistence.createEntityManagerFactory("kgcJPA");
// 2、通过实体管理器工厂获取实体管理器
EntityManager manager = factory.createEntityManager();
String jpql = "from Student where firstName like ?1 or lastName like ?2";
Query query = manager.createQuery(jpql);
// 对占位符赋值
query.setParameter(1, "%孙%");
query.setParameter(2, "%孙%");
// 起始索引
query.setFirstResult(0);
// 每页记录数
query.setMaxResults(10);
List list = query.getResultList();
manager.close();
list.forEach(student -> System.out.println(JSON.toJSONString(student)));
System.out.println("查询结束");
}
```
### [03.springmvc +spring-data-jpa单表操作](demo03)
#### 3.1 需求介绍
本章节我们是实现的功能是spring data jpa 数据库表操作。
```
springDataJpa的入门操作
案例:基本CRUD
搭建环境
创建工程导入坐标
配置spring的配置文件(配置spring Data jpa的整合)
编写实体类,使用jpa注解配置映射关系
编写一个符合springDataJpa的dao层接口
* 只需要编写dao层接口,不需要编写dao层接口的实现类
* dao层接口规范
1.需要继承两个接口(JpaRepository,JpaSpecificationExecutor)
2.需要提供响应的泛型
```
基本方法
| 方法名 | 参数 | 用途 |
| --------------- | ---- | -------------------------------------------------------- |
| findAll() | 无 | 查询全部 |
| findById(id) | id | 根据id查询 |
| getOne(id) | id | 根据id查询 |
| saveAndFlush(t) | 对象 | 保存或者更新(依据:传递的实体类对象中,是否包含id属性) |
| deleteById(id); | id | 根据id删除 内部先执行一次查询然后再执行删除 |
| count() | 无 | 统计记录数 |
| existsById(id) | id | 根据id判断该条记录是否存在 |
#### 3.2 开发包介绍
> [开发包介绍](#1.2 开发包介绍)
#### 3.3 搭建开发环境
创建的数据库表(存储信息)
```sql
DROP TABLE IF EXISTS `clazz`;
CREATE TABLE `clazz` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '班级主键',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '班级名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`uuid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '系统唯一标识符',
`id_card` varchar(18) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '中国身份证号',
`first_name` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '曾用名同身份证姓名',
`last_name` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '现用名 生活中的名字',
`mobile` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '中国手机号码',
`auth_text` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码 DES加密',
`cid` int DEFAULT NULL COMMENT '所在班级编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
##### 3.3.1 maven工程导入坐标
```xml
4.0.0
cn.kgc.tangcco
demo03
1.0-SNAPSHOT
demo03
war
15
15
15
15
utf-8
utf-8
UTF-8
true
true
1.9.6
0.9.5.5
3.3.0
1.4
2.8.0
3.11
3.6
1.2.4
3.9.0
1.2.75
1.1.2
30.0-jre
4.2.3
5.5.7
1.1.2
2.10.8
5.4.27.Final
5.7.0
1.2.17
1.18.16
8.0.22
4.0.1
1.7.30
1.7.30
5.3.2
javax.servlet
javax.servlet-api
4.0.1
org.junit.jupiter
junit-jupiter-api
${junit.version}
test
org.junit.jupiter
junit-jupiter-engine
${junit.version}
test
junit
junit
4.13.1
test
com.github.binarywang
java-testdata-generator
${generator.version}
org.projectlombok
lombok
${lombok.version}
provided
org.springframework
spring-context
${spring.version}
org.springframework
spring-orm
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-aspects
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-test
${spring.version}
org.aspectj
aspectjrt
${aspectj.version}
org.aspectj
aspectjweaver
${aspectj.version}
cglib
cglib
${cglib.version}
mysql
mysql-connector-java
${mysql.version}
com.mchange
c3p0
${c3p0.version}
com.alibaba
druid
${druid.version}
commons-logging
commons-logging
1.2
log4j
log4j
${log4j.version}
org.slf4j
slf4j-api
${slf4j-api.version}
org.slf4j
slf4j-log4j12
${slf4j-log4j12.version}
test
com.alibaba
fastjson
${fastjson.version}
cn.hutool
hutool-all
${hutool-all.version}
org.apache.commons
commons-lang3
${commons-lang3.varsion}
commons-io
commons-io
${commons-io.varsion}
commons-fileupload
commons-fileupload
${commons-fileupload.varsion}
commons-net
commons-net
${commons-net.varsion}
com.google.inject
guice
${guice.version}
com.google.guava
guava
${guava.version}
joda-time
joda-time
${joda-time.version}
com.github.binarywang
java-testdata-generator
${java-testdata-generator.version}
org.hibernate
hibernate-core
${hibernate.version}
org.hibernate
hibernate-entitymanager
${hibernate.version}
org.hibernate
hibernate-c3p0
${hibernate.version}
org.hibernate
hibernate-validator
7.0.0.Final
javax.validation
validation-api
2.0.1.Final
org.springframework.data
spring-data-jpa
2.4.2
javax.el
javax.el-api
3.0.0
org.glassfish
javax.el
3.0.0
org.apache.maven.plugins
maven-war-plugin
3.3.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.1.0
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-compiler-plugin
3.8.1
UTF-8
${jdk.version}
${jdk.version}
org.apache.maven.plugins
maven-surefire-plugin
2.22.2
true
org.apache.maven.plugins
maven-source-plugin
3.2.1
attach-sources
jar
org.apache.maven.plugins
maven-surefire-plugin
2.22.2
true
org.apache.tomcat.maven
tomcat7-maven-plugin
2.2
8080
/
UTF-8
kgc
tangcco
http://localhost:8080/manager/text
org.eclipse.jetty
jetty-maven-plugin
9.4.35.v20201120
/
8080
```
##### 3.3.2 spring框架的配置文件
###### db.properties
```properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://47.94.130.233:3306/ssm?useUnicode=true&characterEncoding=UTF8&useSSL=true&serverTimeZone=Aisa/Shanghai
jdbc.username=root
jdbc.password=123456
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=1800
jdbc.logAbandoned=true
```
###### applicationContext.xml
```xml
true
none
none
```
###### springmvc-server.xml
```xml
text/html;charset=UTF-8
application/json;charset=UTF-8
```
###### web.xml
```xml
springMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/spring-servlet.xml
1
springMVC
/
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
CharacterEncodingFilter
/
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:spring/applicationContext.xml
OpenSessionInViewFilter
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
OpenSessionInViewFilter
/*
```
##### 3.3.3 编写实体类和数据库表的映射配置
> [编写实体类和数据库表的映射配置 ](#2.3.3 编写实体类和数据库表的映射配置 )
#### 3.4 spring Data JPA入门案例
##### 3.4.1 编写符合spring Data JPA规范的dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Clazz;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface ClazzDao extends JpaRepository , JpaSpecificationExecutor {
}
```
##### 3.4.2 编写service层接口的实现类
```java
package cn.kgc.tangcco.service.impl;
import cn.kgc.tangcco.dao.ClazzDao;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.model.ResultCode;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.service.ClazzService;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:37
*/
@Service
public class ClazzServiceImpl implements ClazzService {
@Autowired
private ClazzDao clazzDao;
@Override
public ResponseText> queryClazzs(Clazz clazz) {
List clazzList = clazzDao.findAll();
if (clazzList == null || clazzList.size() == 0) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazzList);
}
@Override
public ResponseText queryClazz(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
Optional optional = clazzDao.findById(id);
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), optional.get());
}
@Override
@Transactional(readOnly = true)//查询的只读就行
public ResponseText getClazz(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
try {
Clazz clazz = clazzDao.getOne(id);
if (clazz != null && !StringUtils.isBlank(clazz.getName())) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazz);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
} catch (Exception exception) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
}
@Transactional(rollbackFor = {Exception.class, RuntimeException.class}, propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
@Override
public ResponseText saveOrUpdate(Clazz clazz) {
if (clazz == null || StringUtils.isEmpty(clazz.getName())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), ResultCode.FAILED.getDesc());
}
if (clazz != null && clazz.getId() != null && clazz.getId() > 0) {
Optional optional = clazzDao.findById(clazz.getId());
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
} else {
clazz.setId(optional.get().getId());
}
}
clazz = clazzDao.saveAndFlush(clazz);
if (clazz == null) {
return new ResponseText<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg(), ResultCode.FAILED.getDesc());
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazz);
}
@Transactional(rollbackFor = {Exception.class, RuntimeException.class}, propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
@Override
public ResponseText remove(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), ResultCode.PARAM_ERROR.getDesc());
}
clazzDao.deleteById(id);
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), ResultCode.SUCCESS.getDesc());
}
@Override
public ResponseText count() {
long count = clazzDao.count();
if (count > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), count);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), 0L);
}
@Override
public ResponseText exists(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), false);
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazzDao.existsById(id));
}
}
```
##### 3.4.3 编写Handler接收请求响应操作后的数据
```java
package cn.kgc.tangcco.action;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.service.ClazzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 15:09
*/
@RestController
@RequestMapping(value = "/clazz")
public class ClazzAction {
@Autowired
private ClazzService clazzService;
@GetMapping(value = "/list")
public ResponseText> queryClazzList() {
return clazzService.queryClazzs(new Clazz());
}
@GetMapping(value = "/findOne")
public ResponseText queryClazz(Integer id) {
return clazzService.queryClazz(id);
}
@GetMapping(value = "/getOne")
public ResponseText getClazz(Integer id) {
return clazzService.getClazz(id);
}
@PutMapping(value = "/save")
public ResponseText save(Clazz clazz, BindingResult bindingResult) {
return clazzService.saveOrUpdate(clazz);
}
@DeleteMapping(value = "/remove/{id}")
public ResponseText removeClazz(@PathVariable(name = "id") Integer id) {
return clazzService.remove(id);
}
@GetMapping(value = "/count")
public ResponseText count() {
return clazzService.count();
}
@GetMapping(value = "/exists")
public ResponseText exists(Integer id) {
return clazzService.exists(id);
}
}
```
##### 3.4.4 查询所有并使用PostMan测试
```java
@Override
public ResponseText> queryClazzs(Clazz clazz) {
List clazzList = clazzDao.findAll();
if (clazzList == null || clazzList.size() == 0) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(),null);
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazzList);
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/list
请求方式:GET
返回结果:
```json
{
"code": "200",
"data": [
{
"id": 1,
"name": "kjde1021"
},
{
"id": 2,
"name": "kjde1022"
},
{
"id": 3,
"name": "kjde1023"
},
{
"id": 4,
"name": "kjde1024"
},
{
"id": 5,
"name": "kjde1025"
}
],
"msg": "操作成功"
}
```
##### 3.4.5 根据ID立即查询PostMan测试
```java
@Override
public ResponseText queryClazz(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
Optional optional = clazzDao.findById(id);
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), optional.get());
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/findOne
请求方式:GET
请求参数:
| key | value |
| ---- | ----- |
| id | 1 |
返回结果:
```json
{
"code": "200",
"data": {
"id": 1,
"name": "kjde1021"
},
"msg": "操作成功"
}
```
##### 3.4.6 根据ID懒加载查询PostMan测试
```java
@Override
@Transactional(readOnly = true)//查询的只读就行
public ResponseText getClazz(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
try {
Clazz clazz = clazzDao.getOne(id);
if (clazz != null && !StringUtils.isBlank(clazz.getName())) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazz);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
} catch (Exception exception) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/getOne
请求方式:GET
请求参数:
| key | value |
| ---- | ----- |
| id | 2 |
返回结果:
```json
{
"code": "200",
"data": {
"id": 2,
"name": "kjde1022"
},
"msg": "操作成功"
}
```
##### 3.4.7 新增数据并使用PostMan测试
```java
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class},propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
public ResponseText saveOrUpdate(Clazz clazz) {
if (clazz == null || StringUtils.isEmpty(clazz.getName())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), ResultCode.FAILED.getDesc());
}
if (clazz != null && clazz.getId() != null && clazz.getId() > 0) {
Optional optional = clazzDao.findById(clazz.getId());
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
} else {
clazz.setId(optional.get().getId());
}
clazz = clazzDao.saveAndFlush(clazz);
if (clazz == null) {
return new ResponseText<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg(), ResultCode.FAILED.getDesc());
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazz);
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/save
请求方式:PUT
请求参数:
| key | value |
| ---- | -------- |
| name | kjde1030 |
返回结果:
```json
{
"code": "200",
"data": {
"id": 6,
"name": "kjde1030"
},
"msg": "操作成功"
}
```
##### 3.4.8 根据ID修改数据并使用PostMan测试
```java
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class},propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
public ResponseText saveOrUpdate(Clazz clazz) {
if (clazz == null || StringUtils.isEmpty(clazz.getName())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), ResultCode.FAILED.getDesc());
}
if (clazz != null && clazz.getId() != null && clazz.getId() > 0) {
Optional optional = clazzDao.findById(clazz.getId());
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
} else {
clazz.setId(optional.get().getId());
}
clazz = clazzDao.saveAndFlush(clazz);
if (clazz == null) {
return new ResponseText<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg(), ResultCode.FAILED.getDesc());
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazz);
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/save
请求方式:PUT
请求参数:
| | |
| ---- | -------- |
| id | 6 |
| name | kade2021 |
返回结果:
```json
{
"code": "200",
"data": {
"id": 6,
"name": "kjde1030"
},
"msg": "操作成功"
}
```
##### 3.4.9 根据ID删除数据PostMan测试
```java
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class},propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
public ResponseText remove(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), ResultCode.PARAM_ERROR.getDesc());
}
clazzDao.deleteById(id);
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), ResultCode.SUCCESS.getDesc());
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/remove/6
请求方式:DELETE
返回结果:
```json
{
"code": "200",
"data": "请求成功",
"msg": "操作成功"
}
```
##### 3.4.10 查询总记录数并使用PostMan测试
```java
@Override
public ResponseText count() {
long count = clazzDao.count();
if (count > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), count);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), 0L);
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/count
请求方式:GET
返回结果:
```json
{
"code": "200",
"data": 5,
"msg": "操作成功"
}
```
##### 3.4.11 根据ID判断该条记录是否存在PostMan测试
```java
@Override
public ResponseText exists(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(),false);
}
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), clazzDao.existsById(id));
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/exists
请求方式:GET
请求参数:
| key | value |
| ---- | ----- |
| id | 1 |
返回结果:
```json
{
"code": "200",
"data": true,
"msg": "操作成功"
}
```
#### 3.5 spring Data JPA JPQL
> 使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询。
```
jpql的查询方式
jpql : jpa query language (jpq查询语言)
特点:语法或关键字和sql语句类似
查询的是类和类中的属性
需要将JPQL语句配置到接口方法上
1.特有的查询:需要在dao接口上配置方法
2.在新添加的方法上,使用注解的形式配置jpql查询语句
3.注解 : @Query
4.使用原生SQL需要在@Query注解中增加nativeQuery = true
例如:@Query(value = "原生SQL语句",nativeQuery = true)
```
#### 3.6 使用jpql完成基本操作
> 注意:jpql不支持insert操作,执行update和delete操作需要在持久层接口方法增加@Modifying注解
##### 3.6.1 编写符合spring Data JPA规范的dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {
/**
* 根据ID查找学生信息
*
* @param id 学生id
* @return 学生信息
*/
@Query("from Student where id = ?1")
public Student selectOne(Integer id);
/**
* 按照名字模糊查找
*
* @param firstName 学生模糊姓名
* @return 模糊姓名查找返回的学生列表
*/
@Query(value = "from Student where firstName like ?1 or lastName like ?2")
public List findStudentLikeName(String firstName, String lastName);
/**
* 更新数据
*
* @param id 更新条件
* @param firstName 曾用名
* @param lastName 现用名
* @param idCard 身份证
* @param mobile 手机号
* @param authText 密码,des加密后的字符串
* @param cid 所在班级编号
*/
@Modifying
@Query(value = "update Student set firstName = ?2,lastName = ?3, idCard = ?4, mobile = ?5, authText = ?6,cid = ?7 where id = ?1")
public int update(Integer id, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid);
/**
* 使用原生SQL模糊查找某班级的学生信息列表
*
* @param cid 班级编号
* @param firstName 曾用名
* @param lastName 现用名
* @return 模糊查找某班级的学生信息列表
*/
@Query(value = "SELECT * FROM `student` WHERE cid = ?1 AND (first_name like ?2 OR last_name like ?3)", nativeQuery = true)
public List nativeQuery(Integer cid, String firstName, String lastName);
}
```
##### 3.6.2 编写service层接口的实现类
```java
package cn.kgc.tangcco.service.impl;
import cn.kgc.tangcco.dao.StudentDao;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.model.ResultCode;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.pojo.Student;
import cn.kgc.tangcco.service.StudentService;
import cn.kgc.tangcco.utils.cryptography.BaseCryptographyUtils;
import cn.kgc.tangcco.utils.reflect.BaseReflect;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 14:44
*/
@Service
public class StudentServiceImpl implements StudentService {
private final static String key = "lihaozhelihaozhelihaozhelihaozhelihaozhelihaozhelihaozhelihaozhe";
@Autowired
private StudentDao studentDao;
@Override
public ResponseText findOne(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
Optional optional = studentDao.findById(id);
if (optional.isEmpty()) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
Student student = optional.get();
student.setAuthText(BaseCryptographyUtils.desDecodeHexString(student.getAuthText(), key));
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}
@Override
public ResponseText getOne(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
try {
Student student = studentDao.getOne(id);
student.setAuthText(BaseCryptographyUtils.desDecodeHexString(student.getAuthText(), key));
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}catch (Exception exception){
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
}
@Override
public ResponseText selectOne(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
Student student = studentDao.selectOne(id);
if (student == null) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
student.setAuthText(BaseCryptographyUtils.desDecodeHexString(student.getAuthText(), key));
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}
@Override
public ResponseText> findLike(String firstName) {
if (StringUtils.isEmpty(firstName)) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), new ArrayList<>());
}
StringBuilder param = new StringBuilder();
param.append("%");
param.append(firstName);
param.append("%");
List students = studentDao.findStudentLikeName(param.toString(), param.toString());
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
@Transactional(rollbackFor = {Exception.class, RuntimeException.class}, propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
@Override
public ResponseText update(Student student) {
if (student == null || student.getId() == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
if (!studentDao.existsById(student.getId())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
String authText = BaseCryptographyUtils.desEncodeHexString(student.getAuthText(), key);
int status = studentDao.update(student.getId(), student.getFirstName(), student.getLastName(), student.getIdCard(), student.getMobile(), authText, student.getCid());
// System.out.println(1 / 0);
if (status > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}
return new ResponseText<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg(), student);
}
@Override
public ResponseText> nativeQuery(Student student) {
if (student == null || student.getCid() == null || StringUtils.isBlank(student.getFirstName())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(student.getFirstName());
nickname.append("%");
List students = studentDao.nativeQuery(student.getCid(), nickname.toString(), nickname.toString());
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
}
```
##### 3.6.3 编写Handler接收请求响应操作后的数据
```java
package cn.kgc.tangcco.action;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.pojo.Student;
import cn.kgc.tangcco.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 14:48
*/
@RestController
@RequestMapping(value = "/student")
public class StudentAction {
@Autowired
private StudentService studentService;
@GetMapping(value = "/findOne")
public ResponseText findOne(Integer id) {
return studentService.findOne(id);
}
@GetMapping(value = "/getOne")
public ResponseText getOne(Integer id) {
return studentService.getOne(id);
}
@GetMapping(value = "/selectOne")
public ResponseText selectOne(Integer id) {
return studentService.getOne(id);
}
@GetMapping(value = "/findLike")
public ResponseText> findLike(String firstName) {
return studentService.findLike(firstName);
}
@PutMapping(value = "/update")
public ResponseText update(Student student) {
return studentService.update(student);
}
@PostMapping(value = "/nativeQuery")
public ResponseText> nativeQuery(Student student) {
return studentService.nativeQuery(student);
}
}
```
##### 3.6.4 根据ID查询PostMan测试
> findById(id)与getOne(id)略
>
> 注意getOne(id)使用异常判断返回结果
dao层接口
```java
/**
* 根据ID查找学生信息
*
* @param id 学生id
* @return 学生信息
*/
@Query("from Student where id = ?1")
public Student selectOne(Integer id);
```
service层实现类
```java
@Override
public ResponseText selectOne(Integer id) {
if (id == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
Student student = studentDao.selectOne(id);
if (student == null) {
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
student.setAuthText(BaseCryptographyUtils.desDecodeHexString(student.getAuthText(),key));
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}
```
PonsMan测试
请求地址:http://localhost:8080/clazz/selectOne
请求方式:GET
请求参数:
| key | value |
| ---- | ----- |
| id | 1 |
返回结果:
```json
{
"code": "200",
"data": {
"authText": "123456",
"cid": 2,
"firstName": "夏侯勺",
"id": 1,
"idCard": "238108199212286379",
"lastName": "夏侯勺",
"mobile": "13712323067",
"uuid": "f3b4a8b465dc4ad483c1ca54d671b163"
},
"msg": "操作成功"
}
```
##### 3.6.5 多占位符模糊查询并使用PostMan测试
dao层接口
```java
/**
* 按照名字模糊查找
*
* @param firstName 学生模糊姓名
* @return 模糊姓名查找返回的学生列表
*/
@Query(value = "from Student where firstName like ?1 or lastName like ?2")
public List findStudentLikeName(String firstName, String lastName);
```
service层实现类
```java
@Override
public ResponseText> findLike(String firstName) {
if (StringUtils.isEmpty(firstName)) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
StringBuilder param = new StringBuilder();
param.append("%");
param.append(firstName);
param.append("%");
List students = studentDao.findStudentLikeName(param.toString(), param.toString());
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), null);
}
```
PonsMan测试
请求地址:http://localhost:8080/student/findLike
请求方式:GET
请求参数:
| name | value |
| --------- | ----- |
| firstName | 孙 |
返回结果:
```json
{
"code": "200",
"data": [
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "公孙憎",
"id": 12,
"idCard": "448456198211048370",
"lastName": "公孙憎",
"mobile": "13720463226",
"uuid": "c4da87838fa74d1daa8286f8f4b0e38a"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 2,
"firstName": "孙盯",
"id": 61,
"idCard": "542406198509154162",
"lastName": "孙盯",
"mobile": "15862199605",
"uuid": "f1a7304c1be747b39b1535130fd717eb"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "孙章",
"id": 102,
"idCard": "646615197302024483",
"lastName": "孙章",
"mobile": "15573942169",
"uuid": "09a6e376e25745afa9e372be1606ee59"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "公孙萝倘",
"id": 110,
"idCard": "454080199509165300",
"lastName": "公孙萝倘",
"mobile": "13100349323",
"uuid": "334b107f91f3490a89dffa85ae8cc09f"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 5,
"firstName": "公孙绚吃",
"id": 114,
"idCard": "71350119840129870X",
"lastName": "公孙绚吃",
"mobile": "17642217181",
"uuid": "f36a08fbfbc74976bafd186ece1fe909"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "公孙侯锦",
"id": 118,
"idCard": "411287198403086218",
"lastName": "公孙侯锦",
"mobile": "13721248393",
"uuid": "7e31bb44ae8e4d918f4542f5e5139598"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "孙捶",
"id": 128,
"idCard": "339375198205213949",
"lastName": "孙捶",
"mobile": "13026338019",
"uuid": "4ae0d4d1d0ba4b5ea1ed226108a54535"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 5,
"firstName": "公孙婴",
"id": 130,
"idCard": "617514199408240160",
"lastName": "公孙婴",
"mobile": "13449740380",
"uuid": "5f5525b2e5184628836ef9942e321e82"
}
],
"msg": "操作成功"
}
```
##### 3.6.6 更新数据并使用PostMan测试
dao层接口
```java
/**
* 更新数据
*
* @param id 更新条件
* @param firstName 曾用名
* @param lastName 现用名
* @param idCard 身份证
* @param mobile 手机号
* @param authText 密码,des加密后的字符串
* @param cid 所在班级编号
*/
@Modifying
@Query(value = "update Student set firstName = ?2,lastName = ?3, idCard = ?4, mobile = ?5, authText = ?6,cid = ?7 where id = ?1")
public void update(Integer id, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid);
```
service层实现类
```java
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class},propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false)
public ResponseText update(Student student) {
if (student == null || student.getId() == null) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
if (!studentDao.existsById(student.getId())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
String authText = BaseCryptographyUtils.desEncodeHexString(student.getAuthText(), key);
studentDao.update(student.getId(), student.getFirstName(), student.getLastName(), student.getIdCard(), student.getMobile(), authText, student.getCid());
// System.out.println(1 / 0);
if (status > 0){
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), student);
}
return new ResponseText<>(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMsg(), student);
}
```
PonsMan测试
请求地址:http://localhost:8080/student/update
请求方式:PUT
请求参数:
| key | value |
| --------- | ------------------ |
| id | 1 |
| firstName | 王柔 |
| lastName | 王柔 |
| idCard | 653863198001212849 |
| mobile | 17004762790 |
| authText | 654321 |
| cid | 5 |
返回结果:
```json
{
"code": "200",
"data": {
"authText": "654321",
"cid": 5,
"firstName": "王柔",
"id": 1,
"idCard": "653863198001212849",
"lastName": "王柔",
"mobile": "17004762790",
"uuid": "f3b4a8b465dc4ad483c1ca54d671b163"
},
"msg": "操作成功"
}
```
##### 3.6.7 jpql使用原生SQL语句
dao层接口
```java
/**
* 使用原生SQL模糊查找某班级的学生信息列表
*
* @param cid 班级编号
* @param firstName 曾用名
* @param lastName 现用名
* @return 模糊查找某班级的学生信息列表
*/
@Query(value = "SELECT * FROM `student` WHERE cid = ?1 AND (first_name like ?2 OR last_name like ?3)", nativeQuery = true)
public List nativeQuery(Integer cid, String firstName, String lastName);
```
service层实现类
```java
@Override
public ResponseText> nativeQuery(Student student) {
if (student == null || student.getCid() == null || StringUtils.isBlank(student.getFirstName())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(student.getFirstName());
nickname.append("%");
List students = studentDao.nativeQuery(student.getCid(), nickname.toString(), nickname.toString());
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
```
PonsMan测试
请求地址:http://localhost:8080/student/nativeQuery
请求方式:POST
请求参数:
| key | value |
| --------- | ----- |
| cid | 3 |
| firstName | 孙 |
返回结果:
```json
{
"code": "200",
"data": [
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "孙章",
"id": 102,
"idCard": "646615197302024483",
"lastName": "孙章",
"mobile": "15573942169",
"uuid": "09a6e376e25745afa9e372be1606ee59"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "公孙萝倘",
"id": 110,
"idCard": "454080199509165300",
"lastName": "公孙萝倘",
"mobile": "13100349323",
"uuid": "334b107f91f3490a89dffa85ae8cc09f"
}
],
"msg": "操作成功"
}
```
#### 3.7 spring data jpa Specification动态查询
```java
public interface JpaSpecificationExecutor {
// 按照指定条件查询单个结果
Optional findOne(@Nullable Specification var1);
// 按照查询所有符合条件的结果
List findAll(@Nullable Specification var1);
// 按照指定条件分页查询
Page findAll(@Nullable Specification var1, Pageable var2);
// 按照查询所有符合条件的结果 并安装指定条件排序
List findAll(@Nullable Specification var1, Sort var2);
// 统计分析
long count(@Nullable Specification var1);
}
```
> Specification 查询条件对象
##### 3.7.1 编写符合spring Data JPA规范的dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {}
```
##### 3.7.2 编写service层接口的实现类
```java
package cn.kgc.tangcco.service.impl;
import cn.kgc.tangcco.dao.StudentDao;
import cn.kgc.tangcco.model.PageParam;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.model.ResultCode;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.pojo.Student;
import cn.kgc.tangcco.service.StudentService;
import cn.kgc.tangcco.utils.cryptography.BaseCryptographyUtils;
import cn.kgc.tangcco.utils.reflect.BaseReflect;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 14:44
*/
@Service
public class StudentServiceImpl implements StudentService {
private final static String key = "lihaozhelihaozhelihaozhelihaozhelihaozhelihaozhelihaozhelihaozhe";
@Autowired
private StudentDao studentDao;
@Override
public ResponseText loginByMobileAndAuthText(Student student) {
if (student == null || StringUtils.isBlank(student.getMobile()) || StringUtils.isBlank(student.getAuthText())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
student.setAuthText(BaseCryptographyUtils.desEncodeHexString(student.getAuthText(), key));
try {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), studentDao.findOne((root, cq, cb) -> {
return cb.and(cb.equal(root.get("mobile"), student.getMobile()), cb.equal(root.get("authText"), student.getAuthText()));
}).get());
} catch (Exception exception) {
return new ResponseText<>(ResultCode.LOGIN_FAILED.getCode(), ResultCode.LOGIN_FAILED.getMsg(), null);
}
}
@Override
public ResponseText> specificationLike(String firstName) {
if (StringUtils.isBlank(firstName)) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), new ArrayList<>());
}
List students = studentDao.findAll((root, cq, cb) -> {
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(firstName);
nickname.append("%");
return cb.or(cb.like(root.get("firstName").as(String.class), nickname.toString()), cb.like(root.get("lastName").as(String.class), nickname.toString()));
}, Sort.by(Sort.Direction.DESC, "cid"));
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
@Override
public Page page(Student student, PageParam pageParam) {
return studentDao.findAll((root, cq, cb) -> {
Predicate cid = null;
Predicate nickName = null;
if (student.getCid() != null && student.getCid() > 0) {
cid = cb.equal(root.get("cid"), student.getCid());
}
if (!StringUtils.isBlank(student.getFirstName())) {
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(student.getFirstName());
nickname.append("%");
nickName = cb.or(cb.like(root.get("firstName").as(String.class), nickname.toString()), cb.like(root.get("lastName").as(String.class), nickname.toString()));
}
if (cid != null && nickName != null) {
return cb.and(cid, nickName);
} else if (cid != null && nickName == null) {
return cid;
} else if (cid == null && nickName != null) {
return nickName;
} else {
return null;
}
}, PageRequest.of(pageParam.getPageNum() - 1, pageParam.getPageSize(), Sort.by(Sort.Direction.DESC, "id")));
}
}
```
##### 3.7.3 编写Handler接收请求响应操作后的数据
```java
package cn.kgc.tangcco.action;
import cn.kgc.tangcco.model.PageParam;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.pojo.Student;
import cn.kgc.tangcco.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 14:48
*/
@RestController
@RequestMapping(value = "/student")
public class StudentAction {
@Autowired
private StudentService studentService;
@PostMapping(value = "/loginByMobileAndAuthText")
public ResponseText loginByMobileAndAuthText(Student student) {
return studentService.loginByMobileAndAuthText(student);
}
@GetMapping(value = "/specificationLike")
public ResponseText> specificationLike(String firstName) {
return studentService.specificationLike(firstName);
}
@PostMapping(value = "/page")
public Page page(Student student,
@RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
@RequestParam(value = "limit", required = false, defaultValue = "5") Integer limit) {
return studentService.page(student, new PageParam(page, limit));
}
}
```
##### 3.7.4 多条件查询实现登录功能并使用PostMan测试
dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {}
```
service层实现类
```java
@Override
public ResponseText loginByMobileAndAuthText(Student student) {
if (student == null || StringUtils.isBlank(student.getMobile()) || StringUtils.isBlank(student.getAuthText())) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), null);
}
student.setAuthText(BaseCryptographyUtils.desEncodeHexString(student.getAuthText(), key));
try {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), studentDao.findOne((root, cq, cb) -> {
return cb.and(cb.equal(root.get("mobile"), student.getMobile()), cb.equal(root.get("authText"), student.getAuthText()));
}).get());
}catch (Exception exception){
return new ResponseText<>(ResultCode.LOGIN_FAILED.getCode(), ResultCode.LOGIN_FAILED.getMsg(), null);
}
}
```
PonsMan测试
请求地址:http://localhost:8080/student/loginByMobileAndAuthText
请求方式:POST
请求参数:
| name | value |
| -------- | ----------- |
| mobile | 15311484568 |
| authText | 123456 |
登录成功返回结果:
```json
{
"code": "200",
"data": {
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "王柔",
"id": 1,
"idCard": "653863198001212849",
"lastName": "王柔",
"mobile": "17004762790",
"uuid": "f3b4a8b465dc4ad483c1ca54d671b163"
},
"msg": "操作成功"
}
```
登录失败返回结果:
```json
{
"code": "10002",
"msg": "登录失败"
}
```
##### 3.7.5 模糊查询后排序并使用PostMan测试
dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {}
```
service层实现类
```java
@Override
public ResponseText> specificationLike(String firstName) {
if (StringUtils.isBlank(firstName)) {
return new ResponseText<>(ResultCode.PARAM_ERROR.getCode(), ResultCode.PARAM_ERROR.getMsg(), new ArrayList<>());
}
List students = studentDao.findAll((root, cq, cb) -> {
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(firstName);
nickname.append("%");
return cb.or(cb.like(root.get("firstName").as(String.class), nickname.toString()), cb.like(root.get("lastName").as(String.class), nickname.toString()));
},Sort.by(Sort.Direction.DESC, "cid"));
if (students != null && students.size() > 0) {
return new ResponseText<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), students);
}
return new ResponseText<>(ResultCode.DATA_EMPTY.getCode(), ResultCode.DATA_EMPTY.getMsg(), new ArrayList<>());
}
```
PonsMan测试
请求地址:http://localhost:8080/student/specificationLike
请求方式:GET
请求参数:
| name | value |
| --------- | ----- |
| firstName | 孙 |
登录成功返回结果:
```json
{
"code": "200",
"data": {
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "王柔",
"id": 1,
"idCard": "653863198001212849",
"lastName": "王柔",
"mobile": "17004762790",
"uuid": "f3b4a8b465dc4ad483c1ca54d671b163"
},
"msg": "操作成功"
}
```
登录失败返回结果:
```json
{
"code": "200",
"data": [
{
"authText": "1f4a79344c3e1f58",
"cid": 5,
"firstName": "公孙绚吃",
"id": 114,
"idCard": "71350119840129870X",
"lastName": "公孙绚吃",
"mobile": "17642217181",
"uuid": "f36a08fbfbc74976bafd186ece1fe909"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 5,
"firstName": "公孙婴",
"id": 130,
"idCard": "617514199408240160",
"lastName": "公孙婴",
"mobile": "13449740380",
"uuid": "5f5525b2e5184628836ef9942e321e82"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "孙捶",
"id": 128,
"idCard": "339375198205213949",
"lastName": "孙捶",
"mobile": "13026338019",
"uuid": "4ae0d4d1d0ba4b5ea1ed226108a54535"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "孙章",
"id": 102,
"idCard": "646615197302024483",
"lastName": "孙章",
"mobile": "15573942169",
"uuid": "09a6e376e25745afa9e372be1606ee59"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "公孙萝倘",
"id": 110,
"idCard": "454080199509165300",
"lastName": "公孙萝倘",
"mobile": "13100349323",
"uuid": "334b107f91f3490a89dffa85ae8cc09f"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 2,
"firstName": "孙盯",
"id": 61,
"idCard": "542406198509154162",
"lastName": "孙盯",
"mobile": "15862199605",
"uuid": "f1a7304c1be747b39b1535130fd717eb"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "公孙憎",
"id": 12,
"idCard": "448456198211048370",
"lastName": "公孙憎",
"mobile": "13720463226",
"uuid": "c4da87838fa74d1daa8286f8f4b0e38a"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "公孙侯锦",
"id": 118,
"idCard": "411287198403086218",
"lastName": "公孙侯锦",
"mobile": "13721248393",
"uuid": "7e31bb44ae8e4d918f4542f5e5139598"
}
],
"msg": "操作成功"
}
```
##### 3.7.6 动态SQL分页查询后排序并使用PostMan测试
dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {}
```
service层实现类
```java
@Override
public Page page(Student student, PageParam pageParam) {
return studentDao.findAll((root, cq, cb) -> {
Predicate cid = null;
Predicate nickName = null;
if (student.getCid() != null && student.getCid() > 0) {
cid = cb.equal(root.get("cid"), student.getCid());
}
if (!StringUtils.isBlank(student.getFirstName())) {
StringBuilder nickname = new StringBuilder();
nickname.append("%");
nickname.append(student.getFirstName());
nickname.append("%");
nickName = cb.or(cb.like(root.get("firstName").as(String.class), nickname.toString()), cb.like(root.get("lastName").as(String.class), nickname.toString()));
}
if (cid != null && nickName != null) {
return cb.and(cid, nickName);
} else if (cid != null && nickName == null) {
return cid;
} else if (cid == null && nickName != null) {
return nickName;
} else {
return null;
}
}, PageRequest.of(pageParam.getPageNum() - 1, pageParam.getPageSize(), Sort.by(Sort.Direction.DESC, "id")));
}
```
PonsMan测试
请求地址:http://localhost:8080/student/page?page=2&limit5
> page : 查询页面号
>
> limit: 每页记录数
请求方式:POST
请求参数:
| name | value |
| --------- | ----- |
| cid | 3 |
| firstName | 李 |
第一页返回结果:
```json
{
"content": [
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "宋棍糜",
"id": 200,
"idCard": "916281198302191822",
"lastName": "宋棍糜",
"mobile": "18067192779",
"uuid": "6d0bd2ccb31b433dbacd51ec65f90275"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 1,
"firstName": "李招",
"id": 199,
"idCard": "211497198511043617",
"lastName": "李招",
"mobile": "18722348916",
"uuid": "050b90568f5c42848f11ea2e631701cd"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "朱私",
"id": 198,
"idCard": "643284198309191316",
"lastName": "朱私",
"mobile": "18708644764",
"uuid": "f4e153078ada4050a488dcc1296cd9af"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "孔紊渗",
"id": 197,
"idCard": "350518199010187684",
"lastName": "孔紊渗",
"mobile": "18992171633",
"uuid": "892604fce5db4999956aff79a1928564"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 4,
"firstName": "郑截",
"id": 196,
"idCard": "234689197612188615",
"lastName": "郑截",
"mobile": "17659261592",
"uuid": "c34eff3134094f9d87067390516a1076"
}
],
"empty": false,
"first": true,
"last": false,
"number": 0,
"numberOfElements": 5,
"pageable": {
"offset": 0,
"pageNumber": 0,
"pageSize": 5,
"paged": true,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"unpaged": false
},
"size": 5,
"sort": {
"$ref": "$.pageable.sort"
},
"totalElements": 200,
"totalPages": 40
}
```
第二页返回结果:
```json
{
"content": [
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "李鲜",
"id": 14,
"idCard": "648815198506187214",
"lastName": "鲜于饥贴",
"mobile": "14780974323",
"uuid": "f14b8d3b15d645d0b8d5aa19ed8f76df"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "李夯瑞",
"id": 13,
"idCard": "427623199708063537",
"lastName": "任夯瑞",
"mobile": "18459766061",
"uuid": "34094b667bb64740b8f63d342ce79994"
},
{
"authText": "1f4a79344c3e1f58",
"cid": 3,
"firstName": "李矩",
"id": 3,
"idCard": "213665200001241025",
"lastName": "阎矩痒",
"mobile": "13549677158",
"uuid": "aa25f6ac018c422987bfbe0723040925"
}
],
"empty": false,
"first": false,
"last": true,
"number": 1,
"numberOfElements": 3,
"pageable": {
"offset": 5,
"pageNumber": 1,
"pageSize": 5,
"paged": true,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"unpaged": false
},
"size": 5,
"sort": {
"$ref": "$.pageable.sort"
},
"totalElements": 8,
"totalPages": 2
}
```
#### 3.8 方法名称命名规则查询kgc
```
规则:
findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)
```
| 关键字 | 方法命名 | sql where 字句 |
| ------------------ | ------------------------------ | -------------------------- |
| And | findByNameAndPwd | where name= ? and pwd =? |
| Or | findByNameOrSex | where name= ? or sex=? |
| Is,Equal | findById, | findByIdEquals |
| Between | findByIdBetween | where id between ? and ? |
| LessThan | findByIdLessThan | where id < ? |
| LessThanEqual | findByIdLessThanEquals | where id <= ? |
| GreaterThan | findByIdGreaterThan | where id > ? |
| GreaterThanEqual | findByIdGreaterThanEquals | where id > = ? |
| After | findByIdAfter | where id > ? |
| Before | findByIdBefore | where id < ? |
| IsNull | findByNameIsNull | where name is null |
| isNotNull,Not Null | findByNameNotNull | where name is not |
| Like | findByNameLike | where name like ? |
| NotLike | findByNameNotLike | where name not like ? |
| StartingWith | findByNameStartingWith | where name like '?%' |
| EndingWith | findByNameEndingWith | where name like '%?' |
| Containing | findByNameContaining | where name like '%?%' |
| OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
| Not | findByNameNot | where name <> ? |
| In | findByIdIn(Collection> c) | where id in (?) |
| NotIn | findByIdNotIn(Collection> c) | where id not in (?) |
| True | findByAaaTue | where aaa = true |
| False | findByAaaFalse | where aaa = false |
| IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
### [04.springmvc+spring-data-jpa多表操作](demo04)
#### 4.1 需求介绍
本章节我们是实现的功能是spring data jpa 数据库多表操作。
注解说明
> - **@OneToMany:**
> 作用:建立一对多的关系映射
> 属性:
> **targetEntityClass**:指定多的多方的类的字节码
> **mappedBy**:指定从表实体类中引用主表对象的名称。
> **cascade**:指定要使用的级联操作
> **fetch**:指定是否采用延迟加载
> **orphanRemoval**:是否使用孤儿删除
> - **@ManyToOne**
> 作用:建立多对一的关系
> 属性:
> **targetEntityClass**:指定一的一方实体类字节码
> **cascade**:指定要使用的级联操作
> **fetch**:指定是否采用延迟加载
> **optional**:关联是否可选。如果设置为false,则必须始终存在非空关系。
> - **@JoinColumn**
> 作用:用于定义主键字段和外键字段的对应关系。
> 属性:
> **name**:指定外键字段的名称
> **referencedColumnName**:指定引用主表的主键字段名称
> **unique**:是否唯一。默认值不唯一
> **nullable**:是否允许为空。默认值允许。
> **insertable**:是否允许插入。默认值允许。
> **updatable**:是否允许更新。默认值允许。
> **columnDefinition**:列的定义信息。
```
true
none
none
```
#### 4.2 开发包介绍
> [开发包介绍](#1.2 开发包介绍)
#### 4.3 搭建开发环境
> 程序运行自动创建表
>
> 注意json循环依赖,在实体类代码中有具体体现
##### 4.3.1 maven工程导入坐标
```xml
4.0.0
cn.kgc.tangcco
demo04
1.0-SNAPSHOT
demo04
war
15
15
15
15
utf-8
utf-8
UTF-8
true
true
1.9.6
0.9.5.5
3.3.0
1.4
2.8.0
3.11
3.6
1.2.4
3.9.0
1.2.75
1.1.2
30.0-jre
4.2.3
5.5.7
2.11.3
1.1.2
2.10.8
5.4.27.Final
5.7.0
1.2.17
1.18.16
8.0.22
4.0.1
1.7.30
1.7.30
5.3.2
javax.servlet
javax.servlet-api
4.0.1
org.junit.jupiter
junit-jupiter-api
${junit.version}
test
org.junit.jupiter
junit-jupiter-engine
${junit.version}
test
junit
junit
4.13.1
test
com.github.binarywang
java-testdata-generator
${generator.version}
org.projectlombok
lombok
${lombok.version}
provided
org.springframework
spring-context
${spring.version}
org.springframework
spring-orm
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-aspects
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-test
${spring.version}
org.aspectj
aspectjrt
${aspectj.version}
org.aspectj
aspectjweaver
${aspectj.version}
cglib
cglib
${cglib.version}
mysql
mysql-connector-java
${mysql.version}
com.mchange
c3p0
${c3p0.version}
com.alibaba
druid
${druid.version}
commons-logging
commons-logging
1.2
log4j
log4j
${log4j.version}
org.slf4j
slf4j-api
${slf4j-api.version}
org.slf4j
slf4j-log4j12
${slf4j-log4j12.version}
test
com.alibaba
fastjson
${fastjson.version}
cn.hutool
hutool-all
${hutool-all.version}
org.apache.commons
commons-lang3
${commons-lang3.varsion}
commons-io
commons-io
${commons-io.varsion}
commons-fileupload
commons-fileupload
${commons-fileupload.varsion}
commons-net
commons-net
${commons-net.varsion}
com.google.inject
guice
${guice.version}
com.google.guava
guava
${guava.version}
joda-time
joda-time
${joda-time.version}
com.github.binarywang
java-testdata-generator
${java-testdata-generator.version}
org.hibernate
hibernate-core
${hibernate.version}
org.hibernate
hibernate-entitymanager
${hibernate.version}
org.hibernate
hibernate-c3p0
${hibernate.version}
org.hibernate
hibernate-validator
7.0.0.Final
javax.validation
validation-api
2.0.1.Final
org.springframework.data
spring-data-jpa
2.4.2
javax.el
javax.el-api
3.0.0
org.glassfish
javax.el
3.0.0
com.fasterxml.jackson.core
jackson-core
${jackson.version}
com.fasterxml.jackson.core
jackson-databind
${jackson.version}
com.fasterxml.jackson.core
jackson-annotations
${jackson.version}
org.apache.maven.plugins
maven-war-plugin
3.3.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.1.0
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-compiler-plugin
3.8.1
UTF-8
${jdk.version}
${jdk.version}
org.apache.maven.plugins
maven-surefire-plugin
2.22.2
true
org.apache.maven.plugins
maven-source-plugin
3.2.1
attach-sources
jar
org.apache.maven.plugins
maven-surefire-plugin
2.22.2
true
org.apache.tomcat.maven
tomcat7-maven-plugin
2.2
8080
/
UTF-8
kgc
tangcco
http://localhost:8080/manager/text
org.eclipse.jetty
jetty-maven-plugin
9.4.35.v20201120
/
8080
```
##### 4.3.2 spring框架的配置文件
###### db.properties
```properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://47.94.130.233:3306/ssm?useUnicode=true&characterEncoding=UTF8&useSSL=true&serverTimeZone=Aisa/Shanghai
jdbc.username=root
jdbc.password=123456
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=1800
jdbc.logAbandoned=true
```
###### applicationContext.xml
```xml
true
update
none
```
###### springmvc-server.xml
```xml
```
###### web.xml
```xml
springMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/spring-servlet.xml
1
springMVC
/
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
utf-8
CharacterEncodingFilter
/
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:spring/applicationContext.xml
OpenSessionInViewFilter
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
OpenSessionInViewFilter
/*
```
#### 4.4 一对一 一对多 多对一
##### 4.4.1 编写实体类和数据库表的映射配置
```java
package cn.kgc.tangcco.pojo;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 9:19
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Accessors(chain = true)
@Table(name = "clazz")
@Entity
@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler", "fieldHandler"})
public class Clazz implements Serializable {
private static final long serialVersionUID = -6973342665464585093L;
/**
* 班级编号
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
/**
* 班级名称
*/
@Column(name = "name")
private String name;
@JsonBackReference
// @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id")
@OneToMany(targetEntity = Student.class, mappedBy = "clazz", cascade = {CascadeType.ALL}, orphanRemoval = false, fetch = FetchType.LAZY)
public List students;
public Clazz(String name) {
this.name = name;
}
public Clazz(Integer id, String name) {
this.id = id;
this.name = name;
}
public Clazz(String name, List students) {
this.name = name;
this.students = students;
}
}
```
```java
package cn.kgc.tangcco.pojo;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 9:23
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Accessors(chain = true)
@Table(name = "student")
@Entity
@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler", "fieldHandler"})
public class Student implements Serializable {
private static final long serialVersionUID = -2373830287539636924L;
/**
* 学生编号
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
/**
* 学生唯一标志
*/
@Column(name = "uuid")
private String uuid;
/**
* 学生曾用名
*/
@Column(name = "first_name")
private String firstName;
/**
* 学生现用名
*/
@Column(name = "last_name")
private String lastName;
/**
* 学生身份证
*/
@Column(name = "id_card")
private String idCard;
/**
* 学生手机号
*/
@Column(name = "mobile")
private String mobile;
/**
* 密码
*/
@Column(name = "auth_text")
private String authText;
/**
* 学生所在班级编号
*/
@Column(name = "cid")
private Integer cid;
/**
* 学生所在班级信息
*/
@ManyToOne(targetEntity = Clazz.class, cascade = {CascadeType.MERGE}, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false, nullable = true)
private Clazz clazz;
public Student(String uuid, String firstName, String lastName, String idCard, String mobile, String authText) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.idCard = idCard;
this.mobile = mobile;
this.authText = authText;
}
public Student(String uuid, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.idCard = idCard;
this.mobile = mobile;
this.authText = authText;
this.cid = cid;
}
public Student(String uuid, String firstName, String lastName, String idCard, String mobile, String authText, Clazz clazz) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.idCard = idCard;
this.mobile = mobile;
this.authText = authText;
this.clazz = clazz;
}
public Student(String uuid, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid, Clazz clazz) {
this.uuid = uuid;
this.firstName = firstName;
this.lastName = lastName;
this.idCard = idCard;
this.mobile = mobile;
this.authText = authText;
this.cid = cid;
this.clazz = clazz;
}
}
```
##### 4.4.2 编写符合spring Data JPA规范的dao层接口
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Clazz;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface ClazzDao extends JpaRepository , JpaSpecificationExecutor {}
```
```java
package cn.kgc.tangcco.dao;
import cn.kgc.tangcco.pojo.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* @author 李昊哲
* @Description
* @create 2021/1/12 9:26
* JpaRepository T操作实体类泛型 ID实体类中主键属性的泛型
* JpaSpecificationExecutor T操作实体类泛型
*/
public interface StudentDao extends JpaRepository, JpaSpecificationExecutor {
/**
* 根据ID查找学生信息
*
* @param id 学生id
* @return 学生信息
*/
@Query("from Student where id = ?1")
public Student selectOne(Integer id);
/**
* 按照名字模糊查找
*
* @param firstName 学生模糊姓名
* @return 模糊姓名查找返回的学生列表
*/
@Query(value = "from Student where firstName like ?1 or lastName like ?2")
public List findStudentLikeName(String firstName, String lastName);
/**
* 更新数据
*
* @param id 更新条件
* @param firstName 曾用名
* @param lastName 现用名
* @param idCard 身份证
* @param mobile 手机号
* @param authText 密码,des加密后的字符串
* @param cid 所在班级编号
*/
@Modifying
@Query(value = "update Student set firstName = ?2,lastName = ?3, idCard = ?4, mobile = ?5, authText = ?6,cid = ?7 where id = ?1")
public int update(Integer id, String firstName, String lastName, String idCard, String mobile, String authText, Integer cid);
/**
* 再删除之前
* @param cid
* @return
*/
@Modifying
@Query(value = "update Student set cid = 0 where cid = ?1")
public int nativUpdate(Integer cid);
/**
* 使用原生SQL模糊查找某班级的学生信息列表
*
* @param cid 班级编号
* @param firstName 曾用名
* @param lastName 现用名
* @return 模糊查找某班级的学生信息列表
*/
@Query(value = "SELECT * FROM `student` WHERE cid = ?1 AND (first_name like ?2 OR last_name like ?3)", nativeQuery = true)
public List nativeQuery(Integer cid, String firstName, String lastName);
}
```
##### 4.4.3 编写Handler接收请求响应操作后的数据
```java
package cn.kgc.tangcco.action;
import cn.kgc.tangcco.model.ResponseText;
import cn.kgc.tangcco.pojo.Clazz;
import cn.kgc.tangcco.service.ClazzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 李昊哲
* @Description
* @create 2020/10/30 15:09
*/
@RestController
@RequestMapping(value = "/clazz")
public class ClazzAction {
@Autowired
private ClazzService clazzService;
@GetMapping(value = "/list")
public ResponseText> queryClazzList() {
return clazzService.queryClazzs(new Clazz());
}
@GetMapping(value = "/findOne")
public ResponseText queryClazz(Integer id) {
return clazzService.queryClazz(id);
}
@GetMapping(value = "/getOne")
public ResponseText getClazz(Integer id) {
return clazzService.getClazz(id);
}
@GetMapping(value = "/getOneJson")
public ResponseText