当前位置: 首页 > news >正文

胶州网站建设平台阿里云服务器做网站

胶州网站建设平台,阿里云服务器做网站,计算机网页设计与制作教程,最新网页传奇RBAC 之用户管理 创建表#xff08;Entity#xff09;用户表角色表权限表用户角色表关系注解ManyToMany 角色权限表 接口开发UserControllerUserServiceUserServiceImplUserRepository 问题解决update 更新问题懒加载问题JSON 循环依赖问题 根据上一小结对表的设计#xff0… RBAC 之用户管理 创建表Entity用户表角色表权限表用户角色表关系注解ManyToMany 角色权限表 接口开发UserControllerUserServiceUserServiceImplUserRepository 问题解决update 更新问题懒加载问题JSON 循环依赖问题 根据上一小结对表的设计我们开始编写代码实现权限管理模块的代码。 我们直接通过编写实体映射类让JPA自动帮我们生成一下数据库表。 创建表Entity 首先通过 JPA 将需要用到的5张表都建好。 先将基础实体类修改一下 Data MappedSuperclass EntityListeners(AuditingEntityListener.class) Schema(description 基础实体) public class BaseEntity {IdGeneratedValue(strategy GenerationType.IDENTITY)Schema(description 用户ID)private Long id;Column(columnDefinition tinyint(1) NOT NULL COMMENT 状态)Schema(description 状态)private Integer status;Column(columnDefinition bit NOT NULL COMMENT 0正常1删除)Schema(description 逻辑删除)private Boolean isDelete;CreatedByColumn(updatable false, columnDefinition varchar(32) COMMENT 创建用户)Schema(description 创建用户, hidden true)private String createUser;LastModifiedByColumn(columnDefinition varchar(32) COMMENT 修改用户)Schema(description 修改用户, hidden true)private String updateUser;CreatedDateColumn(updatable false, columnDefinition datetime COMMENT 创建时间)Schema(description 创建时间, hidden true)private Date createTime;LastModifiedDateColumn(columnDefinition datetime COMMENT 修改时间)Schema(description 修改时间, hidden true)private Date updateTime; }将一些每个表都存在的共有属性抽离出来当作一个父类需要这些字段的实体通过继承获得这些字段属性。 MappedSuperclass标注了MappedSuperclass的类将不是一个完整的实体类他将不会映射到数据库表但是他的属性都将映射到其子类的数据库字段中。 Column用来标识实体类中属性与数据表中字段的对应关系。 updatableupdatable属性表示 在使用“UPDATE”脚本插入数据时是否需要更新该字段值。 columnDefinition表示创建表时该字段创建的SQL语句一般用于通过Entity生成表定义时使用。 用户表 先看一下表结构 字段类型含义idbigint(20)主键IDnamevarchar(32)用户名mobilechar(11)手机号avatarvarchar(255)头像emailvarchar(50)邮箱passwordvarchar(12)密码statustinyint(1)状态0正常1锁定is_deletebit0删除1未删除last_login_timedatetime最后登录时间create_timedatetime创建时间create_uservarchar(32)创建用户update_timedatetime更新时间update_uservarchar(32)更新用户 UserEntity Data Entity Table(name sys_user) Schema(description 用户实体) public class UserEntity extends BaseEntity implements Serializable {Column(unique true, columnDefinition varchar(32) NOT NULL COMMENT 名称)Schema(description 用户名称)private String name;Column(columnDefinition char(11) COMMENT 手机号)Schema(description 手机号)private String mobile;Column(columnDefinition varchar(255) COMMENT 头像)Schema(description 头像)private String avatar;Column(columnDefinition varchar(50) COMMENT 邮箱)Schema(description 用户邮箱)private String email;Column(columnDefinition varchar(12) NOT NULL COMMENT 密码)Schema(description 用户密码)private String password;Column(columnDefinition datetime COMMENT 最后登录时间)Schema(description 最后登录时间)private Date lastLoginTime; }角色表 表结构 字段类型含义idbigint(20)主键IDnamevarchar(32)角色名称remarkvarchar(255)备注statustinyint(1)状态is_deletebit0删除1未删除create_timedatetime创建时间create_uservarchar(32)创建用户update_timedatetime更新时间update_uservarchar(32)更新用户 RoleEntity Data Entity Table(name sys_role) Schema(description 角色实体) public class RoleEntity extends BaseEntity implements Serializable {Column(unique true, columnDefinition varchar(32) NOT NULL COMMENT 角色名称)Schema(description 角色名称)private String name;Column(columnDefinition varchar(500) COMMENT 备注)Schema(description 备注)private String remark;}权限表 表结构 字段类型含义idbigint(20)主键IDpidbigint(20)父菜单ID一级菜单为0namevarchar(32)菜单名称urlvarchar(255)菜单URLpermsvarchar(500)授权(多个用逗号分隔如user:list,user:create)typetinyint(1)类型 0目录 1菜单 2按钮iconvarchar(50)菜单图标sorttinyint(2)排序statustinyint(1)状态is_deletebit0删除1未删除create_timedatetime创建时间create_uservarchar(32)创建用户update_timedatetime更新时间update_uservarchar(32)更新用户 MenuEntity Data Entity Table(name sys_menu) Schema(description 菜单实体) public class MenuEntity extends BaseEntity implements Serializable {Column(columnDefinition bigint NOT NULL COMMENT 父菜单ID)Schema(description 父菜单ID)private Long pid;Column(unique true, columnDefinition varchar(32) NOT NULL COMMENT 菜单名称)Schema(description 菜单名称)private String name;Column(columnDefinition varchar(255) COMMENT 菜单url)Schema(description url)private String url;Column(columnDefinition varchar(500) COMMENT 授权(多个用逗号分隔如user:list,user:create))Schema(description 授权(多个用逗号分隔如user:list,user:create))private String perms;Column(columnDefinition tinyint(1) NOT NULL COMMENT 菜单类型0目录1菜单2按钮)Schema(description 菜单类型0目录1菜单2按钮)private Byte type;Column(columnDefinition varchar(50) COMMENT 菜单图标)Schema(description 菜单图标)private String icon;Column(columnDefinition tinyint(2) COMMENT 排序)Schema(description 排序)private Integer sort;}编写好3个entity启动程序查看建表是否成功。控制台打印如下建表语句同时查看数据库发现表创建没有问题。 Hibernate: create table sys_menu (id bigint not null auto_increment,create_time datetime COMMENT 创建时间,create_user varchar(32) COMMENT 创建用户,is_delete bit NOT NULL COMMENT 0正常1删除,status tinyint(1) NOT NULL COMMENT 状态,update_time datetime COMMENT 修改时间,update_user varchar(32) COMMENT 修改用户,icon varchar(50) COMMENT 菜单图标,name varchar(32) NOT NULL COMMENT 菜单名称,perms varchar(500) COMMENT 授权(多个用逗号分隔如user:list,user:create),pid bigint NOT NULL COMMENT 父菜单ID,sort tinyint(2) COMMENT 排序,type tinyint(1) NOT NULL COMMENT 菜单类型0目录1菜单2按钮,url varchar(255) COMMENT 菜单url,primary key (id)) engineInnoDB Hibernate: create table sys_role (id bigint not null auto_increment,create_time datetime COMMENT 创建时间,create_user varchar(32) COMMENT 创建用户,is_delete bit NOT NULL COMMENT 0正常1删除,status tinyint(1) NOT NULL COMMENT 状态,update_time datetime COMMENT 修改时间,update_user varchar(32) COMMENT 修改用户,name varchar(32) NOT NULL COMMENT 角色名称,remark varchar(500) COMMENT 备注,primary key (id)) engineInnoDB Hibernate: create table sys_user (id bigint not null auto_increment,create_time datetime COMMENT 创建时间,create_user varchar(32) COMMENT 创建用户,is_delete bit NOT NULL COMMENT 0正常1删除,status tinyint(1) NOT NULL COMMENT 状态,update_time datetime COMMENT 修改时间,update_user varchar(32) COMMENT 修改用户,avatar varchar(255) COMMENT 头像,email varchar(50) COMMENT 邮箱,last_login_time datetime COMMENT 最后登录时间,mobile char(11) COMMENT 手机号,name varchar(32) NOT NULL COMMENT 名称,password varchar(12) NOT NULL COMMENT 密码,primary key (id)) engineInnoDB同时还为name字段添加了索引因为我们给name字段添加了 uniquetrue 表示name字段为唯一jpa 会为这个字段添加索引。 Hibernate: alter table sys_menu add constraint UK_4kk1vl4bvpaho8ked9v4xkr9d unique (name)Hibernate: alter table sys_role add constraint UK_bqy406dtsr7j7d6fawi1ckyn1 unique (name)Hibernate: alter table sys_user add constraint UK_iic0kskryiymn15fg9bqpmw22 unique (name)用户角色表 使用实体映射来创建单表很好理解但是怎么创建关联表呢我们可以通过Spring Data JPA关系映射中对表关系定义的注解来创建表的关系。 关系注解 注解说OneToOne定义表之间“一对一”的关系。OneToMany定义表之间“一对多”的关系。ManyToOne定义表之间“多对一”的关系。ManyToMany定义表之间“多对多”的关系。 ManyToMany 我们之前分析了我们的表之间的关系都是多对多的关系所以我们使用 ManyToMany 来定义表之间的关系ManyToMany总是会使用中间关系连接表来存储关系Jpa 会自动帮我们创建中间关联表。 ManyToMany 注解用来定义具有多对多多重性的多值关联。 每个多对多关系都有两个方面关系的拥有方和非拥有方。连接表中间表在关系的拥有方指定。 如果关联是双向的任何一方都可以被指定为关系的拥有方。 如果关系是双向的则关系的非拥有方必须使用 ManyToMany 注解的 mappingBy 属性来指定拥有方的关系字段或属性。 user表作为主表在 UserEntity 中添加如下字段 ManyToMany JoinTable(name sys_user_role,joinColumns {JoinColumn(name user_id, referencedColumnName id)},inverseJoinColumns {JoinColumn(name role_id, referencedColumnName id)}) Schema(description 用户角色) private ListRoleEntity roles;JoinTableJoinTable 注解用于关联映射它是在关联的拥有方进行配置。使用 JoinTable 注解将创建一个连接表也称为“中间表”。 name中间连接表名称(sys_user_role)默认是主表_副表user_role joinColumns连接表主表外键user_id inverseJoinColumns连接表副表外键(role_id) role表作为副表需要使用ManyToMany 注解的 mappingBy 属性来指定拥有方的关系字段或属性。 ManyToMany(mappedBy roles) Schema(description 角色包含的用户) private ListUserEntity users;**mappedBy**拥有关系的字段单向关系不需要指定改属性双向关系必须指定改属性的值。 添加好两个字段启动看看是否能够成功创建表控制台打印了如下sql没有爆出表明表已经成功。 角色权限表 这个和用户角色表一模一样直接上代码 ManyToMany JoinTable(name sys_role_menu,joinColumns {JoinColumn(name role_id, referencedColumnName id)},inverseJoinColumns {JoinColumn(name menu_id, referencedColumnName id)}) Schema(description 角色菜单) private ListMenuEntity menus;ManyToMany(mappedBy menus) Schema(description 菜单包含的角色) private ListRoleEntity roles;接口开发 先来梳理一下我们有哪些接口需要开发现在只有 CRUD后面根据需求慢慢加。 分页查询用户根据名称查询用户根据ID查询用户新增|修改用户批量删除用户 直接上代码了毕竟都是简单的crud容易出错的部分拿出讲一下就好了 UserController Tag(name 用户管理) RestController RequestMapping(/sys/user) public class UserController {Resourceprivate UserService userService;GetMapping(/page)Operation(summary 分页查询)public PageUserEntity page(int page, int size) {return userService.page(PageRequest.of(page - 1, size));}GetMapping(/{id})Operation(summary 根据用户ID查询用户)public UserEntity get(PathVariable Long id) {return userService.get(id);}GetMapping(/name/{name})Operation(summary 根据用户名称查询用户)public UserEntity getByName(PathVariable String name) {return userService.getByName(name);}PostMappingOperation(summary 新增|修改用户)public void upsert(RequestBody ListUserEntity users) {userService.upsert(users);}DeleteMapping(/{id})Operation(summary 根据用户ID删除用户)public void delete(PathVariable Long id) {userService.delete(id);} }UserService public interface UserService {/*** 分页查询用户** param pageable 分页参数* return PageUserEntity 分页用户*/PageUserEntity page(Pageable pageable);/*** 根据ID查询用户** param id 用户ID* return UserEntity 用户信息*/UserEntity get(Long id);/*** 根据名称查询用户** param name 用户名称* return UserEntity 用户信息*/UserEntity getByName(String name);/*** 保存/更新用户** param users 用户信息*/void upsert(ListUserEntity users);/*** 删除用户** param id 用户id*/void delete(Long id);}UserServiceImpl Service public class UserServiceImpl implements UserService {Resourceprivate UserRepository userRepository;Overridepublic PageUserEntity page(Pageable pageable) {return userRepository.findAll(pageable);}Overridepublic UserEntity get(Long id) {return userRepository.findById(id).orElse(null);}Overridepublic UserEntity getByName(String name) {return userRepository.findByName(name);}Overridepublic void upsert(ListUserEntity users) {userRepository.saveAll(users);}Overridepublic void delete(Long id) {userRepository.deleteById(id);}}UserRepository Repository public interface UserRepository extends JpaRepositoryUserEntity, Long, Serializable {/*** 根据用户名称查询用户* 这个相当与一个公式 findBy字段名称jpa 就会自动实现查询不用我们再写查询逻辑** param name 用户名称* return 用户信息*/UserEntity findByName(String name);}简单的接口开发完了之后其实还是存在了3个问题接下来我们一一来解决。 问题解决 update 更新问题 jpa 中没有单独的 update 方案他是通过 save 方法来进行更新的如果 id 为空就是新增不为空就是修改。 我们先通过新增方法新增一条数据请求数据如下 [{status: 0,isDelete: true,name: 金克斯,mobile: 11011101111,avatar: ,email: xmxm.com,password: 123456,lastLoginTime: 2023-12-12 12:12:12} ]然后假设我们现在想修改密码为666666请求体如下 [{id: 1,password: 666666} ]按理来说没有如何问题对吧但是一般这个时候就有问题了请看VCR。 我们发现请求失败返回值500这肯定是后端报错了。 {code: 500,message: 系统异常请稍后重试,body: null }查看控制台日志发现报错信息如下 java.sql.SQLIntegrityConstraintViolationException: Column is_delete cannot be null说的是字段 is_delete 不能为空这是数据库的校验但是我们没有修改这个字段呀继续看打印的sql selectue1_0.id,ue1_0.avatar,ue1_0.create_time,ue1_0.create_user,ue1_0.email,ue1_0.is_delete,ue1_0.last_login_time,ue1_0.mobile,ue1_0.name,ue1_0.password,ue1_0.status,ue1_0.update_time,ue1_0.update_user fromsys_user ue1_0 whereue1_0.id?updatesys_user setavatar?,email?,is_delete?,last_login_time?,mobile?,name?,password?,status?,update_time?,update_user? whereid?ok答案出来了jpa 默认更新全部字段先从数据库查询出这条数据然后更新全部数据这可不行这也太费劲了我们需要更新我们像更新的字段就行呀这个可以通过在实体类上添加DynamicUpdate注解表示动态更新查询。 Data Entity DynamicUpdate Table(name sys_user) Schema(description 用户实体) public class UserEntity extends BaseEntity implements Serializable {重启测试一下但是发现还是不行还是更新了全部数据这是因为jpa会把属性值为null也当成是修改意思就是当我们没有传入字段时比如此时 isDeletenull 但是jpa以为我们要把这个 null 更新到数据库 这个怎么解决呢我们自己写一个工具类将属性值为null的数据过滤掉在进行 save 即可是不是感觉很麻烦。。。 编写一个 JpaUtils public class JpaUtils {/*** 从 src 中复制不为 null 的字段到 target** param src 源实体* param target 目标实体*/public static void copyNotNullProperties(Object src, Object target) {BeanUtils.copyProperties(src, target, getNullPropertyNames(src));}/*** 获取实体中为null的属性名称** param source 实体类* return 需要过滤掉的属性名称*/public static String[] getNullPropertyNames(Object source) {final BeanWrapper src new BeanWrapperImpl(source);return Arrays.stream(src.getPropertyDescriptors())// 获取每一个属性名称.map(FeatureDescriptor::getName)// 过滤掉属性值不为null的字段.filter(name - src.getPropertyValue(name) null).toArray(String[]::new);}}修改实现类中的upsert方法 Override public void upsert(ListUserEntity users) {users.forEach(user - {OptionalUserEntity userEntity userRepository.findById(user.getId());if (userEntity.isPresent()) {// 修改JpaUtils.copyNotNullProperties(user, userEntity.get());userRepository.save(userEntity.get());} else {// 新增userRepository.save(user);}}); }ok到此这个问题解决。 懒加载问题 我们在查询用户时会抛出异常 Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.xm.module.sys.entity.UserEntity.roles: could not initialize proxy - no Session]意思是获取 roles 的时候是懒加载的但是懒加载失败因为找不到session那我们就修改为及时加载 ManyToMany(fetch FetchType.EAGER) JoinTable(name sys_user_role,joinColumns {JoinColumn(name user_id, referencedColumnName id)},inverseJoinColumns {JoinColumn(name role_id, referencedColumnName id)}) Schema(description 用户角色) private ListRoleEntity roles;**fetch**关联是应该延迟加载还是必须马上加载。EAGER 策略表示必须马上获取关联的实体LAZY 策略表示用到关联对象时才去加载。默认值为 javax.persistence.FetchType.LAZY JSON 循环依赖问题 我们先为用户关联上一个角色然后再去查询该用户信息会显示这个这是因为循环依赖导致返回数据非常大因为我们的 UserEntity 中包含了 RoleEntity而 RoleEntity 中有包含有 UserEntity就会导致这个问题。 后台报错 Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)]解决方案 在副表的字段上添加JsonIgnore注解表示序列化的时候忽略这个子段。 JsonIgnore ManyToMany(mappedBy roles) Schema(description 角色包含的用户) private ListUserEntity users;ManyToMany(fetch FetchType.EAGER) JoinTable(name sys_role_menu,joinColumns {JoinColumn(name role_id, referencedColumnName id)},inverseJoinColumns {JoinColumn(name menu_id, referencedColumnName id)}) Schema(description 角色菜单) private ListMenuEntity menus;最后解决掉这些问题查询OK这个JPA的坑还是有点多如果不清楚他的原理很容易冒出一些奇怪的问题。
http://www.hkea.cn/news/14271280/

