From 2b619798a166301ca4f0312be53d966e62eb2f09 Mon Sep 17 00:00:00 2001 From: "Yangkai.Shen" <237497819@qq.com> Date: Thu, 10 Oct 2019 11:08:46 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20jpa=E5=A2=9E=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E4=B8=8A=E4=B8=8B=E7=BA=A7=E8=87=AA=E5=85=B3=E8=81=94?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E6=88=B7=E9=83=A8=E9=97=A8=E5=A4=9A=E5=AF=B9?= =?UTF-8?q?=E5=A4=9A=E5=85=B3=E8=81=94=EF=BC=8C[PR#59](https://github.com/?= =?UTF-8?q?xkcoding/spring-boot-demo/pull/59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring-boot-demo-orm-jpa/README.md | 203 +++++++++++++++++- spring-boot-demo-orm-jpa/pom.xml | 120 +++++------ .../xkcoding/orm/jpa/entity/Department.java | 10 +- .../com/xkcoding/orm/jpa/entity/User.java | 20 +- .../orm/jpa/repository/DepartmentDao.java | 10 +- .../src/main/resources/db/schema.sql | 10 +- .../orm/jpa/repository/DepartmentDaoTest.java | 22 +- 7 files changed, 287 insertions(+), 108 deletions(-) diff --git a/spring-boot-demo-orm-jpa/README.md b/spring-boot-demo-orm-jpa/README.md index 3e2dc3b..fd30136 100644 --- a/spring-boot-demo-orm-jpa/README.md +++ b/spring-boot-demo-orm-jpa/README.md @@ -1,7 +1,10 @@ # spring-boot-demo-orm-jpa -> 此 demo 主要演示了 Spring Boot 如何使用 JPA 操作数据库。 +> 此 demo 主要演示了 Spring Boot 如何使用 JPA 操作数据库,包含简单使用以及级联使用。 + +## 主要代码 + +### pom.xml -## pom.xml ```xml ``` -## JpaConfig.java +### JpaConfig.java ```java /** *

@@ -123,7 +126,7 @@ public class JpaConfig { } } ``` -## User.java +### User.java ```java /** *

@@ -136,12 +139,12 @@ public class JpaConfig { * @date: Created in 2018/11/7 14:06 * @copyright: Copyright (c) * @version: V1.0 - * @modified: yangkai.shen + * @modified: 76peter */ @EqualsAndHashCode(callSuper = true) -@Data @NoArgsConstructor @AllArgsConstructor +@Data @Builder @Entity @Table(name = "orm_user") @@ -183,9 +186,86 @@ public class User extends AbstractAuditModel { */ @Column(name = "last_login_time") private Date lastLoginTime; + + /** + * 关联部门表 + * 1、关系维护端,负责多对多关系的绑定和解除 + * 2、@JoinTable注解的name属性指定关联表的名字,joinColumns指定外键的名字,关联到关系维护端(User) + * 3、inverseJoinColumns指定外键的名字,要关联的关系被维护端(Department) + * 4、其实可以不使用@JoinTable注解,默认生成的关联表名称为主表表名+下划线+从表表名, + * 即表名为user_department + * 关联到主表的外键名:主表名+下划线+主表中的主键列名,即user_id,这里使用referencedColumnName指定 + * 关联到从表的外键名:主表中用于关联的属性名+下划线+从表的主键列名,department_id + * 主表就是关系维护端对应的表,从表就是关系被维护端对应的表 + */ + @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinTable(name = "orm_user_dept", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "dept_id", referencedColumnName = "id")) + private Collection departmentList; + } ``` -## AbstractAuditModel.java +### Department.java +```java +/** + *

+ * 部门实体类 + *

+ * + * @package: com.xkcoding.orm.jpa.entity + * @description: 部门实体类 + * @author: 76peter + * @date: Created in 2019/10/1 18:07 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: 76peter + */ +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Entity +@Table(name = "orm_department") +@ToString(callSuper = true) +public class Department extends AbstractAuditModel { + + /** + * 部门名 + */ + @Column(name = "name", columnDefinition = "varchar(255) not null") + private String name; + + /** + * 上级部门id + */ + @ManyToOne(cascade = {CascadeType.REFRESH}, optional = true) + @JoinColumn(name = "superior", referencedColumnName = "id") + private Department superior; + /** + * 所属层级 + */ + @Column(name = "levels", columnDefinition = "int not null default 0") + private Integer levels; + /** + * 排序 + */ + @Column(name = "order_no", columnDefinition = "int not null default 0") + private Integer orderNo; + /** + * 子部门集合 + */ + @OneToMany(cascade = {CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER, mappedBy = "superior") + private Collection children; + + /** + * 部门下用户集合 + */ + @ManyToMany(mappedBy = "departmentList") + private Collection userList; + +} +``` +### AbstractAuditModel.java ```java /** *

@@ -228,7 +308,7 @@ public abstract class AbstractAuditModel implements Serializable { private Date lastUpdateTime; } ``` -## UserDao.java +### UserDao.java ```java /** *

@@ -248,7 +328,33 @@ public interface UserDao extends JpaRepository { } ``` -## application.yml +### DepartmentDao.java +```java +/** + *

+ * User Dao + *

+ * + * @package: com.xkcoding.orm.jpa.repository + * @description: Department Dao + * @author: 76peter + * @date: Created in 2019/10/1 18:07 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: 76peter + */ +@Repository +public interface DepartmentDao extends JpaRepository { + /** + * 根据层级查询部门 + * + * @param level 层级 + * @return 部门列表 + */ + List findDepartmentsByLevels(Integer level); +} +``` +### application.yml ```yaml server: port: 8080 @@ -290,7 +396,7 @@ logging: org.hibernate.SQL: debug org.hibernate.type: trace ``` -## UserDaoTest.java +### UserDaoTest.java ```java /** *

@@ -403,7 +509,82 @@ public class UserDaoTest extends SpringBootDemoOrmJpaApplicationTests { } ``` +### DepartmentDaoTest.java +```java +/** + *

+ * jpa 测试类 + *

+ * + * @package: com.xkcoding.orm.jpa.repository + * @description: jpa 测试类 + * @author: 76peter + * @date: Created in 2018/11/7 14:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: 76peter + */ +@Slf4j +public class DepartmentDaoTest extends SpringBootDemoOrmJpaApplicationTests { + @Autowired + private DepartmentDao departmentDao; + @Autowired + private UserDao userDao; + + /** + * 测试保存 ,根节点 + */ + @Test + @Transactional + public void testSave() { + Collection departmentList = departmentDao.findDepartmentsByLevels(0); + + if (departmentList.size() == 0) { + Department testSave1 = Department.builder().name("testSave1").orderNo(0).levels(0).superior(null).build(); + Department testSave1_1 = Department.builder().name("testSave1_1").orderNo(0).levels(1).superior(testSave1).build(); + Department testSave1_2 = Department.builder().name("testSave1_2").orderNo(0).levels(1).superior(testSave1).build(); + Department testSave1_1_1 = Department.builder().name("testSave1_1_1").orderNo(0).levels(2).superior(testSave1_1).build(); + departmentList.add(testSave1); + departmentList.add(testSave1_1); + departmentList.add(testSave1_2); + departmentList.add(testSave1_1_1); + departmentDao.saveAll(departmentList); + + Collection deptall = departmentDao.findAll(); + log.debug("【部门】= {}", JSONArray.toJSONString((List) deptall)); + } + + + userDao.findById(1L).ifPresent(user -> { + user.setName("添加部门"); + Department dept = departmentDao.findById(2L).get(); + user.setDepartmentList(departmentList); + userDao.save(user); + }); + + log.debug("用户部门={}", JSONUtil.toJsonStr(userDao.findById(1L).get().getDepartmentList())); + + + departmentDao.findById(2L).ifPresent(dept -> { + Collection userlist = dept.getUserList(); + //关联关系由user维护中间表,department userlist不会发生变化,可以增加查询方法来处理 重写getUserList方法 + log.debug("部门下用户={}", JSONUtil.toJsonStr(userlist)); + }); + + + userDao.findById(1L).ifPresent(user -> { + user.setName("清空部门"); + user.setDepartmentList(null); + userDao.save(user); + }); + log.debug("用户部门={}", userDao.findById(1L).get().getDepartmentList()); + + } +} +``` + +### 其余代码及 SQL 参见本 demo ## 参考 -Spring Data JPA 官方文档:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ \ No newline at end of file +- Spring Data JPA 官方文档:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ diff --git a/spring-boot-demo-orm-jpa/pom.xml b/spring-boot-demo-orm-jpa/pom.xml index 7a846de..2bd654a 100644 --- a/spring-boot-demo-orm-jpa/pom.xml +++ b/spring-boot-demo-orm-jpa/pom.xml @@ -1,80 +1,74 @@ - 4.0.0 + 4.0.0 - spring-boot-demo-orm-jpa - 1.0.0-SNAPSHOT - jar + spring-boot-demo-orm-jpa + 1.0.0-SNAPSHOT + jar - spring-boot-demo-orm-jpa - Demo project for Spring Boot + spring-boot-demo-orm-jpa + Demo project for Spring Boot - - com.xkcoding - spring-boot-demo - 1.0.0-SNAPSHOT - + + com.xkcoding + spring-boot-demo + 1.0.0-SNAPSHOT + - - UTF-8 - UTF-8 - 1.8 - + + UTF-8 + UTF-8 + 1.8 + - - - org.springframework.boot - spring-boot-starter-data-jpa - + + + org.springframework.boot + spring-boot-starter-data-jpa + - - org.springframework.boot - spring-boot-starter - + + org.springframework.boot + spring-boot-starter + - - mysql - mysql-connector-java - + + mysql + mysql-connector-java + - - org.springframework.boot - spring-boot-starter-test - test - + + org.springframework.boot + spring-boot-starter-test + test + - - cn.hutool - hutool-all - + + cn.hutool + hutool-all + - - com.google.guava - guava - + + com.google.guava + guava + - - org.projectlombok - lombok - true - - - com.alibaba - fastjson - 1.2.58 - test - - + + org.projectlombok + lombok + true + + - - spring-boot-demo-orm-jpa - - - org.springframework.boot - spring-boot-maven-plugin - - - + + spring-boot-demo-orm-jpa + + + org.springframework.boot + spring-boot-maven-plugin + + + diff --git a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/Department.java b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/Department.java index 41dadc1..3b71bec 100644 --- a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/Department.java +++ b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/Department.java @@ -38,8 +38,8 @@ public class Department extends AbstractAuditModel { /** * 上级部门id */ - @ManyToOne(cascade = {CascadeType.REFRESH},optional = true) - @JoinColumn(name = "superior",referencedColumnName = "id") + @ManyToOne(cascade = {CascadeType.REFRESH}, optional = true) + @JoinColumn(name = "superior", referencedColumnName = "id") private Department superior; /** * 所属层级 @@ -49,12 +49,12 @@ public class Department extends AbstractAuditModel { /** * 排序 */ - @Column(name = "orderno", columnDefinition = "int not null default 0") - private Integer orderno; + @Column(name = "order_no", columnDefinition = "int not null default 0") + private Integer orderNo; /** * 子部门集合 */ - @OneToMany(cascade={CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER,mappedBy="superior") + @OneToMany(cascade = {CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER, mappedBy = "superior") private Collection children; /** diff --git a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/User.java b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/User.java index 167a80e..27fb30a 100644 --- a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/User.java +++ b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/entity/User.java @@ -66,21 +66,19 @@ public class User extends AbstractAuditModel { @Column(name = "last_login_time") private Date lastLoginTime; - /** * 关联部门表 + * 1、关系维护端,负责多对多关系的绑定和解除 + * 2、@JoinTable注解的name属性指定关联表的名字,joinColumns指定外键的名字,关联到关系维护端(User) + * 3、inverseJoinColumns指定外键的名字,要关联的关系被维护端(Department) + * 4、其实可以不使用@JoinTable注解,默认生成的关联表名称为主表表名+下划线+从表表名, + * 即表名为user_department + * 关联到主表的外键名:主表名+下划线+主表中的主键列名,即user_id,这里使用referencedColumnName指定 + * 关联到从表的外键名:主表中用于关联的属性名+下划线+从表的主键列名,department_id + * 主表就是关系维护端对应的表,从表就是关系被维护端对应的表 */ @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinTable(name = "orm_usersetdept",joinColumns = @JoinColumn(name = "userid",referencedColumnName="id"), - inverseJoinColumns = @JoinColumn(name = "deptid",referencedColumnName="id")) - //1、关系维护端,负责多对多关系的绑定和解除 - //2、@JoinTable注解的name属性指定关联表的名字,joinColumns指定外键的名字,关联到关系维护端(User) - //3、inverseJoinColumns指定外键的名字,要关联的关系被维护端(Department) - //4、其实可以不使用@JoinTable注解,默认生成的关联表名称为主表表名+下划线+从表表名, - //即表名为user_department - //关联到主表的外键名:主表名+下划线+主表中的主键列名,即user_id,这里使用referencedColumnName指定 - //关联到从表的外键名:主表中用于关联的属性名+下划线+从表的主键列名,department_id - //主表就是关系维护端对应的表,从表就是关系被维护端对应的表 + @JoinTable(name = "orm_user_dept", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "dept_id", referencedColumnName = "id")) private Collection departmentList; } diff --git a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/repository/DepartmentDao.java b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/repository/DepartmentDao.java index 8173dca..dc3fab4 100644 --- a/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/repository/DepartmentDao.java +++ b/spring-boot-demo-orm-jpa/src/main/java/com/xkcoding/orm/jpa/repository/DepartmentDao.java @@ -4,7 +4,7 @@ import com.xkcoding.orm.jpa.entity.Department; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.Collection; +import java.util.List; /** @@ -22,5 +22,11 @@ import java.util.Collection; */ @Repository public interface DepartmentDao extends JpaRepository { - public Collection findDepartmentsByLevels(Integer level); + /** + * 根据层级查询部门 + * + * @param level 层级 + * @return 部门列表 + */ + List findDepartmentsByLevels(Integer level); } diff --git a/spring-boot-demo-orm-jpa/src/main/resources/db/schema.sql b/spring-boot-demo-orm-jpa/src/main/resources/db/schema.sql index b03402f..a8c91a3 100644 --- a/spring-boot-demo-orm-jpa/src/main/resources/db/schema.sql +++ b/spring-boot-demo-orm-jpa/src/main/resources/db/schema.sql @@ -19,16 +19,16 @@ CREATE TABLE `orm_department` ( `name` VARCHAR(32) NOT NULL COMMENT '部门名称', `superior` INT(11) COMMENT '上级id', `levels` INT(11) NOT NULL COMMENT '层级', - `orderno` INT(11) NOT NULL DEFAULT 0 COMMENT '排序', + `order_no` INT(11) NOT NULL DEFAULT 0 COMMENT '排序', `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '创建时间', `last_update_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '上次更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Spring Boot Demo Orm 系列示例表'; ---DROP TABLE IF EXISTS `orm_usersetdept`; -CREATE TABLE `orm_usersetdept` ( +DROP TABLE IF EXISTS `orm_user_dept`; +CREATE TABLE `orm_user_dept` ( `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键', - `userid` INT(11) NOT NULL COMMENT '用户id', - `deptid` INT(11) NOT NULL COMMENT '部门id', + `user_id` INT(11) NOT NULL COMMENT '用户id', + `dept_id` INT(11) NOT NULL COMMENT '部门id', `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '创建时间', `last_update_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '上次更新时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Spring Boot Demo Orm 系列示例表'; diff --git a/spring-boot-demo-orm-jpa/src/test/java/com/xkcoding/orm/jpa/repository/DepartmentDaoTest.java b/spring-boot-demo-orm-jpa/src/test/java/com/xkcoding/orm/jpa/repository/DepartmentDaoTest.java index 8dba3cc..054a5bf 100644 --- a/spring-boot-demo-orm-jpa/src/test/java/com/xkcoding/orm/jpa/repository/DepartmentDaoTest.java +++ b/spring-boot-demo-orm-jpa/src/test/java/com/xkcoding/orm/jpa/repository/DepartmentDaoTest.java @@ -1,5 +1,6 @@ package com.xkcoding.orm.jpa.repository; +import cn.hutool.json.JSONUtil; import com.xkcoding.orm.jpa.SpringBootDemoOrmJpaApplicationTests; import com.xkcoding.orm.jpa.entity.Department; import com.xkcoding.orm.jpa.entity.User; @@ -39,11 +40,12 @@ public class DepartmentDaoTest extends SpringBootDemoOrmJpaApplicationTests { @Transactional public void testSave() { Collection departmentList = departmentDao.findDepartmentsByLevels(0); - if(departmentList.size()==0){ - Department testSave1 = Department.builder().name("testSave1").orderno(0).levels(0).superior(null).build(); - Department testSave1_1 = Department.builder().name("testSave1_1").orderno(0).levels(1).superior(testSave1).build(); - Department testSave1_2 = Department.builder().name("testSave1_2").orderno(0).levels(1).superior(testSave1).build(); - Department testSave1_1_1 = Department.builder().name("testSave1_1_1").orderno(0).levels(2).superior(testSave1_1).build(); + + if (departmentList.size() == 0) { + Department testSave1 = Department.builder().name("testSave1").orderNo(0).levels(0).superior(null).build(); + Department testSave1_1 = Department.builder().name("testSave1_1").orderNo(0).levels(1).superior(testSave1).build(); + Department testSave1_2 = Department.builder().name("testSave1_2").orderNo(0).levels(1).superior(testSave1).build(); + Department testSave1_1_1 = Department.builder().name("testSave1_1_1").orderNo(0).levels(2).superior(testSave1_1).build(); departmentList.add(testSave1); departmentList.add(testSave1_1); departmentList.add(testSave1_2); @@ -51,7 +53,7 @@ public class DepartmentDaoTest extends SpringBootDemoOrmJpaApplicationTests { departmentDao.saveAll(departmentList); Collection deptall = departmentDao.findAll(); - log.debug("【部门】= {}", JSONArray.toJSONString((List)deptall)); + log.debug("【部门】= {}", JSONArray.toJSONString((List) deptall)); } @@ -61,14 +63,14 @@ public class DepartmentDaoTest extends SpringBootDemoOrmJpaApplicationTests { user.setDepartmentList(departmentList); userDao.save(user); }); - User users = userDao.findById(1L).get(); - log.debug("用户部门={}", JSONArray.toJSONString((List)userDao.findById(1L).get().getDepartmentList())); + + log.debug("用户部门={}", JSONUtil.toJsonStr(userDao.findById(1L).get().getDepartmentList())); departmentDao.findById(2L).ifPresent(dept -> { Collection userlist = dept.getUserList(); //关联关系由user维护中间表,department userlist不会发生变化,可以增加查询方法来处理 重写getUserList方法 - log.debug("部门下用户={}", JSONArray.toJSONString((List)userlist)); + log.debug("部门下用户={}", JSONUtil.toJsonStr(userlist)); }); @@ -79,8 +81,6 @@ public class DepartmentDaoTest extends SpringBootDemoOrmJpaApplicationTests { }); log.debug("用户部门={}", userDao.findById(1L).get().getDepartmentList()); - } - }