我try 创建一个方面来覆盖 HttpServletRequest个 参数,然后才实际执行控制器处理程序方法.但事实证明,HttpServletRequest始终是RequestFacade实例,即使我在方面方法中将其替换为Custom HttpServletRequestWrapper.

以下是代码:

// the annotation:

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

// the aspect:
@Component
@Aspect
@Slf4j
public class MyAspect {
    @Pointcut("@annotation(com.example.springtest.annotation.MyAnnotation)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object setHeader(ProceedingJoinPoint pjp) throws Throwable {
        var args = pjp.getArgs();
        var signature = (MethodSignature) pjp.getSignature();
        var method = signature.getMethod();
        var annotations = method.getDeclaredAnnotations();
        var need = Arrays.stream(annotations).anyMatch(a -> a.annotationType().equals(MyAnnotation.class));
        if (!need) {
            return pjp.proceed();
        }

        for (var i = 0; i < args.length; i++) {
            var arg = args[i];
            if (arg instanceof HttpServletRequest request) {
                args[i] = new HttpServletRequestWrapper(request) {
                    @Override
                    public String getHeader(String name) {
                        if (name.equalsIgnoreCase("my-header")) {
                            return "my-header";
                        } else {
                            return super.getHeader(name);
                        }
                    }
                };
            }
        }
        return pjp.proceed();
    }

}

// the bootstrap class:
@Configurable
@EnableAspectJAutoProxy
@SpringBootApplication
public class SpringtestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringtestApplication.class, args);
    }

}

// and the controller
@RestController
public class TestController {

    private static final Logger log = LoggerFactory.getLogger(TestController.class);

    @MyAnnotation
    @GetMapping("/get-my-header")
    public String getMyHeader(HttpServletRequest request) {
        if (Objects.requireNonNull(request) instanceof HttpServletRequestWrapper) {
            log.info("is wrapper");
        } else {
            log.info("request:{}", request.getClass());
        }
        return request.getHeader("my-header");
    }
}

那么,那里发生了什么呢?在我替换了HttpServletRequest参数之后,是否有其他代理类实例更改了它?

日志(log)显示方面和控制器中的请求参数都是RequestFacade实例.

我还try 创建一个服务方法,并将我的定制HttpServletRequestWrapper实例直接发送给它.这一次,该参数没有更改.

推荐答案

修改请求头恐怕不是那么容易的.我也担心这方面不是一条可行的道路.

下面是一个Spring Boot2的最小且可重现的示例,它通过在一个定制拦截器中为请求设置一个命名attribute来实现您想要的结果,该拦截器是在@RestController的方法中捕获的.

Interceptor

@Component
public class CustomInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        request.setAttribute("fooAttribute", "fooValue");
        return true;
    }
}

Configuration

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private CustomInterceptor customInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(customInterceptor);
    }
}

Controller

我让属性在主体中返回.

@GetMapping("hello")
public ResponseEntity<String> hello(@RequestAttribute String fooAttribute) {
    return ResponseEntity.ok(fooAttribute);
}

测试一下:

curl http://localhost:8080/hello
fooValue

Java相关问答推荐

判断大写字符串的Java方法总是返回假

获取拦截器内部的IP地址

在Java 8之后,HashMap的最坏情况下时间复杂度仍然是O(n)而不是O(log n)?

Java:根据4象限中添加的行数均匀分布行的公式

Java事件系统通用转换为有界通配符

使用包私有构造函数强制子类Java类

JUnit—如何模拟局部变量对象方法调用

@org.springframework.beans.factory.annotation.Autowired(required=true)-注入点有以下注释:-SpringBoot

将不受支持的时区UT重写为UTC是否节省?

只需最少的代码更改即可将版本号标记添加到日志(log)

将响应转换为带值的键

Spring @Value default无法计算表达式

%This内置函数示例

try 从REST API返回对象列表时出错

在缺少字段时使用Jackson With Options生成Optional.Empty()

Java嵌套流查找任意值

持续时间--为什么在秒为负数的情况下还要做额外的工作?

如果c不为null,Arrays.sort(T[]a,Comparator<;?super T>;c)是否会引发ClassCastException?

如何使用stream.allMatch()为空流返回false?

MapStruct记录到记录的映射不起作用