Springboot引數校驗--最全
Springboot引數校驗
validator內建註解
註解 | 詳細資訊 |
---|---|
@Null | 被註釋的元素必須為 null |
@NotNull | 被註釋的元素必須不為 null |
@AssertTrue | 被註釋的元素必須為 true |
@AssertFalse | 被註釋的元素必須為 false |
@Min(value) | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@Max(value) | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@DecimalMin(value) | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@DecimalMax(value) | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@Size(max, min) | 被註釋的元素的大小必須在指定的範圍內 |
@Digits (integer, fraction) | 被註釋的元素必須是一個數字,其值必須在可接受的範圍內 |
@Past | 被註釋的元素必須是一個過去的日期 |
@Future | 被註釋的元素必須是一個將來的日期 |
@Pattern(value) | 被註釋的元素必須符合指定的正規表示式 |
Hibernate Validator 附加的 constraint
註解 | 詳細資訊 |
---|---|
@Email | 被註釋的元素必須是電子郵箱地址 |
@Length | 被註釋的字串的大小必須在指定的範圍內 |
@NotEmpty | 被註釋的字串的必須非空 |
@Range | 被註釋的元素必須在合適的範圍內 |
@NotBlank | 驗證字串非null,且長度必須大於0 |
注意:
- @NotNull 適用於任何型別被註解的元素必須不能與NULL
- @NotEmpty 適用於集合或者陣列不能為Null且長度必須大於0
- @NotBlank 只能用於String上面 不能為null,呼叫trim()後,長度必須大於0
這裡寫一個手機號的正則校驗(這只是一個簡單手機號正則校驗)—建議如果想實現複雜的引數校驗可以自定義的約束(後面會寫)
/**
* 手機號
*/
@NotNull(message = "手機號不能為空")
@NotBlank(message = "手機號不能為空")
@Pattern(regexp ="^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手機號格式有誤")
private String mobileNo;
@Validated
這個註解來自package org.springframework.validation.annotation;包下
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
可以 使用在類上、方法上、引數上
若要實現單一引數的效驗
(我感覺若是使用restful風格,這個好像沒用,因為若不傳遞引數會直接報錯)
@Validated註解必須設定在類上
栗子:(單個引數異常處理也配置在了***全域性異常處理***裡面了)
/**
* 根據id查詢使用者
* @param id
* @return
*/
@GetMapping("/find")
@ApiOperation("查詢使用者")
public User find(@NotBlank(message = "id不能為空") String id){
User user = new User();
user.setId(Long.parseLong(id));
return user;
}
若要實現javabean物件效驗
@validated註解必須設定在引數前面
栗子:
/**
* 新增商品
* @param cartDTO
*/
@PostMapping
@ApiOperation("向購物車中新增商品")
public Integer addCart(@RequestBody @Validated CartDTO cartDTO){
return cartService.addCart(cartDTO);
}
我這裡json傳遞的是 {}
響應給我的json是(若想讓響應結果像我這樣還需要設定全域性異常處理後面會說)
{
"code": 1002,
"msg": "引數效驗失敗",
"data": [
"商品id不能為空",
"商品型別不能為空",
"商品屬性id不能為空",
"使用者id不能為空"
]
}
javabean物件是
@Data
public class CartDTO {
@ApiModelProperty(value = "購物車表ID")
@NotNull(message = "更新時欄位id必填",groups = {Update.class})
private Long id;
@ApiModelProperty(value = "使用者ID")
@NotNull(message = "使用者id不能為空")
private Long uid;
@ApiModelProperty(value = "型別")
@NotBlank(message = "商品型別不能為空")
private String type;
@ApiModelProperty(value = "商品ID")
@NotNull(message = "商品id不能為空")
private Long productId;
@ApiModelProperty(value = "商品屬性")
@NotBlank(message = "商品屬性id不能為空")
private String productAttrUnique;
@ApiModelProperty(value = "商品數量")
@Min(message = "商品數量不能小於0",value = 0)
private Integer cartNum;
@ApiModelProperty(value = "0 = 未購買 1 = 已購買")
private Boolean isPay;
@ApiModelProperty(value = "是否為立即購買")
private Boolean isNew;
@ApiModelProperty(value = "拼團id")
private Integer combinationId;
@ApiModelProperty(value = "秒殺產品ID")
private Integer seckillId;
@ApiModelProperty(value = "砍價id")
private Integer bargainId;
}
@Valid
來自package javax.validation;包下
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
它可以使用在使用在類、欄位、構造器、引數上
若要實現javabean物件效驗和@Validated用法是一樣的(這裡就不舉例子了)
@Validated和@Valid的區別
1使用@Validated可以實現分組校驗
栗子:
1、首先你要建立分組(我這裡是建立了兩個,新建驗證、更新驗證)而且必須要繼承Default(javax.validation.groups.Default;)介面
package cn.newhopedairy.newshop.mall.common.cart.groups;
import javax.validation.groups.Default;
public interface Create extends Default {
}
package cn.newhopedairy.newshop.mall.common.cart.groups;
import javax.validation.groups.Default;
public interface Update extends Default {
}
2、在欄位上配置分組屬性(可以配置多個)
@Data
public class CartDTO {
@ApiModelProperty(value = "購物車表ID")
@NotNull(message = "更新時欄位id必填",groups = {Update.class})
@NotNull(message = "新增時欄位id必填",groups = {Create.class})//這裡我只是舉個例子,實際中不會這樣驗證
private Long id;
......
}
3、在驗證的入口處(一般在controller的方法中)
@RestController
@Api("購物車介面")
@RequestMapping("/cart")
@Validated
public class CartController {
/**
* 新增商品
* @param cartDTO
*/
@PostMapping
@ApiOperation("向購物車中新增商品")
//
public Integer addCart(@RequestBody @Validated(value = {Create.class}) CartDTO cartDTO){
return cartService.addCart(cartDTO);
}
/**
* 修改商品數量
* @param cartDTO
* @return
*/
@PatchMapping
@ApiOperation("修改購物車中的商品資料")
public Integer updateCart(@RequestBody @Validated(Update.class) CartDTO cartDTO){
return cartService.updateCart(cartDTO);
}
}
4、測試
呼叫新增商品的方法
http://localhost:8080/cart
請求時的json資料為:
{
"bargainId": 0,
"cartNum": 0,
"combinationId": 0,
"isNew": true,
"isPay": true,
"productAttrUnique": "string",
"productId": 0,
"seckillId": 0,
"type": "string",
"uid": 0
}
響應的json資料為:
{
"code": 1002,
"msg": "引數效驗失敗",
"data": [
"新增時欄位id必填"
]
}
呼叫修改商品的方法
http://localhost:8080/cart
請求時的json資料為:
{
"bargainId": 0,
"cartNum": 0,
"combinationId": 0,
"isNew": true,
"isPay": true,
"productAttrUnique": "string",
"productId": 0,
"seckillId": 0,
"type": "string",
"uid": 0
}
響應的json資料為:
{
"code": 1002,
"msg": "引數效驗失敗",
"data": [
"更新時欄位id必填"
]
}
這樣就是實現了分組效驗的效果
“data”: [
“更新時欄位id必填”
]
“data”: [
“新增時欄位id必填”
]
2@Validated和@Valid配合使用key實現巢狀驗證(@Valid和@Valid配合使用也可以實現使用方式差不多)
@PostMapping
@ApiOperation("查詢使用者")
public User add(@RequestBody @Validated User user){
return user;
}
@Data
@ApiModel(value="User物件", description="")
public class User implements Serializable {
@ApiModelProperty(value = "年齡")
@Min(value = 1,message = "年齡不能小於1")
private Integer age;
@ApiModelProperty(value = "郵箱")
private String email;
@Valid
private Car car;
}
@Data
@ApiModel(value="User物件", description="")
public class Car {
@NotBlank(message = "車的顏色不能為空")
private String color;
@Min(value = 5,message = "車長必須超過5米")
private Integer type;
}
請求引數:
{
"age": 10,
"car": {"color": "",
"type": 10},
"email": "string",
"id": 0,
"name": "string"
}
響應引數:
{
"code": 1002,
"msg": "引數效驗失敗",
"data": [
"車的顏色不能為空"
]
}
自定義異常
package com.example.hk_jsr303.exception;
import com.example.hk_jsr303.result.ResultVO;
import lombok.Getter;
import lombok.Setter;
/**
* @Classname MyException
* @Description TODO
* @Date 2020/12/9 23:46
* @Created by hekun
*/
@Getter
@Setter
public class MyException extends RuntimeException {
private int code;
private String msg;
public MyException(){}
public MyException(ResultVO resultVO) {
this.code=resultVO.getCode();
this.msg=resultVO.getMsg();
}
}
定義全域性異常處理
更具體的定義可以看一下這篇blog:
https://juejin.cn/post/6872226869605826573#heading-6
package com.example.hk_jsr303.exception;
import com.example.hk_jsr303.result.ResultVO;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @Classname GlobalExceptionHandler
* @Description TODO
* @Date 2020/12/9 15:11
* @Created by hekun
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 方法引數錯誤異常
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultVO<Object> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
//log.error("方法引數錯誤異常");
List<String> list=new ArrayList<>();
// 從異常物件中拿到ObjectError物件
if (!e.getBindingResult().getAllErrors().isEmpty()){
for(ObjectError error:e.getBindingResult().getAllErrors()){
list.add(error.getDefaultMessage().toString());
}
}
// 然後提取錯誤提示資訊進行返回
return new ResultVO(1002,"引數效驗失敗",list);
}
/**
* 單個引數異常處理
*
* @param ex
* @return
*/
@ExceptionHandler(value = ConstraintViolationException.class)
public Object constraintViolationException(ConstraintViolationException ex) {
// 獲取具體的錯誤資訊
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
// 列印資料
violations.forEach(e -> System.out.println(e.getMessage()));
return "單個-請求引數錯誤";
}
}
//下面這個結果類要使用到
@Getter
@Setter
public class ResultVO<T> {
/**
* 狀態碼,比如1000代表響應成功
*/
private int code;
/**
* 響應資訊,用來說明響應情況
*/
private String msg;
/**
* 響應的具體資料
*/
private T data;
public ResultVO(int code,String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResultVO(int code,String msg) {
this.code = code;
this.msg = msg;
}
}
自定義約束
一般情況內建的約束一般是夠用了,如果有別的情況也是可以自己定義約束條件的
假設我們要給車設定一個顏色,而且顏色只能設定為red或者green
1、注意:@ListValue這個註解是我們自定義的
@Data
@ApiModel(value="User物件", description="")
public class Car {
@NotBlank(message = "車的顏色不能為空")
@ListValue(vals = {"red","green"},message = "車的顏色不對")
private String color;
@Min(value = 5,message = "車長必須超過5米")
private Integer type;
}
2、我們要建立這個註解@ListValue,我們可以模仿官方寫的註解比如@Min
package com.example.hk_jsr303.groups;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Constraint(validatedBy = {ListValueConstraintValidator.class})//自定義的約束校驗器 ---很重要
//自定義的約束校驗器 作用我們要在裡面寫一下校驗規則 isValid() 方法返回true表示校驗成功
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
public @interface ListValue {
//錯誤資訊的提示
String message() default "{com.sjl.common.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
//自定義值的型別
String[] vals() default {};
}
3、寫我們自己的約束校驗器ListValueConstraintValidator ,這裡要注意繼承ConstraintValidator
package com.example.hk_jsr303.groups;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
/**
* @Classname ListValueConstraintValidator
* @Description TODO
* @Date 2020/12/9 22:58
* @Created by hekun
*/
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,String> {
private static Set<String> set = new HashSet<>();
@Override
public void initialize(ListValue constraintAnnotation) {
for (String val : constraintAnnotation.vals()) {
set.add(val);
}
}
/**
* 判斷是否通過校驗
*
* @param value 傳入的值
* @param context
* @return
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
5、進行測試
/**
* 新增車輛
* @param car
* @return
*/
@PostMapping("/car")
@ApiOperation("新增車輛")
public Car addCar(@RequestBody @Validated Car car){
return car;
}
請求json:
{
"color": "red1",
"type": 10
}
響應json:
{
"code": 1002,
"msg": "引數效驗失敗",
"data": [
"車的顏色不對"
]
}
參考文件
https://juejin.cn/post/6844904118536912904#heading-7
https://juejin.cn/post/6844904016380461070#heading-6
https://juejin.cn/post/6872226869605826573#heading-7
https://juejin.cn/post/6844904133296652296#heading-6
https://www.cnblogs.com/songjilong/p/12663564.html
https://blog.csdn.net/justry_deng/article/details/86571671?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-8.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-8.control
相關文章
- 引數校驗
- Java SpringBoot上的引數校驗JSR 303 ValidationJavaSpring BootJS
- SpringBoot如何優雅的進行引數校驗Spring Boot
- SpringBoot Validation優雅的全域性引數校驗Spring Boot
- SpringBoot 實戰 (十五) | 服務端引數校驗之一Spring Boot服務端
- SpringBoot介面 - 如何優雅的對引數進行校驗?Spring Boot
- Spring Boot 引數校驗Spring Boot
- 引數校驗註解
- WTForms 欄位 引數 校驗ORM
- SpringMVC實現引數校驗SpringMVC
- 介面測試-引數校驗
- fastapi 請求引數 校驗ASTAPI
- SpringBoot2 引數管理實踐,入參出參與校驗Spring Boot
- C# .net framework .net core 3.1 請求引數校驗, DataAnnotations, 自定義引數校驗C#Framework
- 【Vue】元件使用之引數校驗Vue元件
- 使用hibernate validate做引數校驗
- SpringBoot 如何進行引數校驗,老鳥們都這麼玩的!Spring Boot
- 元件引數校驗與非props特性元件
- @Validated、@Valid在service層引數校驗
- Hibernate Validator校驗引數全攻略
- IpAddressService ip地址引數校驗 allIpAddressCheck分析iPad
- Spring WebFlux 基礎教程:引數校驗SpringWebUX
- Flask開發技巧之引數校驗Flask
- SpringBoot使用validator校驗Spring Boot
- 使用Spring Validation優雅地校驗引數Spring
- 【深度思考】如何優雅的校驗引數?
- 【超實用攻略】SpringBoot + validator 輕鬆實現全註解式的引數校驗Spring Boot
- SpringBoot分組校驗及自定義校驗註解Spring Boot
- Spring Boot實現通用的介面引數校驗Spring Boot
- Oracle RAC一鍵部署004(RAC引數校驗)Oracle
- Dubbo服務如何優雅的校驗引數
- Spring AOP @PathVariable和@RequestParam 引數進行校驗(valid)Spring
- 如何優雅的做引數校驗-JSR330JS
- 如何在專案中優雅的校驗引數
- SpringBoot自定義校驗註解Spring Boot
- SpringBoot整合Hibernate Validator實現引數驗證功能Spring Boot
- Spring Validation-用註解代替程式碼引數校驗Spring
- Spring Boot統一異常處理以及引數校驗Spring Boot