測試開發專題:如何在spring-boot中進行引數校驗

測試軒發表於2020-05-14

上文我們討論了spring-boot如何去獲取前端傳遞過來的引數,那傳遞過來總不能直接使用,需要對這些引數進行校驗,符合程式的要求才會進行下一步的處理,所以本篇文章我們主要討論spring-boot中如何進行引數校驗。

lombok使用介紹

在介紹引數校驗之前,先來了解一下lombok的使用,因為在接下來的例項中或有不少的物件建立,但是又不想寫那麼多的getter和setter,所以先介紹一下這個很強大的工具的使用。

Lombok 是一個可以通過簡單的註解形式來幫助我們簡化消除一些必須有但顯得很臃腫的Java程式碼的工具,通過使用對應的註解,可以在編譯原始碼的時候生成對應的方法。

新增maven依賴

在pom檔案中新增如下內容:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

基礎註解

@Getter給類增加get方法

@Setter給類增加set方法

@Builder給類增加構建者模式

@AllArgsConstructor給類增加全參構造方法

@NoArgsConstructor給類增加無引數構造方法

@RequiredArgsConstructor按照必填屬性增加構造方法

@NonNull變數值不能為空

這裡只簡單列一下常用註解的含義,具體的使用方式在引數校驗的例項中體現。

實戰

上篇文章中我們用BannerCreateDto這個物件了來接收前端傳遞的引數,那時是手動新增的get和set方法,這裡我們用lombok註解來簡化掉之前的樣板程式碼:

@Setter
@Getter
public class BannerCreateDto {
    private String name;
    private Integer pos;
}

介面的定義還是和之前一樣。不同做任何修改:

@PostMapping(value = "/create")
public Map<String, Object> createBanner(@RequestBody BannerCreateDto dto){
    Map<String, Object> res = new HashMap<>();
    res.put("id", 10000);
    res.put("name", dto.getName());
    res.put("pos", dto.getPos());
    return res;
}

重新執行程式,訪問介面

image-20200513215504732還是和之前一樣,能夠請求成功並正常的返回資料。

一般情況下,我們會針對返回的資料,來單獨定義物件來進行描述,這裡我們也定義一個

@Builder
@Getter
public class BannerResponseDto {
    private int id;
    private String name;
    private Integer pos;
}

這裡用到了@Builder、@Getter,在介面中構造物件並返回:

@PostMapping(value = "/create")
public BannerResponseDto createBanner(@RequestBody BannerCreateDto dto){

    return BannerResponseDto.builder()
            .id(500)
            .name(dto.getName())
            .pos(dto.getPos())
            .build();
}

可以看到lombok的@Builder註解,能夠讓類通過構建者模式去建立物件,省去了大量的set程式碼,而且可讀性也很好。

訪問介面,看看資料返回的時候正常:

image-20200513220111657

與之前是一樣的,能夠正常返回資料,那接下來我們就正式看一下,spring-boot如何進行引數校驗了。

引數校驗

引數校驗就是說對前端傳過來的資料進行合理性校驗,看他能否滿足我們的業務規則,那這些對引數進行校驗的程式碼是該放在那裡呢,是在Controller裡還是說單獨存放,又獲取採用其他什麼方式呢?

引數校驗該怎麼做

首先要明確的一點,在Controller,不應該有大量邏輯判斷的程式碼,為什麼呢,我們可想想當引數較多的時候,對每個引數進行合理性校驗的話,那程式碼量該有多少,那就會嚴重汙染Controller,導致維護起來是很艱難的,所以應該要有一個合理的機制能把校驗的程式碼抽離出來,從而保證Controller的簡潔性。

在java的世界裡有這麼個概念叫做 JSR,是Java Specification Requests的首字母縮寫,是程式語言Java規範請求或者說是Java語言的說明書,既然是說明書那就一定有各個版本,在JSR-303版本中,提出了Bean Validation的驗證規範,目前主要有兩個兩個框架實現了Bean Validation規範,一個事自帶的javax.validation.api和hibernate-validator框架,而hibernate-validator框架應用的更加廣泛一點。

