SpringBoot進(jìn)行參數(shù)校驗(yàn)的方法詳解
介紹
在日常的接口開(kāi)發(fā)中,為了防止非法參數(shù)對(duì)業(yè)務(wù)造成影響,經(jīng)常需要對(duì)接口的參數(shù)進(jìn)行校驗(yàn),例如登錄的時(shí)候需要校驗(yàn)用戶名和密碼是否為空,添加用戶的時(shí)候校驗(yàn)用戶郵箱地址、手機(jī)號(hào)碼格式是否正確。 靠代碼對(duì)接口參數(shù)一個(gè)個(gè)校驗(yàn)的話就太繁瑣了,代碼可讀性極差。
Validator框架就是為了解決開(kāi)發(fā)人員在開(kāi)發(fā)的時(shí)候少寫(xiě)代碼,提升開(kāi)發(fā)效率;Validator專門(mén)用來(lái)進(jìn)行接口參數(shù)校驗(yàn),例如常見(jiàn)的必填校驗(yàn),email格式校驗(yàn),用戶名必須位于6到12之間等等。
接下來(lái)我們看看在SpringbBoot中如何集成參數(shù)校驗(yàn)框架。
1.SpringBoot中集成參數(shù)校驗(yàn)
1.1引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
1.2定義參數(shù)實(shí)體類
package com.didiplus.modules.sys.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/25
* Desc: 字典類型領(lǐng)域模型
*/
@Data
@ApiModel(value = "字典類型")
public class SysDictType {
@ApiModelProperty("ID")
private String id;
@NotBlank(message = "字典名稱必填項(xiàng)")
@ApiModelProperty(value = "字典名稱",example = "用戶ID")
private String typeName;
@NotBlank(message = "字典編碼不能為空")
@ApiModelProperty(value = "字典編碼")
private String typeCode;
@Email(message = "請(qǐng)?zhí)顚?xiě)正確的郵箱地址")
@ApiModelProperty(value = "字典編碼")
private String email;
@ApiModelProperty(value = "字典描述")
private String description;
@NotBlank(message = "字典狀態(tài)不能為空")
@ApiModelProperty(value = "字典狀態(tài)")
private String enable;
}
常見(jiàn)的約束注解如下:
| 注解 | 功能 |
|---|---|
| @AssertFalse | 可以為null,如果不為null的話必須為false |
| @AssertTrue | 可以為null,如果不為null的話必須為true |
| @DecimalMax | 設(shè)置不能超過(guò)最大值 |
| @DecimalMin | 設(shè)置不能超過(guò)最小值 |
| @Digits | 設(shè)置必須是數(shù)字且數(shù)字整數(shù)的位數(shù)和小數(shù)的位數(shù)必須在指定范圍內(nèi) |
| @Future | 日期必須在當(dāng)前日期的未來(lái) |
| @Past | 日期必須在當(dāng)前日期的過(guò)去 |
| @Max | 最大不得超過(guò)此最大值 |
| @Min | 最大不得小于此最小值 |
| @NotNull | 不能為null,可以是空 |
| @Null | 必須為null |
| @Pattern | 必須滿足指定的正則表達(dá)式 |
| @Size | 集合、數(shù)組、map等的size()值必須在指定范圍內(nèi) |
| 必須是email格式 | |
| @Length | 長(zhǎng)度必須在指定范圍內(nèi) |
| @NotBlank | 字符串不能為null,字符串trim()后也不能等于"" |
| @NotEmpty | 不能為null,集合、數(shù)組、map等size()不能為0;字符串trim()后可以等于"" |
| @Range | 值必須在指定范圍內(nèi) |
| @URL | 必須是一個(gè)URL |
1.3定義校驗(yàn)類進(jìn)行測(cè)試
package com.didiplus.modules.sys.controller;
import com.didiplus.modules.sys.domain.SysDictType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/25
* Desc: 數(shù)據(jù)字典控制器
*/
@RestController
@Api(tags = "數(shù)據(jù)字典")
@RequestMapping("/api/sys/dictType")
public class SysDictTypeController {
@ApiOperation("字典添加")
@PostMapping("/add")
public SysDictType add(@Validated @RequestBody SysDictType sysDictType) {
return sysDictType;
}
@ApiOperation("字典修改")
@PutMapping("/edit")
public SysDictType edit(@Validated @RequestBody SysDictType sysDictType) {
return sysDictType;
}
}這里我們先定義兩個(gè)方法add,edit,都是使用了 @RequestBody注解,用于接受前端發(fā)送的json數(shù)據(jù)。
1.4打開(kāi)接口文檔模擬提交數(shù)據(jù)

