百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

《若依ruoyi》第四十五章若依通过Spring AOP实现操作日志记录

toyiye 2024-06-21 12:29 13 浏览 0 评论

AOP 提供了一种面向切面操作的扩展机制,通常这些操作是与业务无关的,在实际应用中,可以实现:日志处理、事务控制、参数校验和自定义注解等功能。

一、日志处理

在调试程序时,如果需要在执行方法前打印方法参数,或者在执行方法后打印方法返回结果,可以使用切面来实现。

@Slf4j
@Aspect
@Component
public class LoggerAspect {

    @Around("execution(* cn.codeartist.spring.aop.sample.*.*(..))")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 方法执行前日志
        log.info("Method args: {}", joinPoint.getArgs());
        Object proceed = joinPoint.proceed();
        // 方法执行后日志
        log.info("Method result: {}", proceed);
        return proceed;
    }
}

二、事务控制

Spring 提供的声明式事务也是基于 AOP 来实现的,在需要添加事务的方法上面使用 @Transactional 注解。

@Service
public class DemoService {

    @Transactional(rollbackFor = Exception.class)
    public void insertBatch() {
        // 带事务控制的业务操作
    }
}

三、参数校验

如果需要在方法执行前对方法参数进行校验时,可以使用前置通知来获取切入点方法的参数,然后进行校验。

@Slf4j
@Aspect
@Component
public class ValidatorAspect {

    @Before("execution(* cn.codeartist.spring.aop.sample.*.*(..))")
    public void doBefore(JoinPoint joinPoint) {
        // 方法执行前校验参数
        Object[] args = joinPoint.getArgs();
    }
}

四、自定义注解

因为 AOP 可以拦截到切入点方法,Spring 也支持通过注解的方式来定义切点表达式,所以可以通过 AOP 来实现自定义注解的功能。

例如,自定义一个注解来实现声明式缓存,把方法的返回值进行缓存。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cacheable {

    /**
     * 缓的Key
     */
    String key();

    /**
     * 缓存过期时间
     */
    long timeout() default 0L;

    /**
     * 缓存过期时间单位(默认:毫秒)
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

然后定义一个切片来实现常规的缓存操作,先读缓存,缓存不存在时执行方法,然后把方法的返回结果进行缓存。

@Aspect
@Component
public class AnnotationAspect {

    @Around("@annotation(cacheable)")
    public Object doAround(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {
        // 自定义缓存逻辑
        return joinPoint.proceed();
    }
}

五、若依操作日志处理

代码目录,代码存放在ruoyi-framework模块下面,具体目录如下

package com.ruoyi.framework.aspectj;


1、如下图代码,日志拦截过程分为处理请求前执行、处理完请求后执行、拦截异常操作,其中正常处理和异常处理都会调用handleLog的方法插入操作日志。

其中正常处理,参数送入jsonResult,响应结果参数

异常处理,参数送入e。记录异常日志

/**
 * 处理请求前执行
 */
@Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog)
{
    TIME_THREADLOCAL.set(System.currentTimeMillis());
}

/**
 * 处理完请求后执行
 *
 * @param joinPoint 切点
 */
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
{
    handleLog(joinPoint, controllerLog, null, jsonResult);
}

/**
 * 拦截异常操作
 * 
 * @param joinPoint 切点
 * @param e 异常
 */
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
{
    handleLog(joinPoint, controllerLog, e, null);
}

如下是操作日志插入代码

protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
{
    try
    {
        // 获取当前的用户
        LoginUser loginUser = SecurityUtils.getLoginUser();

        // *========数据库日志=========*//
        SysOperLog operLog = new SysOperLog();
        operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
        // 请求的地址
        String ip = IpUtils.getIpAddr();
        operLog.setOperIp(ip);
        operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
        if (loginUser != null)
        {
            operLog.setOperName(loginUser.getUsername());
        }

        if (e != null)
        {
            operLog.setStatus(BusinessStatus.FAIL.ordinal());
            operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
        }
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        operLog.setMethod(className + "." + methodName + "()");
        // 设置请求方式
        operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
        // 处理设置注解上的参数
        getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
        // 设置消耗时间
        operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
        // 保存数据库
        AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
    }
    catch (Exception exp)
    {
        // 记录本地异常日志
        log.error("异常信息:{}", exp.getMessage());
        exp.printStackTrace();
    }
    finally
    {
        TIME_THREADLOCAL.remove();
    }
}

业务逻辑:

1、获取登录用户信息。

2、创建SysOperLog实列对像,初始化对象值。

3、记录ip地址(IpUtils.getIpAddr())、设置状态是成功还是失败、设置消耗时间。

4、通过异步插入数据库AsyncManager.me().execute(AsyncFactory.recordOper(operLog));

5、异步插入可以减少接口响应时间。

六、未来计划

1、ruoyi非分离版本拆解

2、ruoyi-vue-pro:讲解工作流

3、ruoyi-vue-pro:支付模块,电商模块

4、基于ruoyi-vue-pro项目开发

5、JEECG低代码开发平台

请关注我,本星球会持续推出更多的开源项目代码解析,如有更好的意见请留言回复或者私信。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码