我们经常注解使用对controller传过来的参数进行判空校验,但使用注解校验的话常常会遇到controller层方法接收的必须是一个对象(实体类),而我们要校验并使用的值只有一个或几个,这样就会导致判空会出现校验不灵活的问题,只适合表单提交校验比较合适,但对一个参数或几个参数字段校验就不行了。那么我们可以使用AOP机制完美解决cotroller层中参数进行校验问题。
1.在springmvc.xml配置文件中扫描aop存放aspect的相关类
<context:component-scan base-package="com.awaymeet.fly.platform.aspect"/>
<!--启动AspectJ支持-->
<aop:aspectj-autoproxy proxy-target-class="true" />
2.创建aspect包和VerificationAspect.java类(用于拦截参数校验)
package com.awaymeet.fly.platform.aspect;
import com.awaymeet.fly.platform.exception.bean.Nullable;
import com.awaymeet.fly.platform.exception.bean.ParameterException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
/**
* 处理数据校验,配合 自定义注解
* 默认所有参数为空,若可以为空则在 参数前 加注解,其他校验未写
*/
@Aspect
@Component
public class VerificationAspect {
/**
* 声明切面 应用在,所有 Controller下的, 以Controller结尾的类中的,所有 public 方法
*/
@Pointcut("execution(public * com.awaymeet.fly.platform.controller.*.*(..))")
public void joinPointInAllController() {
}
/**
* 切入点执行前方法
*
* @param point 切入点
*/
@Before("joinPointInAllController()")
public void checkParameter( JoinPoint point) throws Exception {
String[] paramNames = ((CodeSignature) point.getSignature()).getParameterNames(); //key
Object[] args = point.getArgs();//value
// 获得切入的方法
Method method = ((MethodSignature) point.getSignature()).getMethod();
// 获得所有参数
Parameter[] parameters = method.getParameters();
// 保存需要校验的args
Map<Object,Object> map = new HashMap<Object,Object>();
// 对没有Nullable注解的参数进行非空校验
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String name = parameter.getName();
Annotation[] annotations = parameter.getDeclaredAnnotationsByType(Nullable.class);
if (annotations.length < 1) {
if(StringUtils.isEmpty(args[i])){
map.put(paramNames[i],"");
}else{
map.put(paramNames[i],args[i]);
}
}
}
for (Object o : map.keySet()) {
if (StringUtils.isEmpty(map.get(o))) {
String name = "" ;
if(o instanceof String){
name = (String)o ;
}else{
name = o.getClass().getName();
}
//字段名+参数为空!
throw new ParameterException(name +"参数为空!");
}
}
}
}
自定义异常类ParameterException。如果遍历的参数为空则抛出自定义异常,抛出的异常统一在@ControllerAdvice注解类进行异常捕捉。
3.自定义参数可以为空的注解Nullable.java(在controller层的参数前添加该注解表示:该参数可为空)
package com.awaymeet.fly.platform.exception.bean;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.PARAMETER;
/**
* 数据校验 | 可空
* 加在 Controller 的函数 的 参数 前面,本注解代表可空, 其他未写
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({PARAMETER})
public @interface Nullable {
}
自定义异常类ParameterException.java
package com.awaymeet.fly.platform.exception.bean;
public class ParameterException extends Exception {
public ParameterException(Exception e) {
super(e);
}
public ParameterException(String message) {
super(message);
}
}
4.使用@ControllerAdvice注解创建统一异常处理类GlobalExceptionHandler.java
package com.awaymeet.fly.platform.exception;
import com.awaymeet.fly.common.pojo.APPFinalConfig;
import com.awaymeet.fly.common.pojo.JResult;
import com.awaymeet.fly.common.utils.JsonUtils;
import com.awaymeet.fly.platform.exception.bean.InternalAPIServiceException;
import com.awaymeet.fly.platform.exception.bean.UserException;
import org.apache.log4j.Logger;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.lang.reflect.UndeclaredThrowableException;
/**
* @Title: exceptionHandle
* @Description: 默认异常处理
* @author lc
* @param ex
* @return JResult 返回类型
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public JResult exceptionHandle( Exception ex)
throws IOException {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
result.setDescription("系统出现异常");
return result ;
}
/**
* @Description: 对象参数异常处理
* @author lc
* @param ex
* @throws
* @return JResult 返回类型
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public JResult bindException(BindException ex) {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
StringBuilder msg = new StringBuilder() ;
BindException exception = (BindException)ex ;
for (FieldError error : exception.getBindingResult().getFieldErrors()) {
/*msg.append("参数");
msg.append(error.getField());
msg.append("=");
msg.append(error.getRejectedValue());
msg.append(",说明:");*/
msg.append(error.getDefaultMessage());
}
result.setDescription(msg.toString());
return result ;
}
/**
* @Title: exceptionHandle
* @Description: 单个或几个参数异常处理
* @author lc
* @param ex
* @throws IOException
* @return JResult 返回类型
*/
@ExceptionHandler(UndeclaredThrowableException.class)
@ResponseBody
public JResult parameterException(UndeclaredThrowableException ex)
throws IOException {
log.error(APPFinalConfig.ERROR, ex);
JResult result = new JResult();
result.setErrorCode(APPFinalConfig.ERROR);
result.setState("-1001");
result.setDescription(ex.getCause().getMessage());
return result ;
}
}
5.controller层请求的相应方法体
@RequestMapping("/select")
@ResponseBody
public JResult select(long id ,String inspectionName ){
return auditAndRagistService.select(id);
}
最后运行项目,发送请求!