相关文章:

  • 做网站优化哪家好茂名手机网站建设公司
  • 如何仿别人网站的莫板专门做五金的网站
  • 网站建设服务优势百度识图在线
  • 建网站系统平台网站加手机建设png图标
  • 丹江口网站制作wordpress全屏主题
  • 网站建设的培训班物联网今天正式开网
  • WordPress仿站助手网站常用代码
  • php网站接入支付宝ps网站建设要知道的知识
  • 关于门户网站建设中国网络优化推广
  • 网站设计论文总结与展望企业管理软件市场规模
  • 上海工程建设信息网官网seo是指什么岗位
  • 网站设计报价表企业邮箱下载
  • 一般云主机可以做视频网站吗h5建站系统源码
  • 做暧动漫视频在线观看网站做网站买空间
  • 上海品划网络做网站什么网店可以免费开店
  • 杭州 高端网站建设 推荐成都装饰网站建设
  • 网站建设费包括什么京东做代码的网站吗
  • 网站后台的东西都是要上传到在虚拟主机上面吗店铺在百度免费定位
  • 网站建设与管理专业就业方向wordpress的模板文件下载
  • 做淘客网站去哪里购买空间东莞型网站建设
  • 做导购网站赚钱爱站网官网
  • MIUI官方网站开发版app网站开发公司的logo
  • 嘉兴seo网站建设天门市城市建设管理局网站
  • 东莞大朗网站设计礼仪策划网站建设
  • 响应式网站生成天津优化加盟
  • 怀化网站优化联系方式怎么做网站弄网盟
  • 洛阳做网站的公司哪家好企业营销型网站建设开发
  • 重庆网站seo建设一个人搞得定网站建设
  • 深圳建设网站培训机构免费搭建手机网站
  • 推广点击器seo平台优化服务