java 单机接口限流处理方案
381
2022-06-06
之前写了一个博客是关于使用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源码地址
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~