那我們就用這種Bean Validation這種驗證框架進行引數的驗證

實戰

@RestController
@Validated
public class BannerController {


    @GetMapping("/v3/banner")
    public Map<String, Object> getBannerDetailV2(@RequestParam Integer id, @RequestParam @Max(10) Integer pos){
        Map<String, Object> body = new HashMap<>();
        body.put("id", id);
        body.put("pos", pos);
        return body;
    }
}

上面程式碼中,@Max(10)註解來驗證輸入引數的pos,限制其輸入引數最大值為10,執行程式我們來測試一下:

image-20200513230808654

訪問介面http://localhost:8081/v3/banner?id=12&pos=33後,看到我們控制檯的輸出提示輸入不能超過10,這裡的這個message不是我寫的哈,這是java國際化後的效果能夠根據你所在地區決定顯示什麼語言。

當然這裡我們也可以自定義錯誤的message:

@GetMapping("/v3/banner")
public Map<String, Object> getBannerDetailV2(@RequestParam Integer id,
                                             @RequestParam @Max(value = 10, message = "超過10了,趕緊看看哇") Integer pos){
    Map<String, Object> body = new HashMap<>();
    body.put("id", id);
    body.put("pos", pos);
    return body;
}

還是上面的請求路徑,看看控制檯輸出:

image-20200513231126756

可以看到控制檯輸出了我們自定義的內容。這裡有一點要注意,要想使得校驗生效,比如在Controller上方打上@Validated註解,至於為什麼我們後面分解

上面的驗證都是比較基礎的資料型別,但是如果現在要有驗證更加複雜一點的java物件呢,又該如何操作,那接下來我們再看看這部分的內容。

java物件進行驗證

單個物件

還是用上面的BannerResponseDto來進行演示

import org.hibernate.validator.constraints.Length;
@Setter
@Getter
public class BannerCreateDto {
    @Length(min = 2, max = 4, message = "banner名稱必須是2-10個字元")
    private String name;
    private Integer pos;
}

對於這些基礎型別的成員變數仍然使用這些基礎註解進行校驗定義,上面我們使用了 @Length註解來定義banner名稱的字元長度範圍,並定義發生錯誤時提示的message,這裡還需要在Controller裡額外的處理一下:

@PostMapping("/v3/banner/create")
public BannerResponseDto createBanner(@RequestBody @Validated BannerCreateDto dto){

    return BannerResponseDto.builder()
            .id(500)
            .name(dto.getName())
            .pos(dto.getPos())
            .build();
}

@Validated BannerCreateDto這裡必須要加@Validated註解,否則無法觸發校驗機制。

巢狀

如果某個類的成員變數也是一個自定義物件,那校驗該是什麼樣的呢,下面我們來看一下。

先定義一個新的物件,用來接收banner到的素材資訊

@Getter
@Setter
public class MaterialDto {
    @Length(min = 2, max = 5, message = "素材的名稱長度範圍必須在2-5之內")
    private String name;
}

然後banner物件增加一個成員變數

@Setter
@Getter
public class BannerCreateDto {
    @Length(min = 2, max = 4, message = "banner名稱必須是2-10個字元")
    private String name;
    private Integer pos;

    @Valid
    private MaterialDto materialDto;
}

這裡有一點,要想使得這種級聯的關係能夠觸發校驗機制,必須 @Valid註解進行標記,我們來請求一下url看看效果

image-20200513234439584

可以看到校驗沒通過,再看看控制檯輸出內容:

image-20200513234506001

輸出了我們定義的錯誤資訊。

總結

本篇文章主要介紹了裡面lombok的使用,以及校驗規範介紹和校驗框架基本註解的使用,還有自定義物件校驗,下篇文章我們將通過自定義註解來實現更加個性化的校驗規則,敬請期待。

歡迎大家去 我的部落格 瞅瞅,裡面有更多關於測試實戰的內容哦!!

相關文章