偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

還在用 if 硬剛參數(shù)校驗(yàn)?這波操作土到掉渣!SpringBoot 高階玩法直接封神

開發(fā) 前端
使用 Spring Validation,我們可以大大減少重復(fù)的 if 語句,讓代碼更加簡潔明了,校驗(yàn)邏輯和業(yè)務(wù)邏輯分離,提高代碼的可維護(hù)性和可復(fù)用性。自定義校驗(yàn)功能更是讓我們能夠應(yīng)對各種復(fù)雜的業(yè)務(wù)需求,打造專屬的校驗(yàn)規(guī)則。全局異常處理則讓錯誤處理更加統(tǒng)一、規(guī)范,提升整個系統(tǒng)的健壯性。

兄弟們,有一個現(xiàn)象特別有意思:新手寫代碼的時候,特別喜歡用 if 語句來做參數(shù)校驗(yàn),一頓操作猛如虎,代碼寫得像瀑布。老手呢,雖然知道這樣不好,但有時候?yàn)榱粟s進(jìn)度,也不得不繼續(xù)用這種 “土方法”。咱就是說,難道就沒有更優(yōu)雅、更高效的辦法嗎?當(dāng)然有啦!今天咱就來聊聊 Spring Boot 里那些能讓參數(shù)校驗(yàn)直接 “封神” 的高階玩法。

一、傳統(tǒng)參數(shù)校驗(yàn):土味十足的 “體力活”

先說說大家最熟悉的傳統(tǒng)參數(shù)校驗(yàn)吧。假設(shè)咱們有一個用戶注冊的接口,需要校驗(yàn)用戶名、手機(jī)號、郵箱等參數(shù)。按照傳統(tǒng)做法,那就是在方法里瘋狂寫 if 語句:

public User register(String username, String phone, String email) {
    if (username == null || username.trim().length() < 3 || username.trim().length() > 20) {
        throw new IllegalArgumentException("用戶名長度必須在3到20之間");
    }
    if (phone == null || !phone.matches("^1[3-9]\\d{9}$")) {
        throw new IllegalArgumentException("手機(jī)號格式不正確");
    }
    if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
        throw new IllegalArgumentException("郵箱格式不正確");
    }
    // 接下來是業(yè)務(wù)邏輯
    User user = new User();
    user.setUsername(username);
    user.setPhone(phone);
    user.setEmail(email);
    return userService.save(user);
}

這樣的代碼看起來是不是特別 “樸實(shí)無華”?但問題可不少。首先,代碼冗余度極高,每個參數(shù)都要寫好幾行校驗(yàn)邏輯,要是參數(shù)多一點(diǎn),整個方法就變得又長又臭,跟裹腳布似的。其次,維護(hù)起來特別麻煩,要是哪天需求變了,比如用戶名長度限制改了,你得在所有用到這個校驗(yàn)的地方都改一遍,稍有不慎就會漏掉,埋下 bug 的隱患。而且,這種校驗(yàn)邏輯和業(yè)務(wù)邏輯混在一起,顯得特別混亂,就像把菜湯和米飯攪在一起吃,看著就鬧心。

再從代碼的可復(fù)用性來說,如果你在多個地方都需要校驗(yàn)手機(jī)號,難道每次都要把那段正則表達(dá)式和 if 語句復(fù)制粘貼一遍嗎?這也太 low 了吧,完全不符合咱們程序員 “DRY(Don't Repeat Yourself)” 的原則。而且,這種土味校驗(yàn)方法對于復(fù)雜的業(yè)務(wù)場景根本招架不住,比如需要多個參數(shù)之間相互校驗(yàn),或者需要結(jié)合數(shù)據(jù)庫查詢來做校驗(yàn),這時候 if 語句就顯得力不從心了,就像讓一個小學(xué)生去解高考數(shù)學(xué)題,根本搞不定。

二、Spring Validation:參數(shù)校驗(yàn)的 “正規(guī)軍”

好在 Spring 框架為我們提供了一套強(qiáng)大的參數(shù)校驗(yàn)機(jī)制 ——Spring Validation,它就像是參數(shù)校驗(yàn)領(lǐng)域的 “正規(guī)軍”,讓我們告別土味的 if 語句,走向優(yōu)雅開發(fā)的道路。

(一)基本用法:注解加持,簡潔高效

Spring Validation 主要通過一系列的注解來實(shí)現(xiàn)參數(shù)校驗(yàn),這些注解可以直接加在方法的參數(shù)上,或者加在實(shí)體類的字段上。咱們先來看一個簡單的例子,還是以用戶注冊為例,這次我們用實(shí)體類來接收參數(shù):

public class UserRegisterForm {
    @NotBlank(message = "用戶名不能為空")
    @Size(min = 3, max = 20, message = "用戶名長度必須在3到20之間")
    private String username;
    @NotBlank(message = "手機(jī)號不能為空")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機(jī)號格式不正確")
    private String phone;
    @NotBlank(message = "郵箱不能為空")
    @Email(message = "郵箱格式不正確")
    private String email;
    // 省略 getter 和 setter 方法
}

然后在控制器的方法里,加上 @Valid 注解來開啟參數(shù)校驗(yàn):

@PostMapping("/register")
public ResponseEntity<?> register(@Valid @RequestBody UserRegisterForm form, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        List<String> errorMessages = bindingResult.getAllErrors().stream()
               .map(ObjectError::getDefaultMessage)
               .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(errorMessages);
    }
    // 業(yè)務(wù)邏輯
    User user = new User();
    user.setUsername(form.getUsername());
    user.setPhone(form.getPhone());
    user.setEmail(form.getEmail());
    userService.save(user);
    return ResponseEntity.ok().build();
}

