1. 程式人生 > 程式設計 >SpringBoot使用validation-api實現引數校驗的示例

SpringBoot使用validation-api實現引數校驗的示例

我們在開發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 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("","引數體不能為空");
  }


  /**
   * 引數效驗異常處理器
   *
   * @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-api實現引數校驗的示例的文章就介紹到這了,更多相關SpringBoot validation引數校驗內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!