自定义注解对接口传入参数进行空判断
**前言:**> 本来项目是Springboot的,用的是 validation 对接口传入的参数进行判空处理,自己测试没得问题(测试服务器上也没得问题),但是技术经理最后需要打成war包(springboot多为jar包)部署到Tomcat上,但是发现打包为war包之后validation就突然失效了,略微查找之后没得找到问题根源,当时由于时间紧张,@RequestParam不能满足需求,就自己写了自定义的注解通过切面暂时实现,感觉挺有意思,就记录一下:直接上代码
#### 一. 判断入参不为空的注解
##### 1.1 : 定义注解 StringNullRegex (名字自己随意取)
import java.lang.annotation.*;
/**
* @Description 判断接口入参不能为空的自定义注解
* @AuThor 江
*/
@Target(ElementType.METHOD) // 作用于方法
@Retention(RetentionPolicy.RUNTIME)
public @interface StringNullRegex {
}
##### 1.2 : 注解功能实现 StringNullRegexAspect
```java
import com.example.waitdemo.utils.HttpResult;
import com.example.waitdemo.utils.StringNullUtil;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
/**
* @Description StringNullRegex注解的实现
* @ClassName StringNullRegexAspect
*/
@Aspect // 切面
@Component// 表示这是一个bean,由Spring进行管理 或者说输入spring
public class StringNullRegexAspect {
// 配置织入点 @annotation 为自定义的注解的位置(路径)
@Pointcut("@annotation(com.example.waitdemo.config.StringNullRegex)")
public void annotationPointcut() {
}
/**
*
*/
@Around("annotationPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
// 通过方法获取参数及其内容的 map
Map<String, String> parameter = getParameter(method, joinPoint.getArgs());
// 对参数进行判空处理
for (String key : parameter.keySet()) {
if (StringNullUtil.isEmpty(parameter.get(key))){
return HttpResult.newError(key + "参数不能为空!");
}
}
return joinPoint.proceed();
}
// 获取参数及对应数据
private Map<String, String> getParameter(Method method, Object[] args) {
Map<String, String> argList = newHashMap<>();
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
argList.put(parameters.getName(), String.valueOf(args));
}
if (argList.size() == 0) {
return null;
} else if (argList.size() == 1) {
return argList;
} else {
return argList;
}
}
}
```
#### 二. 判断入参为对象 不为空的注解
##### 2.1 : 定义注解 NotNotNull (名字自己随意取,这里是为了和 NotNull 区分开)
```java
/**
* @Description 配合 ClassNotNull 进行实体类验证
* 作用于实体类的字段上边
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) // 作用于字段
public @interface NotNotNull {
Stringmessage() default "";
}
```
##### 2.2 : 定义注解 ClassNotNull
```
/**
* @Description 配合 NotNotNull 实体类验证
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassNotNull {
}
```
##### 2.3 : 注解功能实现 ClassNotNull
```java
import com.example.waitdemo.utils.HttpResult;
import com.example.waitdemo.utils.StringNullUtil;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @Description
* @ClassName ClassNotNullAspect
*/
@Aspect // 切面
@Component// 表示这是一个bean,由Spring进行管理 或者说输入spring
public class ClassNotNullAspect {
// 配置织入点
@Pointcut("@annotation(com.example.waitdemo.config.ClassNotNull)")
public void ClassNotNullPointcut() {
}
@Around("ClassNotNullPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
//System.out.println("---------");
Object arg = joinPoint.getArgs();
Parameter[] parameters = method.getParameters();
//获取class对象
Class<?> aClass = parameters.getType();
//获取当前对象所有属性使用带Declared的方法可访问private属性
Field[] declaredFields = aClass.getDeclaredFields();
for(Field field:declaredFields){
//开启访问权限
field.setAccessible(true);
//使用此方法 field.get(Object obj) 可以获取当前对象这个列的值
Object o = field.get(arg);
Annotation annotation = field.getDeclaredAnnotation(NotNotNull.class);
//如果没有设置当前注解 不用校验
if(annotation == null){
continue;
}
//如果设置了当前注解,但是没有值,抛出异常
if(StringNullUtil.isEmpty(String.valueOf(o))){
//获取注解接口对象
NotNotNull notNull = (NotNotNull)annotation;
if(StringNullUtil.isNotEmpty(notNull.message())){
System.out.println("notNull.message() = " + notNull.message());
//设置了注解message值 直接返回
// 这里又两种返回方法 ,
// 1: 通过自定义错误,然后进行全局拦截
//throw new ClassNotNullException(notNull.message());
// 2: 自己包装的返回参数 (通过枚举等)
return HttpResult.newError(notNull.message());
}else{
System.out.println("field.getName() = " + field.getName()+" is null");
//没有设置可以拼接
//throw new ClassNotNullException(field.getName()+" is null");
return HttpResult.newError(field.getName()+" is null");
}
}
}
return joinPoint.proceed();
}
}
```
**自定义的注解已经完成,准备使用**
##### 三. 定义用户类:
**自定义注解 NotNotNull的使用位置**
```java
import com.example.waitdemo.config.NotNotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* TODO
*
* @ClassName User
* @Author
* @Date
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
public class UserProperty {
@NotNotNull(message = "名字不能为空!")
private String name;
private Integer age;
@NotNotNull(message = "qq is null")
private Integer qq;
}
```
##### 四. controller 中使用自定义注解
``` java
/**
* @ClassName WaitController
*/
@Log4j2
@RestController
@RequestMapping("/wait")
public class WaitController {
@RequestMapping(value = "/test_string_null",method = RequestMethod.GET)
@StringNullRegex
public HttpResult testStringNullRegex(String name, Integer age){
System.out.println("名字 = " + name);
System.out.println("年龄 = " + age);
return HttpResult.newSuccess();
}
@RequestMapping(value = "/testTwo",method = RequestMethod.GET)
@ClassNotNull
public HttpResult testTwo(UserProperty userProperty){
String name = userProperty.getName();
System.out.println("名字 = " + name);
Integer age = userProperty.getAge();
System.out.println("年龄 = " + age);
Integer qq = userProperty.getQq();
System.out.println("QQ = " + qq);
return HttpResult.newSuccess();
}
}
```
**其他问题:**
> 到这里基本的功能实现了,但是新问题:
> 1. 不支持 多参数中可以为空,可以不为空的问题
>
> 解释: 这个没有用到就没得测试,对象注解中算实现了,但是不太合格,通过自定义注解应该也可以实现,感兴趣的可以试一下^_^ 钻研的精神是可佳的{:1_921:}。不过相比于spring框架自带的非空注解。这么做的优势在哪里哟~
页:
[1]