Custom annotation (validation parameters are required demo)

Annotations are commonly used in the development process, and it also supports custom annotations. The following writes a custom annotation that verifies that the request parameter must be filled.

The first step is to define an annotation class

package com.yulisao.annotation;

import java.lang.annotation.*;

/**
 * 参数非空校验
 * author yulisao
 * createDate 2023/3/30
 */
@Documented
@Target(ElementType.FIELD) // 表明这个注解是用在字段上的
@Retention(RetentionPolicy.RUNTIME) // 表面这个注解是在项目运行的时候执行
public @interface NotNull {
    
     // NotNull 是你给这个注解自定义命名,随你命名
    String message() default ""; // 注解里面有哪些参数(参数的数据类型是字符串,参数名称是message,使用注解时缺省该参数时默认为什么)
    // 还需其他参数就继续按需添加....
}

The second step is to add annotation implementation logic

package com.yulisao.annotation.impl;

import com.yulisao.dto.UserInfo;
import com.yulisao.util.ExceptionUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * author yulisao
 * createDate 2023/3/30
 */
public class NotNullForReqFeild {
    
    

    /**
     * 校验对象
     * @param t
     * @param <T>
     */
    public static <T> void validate(T t) {
    
    
        try {
    
    
            // 校验当前请求对象里面的字段
            Field[] declaredFields = t.getClass().getDeclaredFields(); // 获取对象里面的全部字段
            for (Field declaredField : declaredFields) {
    
     // 遍历对象里面的字段
                if (declaredField.isAnnotationPresent(NotNull.class)) {
    
     // 对添加了自定义注解的字段的逻辑
                    declaredField.setAccessible(true);
                    Object value = declaredField.get(t);
                    if (value == null || StringUtils.isBlank(String.valueOf(value))) {
    
     // 如果没传值
                        ExceptionUtil.buildException(declaredField.getAnnotation(NotNull.class).message()); // 取出自定义注解上的参数值进行提示
                    }
                    // 同时校验对于加了自定义注解的数值类型的字段,校验其值不能是负数和0
                    // 如果是也针对没加自定义注解的字段,可以把这个正数规则的if移动到外面一层。
                    // 最后说明一点,对于所有请求都要实现同时校验必填和正数规则的才建议写在这里哟, 不然有些功能的请求只校验必填但可以传负数的,也被这个校验住了就不方便了。
                    /*if (value instanceof Integer && ((Integer) value).intValue() <= 0) {
                       // 报错抛异常 或者 其他处理
                    }*/
                }
            }

            // 校验当前请求对象所继承的父对象里面的字段
            Field[] superDeclaredFields = t.getClass().getSuperclass().getDeclaredFields();
            for (Field declaredField : superDeclaredFields) {
                if (declaredField.isAnnotationPresent(NotNull.class)) {
    
    
                    declaredField.setAccessible(true);
                    Object value = declaredField.get(t);
                    if (value == null || StringUtils.isBlank(String.valueOf(value))) {
    
    
                        ExceptionUtil.buildException(declaredField.getAnnotation(NotNull.class).message());
                    }
                }
            }

            // 校验请求对象里面的账户类型字段的值是否规范 假设正确的值只能是 1
            // t可以就是UserInfo对象也可以是某个对象继承了UserInfo,写在这里面如果当前请求对象不满足这两种情形自然也不会进入if,当然也就没啥影响。但也不建议
            /*if (t instanceof UserInfo) {
    
    
                UserInfo userInfo = (UserInfo) t;
                if (userInfo != null) {
    
    
                    if (userInfo .getUserType() != 1) {
    
    
                        // 报错抛异常 或者 其他处理
                    }
                }
            }*/
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 校验list<对象>
     * @param list
     * @param <T>
     */
    public static <T> void validate(List<T> list) {
    
    
        if (CollectionUtils.isEmpty(list))
            ExceptionUtil.buildException("The request parameter cannot be empty");

        for (T t : list) {
    
    
            validate(t);
        }
    }
}

Among them, the exception tool class ExceptionUtil.buildException() I will not post the code here, write one or replace it by myself

The third step is to add annotations

package com.yulisao.dto;

import com.yulisao.annotation.NotNull; // 这里要使用你自己自定义的注解,不要引错包了
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
public class User extends UserInfo {
    
    

	@NotNull(message = "姓名不能为空") // 为空时给什么提示错误信息
	@ApiModelProperty(value = "姓名")
    private String name;

	@ApiModelProperty(value = "手机号码") // 非必填字段就不要添加自定义注解
    private String mobile;
}
package com.yulisao.dto;

import com.yulisao.annotation.NotNull;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * author yulisao
 * createDate 2023/6/1
 */
@Data
public class UserInfo {
    
    
  
    @NotNull(message = "用户类型不能为空")
    @ApiModelProperty(value = "用户类型 1-个人 2-企业")
    private Integer userType;
    
    // more feild...
}

The fourth step is to realize the annotation function

@Operation(summary = "用户查询", description = "用户查询")
@PostMapping("/getUserList")
public RespBody<List<User>> getUserList(@RequestBody ReqBody<User> reqBody) {
    
    
	// 调用自定义注解实现类来执行里面的逻辑。如果每个方法都要这一行校验必填,可以考虑放到拦截器或者切面里面,省事简洁。
    NotNullForReqFeild.validate(reqBody.getParam()); 
    // dosomething ....
    return new RespBody<>();
}

The above is the whole process, and the most important thing is the second step, where the entire custom annotation function is implemented. In fact, the required field spring also provides the annotation @NotNull, the example is as follows. Therefore, custom annotations generally write some other business logic functions, and if there are ready-made ones, they must be used directly and who will work hard to write them by themselves.

import javax.validation.constraints.NotNull; # 依赖包要spring的,不要选错了,否则注解不生效

# 请求对象里面的字段
@NotNull(message = "姓名不能为空")
@ApiModelProperty(value="姓名")
private String name;

# 控制类的请求方法
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.util.List;

# 请求参数外面包了一层的,需要加上@Valid,这样UserQueryRequest里面的注解才会生效哦,才会校验加了@NotNull字段必填
@Operation(summary = "用户查询", description = "用户查询")
@PostMapping("/getUserList")
public RespBody<List<User>> getUserList(@RequestBody @Valid ReqBody<User> reqBody) {
    
    
	// dosomething ....
    return new RespBody<>();
}
 

Guess you like

Origin blog.csdn.net/qq_29539827/article/details/131488939