Spring Web利用切面统一处理参数校验异常的方法
关于spring web的参数校验,其过程是通过org.springframework.validation.DataBinder
,调用org.springframework.validation.Validator
下的validate(Object target, Errors errors)
方法。该Validator的实例为org.springframework.validation.beanvalidation.SpringValidatorAdapter
。该类内部绑定了javax.validation.Validator
的一个实例,一般为org.hibernate.validator.internal.engine.ValidatorImpl
。最终整个校验结果被存储在org.springframework.validation.BindingResult
的实例中。
Controller中关于bindingResult的用法,官网上有一个入门示例.
其中关于参数校验异常的处理是
if (bindingResult.hasErrors()) {
return "form";
}
return "redirect:/results";
这就受不了了,难道要在每一个带有@Valid
的@RequestMapping
都这么if…else…一下?好丑…
怎么解决呢?这个时候就需要强大的AOP(切面)了。切面的概念和Spring集成AOP的方法就不在这里介绍了,请读者自行补充。
那首先来简化官网示例的模型。
- 需要验证的类为Info:
public class Info{
@NotBlank(message="输入信息不能为空")
private String s;
}
- Web Controller为:
@Controller
public class WebController{
@RequestMapping(value="/", method=RequestMethod.POST)
public Response checkPersonInfo(@Valid Info info, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return doErrorHandle();
}
return doNormalHandle();
}
}
好了,开始加入切面方法吧!
- 切面的实现为:
@Aspect
@Component
public class ControllerValidatorInterceptor {
@Around("execution(* com.aerexu.web.*.*(..)) && args(..,bindingResult)")
public Object doAround(ProceedingJoinPoint pjp, BindingResult bindingResult) throws Throwable {
Object retVal;
if (bindingResult.hasErrors()) {
retVal = doErrorHandle();
} else {
retVal = pjp.proceed();
}
return retVal;
}
}
- 对应的Web Controller可以简化为:
@Controller
public class WebController{
@RequestMapping(value="/", method=RequestMethod.POST)
public Response checkPersonInfo(@Valid Info info, BindingResult bindingResult) {
return doNormalHandle();
}
}
其中,execution(* com.aerexu.web.*.*(..))
限定了切面只会尝试切com.aerexu.web包中的方法,args(..,bindingResult)
则限定了方法的最后一个参数是BindingResult
类型且引用会传递给doAround(ProceedingJoinPoint pjp, BindingResult bindingResult)
的bindingResult
。
当bindingResult
含有错误时,则执行doErrorHandle()
并返回结果,controller中的方法doNormalHandle()
并不会被执行。
利用这种方式,Controller内部就可以专注于业务处理,参数验证异常的处理完全独立于切面中了。
如有其它好的实现方式,欢迎讨论。