热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringWebFlux+React搭建后台管理系统(2):主要业务逻辑实现

上一篇简单实现了数据库表的生成以及生成POJO,这里主要介绍后台服务中实现的接口以及如何通过使用webflux实现一些复杂的逻辑,以及登录鉴权等内容。业务接口如下为整理的实现的

上一篇简单实现了数据库表的生成以及生成POJO,这里主要介绍后台服务中实现的接口以及如何通过使用webflux实现一些复杂的逻辑,以及登录鉴权等内容。


业务接口

如下为整理的实现的借口汇总,应为是RESTful接口,一个path会对应多个功能:
































































































UrlHttpMethod描述
/api/auth/logoutget登出
/api/auth/loginpost登入
/api/userget通过用户名获取数据用户
/api/userpost存储用户
/api/userput更新用户数据
/api/userdelete通过id删除用户
/api/user/allget获取全部用户数据
/api/roleget通过权限名称获取
/api/rolepost存储权限
/api/roleput更新权限
/api/roledelete通过id删除权限
/api/role/allget获取所有权限数据
/api/urlget通过url获取接口信息
/api/urlpost存储接口信息
/api/urlput更新接口信息
/api/urldelete通过id删除接口信息
/api/url/allget获取所有接口信息

实现业务逻辑

简单通过user局里,api和user的逻辑基本相同,role更简单一些


1 . 生成Pojo

具体过程上一篇已经讲过了,通过使用idea可以很简单的生成,不过reactive的models和jpa的有些差别,有些点需要注意:



  • 不能使用jpa中EntityListeners自动生成更新人更新日期等,需要自己写

  • mysql中datetime类型对应的类型为LocalDateTime,这也是不同之处

  • 不存在与数据库中的字段使用@Transient进行注释

  • 请求返回json不希望显示的字段使用@JsonIgnore

  • 添加roles字段用于存放权限信息

  • 因为几个对象都有createBy等属性,通过编写DataChange接口通过泛型添加

