溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

發(fā)布時(shí)間:2021-05-25 14:09:33 來(lái)源:億速云 閱讀:144 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)SpringBoot中參數(shù)校驗(yàn)的方法有哪些的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

一、前言

在 Web 開(kāi)發(fā)中經(jīng)常需要對(duì)前端傳過(guò)來(lái)的參數(shù)進(jìn)行校驗(yàn),例如格式校驗(yàn)、非空校驗(yàn)等,基本上每個(gè)接口都需要進(jìn)行校驗(yàn)。如果使用常規(guī)的 IF ELSE 進(jìn)行校驗(yàn),隨著參數(shù)越來(lái)越多,校驗(yàn)邏輯的冗余度也越來(lái)越高,導(dǎo)致維護(hù)性變差。在 Java 中定義了一套基于注解的數(shù)據(jù)校驗(yàn)規(guī)范 Bean Validation ,通過(guò)一些簡(jiǎn)單的注解就能完成必要的邏輯校驗(yàn),相對(duì)來(lái)說(shuō)就方便了很多。而 Bean Validation 只是規(guī)范,并沒(méi)有具體的實(shí)現(xiàn),Hibernate 提供了具體的實(shí)現(xiàn),也即 Hibernate Validator ,這個(gè)也是目前使用得比較多的驗(yàn)證器了。

二、注解介紹

