如果您查看spring如何解决传递给处理程序的参数,那么实现自己所需的功能并不难。默认情况下,spring将使用
ModelAttributeMethodProcessor带有
@ModelAttribute和简单类型注释的for参数。
只看ModelAttributeMethodProcessor.supportsParameter()
方法实现。
@Overridepublic boolean supportsParameter(MethodParameter parameter) { if (parameter.hasParameterAnnotation(ModelAttribute.class)) { return true; } else if (this.annotationNotRequired) { return !BeanUtils.isSimpleProperty(parameter.getParameterType()); } else { return false; }}ModelAttributeMethodProcessor如果
@Valid找到了注释,它还负责启动验证。它以一种有趣的方式执行此操作,以使代码无需
@Valid在类路径上即可进行编译。幸运的是,这很容易利用您的优势。
提取ModelAttributeMethodProcessor.validateIfApplicable() method.
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation annot : annotations) { if (annot.annotationType().getSimpleName().startsWith("Valid")) { Object hints = AnnotationUtils.getValue(annot); binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); break; } }}您可能已经注意到,它只是检查在参数开头是否存在注释,
"Valid"并告诉绑定程序验证其值。
编写自定义注释
首先要做的是编写一个新的注释,您的自定义
HandlerMethodArgumentResolver将支持该注释。
/@Target({ PARAMETER })@Retention(RUNTIME)public @interface ValidModifyingVerb {}请注意,注释的名称故意以开头"Valid"
。
推出自己的 HandlerMethodArgumentResolver
最简单的方法是扩展
ModelAttributeMethodProcessor和修改其行为。由于该
resolveArgument()方法是
最终 方法,因此无法覆盖它。我们可以做的是重写以下三种方法:
supportsParameter(final MethodParameter parameter)
:
告诉spring这个解析器支持参数用注释
@ValidModifyingVerb。
bindRequestParameters(final WebDataBinder binder, final NativeWebRequest request)
:
将是获得对请求的引用并查找其请求方法的理想人选。它还使您有机会在不需要时省略绑定参数。
validateIfApplicable(final WebDataBinder binder, final MethodParameter parameter)
:
使您有机会省略验证。如果您需要验证,由于您自己的注释开头
"Valid"很好,因此它将被自动提取。
实现以上内容将导致类似于此的类。
public class ValidModifyingVerbMethodArgumentResolver extends ModelAttributeMethodProcessor { private String requestMethod; public ValidModifyingVerbMethodArgumentResolver(final boolean annotationNotRequired) { super(annotationNotRequired); } @Override public boolean supportsParameter(final MethodParameter parameter) { return super.supportsParameter(parameter) && parameter.hasParameterAnnotation(ValidModifyingVerb.class); } @Override protected void bindRequestParameters(final WebDataBinder binder, final NativeWebRequest request) { HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class); requestMethod = servletRequest.getMethod(); if (isModifyingMethod(requestMethod)) { ((ServletRequestDataBinder) binder).bind(servletRequest); } } @Override protected void validateIfApplicable(final WebDataBinder binder, final MethodParameter parameter) { if (isModifyingMethod(requestMethod)) { super.validateIfApplicable(binder, parameter); } } private boolean isModifyingMethod(String method) { return !"GET".equals(method); }}剩下的唯一事情就是
ValidModifyingVerbMethodArgumentResolver在应用程序上下文配置中注册为参数解析器,然后就完成了。
public class ApplicationConfiguration extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new ValidModifyingVerbMethodArgumentResolver(true)); }}现在可以将控制器中的处理程序方法简化为:
@RequestMapping("/account/register")public String registerPost( @ValidModifyingVerb RegisterForm registerForm, BindingResult result, RedirectAttributes redirectAttributes) { //... ADD USER HERE IF !result.hasErrors() ... return "account/register";}


