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

SpringBoot-AOP环绕通知记录日志鉴权

toyiye 2024-06-21 12:19 11 浏览 0 评论

1、问题描述

微信公号h5开发,前后端分离,因为是在微信公号里面操作页面,还有涉及到不同手机操作也不一样,导致联调比较麻烦,定位问题也麻烦,以前写过通过aop记录所有前端http请求,就又拿出来梳理了下,记录日志,记录下,希望可以帮到有需要的朋友。

2、解决方案

项目是springboot项目,通过springboot-aop,配置环绕通知,记录调用地址、入参、返回参数、ip,同时记录执行时间等,以便定位问题。具体的入库就是弄个表,保存下获取到的值,这里就不多做介绍了。

2.1 AOP简要说明

(1)什么是AOP?

AOP为Aspect Oriented Programming的缩写,是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

(2)AOP的五种通知方式

前置通知(Before):在目标方法或者说连接点被调用前执行的通知;
后置通知(After):指在某个连接点完成后执行的通知;
返回通知(After-returning):指在某个连接点成功执行之后执行的通知;
异常通知(After-throwing):指在方法抛出异常后执行的通知;
环绕通知(Around):指包围一个连接点通知,在被通知的方法调用之前和之后执行自定义的方法。

(3)说明

软件老王用的比较多的是前置通知和环绕通知;

前置通知用于权限控制的比较多一些,简单说就是再http请求调用方法前,进行鉴权校验等,鉴权通过再放行;

后置通知也简单用过,记录返回值的,用的不是很多;

然后就是用的最多的环绕通知,环绕通知=前置通知+后置通知,记录日志非常方便;

2.2 pom文件配置

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

springboot项目下,gav配置后,代码中直接使用标签就可以配置aop通知了,非常方便。

2.3 代码分解介绍

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;


@Aspect
@Component
public class WebLogAspect {

    @Pointcut("execution(public * com.spring.wx.oauth.conntroller.*.*(..))")
    public void webLog(){

    }
    //@Around:环绕通知
    @Around("webLog()")
    public Object saveSysLog(ProceedingJoinPoint proceedingJoinPoint) {

        System.out.println("环绕通知开始。。。。。");

        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();

        String className = proceedingJoinPoint.getTarget().getClass().getName();
        String methodName = method.getName();

        System.out.println(className);
        System.out.println(methodName);
        System.out.println(className + "." + methodName);

        //请求的参数
        Object[] args = proceedingJoinPoint.getArgs();
        String params = JSON.toJSONString(args);
        System.out.println(params);

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
        System.out.println("HTTP_METHOD : " + request.getMethod());
        System.out.println("IP : " + request.getRemoteAddr());

        //记录时间
        long start = System.currentTimeMillis();
        Object result =null;
        try {
            result = proceedingJoinPoint.proceed();
            System.out.println(result.toString());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println(throwable.getMessage());
        }

        Long time = System.currentTimeMillis() - start;
        System.out.println(time);
        System.out.println("环绕通知结束。。。。。");
        return result;
    }

}

说明:

(1)两个标签,@Component和@Aspect,@Component标签,将类加入到spring容器,@Aspec,aop通知标签,只有pom中配置了gav才会有;

(2) @Pointcut,定义切入点,软件老王这里配置的conntroller包下的所有类;

    @Pointcut("execution(public * com.spring.wx.oauth.conntroller.*.*(..))")
    public void webLog(){

    }

(3) @Around("webLog()"),环绕通知,value为上面配置的切入点;

    @Around("webLog()")
    public void saveSysLog(ProceedingJoinPoint proceedingJoinPoint) 

(4)接着就是使用取值入库或打印

 //打印请求的类和方法
 System.out.println(className + "." + methodName);
 //打印入参
 System.out.println(params);
 
 // 记录下请求内容
 System.out.println("URL : " + request.getRequestURL().toString());
 System.out.println("HTTP_METHOD : " + request.getMethod());
 System.out.println("IP : " + request.getRemoteAddr());
 //记录执行时间
 System.out.println(time);
 

2.4 执行验证

2.4.1 controller类

简单的两个测试方法,一个是返回有异常;一个是正常执行,分别是laowang和shuaige

    @ResponseBody
    @GetMapping("/laowang")
    public String laowang(String test) {

        userService.laowang();
        return "SUCCESS";
    }

    @ResponseBody
    @GetMapping("/shuaige")
    public UserEntity shuaige(String test) {
        UserEntity userEntity = userService.shuaige();
        return userEntity;
    }

2.4.2 service类

    public void laowang() {
        UserEntity userEntity = new UserEntity();
        userEntity.setType(0);
        userEntity.setOpenid("1111");
        insert(userEntity);

        int i = 1/0;
//        System.out.println(i);
    }
    public UserEntity shuaige() {
        UserEntity userEntity = new UserEntity();
        userEntity.setType(0);
        userEntity.setOpenid("1111");

        return userEntity;
    }

2.4.3 运行过程及说明

(1)浏览器地址:http://localhost/laowang?test=333,首先不会进入执行方法,而是进入aop通知;

(2) 执行过程

(3)进入执行方法体,laowang方法是抛异常的方法体(1/0),报错前;

(4)try-catch捕获异常,并打印出来,记录执行时间

(5)shauige方法,无异常方法

浏览器地址:http://localhost/shuaige?test=333,执行过程;

(6)shuaige方法执行完毕,打印返回参数和时间。

3、总结

我们的业务主要需求是:记录入参、出参、执行时间,方便定位问题,AOP的环绕通知已经能满足了;

入参:params;

出参:result.toString(),同时假如方法执行有异常,会将异常记录下来;

执行时间:time;

---20210813--

修改两行代码,增加了通知的返回,通知不返回的话,会把后端方法的返回给“吃掉”,导致前端无法获取后端返回数据(异常)。


@Around("webLog()")

public Object saveSysLog(ProceedingJoinPoint proceedingJoinPoint) {

return result;

}


更多信息请关注@软件老王,关注不迷路,软件老王和他的IT朋友们,分享一些他们的技术见解和生活故事。

相关推荐

为何越来越多的编程语言使用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)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码