你看,這樣一來,代碼是不是清爽多了?原來需要好幾行 if 語句才能完成的校驗(yàn),現(xiàn)在只需要在實(shí)體類的字段上加上對應(yīng)的注解就行了,校驗(yàn)邏輯和業(yè)務(wù)邏輯也分開了,再也不用像以前那樣 “糾纏不清”。而且這些注解都是 Spring 自帶的,常用的校驗(yàn)場景基本都能覆蓋,比如 @NotNull 用于非空校驗(yàn),@Min 和 @Max 用于數(shù)值范圍校驗(yàn),@Email 專門用于郵箱格式校驗(yàn),簡直不要太方便。

(二)分組校驗(yàn):不同場景,精準(zhǔn)校驗(yàn)

在實(shí)際開發(fā)中,我們經(jīng)常會遇到這樣的情況:同一個實(shí)體類在不同的業(yè)務(wù)場景下,需要校驗(yàn)的參數(shù)不一樣。比如用戶注冊時,需要校驗(yàn)所有的必填字段,而用戶修改個人信息時,可能有些字段是允許為空的。這時候,分組校驗(yàn)就派上用場了。

Spring Validation 支持分組校驗(yàn),我們可以通過定義不同的分組接口,來指定不同場景下需要校驗(yàn)的字段。首先,定義一個分組接口:

public interface RegisterGroup {
}
public interface UpdateGroup {
}

然后在實(shí)體類的字段上指定分組:

public class UserForm {
    @NotBlank(message = "用戶名不能為空", groups = {RegisterGroup.class})
    private String username;
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機(jī)號格式不正確", groups = {RegisterGroup.class, UpdateGroup.class})
    private String phone;
    @Email(message = "郵箱格式不正確", groups = {UpdateGroup.class})
    private String email;
    // 省略 getter 和 setter 方法
}

在控制器方法中,指定需要校驗(yàn)的分組:

@PostMapping("/register")
public ResponseEntity<?> register(@Validated(RegisterGroup.class) @RequestBody UserForm form, BindingResult bindingResult) {
    // 注冊場景的校驗(yàn)和業(yè)務(wù)邏輯
}
@PutMapping("/update")
public ResponseEntity<?> update(@Validated(UpdateGroup.class) @RequestBody UserForm form, BindingResult bindingResult) {
    // 更新場景的校驗(yàn)和業(yè)務(wù)邏輯
}

這樣,在注冊場景下,就會按照 RegisterGroup 分組來校驗(yàn),用戶名、手機(jī)號都會被校驗(yàn);而在更新場景下,就會按照 UpdateGroup 分組來校驗(yàn),手機(jī)號和郵箱會被校驗(yàn),用戶名允許為空(因?yàn)樵?UpdateGroup 分組中沒有對用戶名進(jìn)行校驗(yàn))。分組校驗(yàn)就像是給不同的業(yè)務(wù)場景定制了專屬的校驗(yàn) “套餐”,精準(zhǔn)又高效,再也不用為了不同場景寫不同的實(shí)體類或者重復(fù)寫校驗(yàn)邏輯了,簡直是開發(fā)中的 “貼心小棉襖”。

(三)方法級校驗(yàn):復(fù)雜邏輯,輕松搞定

雖然字段級的注解已經(jīng)能滿足大部分的校驗(yàn)需求,但對于一些復(fù)雜的校驗(yàn)邏輯,比如需要多個參數(shù)之間相互校驗(yàn),或者需要結(jié)合業(yè)務(wù)邏輯進(jìn)行校驗(yàn),這時候就需要用到方法級的校驗(yàn)了。Spring Validation 允許我們在方法上添加校驗(yàn)注解,或者自定義方法級的校驗(yàn)邏輯。

比如,我們有一個訂單創(chuàng)建的方法,需要校驗(yàn)訂單金額和優(yōu)惠金額的關(guān)系,優(yōu)惠金額不能超過訂單金額,而且訂單金額和優(yōu)惠金額都不能為負(fù)數(shù)。這時候,我們可以在方法上添加校驗(yàn)邏輯:

