SpringBoot如何優(yōu)雅實(shí)現(xiàn)接口參數(shù)驗(yàn)證
1. 為什么需要參數(shù)驗(yàn)證
在應(yīng)用程序的開發(fā)中,我們經(jīng)常會(huì)遇到需要保證傳入?yún)?shù)的正確性的情況。例如,當(dāng)我們?cè)谧?cè)用戶時(shí),需要驗(yàn)證用戶填寫的表單數(shù)據(jù)是否符合規(guī)范,是否缺少必填字段,或者格式是否正確,等等。如果不對(duì)參數(shù)進(jìn)行驗(yàn)證,我們的應(yīng)用程序可能會(huì)因此受到攻擊或者運(yùn)行出錯(cuò)。
為了保證參數(shù)的正確性,我們需要使用參數(shù)驗(yàn)證機(jī)制,來檢測(cè)并處理傳入的參數(shù)格式是否符合規(guī)范。
2. 如何進(jìn)行參數(shù)驗(yàn)證
Spring Boot內(nèi)置了一個(gè)很強(qiáng)大的參數(shù)驗(yàn)證框架——JSR 303 Bean Validation 標(biāo)準(zhǔn),它可以對(duì)我們的實(shí)體類參數(shù)進(jìn)行校驗(yàn),并且可以給我們提供詳細(xì)的錯(cuò)誤提示信息。
具體步驟如下:
1. 添加依賴
在 pom.xml
文件中添加以下依賴:
<!-- 添加 JSR-303 Bean Validation 依賴 --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <!-- Hibernate Validator 的實(shí)現(xiàn) --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.5.Final</version> </dependency>
2. 在實(shí)體類中添加參數(shù)驗(yàn)證注解
public class User { @NotNull(message="用戶名不能為空") private String username; @NotNull(message="密碼不能為空") @Size(min=6, max=20, message="密碼長(zhǎng)度應(yīng)該在6到20位") private String password; // getter 和 setter 方法 }
在實(shí)體類中使用注解,如上代碼所示,可以指定當(dāng)前字段是否可以為 null,以及字符串的長(zhǎng)度和格式等信息,如果傳入的參數(shù)不符合預(yù)定的規(guī)則,在校驗(yàn)時(shí)就會(huì)產(chǎn)生相應(yīng)的提示。
常用的參數(shù)驗(yàn)證注解:
- @NotNull:驗(yàn)證注解的元素值不為null;
- @NotEmpty:驗(yàn)證注解的元素值不為null,且String類型也不為 "";
- @NotBlank:驗(yàn)證注解的元素值不為null,且允許去除兩端空格后不為空;
- @Size:驗(yàn)證注解的元素值長(zhǎng)度在min和max范圍內(nèi);
- @Digits:驗(yàn)證注解元素值的整數(shù)位數(shù)和小數(shù)位數(shù)是否符合預(yù)期;
- @Range:驗(yàn)證注解元素值的大小是否在指定范圍內(nèi);
- @Email:驗(yàn)證注解的元素值是否為Email格式。
3. 在Controller中加入對(duì)參數(shù)的驗(yàn)證
@RestController @RequestMapping("/user") public class UserController { @PostMapping("/register") public CommonResult<User> register(@RequestBody @Validated User user) { return CommonResult.success(user); } }
在Controller層進(jìn)行參數(shù)校驗(yàn)時(shí),加上 @Validated
注解以告訴Spring進(jìn)行參數(shù)校驗(yàn),@RequestBody
注解用于將請(qǐng)求體中的JSON數(shù)據(jù)綁定到實(shí)體類中。
4. 定義全局異常處理器,并定義返回結(jié)果CommonResult
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(value = MethodArgumentNotValidException.class) public CommonResult<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex){ List<ObjectError> errors = ex.getBindingResult().getAllErrors(); StringBuilder errorMsg = new StringBuilder(); errors.forEach(error -> errorMsg.append(error.getDefaultMessage()).append("; ")); return CommonResult.fail(ResultCode.PARAM_VALID_ERROR.getCode(), errorMsg.toString(), null); } @ExceptionHandler(value = Exception.class) public CommonResult<Object> handleException(Exception ex){ log.error("系統(tǒng)發(fā)生異常:", ex); return CommonResult.fail(ResultCode.SYSTEM_ERROR.getCode(), ResultCode.SYSTEM_ERROR.getMsg(), null); } }
在上述代碼中,我們定義了兩個(gè)異常處理方法,一個(gè)處理 MethodArgumentNotValidException 異常,一個(gè)處理其他類型的異常,使用了 @ExceptionHandler 注解將不同類型的異常映射到不同的處理方法中。
public enum ResultCode { SUCCESS(200, "操作成功"), PARAM_VALID_ERROR(400, "參數(shù)校驗(yàn)失敗"), UNAUTHORIZED(401, "未認(rèn)證"), FORBIDDEN(403, "無權(quán)限"), SYSTEM_ERROR(500, "服務(wù)器內(nèi)部錯(cuò)誤"); private int code; private String msg; ResultCode(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } } public class CommonResult<T> { private int code; private String msg; private T data; public CommonResult() {} public CommonResult(int code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public static <T> CommonResult<T> success(T data) { return new CommonResult<T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), data); } public static <T> CommonResult<T> fail(ResultCode resultCode) { return new CommonResult<T>(resultCode.getCode(), resultCode.getMsg(), null); } public static <T> CommonResult<T> fail(ResultCode resultCode, T data) { return new CommonResult<T>(resultCode.getCode(), resultCode.getMsg(), data); } // getter 和 setter 方法 }
在上述代碼中,我們使用泛型和枚舉類定義各種操作返回的枚舉值,通過封裝返回值,返回給前端統(tǒng)一的返回格式,減少重復(fù)代碼。
5. 通過Postman模擬測(cè)試參數(shù)驗(yàn)證
我們將請(qǐng)求方式設(shè)置為 POST,并將請(qǐng)求的 URL 設(shè)置為 http://localhost:8080/user/register
。另外,我們還需要設(shè)置請(qǐng)求頭的 Content-Type 為 application/json
。
我們傳入了一個(gè)用戶名為 user
,密碼為 123
的用戶并進(jìn)行請(qǐng)求,這個(gè)請(qǐng)求在參數(shù)校驗(yàn)的過程中會(huì)出現(xiàn)異常。
最終的打印結(jié)果為:
{
"code": 400,
"msg": "密碼長(zhǎng)度應(yīng)該在6到20位; ",
"data": null
}
3.自定義注解和驗(yàn)證器
在實(shí)體類中使用注解進(jìn)行參數(shù)驗(yàn)證,這種方式非常簡(jiǎn)單快捷,但對(duì)于一些復(fù)雜的邏輯驗(yàn)證可能不夠靈活。我們也可以采用編寫自定義注解和驗(yàn)證器的方式進(jìn)行參數(shù)驗(yàn)證。
比如,我們可以編寫自定義注解 @Age 和驗(yàn)證器 AgeValidator,使用這兩個(gè)自定義類對(duì)請(qǐng)求參數(shù)進(jìn)行驗(yàn)證,示例代碼如下:
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = {AgeValidator.class}) public @interface Age { String message() default "年齡不在合法范圍內(nèi)"; int minAge() default 0; int maxAge() default 150; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } public class AgeValidator implements ConstraintValidator<Age, Integer> { private int minAge; private int maxAge; @Override public void initialize(Age constraintAnnotation) { this.minAge = constraintAnnotation.minAge(); this.maxAge = constraintAnnotation.maxAge(); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { if(value == null) { return true; // 允許為空值 } if(value < minAge || value > maxAge) { return false; // 驗(yàn)證不通過 } return true; // 驗(yàn)證通過 } } public class User { @NotNull(message="用戶名不能為空") private String username; @Age(message="年齡不在合法范圍內(nèi)", minAge=0, maxAge=120) private Integer age; // getter 和 setter 方法 }
如上代碼展示了如何使用自定義注解和驗(yàn)證器進(jìn)行參數(shù)驗(yàn)證,使用自定義注解時(shí),我們可以指定年齡的最小值和最大值,并使用 AgeValidator 在實(shí)體類中對(duì)年齡進(jìn)行驗(yàn)證。
4.小結(jié)
使用參數(shù)驗(yàn)證機(jī)制可以有效地提高我們應(yīng)用程序的健壯性和安全性,同時(shí)也可以節(jié)省我們進(jìn)行參數(shù)校驗(yàn)的時(shí)間和精力。Spring Boot 內(nèi)置的參數(shù)驗(yàn)證框架 JSR 303 Bean Validation 標(biāo)準(zhǔn)可以幫助我們簡(jiǎn)單快速地完成參數(shù)校驗(yàn),結(jié)合全局異常處理器和自定義的響應(yīng)結(jié)果類,我們可以快速反饋請(qǐng)求信息的正確性,并在出現(xiàn)錯(cuò)誤時(shí)提供詳細(xì)的錯(cuò)誤提示信息,非常方便實(shí)用。
以上就是SpringBoot如何優(yōu)雅實(shí)現(xiàn)接口參數(shù)驗(yàn)證的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot接口參數(shù)驗(yàn)證的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Springboot中攔截GET請(qǐng)求獲取請(qǐng)求參數(shù)驗(yàn)證合法性核心方法
- SpringBoot validator參數(shù)驗(yàn)證restful自定義錯(cuò)誤碼響應(yīng)方式
- SpringBoot整合Hibernate Validator實(shí)現(xiàn)參數(shù)驗(yàn)證功能
- Spring Boot利用JSR303實(shí)現(xiàn)參數(shù)驗(yàn)證的方法實(shí)例
- Kotlin + Spring Boot 請(qǐng)求參數(shù)驗(yàn)證的代碼實(shí)例
- Spring?Boot常用的參數(shù)驗(yàn)證技巧和使用方法
相關(guān)文章
SpringBoot開發(fā)技巧之使用AOP記錄日志示例解析
這篇文章主要為大家介紹了SpringBoot開發(fā)技巧之如何利用AOP記錄日志的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10Idea 搭建Spring源碼環(huán)境的超詳細(xì)教程
這篇文章主要介紹了Idea 搭建Spring源碼環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10