使用Spring boot开发项目与前端人员对接接口时由于在调试,经常传来null、undefined、NaN等非法参数,于是利用spring 的自定义注解以及AOP实现简单的传入参数拦截。
一、使用方法
/**
* 登录
* 当参数是实体类时,通过 参数名.属性名 的方式注解参数
*/
@ArgsNotNull({"user.stuNo", "user.password"})
@PostMapping("login.do")
public ServerResponse login(User user) {
//To do Login
return ServerResponse.createBySuccess();
}
/**
* 通过userId查询
* 当参数是基本类时,通过 参数名 的方式注解参数
*/
@ArgsNotNull({"userId"})
@GetMapping("findByUserId.do")
public ServerResponse findByUserId(String userId) {
//To do findByUserId
return ServerResponse.createBySuccess();
}
二、构建方法
1、添加Spring AOP pom依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
2、自定义参数检查类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 检查参数注解
*
* @author chenyi
* Create on 2019/10/13
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ArgsNotNull {
/**
* 拦截字段
*/
String[] value() default {};
}
3.AOP类,拦截使用了@ArgsNotNull 注解的方法
/**
* 参数检验aop
*
* @author chenyi
* Create on 2019/10/13
*/
@Aspect
@Component
public class ArgsNotNullAop {
/**
* 检查参数是否为空
*/
@Around("@annotation(ArgsNotNull)")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//拦截的方法
Method method = methodSignature.getMethod();
//拦截的方法的注解
ArgsNotNull argsNotNull = method.getAnnotation(ArgsNotNull.class);
//拦截的参数名称
String[] parameters = methodSignature.getParameterNames();
// 拦截的参数值
Object[] args = joinPoint.getArgs();
//注解的参数
String[] needParams = argsNotNull.value();
if (doCheckParams(needParams, parameters, args)) {
return joinPoint.proceed();
}
return ServerResponse.createByWarningMsg("非法请求");
}
/**
* 检查注解当中的参数
*
* @param needParams 注解中的参数,需要检查的参数
* @param parameters 方法中传入的参数名称集合
* @param args 方法中传入的参数集合
*/
private Boolean doCheckParams(String[] needParams, String[] parameters, Object[] args) {
for (String needParam : needParams) {
if (needParam.contains(".") ? isWarpTypeNull(needParam, parameters, args) : isBasicTypeNull(needParam, parameters, args))
return false;
}
return true;
}
/**
* 检查基本类型参数
* true 参数不为空,通过
* false 参数为空,不通过
*
* @param param 需要检查的参数
* @param parameters 方法的参数名称集合
* @param args 方法的参数集合
*/
private Boolean isBasicTypeNull(String param, String[] parameters, Object[] args) {
int index = getParamIndex(param, parameters);
return index >= 0 && args[index] == null;
}
/**
* 检查非基本类型参数
* true 参数不为空,通过
* false 参数为空,不通过
*
* @param param 需要检查的参数
* @param parameters 方法的参数名称集合
* @param args 方法的参数集合
*/
private Boolean isWarpTypeNull(String param, String[] parameters, Object[] args) {
String[] split = param.split("\\.");
int index = getParamIndex(split[0], parameters);
if (index < 0)
return true;
//分解参数类型
Field[] declaredFields = args[index].getClass().getDeclaredFields();
try {
for (Field field : declaredFields) {
String fieldName = field.getName();//字段名称
if (fieldName.equals(split[1])) {
field.setAccessible(true);//获取private成员变量
return field.get(args[index]) == null;
}
}
} catch (IllegalAccessException e) {
return true;
}
return false;
}
/**
* 获取参数位置索引
*
* @param source 源参数
* @param parameters 方法参数列表
*/
private Integer getParamIndex(String source, String[] parameters) {
for (int i = 0; i < parameters.length; i++) {
if (source.equals(parameters[i]))
return i;
}
return -1;
}
}
搞定收工.