Java @RequestMapping MethodInterceptor方面忽略@Validated注释

Java @RequestMapping MethodInterceptor方面忽略@Validated注释,java,spring,validation,interceptor,aspect,Java,Spring,Validation,Interceptor,Aspect,我对MethodInterceptor方面和@Validated注释有一个奇怪的问题。当我添加方法拦截器来截取用@RequestMapping注释的所有方法时,@Validated注释不起作用。当我移除它时,它又可以正常工作了。我想,我的拦截器会覆盖@Validated。有没有什么方法可以做到这一点,因为我不想在我的拦截器中执行验证,因为它是用来审计东西的 以下是验证程序: @Component public class UserValidator implements Validator {

我对
MethodInterceptor
方面和
@Validated
注释有一个奇怪的问题。当我添加方法拦截器来截取用
@RequestMapping
注释的所有方法时,
@Validated
注释不起作用。当我移除它时,它又可以正常工作了。我想,我的拦截器会覆盖
@Validated
。有没有什么方法可以做到这一点,因为我不想在我的拦截器中执行验证,因为它是用来审计东西的

以下是验证程序:

@Component
public class UserValidator implements Validator {

@Override
public void validate(Object target, Errors errors) {
          //validation stuff
      }
}
控制器的代码:

@Controller
@RequestMapping("/profile")
public class UserProfileController {

    @Autowired
    private UserValidator userValidator;

    @InitBinder("userValidator")
    private void userValidatorInitBinder(WebDataBinder binder) {
        binder.setValidator(userValidator);
    }

    @RequestMapping(value = "/reg.do", method = RequestMethod.POST)
    public @ResponseBody RegisterResponse reg(HttpServletRequest httpServletRequest, @RequestBody @Validated CreateUserRequest createUserRequest) {
    }
}
拦截器代码:

@Aspect
@Component
public class MyInterceptor implements MethodInterceptor, Serializable {

    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        Object returnValue = null;
        final StopWatch stopWatch = new StopWatch();
        try {
           stopWatch.start();
           returnValue = invocation.proceed();
           return returnValue;
       } catch (Throwable ex) {
           stopStopwatch(stopWatch);
           throw ex;
       } finally {
           System.out.println(stopwatch);
}
    }
}

我的环境是带有rest控制器(Jackson Mapper)的Spring MVC(3.2)。

您应该检查Spring上下文和POM中的以下元素:

  • 说明您应该配置
    MethodValidationPostProcessor
  • 方法验证后处理器
    ,与Hibernate类似。因此,应该配置依赖项。这应该起作用:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.0.1.Final</version>
    </dependency>
    
    
    javax.validation
    验证api
    1.1.0.1最终版本
    org.hibernate
    休眠验证器
    5.0.1.最终版本
    

    • 问题在于使用了基于代理的AOP,在这种情况下,由于没有接口,它是基于类的代理。由于
      @RequestBody
      @Validated
      方法不是继承的,因此它们不存在于重写该方法的子类中。因此,不再有
      @验证的

      要解决这个问题,有(在这种情况下)两种解决方案

    • 一个
      HandlerInterceptor
      而不是AOP
    • 侦听
      ServletRequestHandledEvent
      s的
      ApplicationListener
    • 向所有控制器添加一个界面,该界面也包含注释
    • 使用加载时或编译时编织,而不是基于代理的AOP
    • 因为这只是一个性能测量,所以使用选项1和2非常容易。选项3可能非常具有侵入性,选项4取决于所使用的servlet容器

      使用
      HandlerInterceptor
      但是,由于这只是一个性能度量,适用于处理程序而不是AOP,我建议使用
      HandlerInterceptor
      ,它将在
      preHandle
      方法中开始计时,并在
      afterCompletion
      方法中结束计时

      public class PerformanceMeasureInterceptor extends HandlerInterceptorAdapter {
      
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              StopWatch sw = new StopWatch();
              sw.start();
              request.setAttribute("performance-measure-sw", sw);
              return true;
          }   
      
          public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
              StopWatch sw = (StopWatch) request.getAttribute("performance-measure-sw");
              if (sw != null) {
                  sw.stop();
                  System.out.println(sw);
              }           
          }
      }
      
      使用
      ApplicationListener
      由于已监视处理请求所需的时间,并且在处理请求后将触发一个包含处理所需时间的。您可以创建侦听事件并将一行写入日志文件(或控制台)的


      您可能希望检查spring已经提供的spring性能拦截器,而不是自己滚动。您可能希望使用的子类之一,而不是您自己的。(虽然这不能帮助您解决代理问题,但它可以帮助您维护自己的性能拦截器)。

      您的方面会导致实际控制器的代理。此代理在检测实际注释时可能有问题。还有为什么
      UserValidator
      也是绑定中使用的对象!!!还发布拦截器的代码。@M.Deinum“UserValidator”是一个单例实例,我在活页夹中注册它,因为我有多动作控制器,所以我有多个验证器,拦截器中的代码只计算请求和“return invocation.procedure();”的时间请阅读我的评论。。。您正在将验证器用作模型对象。。。此
      @RequestBody@validateduservalidator UserValidator
      是方法签名的一部分。。。我非常怀疑传入的请求是否会变成
      UserValidator
      它可能更像
      用户
      。。。如前所述,添加方面的imlpementation..。@M.Deinum是的,我注意到并更新了线程,但这不是问题,实际代码使用CreateUserRequest(上面更新)时没有任何注释。再次请求请为您的方面添加代码。。。当你混合AspectJ风格和aopalliance风格时,这看起来很奇怪。选择一个不要混合。它在没有任何额外配置的情况下运行良好,每当我删除拦截器时,它就会再次正常工作,而且我没有使用hibernate验证注释,我使用的是spring验证程序,它不需要上述2个JAR。我昨天已经做了,但仍然不工作,关于Handler拦截器,我知道,但拦截器的范围超出了时间跟踪,它正在审核每个请求和响应(JSON),因此方法参数已经绑定,我知道HandlerInterceptor可以这样做,但需要额外的代码。我会选择普通的过滤器,谢谢:)根据您的需要(如果只是记录),Spring有
      AbstractRequestLoggingFilter
      ,如果配置正确,它会记录请求,包括有效负载等。正如我所说的,由于子类化,代理方法会遇到问题。
      @Component
      public class PerformanceListener implements ApplicationListener<ServletRequestHandledEvent> {
      
          public void onApplicationEvent(ServletRequestHandledEvent event) {
              System.out.println("Processing: " + event.getRequestUrl() + ", took: " + event.getProcessingTimeMillis + "ms. ");
          }
      }
      
      @Aspect
      @Component
      public class MyInterceptor {
      
          @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
          public Object invoke(ProceedingJoinPoint pjp) throws Throwable {
      
              Object returnValue = null;
              final StopWatch stopWatch = new StopWatch();
              try {
                 stopWatch.start();
                 returnValue = pjp.proceed();
                 return returnValue;
             } catch (Throwable ex) {
                 throw ex;
             } finally {
                 stopStopwatch(stopWatch);
                 System.out.println(stopwatch);
              }
          }
      }