Spring Web利用切面统一处理参数校验异常的方法

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内部就可以专注于业务处理,参数验证异常的处理完全独立于切面中了。
  如有其它好的实现方式,欢迎讨论。 

你可能感兴趣的:(Java,Spring)