Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 在@Around通知中处理带@RequestBody和不带@RequestBody的请求_Spring_Spring Boot_Aspectj_Spring Aop - Fatal编程技术网

Spring 在@Around通知中处理带@RequestBody和不带@RequestBody的请求

Spring 在@Around通知中处理带@RequestBody和不带@RequestBody的请求,spring,spring-boot,aspectj,spring-aop,Spring,Spring Boot,Aspectj,Spring Aop,我有这样的基于方面的日志记录: @Pointcut(“@annotation(Loggable)”) public void loggableAnnotation(){} @环绕(“loggableAnnotation()”) 公共对象simpleProcess(ProceedingJoinPoint joinPoint)抛出可丢弃的{ 返回此.processWithBody(连接点,null); } @大约(“loggableAnnotation()&&args(@org.springfram

我有这样的基于方面的日志记录:

@Pointcut(“@annotation(Loggable)”)
public void loggableAnnotation(){}
@环绕(“loggableAnnotation()”)
公共对象simpleProcess(ProceedingJoinPoint joinPoint)抛出可丢弃的{
返回此.processWithBody(连接点,null);
}
@大约(“loggableAnnotation()&&args(@org.springframework.web.bind.annotation.RequestBody,…))
公共对象processWithBody(ProceedingJoinPoint joinPoint,Object body)抛出Throwable{
//做事
}
当我使用
@RequestBody
执行请求时,会触发通知
processWithBody()
。但是当我执行没有
@RequestBody
(仅
@PathVariable
@RequestParam
)的请求时,
simpleProcess()
不会触发,而是在
processWithBody()
中,我接收路径变量值作为
body
参数


为什么会发生这种情况?我如何以不同的方式处理两种类型的请求(如果可能,请使用相同的建议)?

您犯了三个基本错误:

  • 您正试图从
    args()
    中匹配参数参数注释,但没有效果,这就是为什么
    processWithBody(…)
    匹配不需要的参数并将其绑定到
    body
    。它应该被传输到
    执行()
    切入点

  • 您的切入点语法是错误的,即使您将其转移到
    execution()
    ,例如
    execution(**(@org.springframework.web.bind.annotation.RequestBody*,…)
    将匹配参数的类型(!)是否有
    @RequestBody
    注释,不是参数本身。
    为了实现这一点,您需要将参数本身放入括号中,如
    (*)
    ,即
    执行(**(@org.springframework.web.bind.annotation.RequestBody(*),…)

  • 您必须确保切入点是互斥的,否则多个通知应在同一接合点上匹配。准确地说,您需要区分以下情况:

    • 方法由
      @Loggable
      注释,第一个方法参数由
      @RequestBody
      注释
    • 方法由
      @Loggable
      注释,第一个方法参数不是由
      @RequestBody
      注释
    • 方法由
      @Loggable
      注释,无任何参数
下面是纯Java+AspectJ中的一个示例(没有Spring或Spring AOP),但Spring AOP中的方面语法应该相同:

注释+驱动程序应用程序:

package de.scrum\u master.app;
导入静态java.lang.annotation.ElementType.METHOD;
导入静态java.lang.annotation.RetentionPolicy.RUNTIME;
导入java.lang.annotation.Retention;
导入java.lang.annotation.Target;
@保留(运行时)
@目标(方法)
public@interface Loggable{}
package de.scrum\u master.app;
导入org.springframework.web.bind.annotation.RequestBody;
公共类应用程序{
公共静态void main(字符串[]args){
应用程序=新应用程序();
应用程序。doNotLogMe(“foo”,11);
application.doNotLogMeEither();
申请书。doNotLogMeEither(“foo”,11);
应用程序。logMe(“foo”,11);
申请书.logMeToo(“foo”,11);
application.logMeToo();
}
public void doNotLogMe(@RequestBody String body,int number){}
public void doNotLogMeEither(){}
public void doNotLogMeEither(字符串体,整数){}
@Loggable public void logMe(@RequestBody String body,int number){}
@Loggable public void logMeToo(字符串体,整数){}
@Loggable public void logMeToo(){}
}
方面:

正如您所看到的,我使用的是区分上述三种情况的方法,同时也满足了您对一种常见助手方法的需求,我称之为
logIt(…)
。在那里,您可以放置所有想要使用的复杂日志记录内容,而不会在您的advice方法中有任何重复的代码

package de.scrum\u master.aspect;
导入org.aspectj.lang.ProceedingJoinPoint;
导入org.aspectj.lang.annotation.Around;
导入org.aspectj.lang.annotation.Aspect;
导入org.aspectj.lang.annotation.Pointcut;
@面貌
公共类MyAspect{
@切入点(“注释(de.scrum\u master.app.Loggable)”)
public void loggableAnnotation(){}
@周围(
“loggableAnnotation()&&”+
“执行(**)”
)
公共对象simpleProcessWithoutParameters(ProceedingJoinPoint joinPoint)抛出可丢弃的{
返回logIt(连接点,null);
}
@周围(
“loggableAnnotation()&”+
“执行(**(!@org.springframework.web.bind.annotation.RequestBody(*),…)”
)
公共对象simpleProcessWithParameters(ProceedingJoinPoint joinPoint)抛出可丢弃的{
返回logIt(连接点,null);
}
@周围(
“loggableAnnotation()&&”+
“执行(**(@org.springframework.web.bind.annotation.RequestBody(*),…)&”+
“args(正文,…)”
)
公共对象processWithBody(ProceedingJoinPoint joinPoint,Object body)抛出Throwable{
返回登录(连接点、主体);
}
私有对象logIt(ProceedingJoinPoint,objectbody)抛出Throwable{
System.out.println(连接点+“->”+主体);
返回joinPoint.procedure();
}
}
控制台日志:

execution(void de.scrum\u master.app.Application.logMe(String,int))->foo
执行(void de.scrum_master.app.Application.logMeToo(String,int))->null
执行(void de.scrum_master.app.Application.logMeToo())->null
注:
execution(**(@MyAnn*)
execution(**(@MyAnn(*))
之间的区别是微妙的,因此很棘手。不幸的是,它没有正确地记录在应该放在哪里。准确地说,后一种情况根本没有记录,仅