从零开始使用IDEA搭建Springboot+JPA+Swagger2.0+Logback+Lombok+Redis+Shiro1.4项目(二)
连接数据库,实现增删改差
准备工作
下载postman
,用于数据测试
配置文件
配置 pom.xml 文件
在pom.xml
文件中添加jpa
依赖和mysql
依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置 application.yml 文件
- 配置服务端口。
不配置则默认端口号为8080
。 - 连接数据池。
使用com.mysql.cj.jdbc.Driver
驱动类。
配置url
连接名为userinfo
的数据库。
指定时区为东八区Asia/Shanghai
。
配置数据库的用户名和密码。
配置初始化模式为always
。 - 配置jpa。
配置hibernate.ddl-auto
属性为update
,项目启动时如果与数据库中的表格式不一致则更新,原数据保留。
运行时将sql
输出到控制台。
配置引擎为InnoDB
,不配置则建表时默认引擎为MyISAM
。
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/userinfo?serverTimezone=Asia/Shanghai
username: root
password: root
initialization-mode: always
jpa:
hibernate:
ddl-auto: update
show-sql: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
创建各个层对应的文件夹
entity
存放的是实体类,一个实体类对应一个数据表,包含了该实体类的各个属性,对应数据表中的字段,以及该实体类的属性和其他类的属性之间的映射关系:OneToOne
、OneToMany
、ManyToOne
、ManyToMany
。dao
:数据访问层。主要作用是完成对数据库的增删改差的操作。jpa
中已经封装了很多方法可以直接继承调用,或者根据需求自己写sql
。service
:业务逻辑层。Service
接口和接口的实现ServiceImpl
,用来处理更为细致的逻辑流程操作。controller
:控制层。负责业务调度,进行页面的跳转或者数据的传递。.
代码工作
创建对应的实体类
本项目是一个简单的权限管理系统,主要实体有用户User
、角色Role
、权限Authority
,对应五张表:用户表t_user
、角色表t_role
、权限表t_authority
、用户角色关系表t_user_role
、角色权限关系表t_role_authority
。
User
@Entity:表明该类是一个实体类。
@Table:表明该实体类对应数据库中的表t_user
。
@Id 和 @GeneratedValue:指定主键列和主键增长策略。
package com.demo.entity;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String user_name;
private String account;
private String password;
private String phone;
private Integer age;
private Date creat_time;
private Date update_time;
private Integer status;
public User() {
}
public User(String user_name, String account, String password, String phone, Integer age, Date creat_time, Date update_time, Integer status) {
this.user_name = user_name;
this.account = account;
this.password = password;
this.phone = phone;
this.age = age;
this.creat_time = creat_time;
this.update_time = update_time;
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getCreat_time() {
return creat_time;
}
public void setCreat_time(Date creat_time) {
this.creat_time = creat_time;
}
public Date getUpdate_time() {
return update_time;
}
public void setUpdate_time(Date update_time) {
this.update_time = update_time;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", user_name='" + user_name + '\'' +
", account='" + account + '\'' +
", password='" + password + '\'' +
", phone='" + phone + '\'' +
", age=" + age +
", creat_time=" + creat_time +
", update_time=" + update_time +
", status=" + status +
'}';
}
}
Role
此处省略构造函数以及getter()
、setter()
、toString()
方法。
package com.demo.entity;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String role_name;
private Date creat_time;
private Date update_time;
private Integer status;
......
}
Authority
package com.demo.entity;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_authority")
public class Authority {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String authority_name;
private String url;
private String code;
private Integer status;
private Date creat_time;
private Date update_time;
......
}
添加关系映射
实体类创建完毕之后,给各个类添加关系映射。
User
User 和 Role 是多对多的关系 @ManyToMany,设置属性cascade = CascadeType.DETACH
:级联脱管/游离操作,fetch = FetchType.EAGER
:急加载。
@JoinTable:为 User 和 Role 添加一张中间表,表名为t_user_role
,joinColumns
表明中间表中的user_id
是t_user
表的主键对应的外键, inverseJoinColumns
表明中间表中的role_id
是另一端t_role
表的主键对应的外键。
@JsonIgnoreProperties:可以忽略返回的json
数据中的某些字段,由于是双向多对多的关系,忽略 Role 类中的users
字段,可避免输出死循环。可直接写在类上,也可写在关系映射上。
@Entity
@Table(name = "t_user")
@JsonIgnoreProperties({
"users"})
public class User {
......
@ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
@JoinTable(name = "t_user_role",joinColumns = {
@JoinColumn(name = "user_id")},inverseJoinColumns = {
@JoinColumn(name = "role_id")})
private List<Role> roles;
}
Role
Role 和 User、Authority 是多对多的关系 @ManyToMany,添加中间表,设置外键。
和属性父级角色一对一自关联 @OneToOne,不做其他添加。
@Transient:该属性不会映射到数据库中。
@Entity
@Table(name = "t_role")
@JsonIgnoreProperties({
"parent_role","parent_authority","authorityList","roles"})
public class Role {
......
@ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
@JoinTable(name = "t_user_role",joinColumns = {
@JoinColumn(name = "role_id")},inverseJoinColumns = {
@JoinColumn(name = "user_id")})
private List<User> users;
@ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
@JoinTable(name = "t_role_authority",joinColumns = {
@JoinColumn(name = "role_id")},inverseJoinColumns = {
@JoinColumn(name = "authority_id")})
private List<Authority> authorityList;
@Transient
private List<Authority> authorities;
@OneToOne
private Role parent_role;
@Transient
private List<Role> child_roles;
}
Authority
Authority和Role是多对多的关系ManyToMany
,和属性父级权限一对一自关联OneToOne
。
@Entity
@Table(name = "t_authority")
@JsonIgnoreProperties({
"parent_authority","parent_role","roles"})
public class Authority {
......
@Transient
private List<Authority> child_authorities;
@OneToOne
private Authority parent_authority;
@ManyToMany(cascade = CascadeType.DETACH,fetch = FetchType.LAZY)
@JoinTable(name = "t_role_authority",joinColumns = {
@JoinColumn(name = "authority_id")},inverseJoinColumns = {
@JoinColumn(name = "role_id")})
private List<Role> roles;
}
创建 dao 接口
JPA 封装了很多方法,可以直接使用接口继承调用,使用泛型JpaRepository<T,ID>。
@Query:自定义sql
语句操作数据库,原生sql
注明属性nativeQuery=true
。
@Param:给参数命名,执行sql
时将括号内的参数传到对应位置并进行替换,如:(@Param(account)String account) 对应sql
中的:account
。
UserRepository
package com.demo.dao;
import com.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data