SpringBoot使用validation-api实现参数校验的示例

作者:溪源的奇思妙想 时间:2022-12-02 14:33:40 

我们在开发Java项目的时候,经常需要对参数进行一些必填项、格式、长度等进行校验,如果手写代码对参数校验,每个接口会需要很多低级的代码,这样会降低代码的可读性。那么我们能不能使用一种比较优雅的方式来实现,对请求中的参数进行校验呢?

knife4j的安装与使用可参考我的博客:SpringBoot使用knife4j进行在线接口调试

正文

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

SpringBoot使用validation-api实现参数校验的示例

SpringBoot使用validation-api实现参数校验

注入依赖


<!--参数校验-->
<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>

UserPojoReq.java请求封装类

如果成员变量是其他对象实体,该变量必须加 @Valid,否则嵌套中的验证不生效


@Setter
@Getter
@ToString
@ApiModel("用户对象")
public class UserPojoReq extends Request implements Serializable {
 private static final long serialVersionUID = -354657839724457905L;

@ApiModelProperty(required = true, notes = "主键", example = "123")
 private String id;

@ApiModelProperty(required = true, notes = "用户名", example = "luo")
 @NotNull(message = "用户姓名为必填项,不得为空")
 @Size(min = 2,max = 20,message = "用户名长度要在2—8个字符")
 private String name;

@ApiModelProperty(required = true, notes = "消息", example = "消息")
 private String msg;

}

CouponTypeEnum.class :错误码枚举类


@Getter
public enum CouponTypeEnum {

PARAMETER_ERROR(1001, "请求参数有误!"),
 UNKNOWN_ERROR(9999, "未知的错误!”);

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

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

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

public static String getDescByType(int couponType) {
   for (CouponTypeEnum type : CouponTypeEnum.values()) {
     if (type.couponType == couponType) {
       return type.couponTypeDesc;
     }
   }
   return null;
 }

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

BusinessException.java:自定义业务异常类


/**
* 业务自定义异常
*/
@Getter
public class BusinessException extends RuntimeException {

private static final long serialVersionUID = -1895174013651345407L;
 private final CouponTypeEnum errorCode;
 private String primaryErrorCode;
 private String primaryErrorMsg;
 private String primaryErrorIP;

public BusinessException(CouponTypeEnum errorCode) {
   this(errorCode, errorCode.getCouponTypeDesc());
 }
 public BusinessException(CouponTypeEnum errorCode, String message) {
   super(message);
   this.errorCode = errorCode;
 }
 public BusinessException(CouponTypeEnum errorCode, String message,String primaryErrorCode,String primaryErrorMsg,String primaryErrorIP) {
   super(message);
   this.errorCode = errorCode;
   this.primaryErrorCode=primaryErrorCode;
   this.primaryErrorMsg=primaryErrorMsg;
   this.primaryErrorIP=primaryErrorIP;
 }
 public BusinessException(CouponTypeEnum errorCode,String primaryErrorCode,String primaryErrorMsg,String primaryErrorIP) {
   this(errorCode, errorCode.getCouponTypeDesc());
   this.primaryErrorCode=primaryErrorCode;
   this.primaryErrorMsg=primaryErrorMsg;
   this.primaryErrorIP=primaryErrorIP;
 }

}

GlobalExceptionHandler.class 拦截异常并统一处理

  1. MissingServletRequestParameterException:必填项为null异常

  2. HttpMessageNotReadableException:参数类型不匹配异常

  3. MethodArgumentNotValidException:JSON校验失败异常(比如长度等)

  4. BusinessException:自定义的异常

  5. Exception:其他异常


@RestControllerAdvice("com.luo.producer.controller")
@Slf4j
public class GlobalExceptionHandler {

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

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

/**
  * 参数效验异常处理器
  *
  * @param e 参数验证异常
  * @return ResponseInfo
  */
 @ResponseStatus(HttpStatus.BAD_REQUEST)
 @ExceptionHandler(MethodArgumentNotValidException.class)
 public Response 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 Response(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), fieldError.getDefaultMessage());
     }
   }
   return new Response(CouponTypeEnum.PARAMETER_ERROR);
 }

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

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

验证

测试接口

@Valid被标记的实体将会开启一个校验的功能

@RequestBody:请求实体需要加上@RequestBody否则MethodArgumentNotValidException异常将会被识别成Exception异常,提示信息将与预期不符。


@RestController
@Slf4j
public class UserController {

@PostMapping("/helloluo")
 @MyPermissionTag(value = "true")
 public String helloluo(@RequestBody @Valid UserPojoReq userPojoReq){
   return "Hello World”+userPojoReq;
 }
}

模拟请求参数,进行接口访问:

SpringBoot使用validation-api实现参数校验的示例

来源:https://blog.csdn.net/weixin_40990818/article/details/108427242

标签:SpringBoot,validation,参数校验
0
投稿

猜你喜欢

  • Kotlin协程开发之Flow的融合与Channel容量及溢出策略介绍

    2023-07-02 23:52:01
  • 用c# 自动更新程序

    2023-04-03 09:03:46
  • 浅谈解决Hibernate懒加载的4种方式

    2022-07-04 00:46:39
  • C#判断字符是否为汉字的三种方法分享

    2022-05-24 07:59:41
  • C#强制转换和尝试转换的方法

    2021-10-10 10:48:23
  • Android 通过TCP协议上传指定目录文件的方法

    2023-11-07 23:34:11
  • Java实现颜色渐变效果

    2023-08-25 11:10:45
  • 继承JpaRepository后,找不到findOne()方法的解决

    2022-08-26 18:33:26
  • android使用flutter的ListView实现滚动列表的示例代码

    2023-06-26 09:00:13
  • Flutter利用Hero组件实现自定义路径效果的动画

    2023-06-25 13:46:29
  • C#运算符重载用法实例分析

    2023-02-16 00:33:05
  • Java微信授权登陆的实现示例

    2021-12-11 22:03:04
  • ZooKeeper入门教程一简介与核心概念

    2022-11-24 18:36:00
  • Flutter 底部弹窗如何实现多项选择

    2023-06-24 17:08:17
  • MyBatis插入Insert、InsertSelective的区别及使用心得

    2023-08-25 04:34:28
  • VC对自定义资源加密解密(AES)的详解

    2023-01-10 00:27:15
  • 关于Mybatis-Plus字段策略与数据库自动更新时间的一些问题

    2023-08-05 20:44:22
  • C#自定义画刷原理解析

    2021-06-19 19:17:32
  • Unity实现单机游戏每日签到系统

    2023-05-13 08:42:36
  • Java关键字finally_动力节点Java学院整理

    2022-09-25 11:15:30
  • asp之家 软件编程 m.aspxhome.com