public class Order {
    private BigDecimal amount;
    private BigDecimal discount;
    // 省略 getter 和 setter 方法
    @AssertTrue(message = "優(yōu)惠金額不能超過訂單金額")
    public boolean isDiscountValid() {
        return discount == null || amount == null || discount.compareTo(amount) <= 0;
    }
    @AssertTrue(message = "訂單金額和優(yōu)惠金額不能為負(fù)數(shù)")
    public boolean isAmountNonNegative() {
        return amount == null || amount.compareTo(BigDecimal.ZERO) >= 0 && (discount == null || discount.compareTo(BigDecimal.ZERO) >= 0);
    }
}

然后在控制器方法中,對訂單對象進(jìn)行校驗(yàn):

@PostMapping("/orders")
public ResponseEntity<?> createOrder(@Valid @RequestBody Order order, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        // 處理校驗(yàn)錯誤
    }
    // 業(yè)務(wù)邏輯
    return ResponseEntity.ok().build();
}

這樣,通過方法級的校驗(yàn),我們就可以處理復(fù)雜的參數(shù)之間的關(guān)系校驗(yàn),而不用在控制器方法里寫一堆繁瑣的 if 語句了。方法級校驗(yàn)就像是一把 “萬能鑰匙”,能打開復(fù)雜校驗(yàn)場景的大門,讓我們的代碼更加簡潔、優(yōu)雅。

三、自定義校驗(yàn):打造專屬的校驗(yàn) “神器”

雖然 Spring 自帶的校驗(yàn)注解已經(jīng)很強(qiáng)大了,但在實(shí)際開發(fā)中,我們難免會遇到一些特殊的校驗(yàn)需求,比如校驗(yàn)一個用戶是否存在于數(shù)據(jù)庫中,或者校驗(yàn)一個文件是否符合特定的格式。這時候,我們就需要自定義校驗(yàn)注解和校驗(yàn)器了,打造屬于自己的校驗(yàn) “神器”。

(一)自定義校驗(yàn)注解:隨心所欲,定義規(guī)則

首先,我們需要定義一個自定義的校驗(yàn)注解。比如,我們要校驗(yàn)一個手機(jī)號是否已經(jīng)被注冊,我們可以定義一個 @UniquePhone 注解:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniquePhoneValidator.class)
public @interface UniquePhone {
    String message() default "手機(jī)號已被注冊";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

這里,@Target 注解指定了這個注解可以用在字段和參數(shù)上,@Retention 注解指定了注解在運(yùn)行時有效,@Constraint 注解指定了對應(yīng)的校驗(yàn)器 UniquePhoneValidator。

(二)自定義校驗(yàn)器:實(shí)現(xiàn)邏輯,精準(zhǔn)校驗(yàn)

接下來,我們需要實(shí)現(xiàn)這個校驗(yàn)器 UniquePhoneValidator,它需要繼承 ConstraintValidator<UniquePhone, String> 接口,并重寫 initialize 和 isValid 方法:

public class UniquePhoneValidator implements ConstraintValidator<UniquePhone, String> {

    @Autowired
    private UserService userService;

    @Override
    public void initialize(UniquePhone constraintAnnotation) {
        // 初始化操作,這里可以獲取注解的參數(shù)等
    }

    @Override
    public boolean isValid(String phone, ConstraintValidatorContext context) {
        if (phone == null) {
            returntrue; // 如果允許為空,可以根據(jù)實(shí)際情況處理
        }
        User user = userService.findByPhone(phone);
        return user == null;
    }
}

在 isValid 方法中,我們通過調(diào)用 UserService 的 findByPhone 方法來查詢數(shù)據(jù)庫,判斷該手機(jī)號是否已經(jīng)存在。如果存在,就返回 false,表示校驗(yàn)不通過;如果不存在,就返回 true,表示校驗(yàn)通過。

(三)使用自定義校驗(yàn)注解

定義好自定義校驗(yàn)注解和校驗(yàn)器之后,我們就可以在實(shí)體類中使用它了:

public class UserRegisterForm {
    // 其他字段的校驗(yàn)注解
    @UniquePhone(message = "手機(jī)號已被注冊")
    private String phone;