通過(guò)接口文檔看到前三個(gè)字段都是必填項(xiàng)。

由于email的格式不對(duì)就被攔截了,提示是因?yàn)猷]箱地址不對(duì)。
2.參數(shù)異常加入全局異常處理器
雖然我們之前定義了全局異常攔截器,也看到了攔截器確實(shí)生效了,但是Validator校驗(yàn)框架返回的錯(cuò)誤提示太臃腫了,不便于閱讀,為了方便前端提示,我們需要將其簡(jiǎn)化一下。
直接修改之前定義的 RestExceptionHandler,單獨(dú)攔截參數(shù)校驗(yàn)的三個(gè)異常:
javax.validation.ConstraintViolationException
org.springframework.validation.BindException
org.springframework.web.bind.MethodArgumentNotValidException
代碼如下:
package com.didiplus.common.web.response.Handler;
import com.didiplus.common.web.response.Result;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
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 javax.validation.ValidationException;
import java.util.stream.Collectors;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/24
* Desc: 默認(rèn)全局異常處理。
*/
@RestControllerAdvice
public class RestExceptionHandler {
/**
* 默認(rèn)全局異常處理。
* @param e the e
* @return ResultData
*/
@ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
public ResponseEntity<Result<String>> handleValidatedException(Exception e) {
Result<String> result = null;
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ex =(MethodArgumentNotValidException) e;
result = Result.failure(HttpStatus.BAD_REQUEST.value(),
ex.getBindingResult().getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(";"))
);
} else if (e instanceof ConstraintViolationException){
ConstraintViolationException ex = (ConstraintViolationException) e;
result = Result.failure(HttpStatus.BAD_REQUEST.value(),
ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining(";"))
);
}else if (e instanceof BindException) {
BindException ex = (BindException ) e;
result = Result.failure(HttpStatus.BAD_REQUEST.value(),
ex.getAllErrors().stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(";"))
);
}
return new ResponseEntity<>(result,HttpStatus.BAD_REQUEST);
}
}
美化之后錯(cuò)誤信息提示更加友好

