背景

一个成熟的系统,都会针对一些关键的操作,去创建用户操作日志。

比如:

XX人创建了一条订单,订单号:XXXXXXXXX

因为操作人或者订单号是动态的,所以有些开发人员,不知道获取,就将这种操作日志和业务代码融在一起。

我们当然要杜绝这种现象,一定会有更好的解决方案。

当前项目除了满足上面这个基础需求场景外,还可以满足一些常见的日志记录需求。

下面通过一些测试用例来了解下当前项目吧。

一、支持SpEL表达式

1、使用场景

我们在记录操作日志的时候,为了获取接口中的入参信息,就可以通过SpEL表达式。

2、接口示例

 @GetMapping(value = "/queryUser")
@OperateLog(bizNo = "{#userName}", operateName = "查询用户", operateContent = "通过 {#userName} 查询用户")
public Result<String> queryUser(@RequestParam String userName) {
return Result.success(userName);
}

这里入参 userName 的获取,就是通过SpEL表达式获取到

3、请求接口

http://localhost:8080/queryUser?userName=James

4、输出日志

日志操作记录------ OperateLogDTO(operator=张三, bizNo=James, operateName=查询用户, operateContent=通过 James 查询用户, status=true, errMsg=null)

可以看出通过SpEL表达式,已经将 {#userName} 占位符,成功替换请求的参数 James

二、支持函数表达式

1、使用场景

有些时候我们仅仅是获取请求参数的数据还不够,还需要拿着请求参数的数据,去请求其它接口,才能组成一条完整的日志,最典型的场景就是

商品ID为 XXX 的商品的名称已经从 XXX  改成 XXX

这里前端肯定只会传当前的商品ID和当前修改后的商品名称,也就是说该商品老的名称还需要通过商品ID去商品表查完后,才能组成完整日志。

2、接口示例

@GetMapping(value = "/deleteUser")
@OperateLog(bizNo = "{#userId}", operateName = "删除用户",
operateContent = "用户id为 {#userId} 用户名为 [getUserNameByUserId{#userId}] 已被删除")
public Result<Void> deleteUser(Long userId) {
return Result.success();
}

3、请求接口

http://localhost:8080/deleteUser?userId=888

4、输出日志

日志操作记录------ OperateLogDTO(operator=张三, bizNo=888, operateName=删除用户, operateContent=用户id为 888 用户名为 张老三 已被删除, status=true, errMsg=null)

这里用户名张老三,是模拟查询数据库获取的用户名。

三、支持三目表达式

1、使用场景

有时候我们可能根据是否传主键id来判断是新增还是更新,或者传不同的type来确定什么操作类型。

2、接口示例

@PostMapping(value = "/saveOrUpdateUser")
@OperateLog(bizNo = "{#dto.userId}", operateName = "#dto.userId == null ? '新增用户':'更新用户'",
operateContent = "#dto.userId == null ? '新增' + #dto.userName + '用户':'将用户id为' + #dto.userId + '的用户名更新为' + #dto.userName")
public Result<Void> saveOrUpdateUser(@RequestBody UserDTO dto) {
return Result.success();
}

3、请求示例

请求url

localhost:8080/saveOrUpdateUser

请求参数

{
"userId": 17,
"userName": "赵磊"
}

4、输出日志

传入userId的日志

日志操作记录------ OperateLogDTO(operator=张三, bizNo=null, operateName=更新用户, operateContent=将用户id为17的用户名更新为赵磊, status=true, errMsg=null)

如果不传入userId只传userName,我们再看下日志

日志操作记录------ OperateLogDTO(operator=张三, bizNo=null, operateName=新增用户, operateContent=新增赵磊用户, status=true, errMsg=null)

四、支持标记成功日志或业务异常日志

1、使用场景

请求一个接口的时候,可以分为三种情况:

  • 接口返回成功,同时返回成功状态码
  • 接口返回成功,但返回业务异常状态码,比如:没有查询到该订单信息
  • 接口直接报错,比如我们常见的空指针异常

对于第三种情况,我们可以不去记录这个用户操作日志,如果有需要可以记录在异常记录表中。

但对于第一和第二种情况,我们需要记录操作是成功还是失败。

2、接口示例

@PostMapping(value = "/saveUser")
@OperateLog(bizNo = "{#dto.userId}", operateName = "新增用户", operateContent = "新增用户名为{#dto.userName}")
public Result<Void> saveUser(@RequestBody UserDTO dto) {
return Result.failed("该用户名称已存在");
}

可以看出接口返回的是 该用户名称已存在,业务异常。

3、请求示例

请求url

localhost:8080/saveUser

请求参数

{
"userId": 2,
"userName": "阎平"
}

4、输出日志

日志操作记录------ OperateLogDTO(operator=张三, bizNo=2, operateName=新增用户, operateContent=新增用户名为阎平, status=false, errMsg=该用户名称已存在)

可以看出这里的status状态是 false,同时记录了错误原因 该用户名称已存在

最后附上GitHub源码地址:

https://github.com/yudiandemingzi/spring-boot-operate-log

声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载!

SpringBoot + 自定义注解,实现用户操作日志(支持SpEL表达式)的更多相关文章

  1. SpringBoot自定义注解、AOP打印日志

    前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...

  2. Spring AOP使用注解记录用户操作日志

    最后一个方法:核心的日志记录方法 package com.migu.cm.aspect; import com.alibaba.fastjson.JSON; import com.migu.cm.do ...

  3. 微软企业库5.0 学习之路——第九步、使用PolicyInjection模块进行AOP—PART4——建立自定义Call Handler实现用户操作日志记录

    在前面的Part3中, 我介绍Policy Injection模块中内置的Call Handler的使用方法,今天则继续介绍Call Handler——Custom Call Handler,通过建立 ...

  4. 利用Hibernate监听器实现用户操作日志

    网上搜索发现,实现用户操作日志的方式有:自定义注解方式.Hibernate拦截器方式.Hibernate监听器方式等. 1.自定义注解方式较为麻烦,需要进行操作记录的方法均需要添加注解,但是相对的操作 ...

  5. 我使用Spring AOP实现了用户操作日志功能

    我使用Spring AOP实现了用户操作日志功能 今天答辩完了,复盘了一下系统,发现还是有一些东西值得拿出来和大家分享一下. 需求分析 系统需要对用户的操作进行记录,方便未来溯源 首先想到的就是在每个 ...

  6. SpringBoot 自定义注解 实现多数据源

    SpringBoot自定义注解实现多数据源 前置学习 需要了解 注解.Aop.SpringBoot整合Mybatis的使用. 数据准备 基础项目代码:https://gitee.com/J_look/ ...

  7. 基于NopCommerce的开发框架——缓存、网站设置、系统日志、用户操作日志

    最近忙于学车,抽时间将Nop的一些公用模块添加进来,反应的一些小问题也做了修复.另外有园友指出Nop内存消耗大,作为一个开源电商项目,性能方面不是该团队首要考虑的,开发容易,稳定,代码结构清晰简洁也是 ...

  8. springAOP记录用户操作日志

    项目已经开发完成,需要加用户操作日志,如果返回去加也不太现实,所以使用springAOP来完成比较合适. 注解工具类: @Retention(RetentionPolicy.RUNTIME) @Tar ...

  9. [技术博客] SPRINGBOOT自定义注解

    SPRINGBOOT自定义注解 在springboot中,有各种各样的注解,这些注解能够简化我们的配置,提高开发效率.一般来说,springboot提供的注解已经佷丰富了,但如果我们想针对某个特定情景 ...

  10. RabbitMQ实战场景(一):异步记录用户操作日志

    传统的项目开发中业务流程以串行方式,执行了模块1—>模块2–>模块3 而我们知道,这个执行流程其实对于整个程序来讲是有一定的弊端的,主要有几点: (1)整个流程的执行响应等待时间比较长; ...

随机推荐

  1. {"status":-1,"statusText":"ERR_CONNECT_FAILED"}

    今日使用weex 的stream 遇到一个极坑,也极傻的问题 一.steam.fetch 下面是我使用steam.fetch调用后台接口都截图 二.页面测试 奇怪的是,我借同事是手机来进行测试,有一个 ...

  2. Springboot——参数校验

    springboot参数校验注解 在controller层需要对前端传来的参数进行校验 校验简单数据类型 使用springboot自带的validation工具可以从后端对前端传来的数据进行校验 使用 ...

  3. 2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据

    2023-05-27:给你一个只包含小写英文字母的字符串 s . 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换. 请你返回将 s 变成回文串的 最少操作次数 . 注意 ,输入数据 ...

  4. [TSG开发]法如扫描仪SDK探幽-1.旧版SDK采集流程、问题解析、常见参数

    做什么 法如扫描仪是一个三维的激光扫描仪,可以通过特定的作业模式将空间以三维激光点云的形式保存下来,并且通过特定的算法得出一些想要的具体参数. 这个SDK探幽日志主要是对目前SDK开发中遇到的一些问题 ...

  5. Python潮流周刊#4:Python 2023 语言峰会

    你好,我是猫哥.这里记录每周值得分享的 Python 及通用技术内容,本期是特别加更版,聚焦于 Python 官方 2023 年语言峰会的系列博客. 博客原文:https://pythoncat.to ...

  6. Vue——计算属性、监听属性、Vue生命周期、组件介绍和使用、组件间通信、ref属性

    计算属性 // 1 计算属性是基于他们的依赖变量进行缓存的 // 2 计算属性只有在它的相关依赖变量发生改变时才会重新求值,否则不会变(函数只要页面变化,就会重新运算) // 3 计算属性就像pyth ...

  7. JUC同步锁原理源码解析五----Phaser

    JUC同步锁原理源码解析五----Phaser Phaser Phaser的来源 A reusable synchronization barrier, similar in functionalit ...

  8. CF1770F Koxia and Sequence

    一步都没想到,一定是状态不好吧,一定吧一定吧? 加训数数! 题意 给定 \(n, x, y\),定义好的序列 \(\{a_i\}_{i = 1}^n\) 满足 \(\sum\limits_{i = 1 ...

  9. 深入浅出security学习笔记

    第一章 导入web和security依赖,然后默认提供了一个基于内存的UserDetailsServiceAutoConfiguration如下 会读取写入的user配置,SecurityProper ...

  10. 力扣 (LeetCode)算法入门——Day1

    704. 二分查找 题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. ...