使用 AOP & 自定义注解 实现日志存储~

背景

记录日志是一种重要步骤,可以提高系统的可靠性、安全性和性能,并为故障排查、业务分析和合规要求提供支持。在Spring Boot中,使用日志框架如Logback、Log4j等进行日志记录,可以灵活配置、方便使用,并提供丰富的日志级别和输出格式。

但是一般情况下Logback、Log4j等进行日志记录会把日志记录在text文本中,而且会定期删除。

我们可能会需要很多其他的功能:

  • 很久之前的日志。
  • 日志数据的统计和分析整理。
  • 数据的关联和追踪
  • 日志的安全性和隐私性
  • 日志数据的备份和恢复
  • 数据的共享

这些都得我们想一种新的记录日志的方式。比如 我们在业务中可以将很重要的日志记录在数据库中。

准备

可以参考我上一篇AOP文章来配置环境

Spring AOP & Aspectj 框架 快速入门~

目的

自定义日志记录,然后将记录的日志存储在数据库。由注解 @Log 来自定义标注要记录那些方法或者类。

步骤

1、创建一个注解类 Log

创建一个可以定义在类和方法上的注解。

/**
 * 自定义操作日志记录注解
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
    /**
     * 模块 
     */
    public String title() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

    /**
     * 操作人类别
     */
    public OperatorType operatorType() default OperatorType.MANAGE;

    /**
     * 是否保存请求的参数
     */
    public boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    public boolean isSaveResponseData() default true;
}

2、创建一个切面类

一个简单的记录系统接口的日志切面类,供大家参考:

@Component
@Aspect
public class LogAspect {


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private LogAspect logAspect;

    @Value("${token.header}")
    private String header;

    /**
     * 定义一个开关 可以随时关闭这个切面
     */
    @Value("${aspect.switch}")
    private Boolean aBoolean;


    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doBefore(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handle(joinPoint, jsonResult, null);
    }

    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handle(joinPoint, null, e);
    }

    private void handle(JoinPoint joinPoint, Object jsonResult, Exception e) {
        try {
            if (aBoolean) {
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = attributes.getRequest();

                HashMap<String, Object> map = new HashMap<>();
                // 获取请求的URL
                map.put("url", request.getRequestURL().toString());

                // 获取请求的方法
                map.put("method", request.getMethod());

                // 获取请求的IP地址
                map.put("ip", request.getRemoteAddr());

                // 获取请求的参数
                Object[] args = joinPoint.getArgs();
                String params = "";
                try {
                    if (args != null && args.length > 0) {
                        for (Object arg : args) {
                            if (arg instanceof MultipartFile[]) {
                                params = "files";
                            }
                        }
                        if (!params.equals("files")) {
                            params = JSON.toJSONString(args[0]);
                        }
                    }
                } catch (Exception e1) {
                    params = "参数解析失败";
                }
                map.put("params", params);

                // 获取当前的用户
                String token = request.getHeader(header);
                String userId = "";
                if (ObjectUtils.isNotEmpty(token)) {
                    LoginUser loginUser = SecurityUtils.getLoginUser();
                    if (ObjectUtils.isNotEmpty(loginUser)) {
                        userId = loginUser.getUserId().toString();
                    }
                }
                map.put("userId", userId);

                //记录错误信息
                if (e != null) {
                    map.put("errorMsg", StringUtils.substring(e.getMessage(), 0, 2000));
                }

                //当前时间
                map.put("time", DateUtils.getTime());

                // 是否需要保存result,参数和值
                if (StringUtils.isNotNull(jsonResult)) {
                    map.put("result", StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
                }

                // 异步 保存数据库
                AsyncManager.me().execute(AsyncFactory.recordOper(map));
            }
        } catch (Exception exp) {
            exp.printStackTrace();
        }
    }
}

3、使用

/**
 * 新增商品
 */
@Log(title = "新增商品", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody YdCommAttr ydCommAttr)
{
    return toAjax(ydCommAttrService.insertYdCommAttr(ydCommAttr));
}

参考:

若依 (开源项目) - Gitee.com

觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值