SpringBoot使用validation-api实现对枚举类参数校验

SpringBoot使用validation-api实现对枚举类参数校验

前言

之前写了一个博客是关于使用SpringBoot使用validation-api实现参数校验,当时使用的注解都是validation-api自带的注解只能完成对空值、长度等简单的校验,在我们日常的使用当中会遇到对参数是否在枚举值类的校验,针对这种情况我们怎么来实现呢?

SpringBoot使用validation-api实现参数校验可参考我的博客:SpringBoot使用validation-api实现参数校验

正文

SpringBoot使用validation-api实现对枚举类参数校验

ValidationApi框架就是用来解决参数校验中代码冗余问题,ValidationApi框架提供一些注解用来帮助我们对请求参数进行校验。

Maven依赖

<!--参数校验-->
<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:用于对枚举校验的接口

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

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

ActionTypeEnumValid:用于对枚举类校验的自定义注解

@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:枚举校验器

/**
* 用于校验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:枚举类

@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:使用SpringMVC提供的异常处理机制,对ValidationApi的异常进行封装

@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);
    }
}

验证

请求的封装类

/**
* 指令的封装类
*/
@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";

}

请求接口

  • @Valid 用于开启请求参数校验
@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);
    }

}

通过Knife4j访问对应接口
在这里插入图片描述

源码

项目源码可从的我的github中获取:github源码地址

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_40990818/article/details/109434581