SpringBoot uses validation-api to verify enumeration parameters

SpringBoot uses validation-api to verify enumeration parameters

Preface

I wrote a blog before about using SpringBootto validation-apiimplement parameter verification. The annotations used at the time were all annotations that came with validation-api, which could only complete simple verification of null values, lengths, etc., which we will encounter in our daily use Check whether the parameter is in the enumeration value class. How can we implement it in this case?

SpringBoot uses validation-api to implement parameter verification, please refer to my blog: SpringBoot uses validation-api to implement parameter verification

text

SpringBoot uses validation-api to verify enumeration parameters

The ValidationApi framework is used to solve the problem of code redundancy in parameter verification. The ValidationApiframework provides some annotations to help us verify the request parameters.

Maven dependency

<!--参数校验-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>


<!--提供一些字符串操作-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.3.2</version>
</dependency>


<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.2</version>
    <optional>true</optional>
</dependency>


<!--knife4j接口-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.4</version>
</dependency>

EnumValidate: an interface used to verify enumeration

/**
* 用于实现枚举类的校验
*/
public interface EnumValidate<T> {
    
    

    /**
     * 校验枚举值是否存在
     */
    boolean existValidate(T value);
}

ActionTypeEnumValid: A custom annotation used to verify enumeration classes

@Target({
    
    ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {
    
    ActionTypeEnumValidator.class})
@Documented
public @interface ActionTypeEnumValid {
    
    


    String message() default "";


    Class<?>[] groups() default {
    
    };


    Class<? extends Payload>[] payload() default {
    
    };


    Class<?>[] target() default {
    
    };


    /**
     * 允许的枚举
     *
     * @return
     */
    Class<? extends Enum<?>> enumClass();


}

ActionTypeEnumValidator: Enumeration validator

/**
* 用于校验ActionTypeEnumValidator
*/
public class ActionTypeEnumValidator implements ConstraintValidator<ActionTypeEnumValid,String> {
    
    


    private Class<? extends Enum> enumClass;


    @Override
    public void initialize(ActionTypeEnumValid actionTypeEnumValid) {
    
    
        enumClass = actionTypeEnumValid.enumClass();
    }


    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
    
    
        if (value == null || "".equals(value)) {
    
    
            return true;
        }


        EnumValidate[] enums = (EnumValidate[]) enumClass.getEnumConstants();
        if(enums ==null || enums.length == 0){
    
    
            return false;
        }


        return enums[0].existValidate(value);
    }


}

ActionTypeEnum: Enumeration class

@Getter
public enum ActionTypeEnum implements EnumValidate<String> {
    
    


    ACTION_INVOKR("invoke", "invoke"),
    UNKNOWN_ERROR("no", "no");

    /**
     * 状态值
     */
    private String couponType;

    /**
     * 状态描述
     */
    private String couponTypeDesc;

    ActionTypeEnum(String couponType, String couponTypeDesc) {
    
    
        this.couponType = couponType;
        this.couponTypeDesc = couponTypeDesc;
    }


    public static String getDescByType(String couponType) {
    
    
        for (ActionTypeEnum type : ActionTypeEnum.values()) {
    
    
            if (type.couponType.equals(couponType) ) {
    
    
                return type.couponTypeDesc;
            }
        }
        return null;
    }

    /**
     * 判断是否在枚举类当中
     * @param value
     * @return
     */
    @Override
    public boolean existValidate(String value) {
    
    
        if (value == null || "".equals(value)) {
    
    
            return false;
        }
        for (ActionTypeEnum testEnum : ActionTypeEnum.values()) {
    
    
            if (testEnum.getCouponType().equalsIgnoreCase(value)) {
    
    
                return true;
            }
        }
        return false;
    }

    public String getcouponTypeStr() {
    
    
        return String.valueOf(this.couponType);
    }
}

GlobalExceptionHandler: Use the SpringMVCprovided exception handling mechanism ValidationApito encapsulate the exception

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    
    

    /**
     * 忽略参数异常处理器
     *
     * @param e 忽略参数异常
     * @return Response
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseResult parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
    
    
        log.error("参数异常", e);
        return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), "请求参数 " + e.getParameterName() + " 不能为空");
    }


    /**
     * 缺少请求体异常处理器
     *
     * @param e 缺少请求体异常
     * @return Response
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
    
    
        log.error("缺少请求体异常", e);
        return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), "参数体不能为空");
    }


    /**
     * 参数效验异常处理器
     *
     * @param e 参数验证异常
     * @return ResponseInfo
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseResult parameterExceptionHandler(MethodArgumentNotValidException e) {
    
    
        log.error("参数验证异常", e);
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
        if (exceptions.hasErrors()) {
    
    
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
    
    
                // 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), fieldError.getDefaultMessage());
            }
        }
        return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR);
    }


    /**
     * 自定义参数错误异常处理器
     *
     * @param e 自定义参数
     * @return ResponseInfo
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({
    
    BusinessException.class})
    public ResponseResult paramExceptionHandler(BusinessException e) {
    
    
        log.error("业务异常", e);
        // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
        if (!StringUtils.isEmpty(e.getMessage())) {
    
    
            return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), e.getMessage());
        }
        return new ResponseResult(CouponTypeEnum.PARAMETER_ERROR);
    }


    /**
     * 其他异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({
    
    Exception.class})
    public ResponseResult otherExceptionHandler(Exception e) {
    
    
        log.error("其他异常", e);
        // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
        if (!StringUtils.isEmpty(e.getMessage())) {
    
    
            return new ResponseResult(CouponTypeEnum.UNKNOWN_ERROR.getcouponTypeStr(), e.getMessage());
        }
        return new ResponseResult(CouponTypeEnum.UNKNOWN_ERROR);
    }
}

verification

Requested wrapper class

/**
* 指令的封装类
*/
@Getter
@Setter
@ToString
public class CommandPOJO implements Serializable {
    
    
    private static final long serialVersionUID = -8497328408069586664L;

    //指令
    @NotNull(message = "指令为必填项,不得为空")
    @ActionTypeEnumValid(message = "该指令暂不支持,暂时只支持invoke", enumClass = ActionTypeEnum.class)
    private String action ="invoke";

}

Request interface

  • @Valid Used to enable request parameter verification
@RestController
@Slf4j
@Api(value = "远程调用模块")
@RequestMapping("/xiyuanrpc")
public class RPCController {
    
    

    @PostMapping("/rpcNettybyInvoke")
    @ApiOperation(value = "rpc远程调用")
    @InvokeParameterCheck
    @MethodLogPrint
    public ResponseResult rpcNettybyInvoke(@Valid @RequestBody CommandPOJO pojo) {
    
    
        return NettyClientUtil.rpcNetty(pojo);
    }

}

Access the corresponding interface through Knife4j
Insert picture description here

Source code

The project source code can be obtained from my github: github source code address

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_40990818/article/details/109434581