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参数校验内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot+dubbo+validation 进行rpc参数校验的实现方法

    注意:本文dubbo 版本 2.8.4 springboot 版本 2.0.4.RELEASE 项目结构 test-rest (前端消费着,controller 层,springboot+maven项目) test-api (dubbo服务 的 api ,只记录 service 接口和 model ,maven 项目) test-provider(dubbo 服务提供者,实际的数据库操作及业务层, springboot+maven项目 ) 背景: 使用springmvc做restful,使用du

  • SpringBoot实现接口的各种参数校验的示例

    目录 1.添加依赖 2.接口参数校验 2.1 requestBody参数校验 2.2 requestParam/PathVariable参数校验 3.统一异常处理 4.进阶使用 4.1 分组校验 4.2 嵌套校验 4.3 集合校验 4.4 自定义校验 5.快速失败 (Fail Fast) 6.@Valid和@Validated区别 7.实现原理 7.1 requestBody参数校验实现原理 7.2 方法级别的参数校验实现原理 在我们进行接口开发时,在对参数的接收时,我们需要冗余复杂的校验规则

  • SpringBoot利用validation实现优雅的校验参数

    目录 1.前言 2.常用校验 3.spring boot的数据自动校验功能 3.1 引入依赖 3.2 构建启动类 3.3 创建需要被校验的实体类 3.4 在Controller中校验数据 3.5 统一异常处理 4.自定义校验注解 4.1 @NameValidation 4.2 校验类NameValidationValidator 4.3 在Person类增加新注解 5.总结 1.前言 数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱

  • java开发SpringBoot参数校验过程示例教程

    目录 为什么需要参数校验 SpringBoot中集成参数校验 第一步,引入依赖 第二步,定义要参数校验的实体类 常见的约束注解如下: 第三步,定义校验类进行测试 第四步,体验效果 自定义参数校验 第一步,创建自定义注解 第二步,自定义校验逻辑 第三步,在字段上增加注解 第四步,体验效果 分组校验 第一步:定义分组接口 第二步,在模型中给参数分配分组 第三步,给需要参数校验的方法指定分组 第四步,体验效果 小结 大家好,我是飘渺. 前几天写了一篇SpringBoot如何统一后端返回格式?老鸟们都是

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

    我们在开发Java项目的时候,经常需要对参数进行一些必填项.格式.长度等进行校验,如果手写代码对参数校验,每个接口会需要很多低级的代码,这样会降低代码的可读性.那么我们能不能使用一种比较优雅的方式来实现,对请求中的参数进行校验呢? knife4j的安装与使用可参考我的博客:SpringBoot使用knife4j进行在线接口调试 正文 ValidationApi框架就是用来解决参数校验中代码冗余问题,ValidationApi框架提供一些注解用来帮助我们对请求参数进行校验: SpringBoot使

  • SpringBoot通过自定义注解实现参数校验

    目录 1. 为什么要进行参数校验 2. 如何实现参数校验 3. 注解实现参数校验 4. 自定义注解实现参数校验 1. 为什么要进行参数校验 在后端进行工作时,需要接收前端传来的数据去数据库查询,但是如果有些数据过于离谱,我们就可以直接把它pass掉,不让这种垃圾数据接触数据库,减小数据库的压力. 有时候会有不安分的人通过一些垃圾数据攻击咱们的程序,让咱们的服务器或数据库崩溃,这种攻击虽然低级但不得不防,就像QQ进行登录请求时,它们向后端发送 账号=123,密码=123 的数据,一秒钟还发1w次,

  • SpringBoot中的异常处理与参数校验的方法实现

    兄弟们好,这次来跟老铁交流两个问题,异常和参数校验,在说参数校验之前我们先来说异常处理吧,因为后面参数的校验会牵扯到异常处理这块的内容. 异常处理 说到异常处理,我不知道大家有没有写过或者遇到过如下的写法. public void saveUser() { try { // 所有的业务内容,目测几百行 }catch (Exception e) { e.printStackTrace(); } } 如果出现上述的代码,里面包含了大量的业务代码,如果是你写的,赶紧改掉,不是你写的找写的,吐槽赶紧改掉

  • Spring WebFlux实现参数校验的示例代码

    请求参数校验,在实际的应用中很常见,网上的文章大部分提供的使用注解的方式做参数校验.本文主要介绍 Spring Webflux Function Endpoint 使用 Spring Validation 来校验请求的参数.使用上一篇文章的示例来演示. 使用步骤如下: 1.创建校验器 Validator 2.运用校验器 3.抛出异常,返回 http status 400 错误 PersonValidator.java package com.example.springbootdemo.webf

  • Springboot+Redis实现API接口限流的示例代码

    添加Redis的jar包. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 在application.yml中配置redis spring: ## Redis redis: database: 0 host: 127.0.0.1 p

  • SpringBoot实现接口等幂次校验的示例代码

    目录 主流的实现方案如下: 第一步:书写redis工具类 第二步.书写token工具类 第三步:定义注解,使用在方法上,当控制层的方法上被注释时,表示该请求为等幂性请求 第四步:拦截器配置.选择前置拦截器,每次请求都校验到达的方法上是否有等幂性注解,如果有则进行token校验 第五步:对拦截器进行url模式匹配,并注入spring容器 第六步:控制层 接口等幂性通俗的来说就是同一时间内,发起多次请求只有一次请求成功:其目的时防止多次提交,数据重复入库,表单验证网络延迟重复提交等问题. 比如: 订

随机推荐