Springboot项目使用AOP切面对增删改查操作进行记录日志操作

本文介绍了如何在SpringBoot项目中利用AOP(面向切面编程)对增删改查操作进行日志记录,包括引入相关库、自定义Log注解、添加注解到业务方法以及定义切面并处理日志的成功与失败情况。
摘要由CSDN通过智能技术生成

Springboot项目使用AOP切面对增删改查操作进行记录日志操作



前言

AOP它通过将横切关注点(例如日志记录、事务管理、权限控制等)从主要业务逻辑中分离出来,以模块化的方式进行管理。在AOP中,通过定义切面(Aspect)来捕获和处理横切关注点,然后将其应用于特定的目标对象或方法。


一、AOP是什么?

官方的解释有点抽象,我们举个例子说明:假设我们需要在多个方法中添加日志记录功能。传统的方式是在每个方法中都添加日志代码,但这样会导致代码重复,并且当我们需要修改日志记录逻辑时,需要逐个修改所有方法。而使用AOP,我们只需定义一个切面,将日志记录的逻辑写在切面中。然后,通过在需要添加日志的地方进行配置,就能自动将切面应用到目标方法中,实现日志记录的功能。

二、使用步骤

1.引入库

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

2.编写一个自己定义的Log注解

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TypeByFileValid {
    // 模块名称
    String title() default "";
}


3.根据业务添加注解

    /**
     * 新增
     */
    @PostMapping("/addFile")
    @TypeByFileValid(title = "上传文件")
    public Result addFile(Searcher searcher) {
        Map<String, Object> map = xxxxService.saveFile(searcher);
        return Result.success(map);
    }

    /**
     * 删除
     */
    @PostMapping("/removeFile")
    @TypeByFileValid(title = "删除")
    public Result removeFile(@RequestBody Map<String, Object> param) {
        xxxxService.deleteFile(param);
        return Result.success();
    }

    /**
     * 下载/预览 文件
     */
    @PostMapping("/download")
    @TypeByFileValid(title = "下载")
    public Result download(@RequestBody JSONObject param) {
        return Result.success(xxxxxService.download(param.getString("path")));
    }

4.定义切面

@Slf4j
@Aspect
@Component
public class FileOperationLogAspect implements Ordered {
	 /**
     * 在业务代码执行过程中,业务中如果失败了可能会出现事务回滚,导致失败日志也无法插入数据库中。
     * 所以这里实现Ordered类,改变业务类处理优先级问题
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }


	/**
     * 定义切面
     */
    @Pointcut("@annotation(com.sztech.common.annotation.TypeByFileValid)")
    public void pt() {
    }


 	/**
     * 在方法执行后执行
     * 下载/删除/上传 日志记录
     */
    @AfterReturning(value = "pt()", returning = "rvt")
    public void saveSuccessLog(JoinPoint joinPoint, Object rvt) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取注解方法
        TypeByFileValid logAnnotation = method.getAnnotation(TypeByFileValid.class);
        //获取注解title内容
        String title = logAnnotation.title();
        //获取实际方法参数
        Object[] args = joinPoint.getArgs();
        String name=null;
        OperationLog operationLog = new OperationLog();

        /**
         * 由于上传/删除/下载的入参格式有区别,所以需要单独处理
         */
        if (StringUtils.equals(title,"删除")){
            Map<String, Object> map= (Map<String, Object>)args[0];
            //该删除有可能为批量删除,需单独处理
            List<String> nameList = (List<String>) map.get("xxxName");
            if (ObjectUtils.isNotEmpty(nameList)&&nameList.size()>=2){
                title="批量删除";
                name=nameList.stream().collect(Collectors.joining(","));//若为批量删除,则存"小佳,小一,......."格式
            }else {
                name=nameList.get(0);
            }

        }else if (StringUtils.equals(title,"下载")) {
            JSONObject jsonObject=(JSONObject)args[0];
            name=jsonObject.getString("name");
        }else if (StringUtils.equals(title,"上传文件")) {
            //由于上传文件无法在入参中获取名称,所以迂回一下在出参里面获取上传文件的文件名
            String jsonStr = JSON.toJSONString(rvt);
            Result result = JSON.parseObject(jsonStr, Result.class);
            String data = JSON.toJSONString(result.getData());
            Map<String, Object> map = JSON.parseObject(data, Map.class);
            name = String.valueOf(map.get("name"));

        }
        try {
            operationLog.setName(name);
            operationLog.setTitle(title);
            operationLog.setStatus("成功");
            OperationLogService.save(operationLog);
        }catch (Exception e) {
            log.info("------------------------>日志记录失败");
        }

    }
    /**
     * 单独记录失败的日志
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "pt()", throwing = "ex")
    public void saveFormErrorLog(JoinPoint joinPoint, Exception ex){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取注解方法
        TypeByFileValid logAnnotation = method.getAnnotation(TypeByFileValid.class);
        //获取注解title内容
        String title = logAnnotation.title();
        //获取实际方法参数
        Object[] args = joinPoint.getArgs();
        String name=null;
        OperationLog operationLog = new OperationLog();

        /**
         * 由于上传/删除/下载的入参格式有区别,所以需要单独处理
         */
        if (StringUtils.equals(title,"删除")){
            Map<String, Object> map= (Map<String, Object>)args[0];
            //该删除有可能为批量删除,需单独处理
            List<String> nameList = (List<String>) map.get("xxxName");
            if (ObjectUtils.isNotEmpty(nameList)&&nameList.size()>=2){
                title="批量删除";
                name=nameList.stream().collect(Collectors.joining(","));//若为批量删除,则存"小佳,小一,......"格式
            }else {
                name=nameList.get(0);
            }

        }else if (StringUtils.equals(title,"下载")) {
            JSONObject jsonObject=(JSONObject)args[0];
            name=jsonObject.getString("name");
        }else if (StringUtils.equals(title,"上传文件")) {
            //若是上传失败,则无法记录上传失败的文件名称,这里就只记录title
            //为了结构和切面成功中保持一致,这里重新获取一下title,以便更好的看清
            title ="上传文件";

        }
        try {
            String message = ex.getMessage();
            if (ex instanceof BizException) {
                BizException exception = (BizException) ex;
                message = exception.getMsg();
            }
            operationLog.setLog(message);//失败则记录失败原因
            operationLog.setStatus("失败");
            operationLog.setTitle(title);
            operationLog.setName(name);
            fileOperationLogService.save(operationLog);
        }catch (Exception e) {
            log.info("------------------------>文件归集任务日志记录失败");
        }

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值