    // 省略 getter 和 setter 方法
}

然后在控制器方法中,依然使用 @Valid 注解來開啟校驗(yàn),就像使用 Spring 自帶的注解一樣方便。這樣,我們就實(shí)現(xiàn)了一個基于數(shù)據(jù)庫查詢的自定義校驗(yàn),滿足了特殊的業(yè)務(wù)需求。自定義校驗(yàn)注解和校驗(yàn)器的組合,讓我們可以根據(jù)自己的業(yè)務(wù)需求,靈活地定義各種復(fù)雜的校驗(yàn)規(guī)則,不再受限于 Spring 自帶的注解。這就好比我們可以自己動手打造一把適合自己的 “倚天劍”,在參數(shù)校驗(yàn)的江湖里所向披靡。

四、全局異常處理:讓錯誤處理更優(yōu)雅

前面我們已經(jīng)學(xué)會了如何使用 Spring Validation 來進(jìn)行參數(shù)校驗(yàn),并且通過 BindingResult 來獲取校驗(yàn)錯誤信息。但是,每次都在控制器方法里處理 bindingResult.hasErrors() 這種情況,難免會顯得代碼冗余,而且不夠優(yōu)雅。這時候,我們可以使用 Spring Boot 的全局異常處理機(jī)制,來統(tǒng)一處理參數(shù)校驗(yàn)錯誤,讓代碼更加簡潔、整潔。

首先,我們定義一個全局異常處理類,使用 @RestControllerAdvice 和 @ExceptionHandler 注解:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<String> errorMessages = ex.getBindingResult().getAllErrors().stream()
               .map(ObjectError::getDefaultMessage)
               .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(errorMessages);
    }

    // 其他異常處理方法
}

這樣,當(dāng)參數(shù)校驗(yàn)失敗時,就會拋出 MethodArgumentNotValidException 異常,全局異常處理類會捕獲這個異常,并將校驗(yàn)錯誤信息以統(tǒng)一的格式返回給客戶端。這樣一來,我們的控制器方法就變得更加簡潔了,不再需要每次都處理 bindingResult,只需要專注于業(yè)務(wù)邏輯即可。全局異常處理就像是一個 “管家”,幫我們統(tǒng)一管理各種異常情況,包括參數(shù)校驗(yàn)錯誤,讓我們的代碼更加規(guī)范、優(yōu)雅,維護(hù)起來也更加方便。

五、總結(jié):告別土味校驗(yàn),擁抱優(yōu)雅開發(fā)

說了這么多,咱們來總結(jié)一下。傳統(tǒng)的 if 語句參數(shù)校驗(yàn)方法,雖然簡單直接,但就像 “土八路” 一樣,存在代碼冗余、維護(hù)困難、可復(fù)用性差等問題,在復(fù)雜場景下更是力不從心。而 Spring Boot 提供的參數(shù)校驗(yàn)機(jī)制,就像是 “正規(guī)軍”,通過各種注解、分組校驗(yàn)、方法級校驗(yàn)、自定義校驗(yàn)以及全局異常處理等高階玩法,讓參數(shù)校驗(yàn)變得簡潔、高效、靈活、優(yōu)雅。

使用 Spring Validation,我們可以大大減少重復(fù)的 if 語句,讓代碼更加簡潔明了,校驗(yàn)邏輯和業(yè)務(wù)邏輯分離,提高代碼的可維護(hù)性和可復(fù)用性。自定義校驗(yàn)功能更是讓我們能夠應(yīng)對各種復(fù)雜的業(yè)務(wù)需求,打造專屬的校驗(yàn)規(guī)則。全局異常處理則讓錯誤處理更加統(tǒng)一、規(guī)范,提升整個系統(tǒng)的健壯性。

所以,咱程序員可不能再用那些土味的 if 語句硬剛參數(shù)校驗(yàn)了,趕緊擁抱 Spring Boot 的這些高階玩法吧,讓咱們的代碼也能 “封神”,變得優(yōu)雅又強(qiáng)大。

責(zé)任編輯:武曉燕 來源: 石杉的架構(gòu)筆記
相關(guān)推薦

2021-05-18 09:25:54

SpringBoot參數(shù)校驗(yàn)

2025-05-23 09:30:57

2024-12-31 09:08:32

2019-09-21 21:32:34

數(shù)據(jù)庫SQL分布式

2021-11-04 18:27:02

緩存架構(gòu)Eureka

2012-07-19 10:03:32

2023-03-16 08:23:33

2022-12-30 08:49:41

SpringBoot@Validated

2019-09-19 15:47:31

WindowsWindows 7Windows 10

2024-11-12 16:28:34

2023-02-01 10:40:01

2022-02-22 11:50:16

Python字典代碼

2024-06-03 00:00:06

高性能數(shù)據(jù)傳輸應(yīng)用程序

2024-04-11 09:17:51

ArraysJava安全

2021-10-14 18:15:38

BeanUtils對象生成器

2023-01-16 13:45:30

微軟谷歌

2020-11-20 16:24:33

Windows操作系統(tǒng)老用戶

2025-04-07 00:00:00

CaffeineJava數(shù)據(jù)存取

2021-01-03 17:14:16

ORMObjective S運(yùn)行

2015-05-14 14:27:39

撥號上網(wǎng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號