我们如何实现业务操作日志功能?

news/2025/3/16 5:28:32/

1. 需求

我们经常会有这样的需求,需要对关键的业务功能做操作日志记录,也就是用户在指定的时间操作了哪个功能,操作前后的数据记录,必要的时候可以一键回退,今天我就为大家实现这个的功能,让大家可以直接拿来用。

1.1 日志分类

  1. 系统日志:指的是程序执行过程中的关键步骤记录,根据实际输出的debug、info、warn、error等级别的执行记录信息,主要用来记录核心参数以及返回值,同时为了在出现问题的时候能够快速排查问题
  2. 操作日志:它是用户实际业务操作行为的记录,主要是为了分析用户的行为偏好,一方面用来对业务进行分析,开发人员也可以针对访问的频率去提高特定接口的性能。

2. 设计思路

首先我们得要分析具体要实现这个功能,都需要记录哪些信息,然后怎么要去实现这个功能?
具体功能点:

  1. 记录用户的业务操作行为,具体字段有:操作人、操作时间、操作功能、日志类型、操作内容描述、操作内容、操作前内容。
  2. 需要对外提供页面和管理功能,以便查询追溯和数据回滚。

我们首先要想到,要实现这个功能,最好的办法就是需要和业务逻辑进行解耦,因为它是一种业务辅助功能,同时是对所有业务的一种横向操作,那我们使用什么技术,是不是就呼之欲出了?最容易想到的就是AOP切面+自定义注解

2.1 实现步骤

1、首先定义操作日志注解,注解内定义一些属性,如操作功能名称、描述等;

2、将自定义注解标记在需要进行业务操作记录的方法上,一般查询不需要。

3、定义切入点,编写切面:切入点就是标记业务操作日志注解的目标方法;切面就是保存业务操作日志信息。

对了,在这里我想给大家说一下咱们经常用到的几个技术的区别,过滤器,拦截器,SpringAOP,这个也是我经常的困惑。

2.2 SpringAOP、过滤器、拦截器对比

在匹配中同一目标时,过滤器、拦截器、SpringAOP的执行优先级是:过滤器>拦截器>SpringAOP,执行顺序是先进后出,主要有如下区别:

  1. 过滤器(Filter)
    过滤器,就是起到过滤筛选作用的一种事物,只不过这里的过滤器过滤的对象是客户端访问的web资源。也可以理解为一种预处理手段,对资源进行拦截后,将其中我们认为的杂质(用户自己定义的)过滤,符合条件的放行,不符合的则拦截下来。
    过滤器常见的使用场景:统一设置编码,过滤敏感字符,登录校验,URL级别的访问权限控制,数据压缩。
    在这里插入图片描述
    2.拦截器(Interceptor)
    拦截器是springmvc提供的,类似于过滤器。主要用于拦截用户请求并作相应的处理。
    拦截器的使用场景: 日志记录,权限校验,登录校验,性能检测,经常会用在网关处。
    在这里插入图片描述
    3:AOP
    AOP拦截的是类的元数据(包、类、方法名、参数等),AOP针对具体的代码,能够实现更加复杂的业务逻辑。
    使用的场景:日志记录,性能统计,安全控制,事务处理,异常处理。

3. 具体实现

3.1 引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3.2 数据库表设计

create table if not exists bus_log
(id bigint auto_increment comment '自增id'primary key,bus_name varchar(100) null comment '业务名称',bus_descrip varchar(255) null comment '业务操作描述',oper_person varchar(100) null comment '操作人',oper_time datetime null comment '操作时间',ip_from varchar(50) null comment '操作来源ip',param_file varchar(255) null comment '操作参数报文文件'
)
comment '业务操作日志' default charset ='utf8';

3.3 代码实现

  1. 定义日志注解
/*** 业务日志注解* 可以作用在控制器或其他业务类上,用于描述当前类的功能;* 也可以用于方法上,用于描述当前方法的作用;*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface BusLog {/*** 功能名称* @return*/String name() default "";/*** 功能描述* @return*/String descrip() default "";}
  1. 编写切面

主要步骤是:在环绕通知内执行过目标方法后,获取目标类、目标方法上的业务日志注解上的功能名称和功能描述, 把方法的参数报文写入到文件中,最后保存业务操作日志信息;