validator 內(nèi)置注解

  • @Null 被注釋的元素必須為 null

  • @NotNull 被注釋的元素必須不為 null

  • @AssertTrue 被注釋的元素必須為 true

  • @AssertFalse 被注釋的元素必須為 false

  • @Min(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值

  • @Max(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值

  • @DecimalMin(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須大于等于指定的最小值

  • @DecimalMax(value) 被注釋的元素必須是一個(gè)數(shù)字,其值必須小于等于指定的最大值

  • @Size(max, min) 被注釋的元素的大小必須在指定的范圍內(nèi)

  • @Digits (integer, fraction) 被注釋的元素必須是一個(gè)數(shù)字,其值必須在可接受的范圍內(nèi)

  • @Past 被注釋的元素必須是一個(gè)過(guò)去的日期

  • @Future 被注釋的元素必須是一個(gè)將來(lái)的日期

  • @Pattern(value) 被注釋的元素必須符合指定的正則表達(dá)式

Hibernate Validator 附加的 constraint

  • @Email 被注釋的元素必須是電子郵箱地址

  • @Length 被注釋的字符串的大小必須在指定的范圍內(nèi)

  • @NotEmpty 被注釋的字符串的必須非空

  • @Range 被注釋的元素必須在合適的范圍內(nèi)

  • @NotBlank 驗(yàn)證字符串非 null ,且長(zhǎng)度必須大于0

注意

  • @NotNull 用于驗(yàn)證對(duì)象是否不為 null ,無(wú)法檢測(cè)長(zhǎng)度為0的字符串;

  • @NotEmpty 用于 String、Map 或者數(shù)組等集合類型不能為 null 且長(zhǎng)度必須大于0;

  • @NotBlank 只能用于String,不能為 null ,且調(diào)用 trim() 后,長(zhǎng)度必須大于0;

校驗(yàn)字符串是否為空,使用 @NotNull ,只有參數(shù)不傳的時(shí)候才會(huì)檢測(cè)到,傳了空值(例如空字符串)仍然可以通過(guò)校驗(yàn),因此應(yīng)該使用 @NotBlank

三、添加依賴

SpringBoot 中 Bean Validation 已經(jīng)集成在 starter-web 中,因此無(wú)需再添加依賴。但是本人實(shí)際測(cè)試發(fā)現(xiàn),直接使用好像不行,因此添加了如下依賴:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

四、創(chuàng)建用于校驗(yàn)的實(shí)體類

創(chuàng)建一個(gè) validator 目錄,在里面創(chuàng)建一個(gè) UserDTO 類:

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

本來(lái)想直接復(fù)用之前創(chuàng)建的 entity 類,但是后來(lái)想了下,entity 用于建立數(shù)據(jù)庫(kù)的映射關(guān)系,字段跟數(shù)據(jù)表是一一對(duì)應(yīng)的,而這里的 validator 是用于校驗(yàn)前端傳過(guò)來(lái)的參數(shù),字段跟前端傳的參數(shù)是對(duì)應(yīng)的,因此不能復(fù)用,需要單獨(dú)寫(xiě)一個(gè) validator 類。

順便提一下,在 RestController 中使用自己定義的對(duì)象,需要有 setter、getter 之類的方法,或者使用 lombok 的 @Data 注解。如果不加的話會(huì)報(bào)錯(cuò):

No converter found for return value of type: class validator.UserDTO

使用 getter、setter 方法如下:

public class UserDTO {
	private String username;
	private Integer age;

	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}

	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

使用 lombok 的 @Data 注解如下,代碼與上面等效:

@Data
public class UserDTO {
	private String username;
	private Integer age;
}

五、寫(xiě)一個(gè)測(cè)試用的接口

添加一個(gè) POST 接口,從請(qǐng)求體中獲取參數(shù),然后原封不動(dòng)返回過(guò)去(主要是用來(lái)測(cè)試參數(shù)校驗(yàn)的,這里接口邏輯并不重要)

@PostMapping("validateUser")
public UserDTO userValidate(@RequestBody UserDTO userDTO) {
    return userDTO;
}

六、在實(shí)體類中添加注解

給需要校驗(yàn)的參數(shù)添加注解:

@Data
public class UserDTO {
    @NotBlank(message = "用戶名不能為空")
    private String username;

    @NotBlank(message = "手機(jī)號(hào)不能為空")
    private String mobile;

    @NotNull(message = "性別不能為空")
    private Integer sex;

    @NotNull(message = "年齡不能為空")
    private Integer age;

    @NotBlank(message = "郵箱不能為空")
    @Email(message = "郵箱格式錯(cuò)誤")
    private String email;
}

七、在 controller 方法中添加 Validated 注解

然后需要在 controller 方法體添加 @Validated ,不加 @Validated 校驗(yàn)會(huì)不起作用。

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

用下面的數(shù)據(jù)測(cè)試一下:

{
    "username": "",
    "mobile": "2333",
    "sex": 0,
    "age": 0,
    "email": "233@dby.com"
}

可以看到校驗(yàn)是成功了,但是后臺(tái)拋了一個(gè)異常:

Validation failed for argument [0] in public validator.UserDTO com.hhlnyfz.hhlnyfz.HelloController.userValidate(validator.UserDTO): [Field error in object ‘userDTO' on field ‘username': rejected value []; codes [NotBlank.userDTO.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userDTO.username,username]; arguments []; default message [username]]; default message [用戶名不能為空]] ]

然后返回參數(shù)并不理想,前端也并不容易處理返回參數(shù):

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

八、添加全局異常處理

上面這種情況需要添加一下全局異常處理,這樣比較規(guī)范。創(chuàng)建一個(gè) GlobalExceptionHandler 類,在類的上面添加 @RestControllerAdvice 注解,然后添加如下代碼:

/**
 * 全局異常處理類
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 捕獲 MethodArgumentNotValidException 異常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public HashMap<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 400);
        map.put("msg", e.getMessage());
        map.put("url", request.getRequestURL());
        return map;
    }

    // 其他異常處理方法
}

這邊 @ExceptionHandler 注解中的 MethodArgumentNotValidException.class 用于捕獲請(qǐng)求參數(shù)異常。如果是 Exception.class 表示捕獲全部異常。不要用一個(gè)方法處理所有的異常,而是一個(gè)方法處理一種異常。如果需要處理其他異常,可以在下面添加方法。

還是用剛才的測(cè)試用例,這次異常被捕獲到了,返回的內(nèi)容如下:

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

可以看到 e.getMessage() 把整個(gè)錯(cuò)誤堆棧信息全部打印出來(lái)了,但我們只需要把最后的 default message 返回給前端就行,因此改用 e.getBindingResult().getFieldError().getDefaultMessage() ,然后 IDE 給了提示:

Method invocation ‘getDefaultMessage' may produce ‘NullPointerException'

也就是說(shuō) e.getBindingResult().getFieldError() 可能會(huì)是一個(gè)空指針 null ,于是按照 IDE 的提示用 Objects.requireNonNull 包裹一下,最終代碼如下:

/**
 * 全局異常處理類
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 捕獲 MethodArgumentNotValidException 異常
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public HashMap<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 400);
        map.put("msg", Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
        map.put("url", request.getRequestURL());
        return map;
    }

    // 其他異常處理方法
}

響應(yīng)內(nèi)容如下:

SpringBoot中參數(shù)校驗(yàn)的方法有哪些

當(dāng)然這邊還是有不規(guī)范的地方,沒(méi)有用統(tǒng)一響應(yīng)體進(jìn)行返回,后面會(huì)介紹如何封裝統(tǒng)一響應(yīng)體。

九、分組校驗(yàn)

@Valid@Validated 兩個(gè)注解都可以實(shí)現(xiàn)校驗(yàn),前面的功能用 @Valid 也是可以的,但是 @Validated 功能更強(qiáng)大,可以實(shí)現(xiàn)分組校驗(yàn)。什么是分組校驗(yàn),分組校驗(yàn)實(shí)際上實(shí)現(xiàn)了實(shí)體類的復(fù)用,有時(shí)候并不希望對(duì)所有的參數(shù)都進(jìn)行校驗(yàn),例如下面這個(gè)情況:

@Data
public class Route {
	@NotNull(message = "始發(fā)地省id不能為空")
	private Integer startProvinceId;
	
	@NotNull(message = "目的地省id不能為空")
	private Integer endProvinceId;
	
	@NotBlank(message = "詳細(xì)地址不能為空")
	private String address;
}

假如在一個(gè)接口中只希望校驗(yàn) startProvinceIdaddress ,而在另一個(gè)接口中只希望校驗(yàn) endProvinceIdaddress ,這個(gè)時(shí)候就可以用分組校驗(yàn)。可以定義一個(gè)接口:

public interface ValidateGroup {
	interface RouteValidStart {}
	interface RouteValidEnd {}
}

然后在實(shí)體類中添加分組:

@Data
public class Route {
	@NotNull(groups = {RouteValidStart.class}, message = "始發(fā)地省id不能為空")
	private Integer startProvinceId;
	
	@NotNull(groups = {RouteValidEnd.class}, message = "目的地省id不能為空")
	private Integer endProvinceId;
	
	@NotBlank(groups = {RouteValidStart.class, RouteValidEnd.class}, message = "詳細(xì)地址不能為空")
	private String address;
}

然后在校驗(yàn)的時(shí)候只需要把分組傳入 @Validate 就可以實(shí)現(xiàn)指定參數(shù)的校驗(yàn):

@RequestMapping("addRoute")
public ServerResponse addRoute(@RequestBody @Validated({RouteValidStart.class}) Route route) {
	// ...
	return ServerResponse.success();
}

十、單個(gè)參數(shù)校驗(yàn)

在參數(shù)前面加上注解即可:

@PostMapping("/get")
public ReturnVO getUserInfo(@RequestParam("userId") @NotNull(message = "用戶ID不能為空") String userId){
    return new ReturnVO().success();
}

然后在 Controller 類上面增加 @Validated 注解,注意不是增加在參數(shù)前面。

springboot是什么

springboot一種全新的編程規(guī)范,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程,SpringBoot也是一個(gè)服務(wù)于框架的框架,服務(wù)范圍是簡(jiǎn)化配置文件。

感謝各位的閱讀!關(guān)于“SpringBoot中參數(shù)校驗(yàn)的方法有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI