SpringBoot实现简单的⽤户权限管理(超详细版)
2020-11-21 更新:解决由于.yml⽂件引起的数据库链接问题
⽂章⽬录
⼀、前⾔
为了避免浪费时间进⾏不必要的阅读,这⾥先对项⽬进⾏简单的介绍。在实际应⽤场景中,每个⽤户都有对应的⾓⾊,⽽每个⾓⾊⼜有对应的⼀些⾓⾊。因为⼀个⽤户可以有多个⾓⾊,⼀个⾓⾊也可以被多个⽤户所拥有,⾓⾊和权限的关系也同理,这⾥主要利⽤多对多的映射关系将他们联系起来,对他们进⾏管理。
主要实现的功能:
1. 添加⽤户、⾓⾊和权限
2. 删除⽤户、⾓⾊和权限
3. 给⽤户添加⾓⾊、给⾓⾊添加权限
4. 根据⽤户名称查询⽤户拥有的权限
⼆、项⽬环境
Java版本:jdk1.8.0_181
IDE:IntelliJ IDEA 2019.1.3
数据库:postgresql 9.5
测试⼯具:postman
ps:数据库类型不同不要紧,在创建的时候勾选不⼀样的数据库驱动的就⾏。
三、项⽬⽂件结构
项⽬创建的时候,需要勾选Web中的Spring Web Starter和SQL中Spring Data JPA、PostgreSQL Driver(如果使⽤的是mysql数据库,则勾选MySQL Driver),IDEA会⾃动帮我们在Maven的配置⽂件中添加相关的依赖。
以下是本项⽬的⽬录结构:
四、项⽬代码
数据库连接配置
spring:
datasource:
driver-class-name: org.postgresql.Driver
username: postgres
password:123456
url: jdbc:postgresql://localhost:5432/postgres
jpa:
hibernate:
ddl-auto: update
show-sql:true
properties:
hibernate:
temp:
use_jdbc_metadata_defaults:false
如果遇到数据库连接不成功的问题,可以尝试将 properties: 以及之后的部分删除。
1.Entity层
Entity层为数据库实体层,⼀般⼀个实体类对应数据库中的⼀张数据表,类中的属性与数据表中的字段⼀ ⼀对应。默认情况下,类名即为数据表的表名,属性名则是对应字段名,字段类型也与变量的类型相对应。
本层注解简单解释:
1. @Entity
该注解⽤于表明这个类是⼀个实体类,会给他⽣成⼀张对应的数据表。
2. @Table(name = “table_name”)
该注解主要⽤于修改表名,name的值就是修改的数据表的名称。
3. @Id
该注解⽤于声明主键,标在哪个属性上⾯对应的哪个字段就是主键
4. @GeneratedValue(strategy = GenerationType.IDENTITY)
该注解的strategy属性主要⽤于设置主键的增长⽅式,IDENTITY表⽰主键由数据库⾃⼰⽣成,从1开始单调递增。
5. @Column(name = “column_name”)
该注解的name属性⽤于更改数据表的列名,如果不想⽤默认的就⽤这个属性改吧
6. @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
这个注解得上是本项⽬得核⼼了,它声明了实体之间的多对多关系,使两张数据表关联关联起来,⼀般是通过⽣成⼀张映射表来实现这种映射关系。关于上⾯的cascade属性和fetch属性,有兴趣的读者可以查资料了解。
7. @JoinTable
这个注解是配套@ManyToMany使⽤的,⼀般在多对多关系的维护端标注,⽤于⽣成上⾯提到的映射表。⼀般该注解常⽤三个属性:name属性表⽰⽣成的数据表的名称,joinColumns属性表⽰关系维护端的主键,inverseJoinColumns则表⽰关系被维护端的主键。
关于嵌套在⾥⾯的@JoinColumn注解,在这⾥主要⽤于配置映射表的外键,⼀般有两个属性:name⽤于配置外键在映射表中的名称,referencedColumnName ⽤于表明外键在原表中的字段名称。
8. @JsonBackReference
关于这个注解,建议先去掉试试然后再加上,对⽐⼀下效果。它主要可以使标注属性避免被json序列化,进⽽避免多对多关系的查询中出现死循环的情况。但是加上了这注解后,就不能进⾏反向查询了(也就是说不能利⽤权限名查询拥有这个权限的⾓⾊了)
注意:以下代码都省略了要导⼊的包,getter和setter⽅法。需要导⼊相关包可以⽤快捷键Alt+Insert,
⽤快捷键Alt+Insert然后选择Getter and Setter可以快速⽣成相关⽅法。
User.java
@Entity
@Table(name ="user_tabel")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="user_id")
private Integer userId;
@Column(name ="user_name")
private String userName;
/
/关键点
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name ="user_role",//name是表名
//joinColumns设置的是entity中属性到关系表的映射名称,name是映射表中的字段名
joinColumns ={@JoinColumn(name ="user_id")},
//inverseJoinColumns,name是关系实体Role的id在关系表中的名称
inverseJoinColumns ={@JoinColumn(name ="role_id")}
)
private List<Role> roles;
//省略了getter和setter⽅法
}
Role.java
@Entity
@Table(name ="role_table")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="role_id")
private Integer roleId;
@Column(name ="role_name")
private String roleName;
/
/作为被维护端,只需要设置mappedBy属性,其值与User中对应List类型变量名相同
//@JsonBackReference可以避免属性被json序列化,出现死循环
@JsonBackReference
@ManyToMany(mappedBy ="roles")
private List<User> users;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name ="role_auth",//name是表名
joinColumns =@JoinColumn(name ="role_id"),
inverseJoinColumns =@JoinColumn(name ="auth_id")
)
private List<Authority> authorities;
//省略了getter和setter⽅法
}
Authority.java
@Entity
@Table(name ="auth_table")
public class Authority {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="auth_id")
private Integer authorityId;
@Column(name ="auth_name")
private String authorityName;
@JsonBackReference
@ManyToMany(mappedBy ="authorities")
private List<Role> roles;
//省略了getter和setter⽅法
}
2.dao层
dao层是数据持久层,也被称为mapper层。主要负责访问数据库,向数据库发送SQL语句,完成基础的增删查改任务。主要通过定义继承JpaRepository类的接⼝来实现,<>中填写的是实体类的名称和该实体主键的变量类型。
在接⼝中声明的⽅法不⽤我们去实现,只要满⾜命名规则JpaRepository类会⾃动帮我们⽣成相应的sql
语句。
详情见:
UserRepository.javaspring ioc注解
public interface UserRepository extends JpaRepository<User, Integer>{
public List<User>findAllByUserName(String userName);
public void deleteByUserName(String userName);
}
RoleRepository.java
public interface RoleRepository extends JpaRepository<Role, Integer>{
public List<Role>findAllByRoleName(String roleName);
public void deleteByRoleName(String roleName);
}
AuthorityRepository.java
public interface AuthorityRepository extends JpaRepository<Authority, Integer>{
public List<Authority>findAllByAuthorityName(String authorityName);
public void deleteByAuthorityName(String authorityName);
}
3.service层
service层是业务逻辑层,主要通过调⽤dao层的接⼝,接收dao层返回的数据,完成项⽬的基本功能设计。由于本项⽬的service层是在后⾯才加的,所以有些应该在本层实现的功能写在了controller层orz。
踩到的坑
1. 涉及到两张表以上的更新或者删除操作,为了保证数据库的⼀致性,需要添加 @Transactional事务注解,否则程序会抛出异常。
(关于事务的详情,如果不熟悉的话,强烈建议去弄懂。)
2. 如果要执⾏删除操作,需要先把它的List先清空,也就相当于把映射表中的关系清除。否则会抛出
ption.ConstraintViolationException异常。(我这⾥⽤到了多种清除⽅式:如果删除维护端数据,只是把维护端的List清空就⾏;如果删除被维护端的数据,则把⽤户(维护端)的List中要移除的⾓⾊(被维护端)都remove掉,不知道我是不是想多了)
EntityService.java
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论