@Component
@Aspect
@Slf4j
public class BusLogAop implements Ordered {@Autowiredprivate BusLogDao busLogDao;/*** 定义BusLogAop的切入点为标记@BusLog注解的方法*/@Pointcut(value = "@annotation(com.wuk.BusLog)")public void pointcut() {}/*** 业务操作环绕通知*/@Around("pointcut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) {log.info("----BusAop 环绕通知 start");//执行目标方法Object result = null;try {result = proceedingJoinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}//目标方法执行完成后,获取目标类、目标方法上的业务日志注解上的功能名称和功能描述Object target = proceedingJoinPoint.getTarget();Object[] args = proceedingJoinPoint.getArgs();MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();BusLog anno1 = target.getClass().getAnnotation(BusLog.class);BusLog anno2 = signature.getMethod().getAnnotation(BusLog.class);BusLogBean busLogBean = new BusLogBean();String logName = anno1.name();String logDescrip = anno2.descrip();busLogBean.setBusName(logName);busLogBean.setBusDescrip(logDescrip);busLogBean.setOperPerson("wuk");busLogBean.setOperTime(new Date());JsonMapper jsonMapper = new JsonMapper();String json = null;try {json = jsonMapper.writeValueAsString(args);} catch (JsonProcessingException e) {e.printStackTrace();}//把参数报文写入到文件中OutputStream outputStream = null;try {String paramFilePath = System.getProperty("user.dir") + File.separator + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN) + ".log";outputStream = new FileOutputStream(paramFilePath);outputStream.write(json.getBytes(StandardCharsets.UTF_8));busLogBean.setParamFile(paramFilePath);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}}//保存业务操作日志信息this.busLogDao.insert(busLogBean);log.info("----BusAop 环绕通知 end");return result;}@Overridepublic int getOrder() {return 1;}
}
  1. 业务接口添加注解
@RestController
@Slf4j
@RequestMapping("/person")
public class PersonController {@Autowiredprivate IPersonService personService;@PostMapping@BusLog(name="添加人员信息",descrip = "添加人员信息")public Person add(@RequestBody Person person) {Person result = this.personService.registe(person);log.info("//增加person执行完成");return result;}@PutMapping@BusLog(name="修改人员信息",descrip = "修改人员信息")public void edit(@RequestBody Person person) {this.personService.update(person);}@DeleteMapping@BusLog(name="删除人员信息", descrip = "删除人员信息")public void delete(@PathVariable(name = "id") Integer id) {this.personService.delete(id);}
}
文章来源:https://blog.csdn.net/wu2374633583/article/details/131219500
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/490044.html

相关文章

Spark 4/5

4. 启动Spark Shell编程 4.1 什么是Spark Shell spark shell是spark中的交互式命令行客户端&#xff0c;可以在spark shell中使用scala编写spark程序&#xff0c;启动后默认已经创建了SparkContext&#xff0c;别名为sc 4.2 启动Spark Shell Shell /opt/apps/spark-3.2.3-bi…

OpenCV项目开发实战--一步一步介绍使用 OpenPose进行多人姿势估计C++/python实现

文末附基于Python和C++两种方式实现的测试代码下载链接 在我们上一篇文章中中,我们使用OpenPose模型对单个人执行人体姿态估计。在这篇文章中,我们将讨论如何进行多人姿态估计。 当一张照片中有多个人时,姿势估计会产生多个独立的关键点。我们需要弄清楚哪组关键点属于同一…

NXP恩智浦VEGA织女星开发板免费申请!

文章目录 前言关于RV32M1关于织女星开发板关于RISC-V架构ARM和RISC-V公然开撕总结历史精选 前言 大概两周前申请了一块NXP恩智浦的开发板&#xff0c;今天终于收到了&#xff01;在这里推荐给大家&#xff0c;官方网站刚上线一个月左右&#xff0c;目前申请的人还不算多&#…

《笑着离开惠普》读书笔记之人性化管理的典范

人性化管理的典范 假定人性善的惠普价值观 惠普的创建人之一比尔休利特曾经说过:“惠普的所有政策和措施都是来自于一种信念,那就是我们相信每一个员工都有把工作做好的愿望。只要公司能给他们提供一个合适的舞台和环境,员工必定全力以赴。”这就是著名的惠普之道的内涵和出…

转:惠普V3000系列笔记本电流声的解决方法

http://tech.tom.com  2007年02月27日 22时35分硅谷动力 eNet笔记本论坛有各帖子&#xff0c;讲了电流声的解决方法&#xff0c;不知道是不是针对所有hp机型还是怎么地&#xff0c;大家看看&#xff1a;http://nbbbs.enet.com.cn/thread-2879638-1-4.html。下面我要讲的&am…

hp probook fn_如何在HP ProBook(或兼容笔记本电脑)上安装Mac OS X Lion

hp probook fn There’s nothing more satisfying than building a hackintosh, i.e. installing Mac OS X on a non-Apple machine. Although it isn’t as easy as it sounds, but the end result is worth the effort. Building a PC with specific components and installi…

惠普战66怎么用u盘进入系统_惠普战66笔记本怎么装系统?惠普战66装win10系统步骤...

[文章导读]惠普战66是一款很火爆系列的笔记本,采用了intel 8代cpu,我们知道intel 8代cpu不能安装win7,最近有很多网友问惠普星系列预装的win10系统不好用想重装,但是由于惠普战66笔记本采用UEFI模式,不能像普通方式那样安装,需要用u盘的方式安装,并且BIOS要相关设置以及硬…

python的tqdm一些操作

主要参数 iterable: 可迭代的对象, 在手动更新时不需要进行设置 desc: str, 左边进度条的描述性文字 total: 总的项目数 leave: bool, 执行完成后是否保留进度条 file: 输出指向位置, 默认是终端, 一般不需要设置 ncols: 调整进度条宽度, 默认是根据环境自动调节长度, 如果设置…