Java | 使用切面AOP拦截并修改Controller接口请求参数

这篇具有很好参考价值的文章主要介绍了Java | 使用切面AOP拦截并修改Controller接口请求参数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关注common wx: CodingTechWork

引言

  在开发过程中,会有一些需求将controller层的一些方法入参进行全量转换,最容易想到的可能是在调用下层service方法时,调用公共的方法进行入参转换,这时带来的唯一问题就是代码不雅观,比较冗余。那还有什么方法可以更优雅的解决这个问题吗?答案是有的:切面。
  我们实现一个AOP切面程序,对入参中的需转换的参数进行专项转换,而无需在各个controller层的各个方法中进行转换处理。

实践

controller类

package com.test.selfcoding.controller;

import com.test.selfcoding.bean.PersonBean;
import com.test.selfcoding.service.HelloWorldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Description controller
 * @Author Liao Jy
 * @Date 2023/6/28
 */
@RestController
@RequestMapping("/hello/world")
public class HelloWorldController {

    @Autowired
    private HelloWorldService helloWorldService;

    @GetMapping("/test1")
    public String testGetHelloWorld() {
        return helloWorldService.getHelloWolrd();
    }

    @PostMapping("/test2")
    public String testPostHelloWord(@RequestBody PersonBean personBean) {
        return helloWorldService.postHelloWorld(personBean);
    }

    @GetMapping("/test3")
    public String testPostHelloWord(@RequestParam String personName) {
        return personName + ", hi world!";
    }

}

切面类

package com.test.selfcoding.aspect;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
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.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
 * @Description DefaultArgumentsAspect
 * @Author LiaoJy
 * @Date 2023/6/28
 */

@Component
@Aspect
@Slf4j
public class DefaultArgumentsAspect {
    @Before(value = "execution(* com.test.selfcoding.controller..*(..))")
    public void doBefore(JoinPoint joinPoint) {
        try {
        	//获取入参列表
            Object[] args = joinPoint.getArgs();
            log.info("args: {}", JSON.toJSONString(args));
            //入参判空
            if (null == args || args.length == 0) {
                log.info("no fields!");
                return;
            }
            //获取第一个入参(主要针对@RequestBody,一般只会有一个入参,若遇到多个@RequestParam,需循环处理)
            Object arg = args[0];
            //获取字段域
            Field[] fields = arg.getClass().getDeclaredFields();
            log.info("getDeclaredFields: {}", JSON.toJSONString(fields));
			//判断入参中是否有"name"
            if (Arrays.stream(fields).noneMatch(item -> "name".equals(item.getName()))) {
                log.info("no name field!");
                return;
            }
            //入参中有"name",获取该字段
            Field field = arg.getClass().getDeclaredField("name");
            //判断是否可使用
            boolean accessible = ((!Modifier.isPublic(field.getModifiers())
                    || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
                    || Modifier.isFinal(field.getModifiers())) && !field.isAccessible());
            //若不可用,则需要进行setAccessible
            if (accessible) {
                ServletRequestAttributes attributes
                        = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                // 获取request对象
                HttpServletRequest request = attributes.getRequest();
                log.info("method name: {}", request.getRequestURI());
                field.setAccessible(true);
                //将name参数替换为system
                field.set(arg, "system");
            }
        } catch (Exception e) {
            log.error("切面参数设置异常", e);
        }
    }
}

验证

无参测试接口1

  1. 接口调用
    java 通过切面拦截请求参数,JAVA核心技术,java,开发语言
  2. 控制台日志
2023-06-28 18:06:06.060  INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect      : args: []
2023-06-28 18:06:06.061  INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect      : no fields!
2023-06-28 18:06:06.066  INFO 6495 --- [nio-8001-exec-1] c.t.s.s.impl.HelloWorldServiceImpl       : getHelloWolrd() get str success.
result: hugh, hello world!
  1. 结果分析
    未获取到参数,正常走接口。打印no fields!,无需转换参数。

不包含指定参数测试接口2

  1. 接口调用
    java 通过切面拦截请求参数,JAVA核心技术,java,开发语言

  2. 控制台日志文章来源地址https://www.toymoban.com/news/detail-820435.html

