一. 概述
在开发后端接口, 通常都会涉及检验参数必填校验, 一般我们的处理都是很粗暴的写个
if()
判断, 然后抛异常. 本文将介绍通过代理的思想, 用注解优雅的处理非空判断
二. 实现过程
最终想要的效果->在方法的
参数
加个注解
或者参数的属性
里加个注解
, 注解可以自定义报错信息, 就可以实现自动非空校验
2.1 编写注解
@Target({ElementType.FIELD,ElementType.PARAMETER}) //作用的位置
@Retention(RetentionPolicy.RUNTIME) //作用域
@Documented
public @interface NotNull {
String value() default "{报错信息}";
}
说明: 该注解用来绑定某个必填属性
@Target({ElementType.TYPE,ElementType.METHOD}) //作用的位置
@Retention(RetentionPolicy.RUNTIME) //作用域
@Documented
public @interface CheckParam {
}
说明: 该注解用来绑定某个类或某个方法,作为校验代理拦截的标识
2.2 编写校验代理AOP
@Aspect
@Slf4j
public class CheckParamAop {
@Around("@within(com.midea.cloud.common.annotation.CheckParam) || @annotation(com.midea.cloud.common.annotation.CheckParam)")
public Object cacheClear(ProceedingJoinPoint pjp) throws Throwable {
try {
MethodSignature signature = (MethodSignature) pjp.getSignature();
// 方法参数注解类型
Annotation[][] parameterAnnotations = signature.getMethod().getParameterAnnotations();
// 方法参数的类型
Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
// 获取方法参数
Object[] args = pjp.getArgs();
if(!ObjectUtils.isEmpty(args)){
// 遍历参数
AtomicInteger index = new AtomicInteger(0);
Arrays.stream(args).forEach(o -> {
int indexNo = index.getAndAdd(1);
/**
* 检查方法参数非空
*/
Annotation[] parameterAnnotation = parameterAnnotations[indexNo];
if(!ObjectUtils.isEmpty(parameterAnnotation)){
Arrays.stream(parameterAnnotation).forEach(annotation -> {
if(annotation instanceof NotNull){
NotNull notNull = (NotNull)annotation;
// 注解信息
String message = notNull.value();
// 通过工具类获取多语言信息
String localeMsg = LocaleHandler.getLocaleMsg(message);
// 检查参数非空
Optional.ofNullable(o).
filter(o1 -> !ObjectUtils.isEmpty(o1)).
orElseThrow(()->new BaseException(localeMsg));
}
});
}
/**
* 检查方法参数属性非空
*/
Class<?> parameterType = parameterTypes[indexNo];
Field[] fields = parameterType.getDeclaredFields();
if(!ObjectUtils.isEmpty(fields)){
// 遍历属性
Arrays.stream(fields).forEach(field -> {
NotNull annotation = field.getAnnotation(NotNull.class);
if(null != annotation){
Object value = null;
// 注解信息
String message = annotation.value();
// 通过工具类获取多语言信息
String localeMsg = LocaleHandler.getLocaleMsg(message);
Optional.ofNullable(o).orElseThrow(()->new BaseException(localeMsg));
try {
field.setAccessible(true);
value = field.get(o);
} catch (Exception e) {
log.error("获取属性值报错"+e.getMessage());
log.error("获取属性值报错"+e);
}
// value为空时报错
Optional.ofNullable(value).
filter(o1 -> !ObjectUtils.isEmpty(o1)).
orElseThrow(()->new BaseException(localeMsg));
}
});
}
});
}
} catch (BaseException e) {
throw e;
} catch (Exception e){
log.error("检查参数aop报错:"+e.getMessage());
log.error("检查参数aop报错:"+e);
}
return pjp.proceed();
}
}
三. 使用示例
public class Test{
@Data
class Demo{
@NotNull("名字不能为空!")
private String name;
private String sex;
private Integer age;
}
@CheckParam
public void testNoNullCheck1(Demo demo) {
}
@CheckParam
public void testNoNullCheck2(@NotNull("user不能为空") User user) {
}
}
网友评论