【问题标题】:Modify method argument with aspect使用方面修改方法参数
【发布时间】:2020-01-21 07:51:53
【问题描述】:

最近我在寻找如何在启动控制器逻辑之前更改 HttpServletRequest 对象的标题和正文,我发现实现此目的的唯一方法是使用方面,这个解决方案都很好,但问题是我有很多控制器类,我需要更改这些控制器中特定标头的值,我已经在我的方面添加了所有类:

@Pointcut("execution(* com.mypackage.Controller1..*(..)) || " +
          "execution(* com.mypackage.Controller3.someMethod*(..))
           //A lot of methods and packages
private void anyMethodWithHeader(){

@Around("anyMethodWithHeader()")
    public ResponseEntity<Map<String, Object>> changeHeaderValue(ProceedingJoinPoint jp) throws Throwable{
        //Here I got the object array with the arguments that I need

所以我的问题是: @PointCut 中有一种方法可以将正则表达式或条件表达式或类似的东西放在一行或两行中,以获得特定的标题?

我的意思是,我有很多控制器,这些控制器接收到很多标头,但我只想更改名为 test-token 的标头的值,我想要的只是避免多添加一行每次我在我的项目中添加一个新控制器时,在我看来。

我正在尝试在我的方面和其他内容中添加 @RequestHeader 的包,但没有任何效果。

感谢cmets。

【问题讨论】:

  • 您的控制器方法有什么共同点,使它们与非控制器区别开来?某个基础包?命名模式?类上的@Controller@RestController 注释?目标方法签名中的某些参数类型?如果有类似的东西,或者你可以重构来实现它(例如,将所有控制器移动到名为 *..controller 的子包中),我想我可以帮助你。
  • 你为什么不考虑基于 HandlerInterceptor 的解决方案?docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
  • @kriegaex 我的所有类都在某个包下,它们是@RestController,在许多这些类中,我在方法参数中有一个必需的标头,例如:@RequestHeader(value = "my-header") String myHeader
  • @R.G 我尝试了该解决方案,但与过滤器遇到的问题相同,您可以获得请求的正文和标头,但您无法更改 HttpServletRequest 的内容我尝试使用自定义对象仅处理标头(wilddiary.com/adding-custom-headers-java-httpservletrequest),但使用该解决方案您可以添加自定义标头但我无法更改现有标头的内容,我不想更改所有的逻辑我的课。

标签: java spring-boot aop


【解决方案1】:

你评论了:

@kriegaex 我的所有类都在某个包下,它们是@RestController,在其中许多类中,我在方法参数中有一个必需的标头,例如:

@RequestHeader(value = "my-header") String myHeader

你会得到所有@RestController 类这样的:

@within(org.springframework.web.bind.annotation.RestController)

您可以像这样获得某个包(及其子包)中的所有类:

within(a.certain.package..*)

你可以把它组合成

@within(org.springframework.web.bind.annotation.RestController) &&
within(a.certain.package..*) &&
execution(* *(..))

execution(* *(..)) 部分在 Spring AOP 中不是必需的,因为它只支持方法执行连接点。在 AspectJ 中您需要它,因为您还可以拦截方法调用、构造函数和其他连接点。

如果您真的可以在所有目标方法中 100% 依赖 @RequestHeader 参数注释,则可以使用

execution(* *(.., @org.springframework.web.bind.annotation.RequestHeader (*), ..))

并且还隔离注释及其值,正如我在请求正文中描述的here(只需更改注释并根据您的需要调整其余代码)。

如果您可以依赖请求标头参数在签名中始终处于相同的相对位置,例如从左到右的第一,第二,第三,这会更容易,因为您可以通过args()直接将方法参数绑定到通知方法参数。如果是这种情况,请告诉我,我可以举个例子。

【讨论】:

  • 嗨,抱歉耽搁了,我想我的特殊情况的最佳解决方案是将控制器分成 2 个不同的包,一个带有我需要的标头,另一个我不需要没有那个标题。我不能相信争论的立场,因为团队的许多成员正在创建更多的控制器,我们可能会在编码时犯错误。我会将您的 cmets 标记为答案,非常感谢您的帮助。
  • 如果有人会出现编码错误,他们也可以将控制器放入错误的包中。此外,execution(* *(.., @org.springframework.web.bind.annotation.RequestHeader (*), ..))any 位置找到参数注释,您只需要我链接的解决方案即可动态找出它是哪一个。 IMO,您不应该尝试在您的方面适应各种不良编码,而是制定明确的编码准则并自动执行它们。如果您使用 AspectJ 编译器,AspectJ 也可以在这里为 @DeclareWarning@DeclareError 提供帮助。
【解决方案2】:

切入点可以设置为自定义注释,该注释仅用于您希望由方面处理的方法。除了应用方面时的精细控制之外,注释还可以具有方面本身使用的参数(有效地修改其行为)。

为了说明这个想法,这是我的一个小项目,其中使用了它:


虽然方面在许多情况下都非常强大且非常有用,但在这种特殊情况下,您也可以使用filter

【讨论】:

  • 我在使用方面之前尝试了过滤器,但是不能更改HttpServletRequest的内容,可以添加自定义标头和自定义参数。或者至少是我在寻找解决方案时发现的。
猜你喜欢
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多