使用AOP对Spring @Valid的校验结果做统一处理

@ResponseBody
@RequestMapping(value = "add", method = RequestMethod.POST)
public ResponseModel add(@Valid User user, BindingResult br, HttpServletResponse response) {
		
    if(br.hasErrors()) {
        //将所有的校验错误封装成一个带<br>换行的字符串返回给前端页面进行展示。
        return ResponseModel.validFail(getErrorsSplitNewLine(br));
    }
    accountService.addUser(user);
    return ResponseModel.success("保存用户成功");
}

如上面代码所示,我们一般做表单提交数据校验的时候一般使用@Valid对 Bean对象进行校验,而要使用@Valid对对象进行校验需要引入实现JSR303标准的HibernateValidator实现,如下所示:

<!-- JSR303 Validator定义 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">  
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>  
    <!-- 如果不加下面配置, 默认使用classpath下的 ValidationMessages.properties -->  
    <property name="validationMessageSource" ref="messageSource"/>  
</bean>

而上例中add方法的 BindingResult参数对象会绑定校验的结果。所以要求BindingResult对象参数要紧跟在@Valid的对象参数后面,然后代码中通过判定是否存在校验错误。而代码中通过判断是否存在校验错误,来决定是调回表单页进行重新录入还是继续执行业务逻辑。如上例所示,通过if...else...来判断,

if(br.hasErrors()) {

} else {

}

所以这种代码逻辑就散布在很多Controller里面,丑陋无比。所以本文就使用aop方式来解决这个问题。


@Aspect
public class ParamValidAspect {
@Around("execution(* com.hebao.tech.adm.web.controller.*.*(..)) && args(..,bindingResult)")
    public Object validateParam(ProceedingJoinPoint pjp, BindingResult bindingResult) throws Throwable {
        Object retVal;
        logger.debug("进入AOP-ParamValidAspect-validateParam进行参数有效性校验....");
        if (bindingResult.hasErrors()) {
            String errorInfo = getErrorsSplitNewLine(bindingResult);
            logger.info("AOP-ParamValidAspect-validateParam进行参数校验出错, 出错信息如下:{}", errorInfo);
      
            retVal = ResponseModel.validFail(errorInfo);
        } else {
            //执行目标方法
            retVal = pjp.proceed();
        }
        return retVal;
    }
        /*
	 * 此校验错误信息转化为字符,多个错误信息通过参数[splitChars]进行分隔
	 */
	private String getErrors(BindingResult br, String splitChars) {
		if(splitChars == null) {
			splitChars = "";
		}
		StringBuilder result = new StringBuilder();
		List<ObjectError> errors = br.getAllErrors();
		for (ObjectError vError : errors) {
			result.append(vError.getDefaultMessage());
			result.append(splitChars);
		}
		if(result.length() > 0) {
			result.delete(result.length() - splitChars.length(), result.length());
		}
		return result.toString();
	}
	
	/*
	 * 此校验错误信息转化为字符,多个错误信息通过<br>进行分隔
	 */
	private String getErrorsSplitNewLine(BindingResult br) {
		return getErrors(br, "<br>");
	}
}

@Around("execution(* com.hebao.tech.adm.web.controller.*.*(..)) && args(..,bindingResult)")

使用切点符合运算,表示切入 ...controller的包以及子包,并且方法的最后一个参数为bindingResult,并将实例直接传递给validateParam方法。


并在SpringMVC中加入如下配置:

扫描二维码关注公众号,回复: 3268325 查看本文章
<!--  true表示使用cglib代理技术,false表示使用jdk代理技术 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="paramValidAspect" class="com.hebao.tech.adm.framework.spring.aop.ParamValidAspect"/>


不使用@Component,的原因已经在上一篇博客文章中说过了:

Spring与SpringMVC是2个不同的父子容器, @Aspect如果被spring容器加载的话,而@Controller注解的这些类的实例化以及注入却是由SpringMVC来完成。 @Aspect如果被spring容器加载的时候,可能Spring MVC容器还未初始化, Controller类还未初始化,所以无法正常织入。。

猜你喜欢

转载自blog.csdn.net/oKuZuoZhou/article/details/81024795