2023-06-28 18:08:04.040  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : args: ["xiaowang"]
2023-06-28 18:08:04.055  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"char"},"annotations":[],"declaredAnnotations":[],"type":"[C"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[C","modifiers":18,"name":"value","synthetic":false,"type":"[C"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"int","modifiers":2,"name":"hash","synthetic":false,"type":"int"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"long"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"long","modifiers":26,"name":"serialVersionUID","synthetic":false,"type":"long"},{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"java.io.ObjectStreamField"},"annotations":[],"declaredAnnotations":[],"type":"[Ljava.io.ObjectStreamField;"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[Ljava.io.ObjectStreamField;","modifiers":26,"name":"serialPersistentFields","synthetic":false,"type":"[Ljava.io.ObjectStreamField;"},{"accessible":false,"annotatedType":{"annotatedActualTypeArguments":[{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"}],"annotations":[],"declaredAnnotations":[],"type":{"actualTypeArguments":["java.lang.String"],"rawType":"java.util.Comparator","typeName":"java.util.Comparator<java.lang.String>"}},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":{"$ref":"$[4].annotatedType.type"},"modifiers":25,"name":"CASE_INSENSITIVE_ORDER","synthetic":false,"type":"java.util.Comparator"}]
2023-06-28 18:08:04.056  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : no name field!
  1. 结果分析
    未获取到指定的参数,正常走接口。打印no name field!,无需转换参数。

包含指定参数测试接口3

  1. 接口调用
    java 通过切面拦截请求参数,JAVA核心技术,java,开发语言

  2. 控制台日志

2023-06-28 18:10:15.481  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : args: [{"age":1,"name":"xiaohong"}]
2023-06-28 18:10:15.482  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"java.lang.String","modifiers":2,"name":"name","synthetic":false,"type":"java.lang.String"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"int","modifiers":2,"name":"age","synthetic":false,"type":"int"}]
2023-06-28 18:10:15.482  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : method name: /hello/world/test2
  1. 结果分析
    获取到指定的参数,进行name值替换为system,切面转换参数成功。

到了这里,关于Java | 使用切面AOP拦截并修改Controller接口请求参数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java 设置免登录请求接口被拦截问题

    Java 设置免登录请求接口被拦截问题

    1、在设置免登录时,前端将请求的路由添加到白名单后,请求接口还是被拦截到了,将请求接口也设置后还是会被拦截跳转到登录页面  通过JAVA   注解 @Anonymous  进行设置匿名访问就可以了

    2024年02月09日
    浏览(6)
  • Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    今天主要说说如何通过自定义注解的方式,在 Spring Boot 中来实现 AOP 切面统一打印出入参日志。小伙伴们可以收藏一波。 废话不多说,进入正题! 在看看实现方法之前,我们先看下切面日志输出效果咋样: 从上图中可以看到,每个对于每个请求,开始与结束一目了然,并且

    2024年02月08日
    浏览(10)
  • Controller层自定义注解拦截request请求校验

    Controller层自定义注解拦截request请求校验

    一、背景 笔者工作中遇到一个需求,需要开发一个注解,放在controller层的类或者方法上,用以校验请求参数中(不管是url还是body体内,都要检查,有token参数,且符合校验规则就放行)是否传了一个token的参数,并且token符合一定的生成规则,符合就不予拦截,放行请求,否则

    2024年01月17日
    浏览(13)
  • JAVA:面向切面编程AOP

            把某一些功能提取出来与某一对象进行隔离,提取之后可以对某哥单方面的功能进行修改和扩展         也就是把众多方法中的的所有公共代码抽取出来,放到某个地方集中管理         对业务逻辑的各个部分进行了隔离,从而降低业务逻辑各部分之间的耦合,

    2024年02月07日
    浏览(9)
  • Java注解方式实现aop,切点切面实战

    Java注解方式实现aop,切点切面实战

    注解方式实现aop我们主要分为如下几个步骤(有更好的方法的话,欢迎交流): 1.在切面类(为切点服务的类)前用@Aspect注释修饰,声明为一个切面类。 2.用@Pointcut注释声明一个切点,目的是为了告诉切面,谁是它的服务对象。(此注释修饰的方法的方法体为空,不需要写功

    2024年02月12日
    浏览(9)
  • 【Java 初级】Spring核心之面向切面编程(AOP)

    【Java 初级】Spring核心之面向切面编程(AOP)

    tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。 💕💕 推荐: 体系化学习Java(Java面试专题) AOP(面向切面编程)是一种编程范式,用于将横切关注点(如日志记录、性能统计等

    2024年02月04日
    浏览(15)
  • Spring Boot框架中Controller层API接口如何支持使用多个@RequestBody注解接受请求体参数

    Spring Boot框架中Controller层API接口如何支持使用多个@RequestBody注解接受请求体参数

    众所周知,在Spring Boot框架中,Controller层API接口编码获取请求体参数时,在参数上会使用@RequestBody注解;如果一次请求中,请求体参数携带的内容需要用多个参数接收时,能不能多次使用@RequestBody注解呢? 下面我们先测试一下,参考代码: PostMan进行请求: 服务端后端日志:

    2024年01月17日
    浏览(13)
  • Java AOP 通过注解实现切面及通过注解改变返回值

    学习过java的小伙伴都知道Spring的重要知识点之一就是AOP,AOP也就是切面编程,切面编程它能够帮助我们实现非侵入式的功能增强,解耦现有的业务逻辑和要新增的功能增强。 实际应用中的场景 事务管理、拦截器、日志处理、权限控制等。 AOP的增强方式 前置增强、后置增强

    2024年02月14日
    浏览(12)
  • 【JavaEE】面向切面编程AOP是什么-Spring AOP框架的基本使用

    【JavaEE】面向切面编程AOP是什么-Spring AOP框架的基本使用

    【JavaEE】 AOP(1) 1.1 AOP 与 Spring AOP AOP ( A spect O riented P rogramming),是一种思想,即 面向切面编程 Spring AOP 则是一个框架,Spring项目中需要引入依赖而使用 AOP和Spring AOP的关系就相当于IoC和DI Spring AOP让开发者能够半自动的开发AOP思想下实现的功能 1.2 没有AOP的世界是怎样的

    2024年02月11日
    浏览(11)
  • 1、springboot中使用AOP切面完成全局日志

    1、springboot中使用AOP切面完成全局日志 可选择在控制台输出日志或者收集日志信息存储进数据库中 1、在配置 AOP 切面之前,我们需要了解下 aspectj 相关注解的作用: @Aspect :作用是把当前类标识为一个切面、供容器读取 @Pointcut :(哪些方法或者类需要进行AOP织入)定义一个

    2024年02月02日
    浏览(8)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包