Spring的AOP方式有很多用途,本次记录其使用AOP的方式处理Controller层参数校验问题
思路
- 使用 Hibernate validator 注解式参数校验
- 利用AOP织入Controller层方法,在参数校验完成后检查BindingResult里的校验结果
代码
- AOP类
package com.zp.haveplace.aop;
import com.zp.haveplace.bean.ResponseBean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import java.util.List;
/**
* 在类上使用 @Aspect 注解 使之成为切面类
* 在类上使用 @Component 注解 把切面类加入到IOC容器中
* 采用AOP的方式处理参数问题。(注解方式AOP)
* @author yingjun
*/
@Component
@Aspect
public class BindingResultAop {
/**
* 切入点
* 设置切入点为web层
* AspectJ支持命名切入点,方法必须是返回void类型
* 详见:http://jinnianshilongnian.iteye.com/blog/1415606
* https://blog.csdn.net/Josn_Hao/article/details/72861516
*/
@Pointcut("execution(* com.zp.haveplace.web..*.*(..))")
public void aopMethod(){}
/**
* 检查 Controller 方法的参数是否合法
* 环绕通知:目标方法执行前后分别执行一些代码,发生异常的时候执行另外一些代码
* 参考:https://blog.csdn.net/zcw4237256/article/details/79098342
* https://www.cnblogs.com/afeng7882999/p/4300032.html 校验
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("aopMethod()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
BindingResult bindingResult = null;
for(Object arg:joinPoint.getArgs()){//遍历被通知方法(controller方法)的参数列表
if(arg instanceof BindingResult){//参数校验结果会存放在BindingResult中
bindingResult = (BindingResult) arg;
}
}
if(bindingResult != null){
if(bindingResult.hasErrors()){//检查是否存在校验错误
String errorInfo = "";
List<FieldError> errors = bindingResult.getFieldErrors();//获取字段参数不合法的错误集合
for(FieldError error : errors){
errorInfo = errorInfo + "[" + error.getField() + " " + error.getDefaultMessage() + "]";
}
return new ResponseBean().setExceptionResponse(errorInfo);//返回异常错误
}
}
return joinPoint.proceed();//执行目标方法
}
}
- 配置
spring配置文件中需要加入包扫描和AOP注解支持
<!-- 激活组件扫描功能,扫描aop的相关组件组件 -->
<context:component-scan base-package="com.zp.haveplace.aop"/>
<!-- 启动对@AspectJ注解的支持 会自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
- Controller层使用
@RequestMapping(value = "/issue/exp/delete",method = RequestMethod.POST)
@ResponseBody //包装返回JSON
public ResponseBean deleteActingExp(@Validated(value = {UpdateValidatorGroup.class})ShowExperience showExperience,
BindingResult bindingResult,
HttpServletRequest request)throws Exception{
// showExperience 是需要进行参数校验的类
//.....业务逻辑
return new ResponseBean().setSuccessResponse();
}