@Table("sys_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
@With
public class SysUser implements DataChange {@Idprivate long id;private String username;private String avatar;//@JsonIgnore // 请求返回json不希望显示的字段private String password;private String email;private String mobile;private long frozen;private String createBy;private java.time.LocalDateTime createTime;private String lastUpdateBy;private java.time.LocalDateTime lastUpdateTime;@Transient // 不存在与数据库中的字段private List<String> roles;}

2. 编写Repository



  • 继承ReactiveCrudRepository使用

  • 使用方法和jpa类似

  • 注意返回类型,Mono或者Flux,返回单个用Mono,多个Collection类型的用Flux

  • 基本的crud方法ReactiveCrudRepository中都有

/*** @author: ffzs* @Date: 2020/8/26 下午12:51*/
public interface SysUserRepository extends ReactiveCrudRepository<SysUser, Long> {Mono<SysUser> findByUsername(String username);
}

3. 编写DataChange接口文件



  • 为了更方便使用泛型对几种对象实现设置属性

/*** @author: ffzs* @Date: 2020/8/26 下午11:21*/public interface DataChange {void setCreateBy(String createBy);void setCreateTime(LocalDateTime createTime);void setLastUpdateBy(String lastUpdateBy);void setLastUpdateTime(LocalDateTime lastUpdateTime);
}

4. 编写为对象添加修改时间等属性服务



  • 由于r2dbc不支持自动更新修改时间,修改人的功能

  • 编写如下方法自行进行修改

/*** @author: ffzs* @Date: 2020/8/27 下午1:51*/
@Service
public class MarkDataService {public <T extends DataChange> Mono<T> createObj (T obj) {return ReactiveSecurityContextHolder.getContext().map(it->it.getAuthentication().getPrincipal()).map(it -> {LocalDateTime now = java.time.LocalDateTime.now();obj.setCreateBy((String)it);obj.setCreateTime(now);obj.setLastUpdateBy((String)it);obj.setLastUpdateTime(java.time.LocalDateTime.now());return obj;});}public <T extends DataChange> Mono<T> updateObj (T obj) {return ReactiveSecurityContextHolder.getContext().map(it->it.getAuthentication().getPrincipal()).map(it -> {obj.setLastUpdateBy((String)it);obj.setLastUpdateTime(java.time.LocalDateTime.now());return obj;});}
}

5. 实现user服务层

由于返回基本都是Mono,Flux,webflux的服务层写法跟之前差的还挺多,有几个逻辑需要处理:



  • r2dbc不能实现多对多,一对多的关联字段,因此获取权限的逻辑需要自己写

  • 下面是在user中获取roles的方法

private Mono<SysUser> addRoles (SysUser user) {return sysUserRoleRepository.findByUserId(user.getId()).map(SysUserRole::getRoleId).flatMap(sysRoleRepository::findById).map(SysRole::getName).collectList().map(it -> {user.setRoles(it);return user;});
}


  • 查找结果是在得到的user基础上加上roles

public Mono<SysUser> findByUsername (String username) {return sysUserRepository.findByUsername(username).flatMap(this::addRoles);
}


  • 在添加数据的时候需要将roles的信息分别添加到sys_rolesys_user_role表中

  • sys_role没有的role需要添加进去。下面代码完成这一工作:

private Mono<SysUser> saveRoles (SysUser user) {List<String> roles = user.getRoles();if (roles==null || roles.isEmpty()) return Mono.just(user);return Flux.fromIterable(roles).flatMap(role -> sysRoleRepository.findByName(role).switchIfEmpty(mark.createObj(new SysRole(role)).flatMap(sysRoleRepository::save).map(SysRole::getName).flatMap(sysRoleRepository::findByName)).map(SysRole::getId)).flatMap(roleId -> sysUserRoleRepository.findByUserIdAndRoleId(user.getId(), roleId).switchIfEmpty(mark.createObj(new SysUserRole(user.getId(), roleId)).cast(SysUserRole.class).flatMap(sysUserRoleRepository::save)).map(SysUserRole::getId)).collectList().then(Mono.just(user));
}


  • 使用一个save方法处理添加新数据和更新数据

  • 通过id来区别是跟新还是添加,更新的话id不会是0

  • 更新的时候需要注意创建人和创建时间不要被覆盖

public Mono<SysUser> save (SysUser user) {user.setPassword(password.encode(user.getPassword()));if (user.getId() != 0) { // id不为0为更新updatereturn mark.updateObj(user).flatMap(it -> sysUserRepository.findByUsername(user.getUsername()).map(oldUser -> it.withCreateBy(oldUser.getCreateBy()).withCreateTime(oldUser.getCreateTime()))).flatMap(sysUserRepository::save).flatMap(this::saveRoles);}else { // id为0为createreturn mark.createObj(user).flatMap(sysUserRepository::save).map(SysUser::getUsername).flatMap(sysUserRepository::findByUsername).map(it -> it.withRoles(user.getRoles())).flatMap(this::saveRoles);}
}


  • 删除的时候,需要将user带的roles一起删掉

public Mono<Void> deleteById (Long id) {return sysUserRepository.deleteById(id).flatMap(it -> sysUserRoleRepository.deleteByUserId(id));
}

5. 实现User的控制层

控制层就是简单的api,实现了简单的功能:



  • 通过SysHttpResponse统一包装回复

  • 出现的错误可以通过错误类型给出相应恢复

  • 对于更改数据删除数据给ADMIN等权限限制

@PostMapping
@PreAuthorize("hasAnyRole('ADMIN', 'IT')")
Mono<SysHttpResponse> save (@RequestBody SysUser user) {return sysUserService.save(user).map(it->SysHttpResponse.builder().status(HttpStatus.OK.value()).message("存储成功").data(it).build()).onErrorResume(err -> {SysHttpResponse response = new SysHttpResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "运行出错", err.getMessage());if (err instanceof DataIntegrityViolationException) {response = new SysHttpResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "存储数据某些字段不唯一", err.getMessage());}return Mono.just(response);});
}


  • 因为姓名重复导致的报错可以得到相应的回复

在这里插入图片描述



  • 由于权限导致不能访问
    在这里插入图片描述


6. 登录控制层实现

实现方法和Spring WebFlux (7): Springboot Security+jwt登录鉴权写的差不多,这里添加了logout,用来删除redis中的token

@GetMapping("logout")
public Mono<SysHttpResponse> logout (@RequestParam("token") String token) {return Mono.just(token).flatMap(redisService::deleteToken).flatMap(it -> Mono.just(SysHttpResponse.ok(it))).onErrorResume(e -> Mono.just(SysHttpResponse.error5xx("删除token出错", e.getMessage()))).switchIfEmpty(Mono.just(SysHttpResponse.error5xx("删除token出错", null)));
}

简单测试



  • 登录

在这里插入图片描述



  • 插入数据

在这里插入图片描述

在这里插入图片描述

不过多展示了,代码在下面,可以自己尝试一下。。


代码:

github
gitee


推荐阅读
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • Activiti7流程定义开发笔记
    本文介绍了Activiti7流程定义的开发笔记,包括流程定义的概念、使用activiti-explorer和activiti-eclipse-designer进行建模的方式,以及生成流程图的方法。还介绍了流程定义部署的概念和步骤,包括将bpmn和png文件添加部署到activiti数据库中的方法,以及使用ZIP包进行部署的方式。同时还提到了activiti.cfg.xml文件的作用。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
author-avatar
手机用户2502897401
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有