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

 更新时间:2020年09月08日 09:28:39   作者:溪源的奇思妙想  
这篇文章主要介绍了SpringBoot使用validation-api实现参数校验的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

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

正文

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

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实现参数校验的示例的文章就介绍到这了,更多相关SpringBoot validation参数校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java使用Filter实现登录验证

    Java使用Filter实现登录验证

    本文主要介绍了Java使用Filter实现登录验证,Filter类似于门卫,你在进入之前门卫需要盘查你,身份合法进入,身份不合法拦截,感兴趣的可以了解一下
    2023-11-11
  • java大话之创建型设计模式教程示例

    java大话之创建型设计模式教程示例

    这篇文章主要为大家介绍了java大话之创建型设计模式教程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Java中Iterator与ListIterator迭代的区别

    Java中Iterator与ListIterator迭代的区别

    本文主要介绍了Java中Iterator与ListIterator迭代的区别,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • 面试JAVA时,问到spring该怎么回答

    面试JAVA时,问到spring该怎么回答

    这篇文章主要介绍了Spring面试资料,学Java的小伙伴都知道Spring是面试的必问环节,看完了一天就可掌握数据结构和算法的面试题,快来看看吧
    2021-08-08
  • Java浅析枚举类的使用

    Java浅析枚举类的使用

    枚举类型可以取代以往常量的定义方式,即将常量封装在类或接口中。此外,枚举类型还提供了安全检查功能。本文就来和大家讲讲Java中枚举类的用法,需要的可以参考一下
    2022-07-07
  • 新手初学Java数组

    新手初学Java数组

    数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们数组的声明创建
    2021-07-07
  • springcloud-gateway整合jwt+jcasbin实现权限控制的详细过程

    springcloud-gateway整合jwt+jcasbin实现权限控制的详细过程

    这篇文章主要介绍了springcloud-gateway整合jwt+jcasbin实现权限控制,基于springboot+springcloud+nacos的简单分布式项目,项目交互采用openFeign框架,单独提取出来成为一个独立的model,需要的朋友可以参考下
    2023-02-02
  • Java深入探究Object类的方法

    Java深入探究Object类的方法

    java继承中说到的Object类是java中一个特殊的类,所有的类都是直接或者间接的继承自Object类,即如果某个类没有使用extends关键字则默认是java.lang.Object类的子类,所以所有的类都可以使用Object类中定义的方法,下面介绍Object类的常用方法
    2022-05-05
  • springboot为异步任务规划自定义线程池的实现

    springboot为异步任务规划自定义线程池的实现

    本文主要介绍了springboot为异步任务规划自定义线程池,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Java中文件管理系统FastDFS详解

    Java中文件管理系统FastDFS详解

    这篇文章主要介绍了Java中文件管理系统FastDFS详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07

最新评论