gpt4 book ai didi

java - @RequestMapping MethodInterceptor 方面忽略 @Validated 注释

转载 作者:行者123 更新时间:2023-12-01 12:31:59 25 4
gpt4 key购买 nike

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

这是 validator :

@Component
public class UserValidator implements Validator {

@Override
public void validate(Object target, Errors errors) {
//validation stuff
}
}

Controller 的代码:

@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);
}
}
}

我的环境是带有休息 Controller (Jackson Mapper)的 Spring MVC (3.2)。

最佳答案

问题是使用基于代理的 AOP,在本例中,由于不存在接口(interface),它是基于类的代理。作为@RequestBody@Validated方法不是继承的,它们不存在于重写该方法的子类中。因此不再有@Validated .

为了解决这个问题,(对于这种情况)有几个解决方案。

  1. 一个HandlerInterceptor而不是 AOP
  2. ApplicationListener它听 ServletRequestHandledEvent s
  3. 向所有 Controller 添加一个接口(interface),其中也包含注释
  4. 使用加载时或编译时编织而不是基于代理的 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<ServletRequestHandlerEvent>

作为 DispatcherServlet 已经监视处理请求所需的时间,并在处理请求后触发 ServletRequestHandledEvent 其中包含处理所花费的时间。您可以创建一个 ApplicationListener 它监听事件并将一行写入日志文件(或控制台)。

@Component
public class PerformanceListener implements ApplicationListener<ServletRequestHandledEvent> {

public void onApplicationEvent(ServletRequestHandledEvent event) {
System.out.println("Processing: " + event.getRequestUrl() + ", took: " + event.getProcessingTimeMillis + "ms. ");
}
}

使用加载时编织

当使用加载时编织时,类的字节码会在类加载后立即修改,因此无需为该类创建代理。这允许 @Validated仍然继续工作。

根据所使用的 servlet 容器,它可能就像替换 <aop:aspectj-autoproxy /> 一样简单或@EnableAspectJAutoProxy<context:load-time-weaving />@EnableLoadTimeWeaving 。对于其他容器,需要设置 javaagent 以允许发生加载时编织。欲了解更多信息,请查看reference guide

使用编译时编织

使用编译时编织时,类的字节码会在项目的编译阶段进行修改。这需要修改您的编译和 ajc 的使用(AspectJ 编译器)。这可能很难工作,您可能需要检查 Compile time weaving for DI in non-spring managed classes了解更多相关信息。

注意

你的 Aspect 很奇怪,因为它混合了 2 种不同风格的 AOP。首先它使用 AspectJ,其次它尝试成为 aopalliance MethodInterceptor 。尽量不要混合使用方法,因为这可能会导致奇怪的问题。

我建议坚持使用 AspectJ,所以尝试修改你的 Aspect,你可能还想添加 stopStopWatch方法到finally而不是仅到catch block 。

@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);
}
}
}

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

关于java - @RequestMapping MethodInterceptor 方面忽略 @Validated 注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25863782/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com