3.自定義參數(shù)校驗(yàn)
雖然Spring Validation 提供的注解基本上夠用,但是面對(duì)復(fù)雜的定義,我們還是需要自己定義相關(guān)注解來(lái)實(shí)現(xiàn)自動(dòng)校驗(yàn)。
比如上面實(shí)體類中添加的sex性別屬性,只允許前端傳遞傳 M,F(xiàn) 這2個(gè)枚舉值,如何實(shí)現(xiàn)呢?
3.1創(chuàng)建自定義注解
package com.didiplus.common.annotation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/26
* Desc:
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Repeatable(EnumString.List.class)
@Documented
@Constraint(validatedBy = EnumStringValidator.class)//標(biāo)明由哪個(gè)類執(zhí)行校驗(yàn)邏輯
public @interface EnumString {
String message() default "value not in enum values.";
Class<?>[] groups() default {};
Class<? extends Payload>[] palyload() default {};
/**
* @return date must in this value array
*/
String[] value();
/**
* Defines several {@link EnumString} annotations on the same element.
*
* @see EnumString
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@interface List {
EnumString[] value();
}
}3.2自定義校驗(yàn)邏輯
package com.didiplus.common.annotation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.List;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/26
* Desc:
*/
public class EnumStringValidator implements ConstraintValidator<EnumString,String> {
private List<String> enumStringList;
@Override
public void initialize(EnumString constraintAnnotation) {
enumStringList = Arrays.asList(constraintAnnotation.value());
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if(value == null) {
return true;
}
return enumStringList.contains(value);
}
}3.3在字段上增加注解
@ApiModelProperty(value = "性別")
@EnumString(value = {"F","M"}, message="性別只允許為F或M")
private String sex;3.4體驗(yàn)效果

4.分組校驗(yàn)
一個(gè)對(duì)象在新增的時(shí)候某些字段是必填,在更新是有非必填。如上面的 SysDictType中id 屬性在新增操作時(shí)都是必填。 面對(duì)這種場(chǎng)景你會(huì)怎么處理呢?
其實(shí) Validator校驗(yàn)框架已經(jīng)考慮到了這種場(chǎng)景并且提供了解決方案,就是分組校驗(yàn)。 要使用分組校驗(yàn),只需要三個(gè)步驟:
4.1定義分組接口
package com.didiplus.common.base;
import javax.validation.groups.Default;
/**
* Author: didiplus
* Email: 972479352@qq.com
* CreateTime: 2022/4/26
* Desc:
*/
public interface ValidGroup extends Default {
interface Crud extends ValidGroup{
interface Create extends Crud{
}
interface Update extends Crud{
}
interface Query extends Crud{
}
interface Delete extends Crud{
}
}
}4.2在模型中給參數(shù)分配分組
@Null(groups = ValidGroup.Crud.Create.class)
@NotNull(groups = ValidGroup.Crud.Update.class,message = "字典ID不能為空")
@ApiModelProperty("ID")
private String id;4.3體現(xiàn)效果


以上就是SpringBoot進(jìn)行參數(shù)校驗(yàn)的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot參數(shù)校驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring動(dòng)態(tài)監(jiān)聽(tīng)Nacos配置中心key值變更的實(shí)現(xiàn)方法
Nacos本身提供支持監(jiān)聽(tīng)配置變更的操作,但在使用起來(lái),個(gè)人感覺(jué)不是很友好,無(wú)法精確到某個(gè)key的變更監(jiān)聽(tīng),所以本文小編給大家介紹了Spring動(dòng)態(tài)監(jiān)聽(tīng)Nacos配置中心key值變更的實(shí)現(xiàn)方法,需要的朋友可以參考下2024-08-08
在Java的JDBC使用中設(shè)置事務(wù)回滾的保存點(diǎn)的方法
這篇文章主要介紹了在Java的JDBC使用中設(shè)置事務(wù)回滾的保存點(diǎn)的方法,JDBC是Java用于連接各種數(shù)據(jù)庫(kù)的API,需要的朋友可以參考下2015-12-12
lombok注解@Data使用在繼承類上時(shí)出現(xiàn)警告的問(wèn)題及解決
Lombok的@Data注解簡(jiǎn)化了實(shí)體類代碼,但在子類中使用時(shí)會(huì)出現(xiàn)警告,指出equals和hashCode方法不會(huì)考慮父類屬性,解決方法有兩種:一是在父類上使用@EqualsAndHashCode(callSuper=true)注解;二是通過(guò)配置lombok.config文件,均能有效解決警告問(wèn)題2024-10-10
解決spring?data?jpa?saveAll()?保存過(guò)慢問(wèn)題
這篇文章主要介紹了解決spring?data?jpa?saveAll()保存過(guò)慢問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringCloud?Hystrix?斷路器的實(shí)現(xiàn)
本文主要介紹了SpringCloud?Hystrix?斷路器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
sharding-jdbc 兼容 MybatisPlus動(dòng)態(tài)數(shù)據(jù)源的配置方法
這篇文章主要介紹了sharding-jdbc 兼容 MybatisPlus動(dòng)態(tài)數(shù)據(jù)源的配置方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-07-07
SpringBoot配置Profile實(shí)現(xiàn)多環(huán)境支持
這篇文章主要介紹了SpringBoot配置Profile實(shí)現(xiàn)多環(huán)境支持操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
MyBatis配置的應(yīng)用與對(duì)比jdbc的優(yōu)勢(shì)
這篇文章主要介紹了MyBatis配置的使用與相對(duì)于jdbc的優(yōu)勢(shì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

