Kin*_*cka 2 java spring jsp spring-mvc bean-validation
我有一个表单处理Spring MVC控制器,带有JSR-303 bean验证@Valid.
整个处理GET程序的唯一目的是(几乎)相同POST,但省略@Valid注释以防止在提交表单之前<form:errors ...>在第一个用户GET请求中显示JSP中的错误.
我的问题是:
GET以干净的方式删除冗余方法?POST只做一个@Valid?这是我的示例代码:
@RequestMapping( value = "/account/register" , method = RequestMethod.GET )
public String registerGet( @ModelAttribute( "registerForm" ) RegisterForm registerForm ) {
return "account/register";
}
@RequestMapping( value = "/account/register" , method = RequestMethod.POST )
public String registerPost( @ModelAttribute( "registerForm" ) @Valid RegisterForm registerForm ,
BindingResult result ,
RedirectAttributes redirectAttributes ) {
... ADD USER HERE IF !result.hasErrors() ...
return "account/register";
}
Run Code Online (Sandbox Code Playgroud)
如果看看spring如何解析传递给处理程序的参数,那么实现自己完全正如你想要的那样并不是很困难.默认情况下,spring将使用ModelAttributeMethodProcessor带有注释的for参数@ModelAttribute和简单类型.
只需看看ModelAttributeMethodProcessor.supportsParameter()方法实现.
/**
* @return true if the parameter is annotated with {@link ModelAttribute}
* or in default resolution mode also if it is not a simple type.
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
return true;
}
else if (this.annotationNotRequired) {
return !BeanUtils.isSimpleProperty(parameter.getParameterType());
}
else {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
ModelAttributeMethodProcessor如果@Valid找到注释,还负责验证.它以一种有趣的方式实现这一点,使代码编译而不@Valid在类路径上.幸运的是,这使您可以轻松利用自己的优势.
提取 ModelAttributeMethodProcessor.validateIfApplicable() method.
/**
* Validate the model attribute if applicable.
* <p>The default implementation checks for {@code @javax.validation.Valid}.
* @param binder the DataBinder to be used
* @param parameter the method parameter
*/
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您可能已经注意到的那样,它只是检查参数上是否存在注释,并指示"Valid"绑定器验证它的值.
首先要做的是编写一个自定义HandlerMethodArgumentResolver将支持的新注释.
//** Validates only when the request method is a modifying verb e.g. POST/PUT/PATCH/DELETE */
@Target({ PARAMETER })
@Retention(RUNTIME)
public @interface ValidModifyingVerb {}
Run Code Online (Sandbox Code Playgroud)
请注意,注释的名称是故意以"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;
/**
* @param annotationNotRequired if "true", non-simple method arguments and
* return values are considered model attributes with or without a
* {@code @ModelAttribute} annotation.
*/
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);
}
}
Run Code Online (Sandbox Code Playgroud)
剩下的唯一事情就是ValidModifyingVerbMethodArgumentResolver在应用程序上下文配置中注册为参数解析器,然后就完成了.
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new ValidModifyingVerbMethodArgumentResolver(true));
}
}
Run Code Online (Sandbox Code Playgroud)
控制器中的处理程序方法现在可以简化为:
@RequestMapping("/account/register")
public String registerPost(
@ValidModifyingVerb RegisterForm registerForm,
BindingResult result,
RedirectAttributes redirectAttributes) {
//... ADD USER HERE IF !result.hasErrors() ...
return "account/register";
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1269 次 |
| 最近记录: |