最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot參數(shù)校驗(yàn),消除if else方式

 更新時(shí)間:2026年04月12日 11:00:02   作者:別團(tuán)等shy哥發(fā)育  
文章介紹了使用JSR303和Spring Boot中的spring-boot-starter-validation進(jìn)行數(shù)據(jù)驗(yàn)證的方法,包括注解使用、分組驗(yàn)證、嵌套對(duì)象校驗(yàn)、快速失敗配置以及自定義校驗(yàn)規(guī)則等內(nèi)容

1、參數(shù)校驗(yàn)簡(jiǎn)介

在實(shí)際工作中,得到數(shù)據(jù)得到的第一步就是校驗(yàn)數(shù)據(jù)的正確性,如果存在錄入上的問(wèn)題,一般會(huì)通過(guò)注解校驗(yàn),發(fā)現(xiàn)錯(cuò)誤后返回給用戶,但是對(duì)于一些邏輯上的錯(cuò)誤,比如 購(gòu)買金額 = 購(gòu)買數(shù)量 × 單價(jià) 購(gòu)買金額=購(gòu)買數(shù)量\times 單價(jià) 購(gòu)買金額=購(gòu)買數(shù)量×單價(jià),這樣的規(guī)則就很難使用注解方式驗(yàn)證了,此時(shí)可以使用Spring提供的驗(yàn)證器(Validator)規(guī)則去驗(yàn)證。

由于Validator框架通過(guò)硬編碼完成數(shù)據(jù)校驗(yàn),在實(shí)際開發(fā)中會(huì)顯得比較麻煩,因此現(xiàn)在開發(fā)更加推薦使用JSR 303完成服務(wù)端的數(shù)據(jù)校驗(yàn)。

Spring3開始支持JSR 303驗(yàn)證框架,JSR 303是Java為Bean數(shù)據(jù)合法性校驗(yàn)所提供的標(biāo)準(zhǔn)框架。

JSR 303支持XML風(fēng)格的和注解風(fēng)格的驗(yàn)證,通過(guò)在Bean屬性上標(biāo)注類似于@NotNull、@Max等的標(biāo)準(zhǔn)注解指定校驗(yàn)規(guī)則,并通過(guò)標(biāo)準(zhǔn)的驗(yàn)證接口對(duì)Bean進(jìn)行驗(yàn)證。

訪問(wèn)http://jcp.org/en/jsr/detail?id=303可以查看詳細(xì)內(nèi)容并下載JSR 303 Bean Validation。JSR 303 不需要編寫驗(yàn)證器,它定義了一套可標(biāo)注在成員變量、屬性方法上的校驗(yàn)注解,如下表所示:

約束說(shuō)明
@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是JSR 303的一個(gè)參考實(shí)現(xiàn),除了支持所有標(biāo)準(zhǔn)的校驗(yàn)注解之外,還擴(kuò)展了如下表所示的注解。

約束說(shuō)明
@NotBlank檢查被注解的元素是不是Null,以及被去掉前后空格的長(zhǎng)度是否大于0
@Email被注解的元素必須是電子郵件格式
@URL被注解的元素必須是合法的URL地址
@length被注解的字符串的字符串的大小必須在指定的范圍內(nèi)
@NotEmpty校驗(yàn)集合元素或數(shù)組元素或者字符串是否非空。通常作用于集合字段或數(shù)組字段,此時(shí)需要集合或者數(shù)字的元素個(gè)數(shù)大于0。也可以作用于字符串,此時(shí)校驗(yàn)字符串不能為null或空串(可以是一個(gè)空格)。
@Range被注解的元素必須在合適的范圍內(nèi)

2、實(shí)戰(zhàn)

spring-boot-starter-validation是Spring Boot 框架中的一個(gè)模塊,它構(gòu)建在Hibernate Validator的基礎(chǔ)之上,并提供了對(duì)Bean Validation的集成支持。它可以通過(guò)SpringBoot的自動(dòng)配置機(jī)制輕松集成到Spring應(yīng)用程序中。使用 spring-boot-starter-validation,你可以在SpringBoot應(yīng)用程序中使用 Hibernate Validator的功能,而不需要顯式地配置Hibernate Validator。

因此,Hibernate Validator是一個(gè)獨(dú)立的驗(yàn)證框架,而 spring-boot-starter-validation 則是一個(gè)為 Spring Boot應(yīng)用程序提供集成 Hibernate Validator 的模塊。

在這里搭建一個(gè)簡(jiǎn)單的SpringBoot項(xiàng)目,并引入如下依賴:

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

2.1 全局異常處理

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    //參數(shù)校驗(yàn)異常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Result error(MethodArgumentNotValidException e){
        log.warn(e.getMessage());
        return Result.fail()
                .code(ResultCodeEnum.ARGUMENT_VALID_ERROR.getCode())
                .message(e.getBindingResult().getFieldError().getDefaultMessage());
    }
    //參數(shù)校驗(yàn)異常
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Result error(BindException e){
        log.warn(e.getMessage());
        StringBuilder sb = new StringBuilder();
        for (ObjectError error : e.getBindingResult().getAllErrors()) {
            sb.append(error.getDefaultMessage());
        }
        return Result.fail()
                .code(ResultCodeEnum.ARGUMENT_VALID_ERROR.getCode())
                .message(sb.toString());
    }
    //參數(shù)校驗(yàn)異常
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Result error(ConstraintViolationException e){
        log.warn(e.getMessage());
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            sb.append(violation.getMessage());
        }
        return Result.fail()
                .code(ResultCodeEnum.ARGUMENT_VALID_ERROR.getCode())
                .message(sb.toString());
    }
    //全局異常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        log.warn(e.getMessage());
        return Result.fail().message("執(zhí)行了全局異常處理");
    }
}

2.2 快速開始

2.2.1 實(shí)體類

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

    @NotBlank(message = "姓名不能為空")
    private String name;

    @Size(min=11,max=11,message = "手機(jī)號(hào)長(zhǎng)度不符合要求")
    private String phone;

    @NotNull(message = "性別不能為空")
    private Integer sex;
}
@Data
public class UserUpdateVo {

    @NotBlank(message = "id不能為空")
    private String id;

    @NotBlank(message = "用戶名不能為空")
    private String userName;

    @NotBlank(message = "姓名不能為空")
    private String name;

    @Size(min=11,max=11,message = "手機(jī)號(hào)長(zhǎng)度不符合要求")
    private String phone;

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

2.2.1 定義請(qǐng)求接口

@Validated
@RestController
public class UserController {

    @PostMapping("create")
    public Result createUser(@Validated @RequestBody UserCreateVo userCreateVo){
        return Result.ok("參數(shù)校驗(yàn)成功");
    }

    @PostMapping("update")
    public Result updateUser(@Validated @RequestBody UserUpdateVo userUpdateVo){
        return Result.ok("參數(shù)校驗(yàn)成功");
    }
}

2.2.2 測(cè)試

新增接口測(cè)試:

這里故意不寫用戶名

更新接口測(cè)試:

2.3 路徑傳參校驗(yàn)

有時(shí)候我們是通過(guò)@Pathvariable注解實(shí)現(xiàn)參數(shù)傳遞的,這個(gè)時(shí)候校驗(yàn)如下:

@GetMapping("getUserById/{id}")
public Result getUserById(@PathVariable @Size(min=2,max=5,message = "id長(zhǎng)度不符合要求") String id){
    return Result.ok("參數(shù)校驗(yàn)成功");
}

可以看到,校驗(yàn)規(guī)則是生效的。

2.4 分組校驗(yàn)

我們前邊寫了兩個(gè)Vo類:UserCreateVoUserUpdateVo。如果每個(gè)請(qǐng)求都要定制Vo類的話,那我們還不如直接用if else梭哈呢。

比如我們新增的時(shí)候一般不需要id,但是修改的時(shí)候需要傳入id。

2.4.1 定義分組校驗(yàn)接口

//分組校驗(yàn)
public class UserGroup {
    public interface CreateGroup extends Default {
    }
    public interface UpdateGroup extends Default {
    }
}

2.4.2 統(tǒng)一Vo校驗(yàn)類

@Data
public class UserVo {

    @NotBlank(message = "id不能為空",groups = UserGroup.UpdateGroup.class)
    private String id;

    @NotBlank(message = "用戶名不能為空",groups = 
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String userName;

    @NotBlank(message = "姓名不能為空",groups = 
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String name;

    @Size(min=11,max=11,message = "手機(jī)號(hào)長(zhǎng)度不符合要求",groups = 
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String phone;

    @NotNull(message = "性別不能為空",groups = 
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private Integer sex;
}

2.4.3 修改接口

參數(shù)上邊添加@Validated接口,并指定分組名稱,并統(tǒng)一使用UserVo類接收參數(shù)。

@Validated
@RequestMapping("/user")
@RestController
public class UserController {

    @PostMapping("create")
    public Result createUser(@Validated(UserGroup.CreateGroup.class) @RequestBody UserVo userVo){
        return Result.ok("參數(shù)校驗(yàn)成功");
    }

    @PutMapping("update")
    public Result updateUser(@Validated(UserGroup.UpdateGroup.class) @RequestBody UserVo userVo){
        return Result.ok("參數(shù)校驗(yàn)成功");
    }

    @GetMapping("getUserById/{id}")
    public Result getUserById(@PathVariable @Size(min=2,max=5,message = "id長(zhǎng)度不符合要求") String id){
        return Result.ok("參數(shù)校驗(yàn)成功");
    }

}

2.4.4 測(cè)試

新增接口:

修改接口:

2.5 嵌套對(duì)象校驗(yàn)

存在嵌套對(duì)象校驗(yàn)的時(shí)候,使用@Valid注解解決。

2.5.1 添加一個(gè)角色實(shí)體

@Data
public class Role {
    @NotBlank(message = "角色名稱不能為空")
    private String roleName;
}

2.5.2 修改VO類

在User類中引入角色實(shí)體,并加入@Valid注解。

@Data
public class UserVo {

    @NotBlank(message = "id不能為空",groups = UserGroup.UpdateGroup.class)
    private String id;

    @NotBlank(message = "用戶名不能為空",groups =
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String userName;

    @NotBlank(message = "姓名不能為空",groups =
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String name;

    @Size(min=11,max=11,message = "手機(jī)號(hào)長(zhǎng)度不符合要求",groups =
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private String phone;

    @NotNull(message = "性別不能為空",groups =
            {UserGroup.CreateGroup.class,UserGroup.UpdateGroup.class})
    private Integer sex;

    @Valid
    @NotNull(message = "角色信息不能為空")
    private Role role;
}

2.5.3 測(cè)試

測(cè)試新增接口,故意不傳角色信息:

測(cè)試修改接口,故意不傳角色信息:

2.6 快速失敗配置

默認(rèn)validation的校驗(yàn)規(guī)則默認(rèn)會(huì)檢查所有屬性的校驗(yàn)規(guī)則,在每一條規(guī)則都校驗(yàn)完成后才拋出異常,這樣子難免效率會(huì)很低,我們希望在發(fā)現(xiàn)錯(cuò)誤后就不再向后檢查,可以通過(guò)“快速失敗”配置解決,參考代碼如下:

/**
 * 參數(shù)校驗(yàn)相關(guān)配置
 */
@Configuration
public class ValidConfig {
    /**
     * 快速返回校驗(yàn)器
     * @return
     */
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                //快速失敗模式
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

    /**
     * 設(shè)置快速校驗(yàn),返回方法校驗(yàn)處理器
     * 使用MethodValidationPostProcessor注入后,會(huì)啟動(dòng)自定義校驗(yàn)器
     * @return
     */
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor(){
        MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
        methodValidationPostProcessor.setValidator(validator());
        return methodValidationPostProcessor;
    }
}

2.7 自定義校驗(yàn)規(guī)則

有時(shí)候框架自帶的校驗(yàn)無(wú)法滿足我們業(yè)務(wù)的需求,這個(gè)時(shí)候可以根據(jù)自己的需求定制校驗(yàn)規(guī)則。

這里我們自定義一個(gè)手機(jī)號(hào)校驗(yàn)的注解,僅作示例使用,因?yàn)楣俜揭呀?jīng)提供了手機(jī)號(hào)的校驗(yàn)注解。

2.7.1 定義注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Constraint(validatedBy = PhoneValidator.class)
public @interface PhoneValid {
    String message() default "請(qǐng)?zhí)顚懻_的手機(jī)號(hào)";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

@Constraint注解是Hibernate Validator的注解,用于實(shí)現(xiàn)自定義校驗(yàn)規(guī)則,通過(guò)validatedBy參數(shù)指定進(jìn)行參數(shù)校驗(yàn)的實(shí)現(xiàn)類。

2.7.2 校驗(yàn)實(shí)現(xiàn)類

實(shí)現(xiàn)ConstraintValidator接口。

ConstraintValidator<A extends Annotation, T>中,第一個(gè)參數(shù)為注解,即Annotation,第二個(gè)參數(shù)是泛型。

public class PhoneValidator implements ConstraintValidator<PhoneValid,Object> {
    /**
     * 11位手機(jī)號(hào)的正則表達(dá)式,以13、14、15、17、18頭
     * ^:匹配字符串的開頭
     * 13\d:匹配以13開頭的手機(jī)號(hào)碼
     * 14[579]:匹配以145、147、149開頭的手機(jī)號(hào)
     * 15[^4\D]:匹配以15開頭且第3位數(shù)字不為4的手機(jī)號(hào)碼
     * 17[^49\D]:匹配以17開頭且第3位數(shù)字部位4或9的手機(jī)號(hào)碼
     * 18\d :匹配以18開頭的手機(jī)號(hào)碼
     * \d{8}:匹配手機(jī)號(hào)碼的后8位,即剩余的8個(gè)數(shù)字
     * $:匹配字符串的結(jié)尾
     */
    public static final String REGEX_PHONE="^(13\\d|14[579]|15[^4\\D]|17[^49\\D]|18\\d)\\d{8}$";


    //初始化注解
    @Override
    public void initialize(PhoneValid constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    //校驗(yàn)參數(shù),true表示校驗(yàn)通過(guò),false表示校驗(yàn)失敗
    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        String phone = String.valueOf(o);
        if(phone.length()!=11){
            return false;
        }
        //正則校驗(yàn)
        return phone.matches(REGEX_PHONE);
    }
}

2.7.3 在實(shí)體中添加自定義注解

2.7.4 測(cè)試自定義校驗(yàn)規(guī)則

先使用一個(gè)正確的手機(jī)號(hào)測(cè)試,校驗(yàn)成功。

再用一個(gè)錯(cuò)誤的手機(jī)號(hào)測(cè)試,校驗(yàn)失敗。

就介紹到這里,其實(shí)參數(shù)校驗(yàn)的用法很多,這里只是介紹下常用的功能。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java高效實(shí)現(xiàn)復(fù)制PPT(PowerPoint)幻燈片

    Java高效實(shí)現(xiàn)復(fù)制PPT(PowerPoint)幻燈片

    在日常的開發(fā)工作中,我們經(jīng)常會(huì)遇到需要對(duì)Office文檔進(jìn)行編程處理的需求,本文將為您揭示如何利用強(qiáng)大的 Spire.Presentation for Java進(jìn)行PPT復(fù)制,有需要的小伙伴可以了解下
    2025-09-09
  • JUC之Semaphore源碼分析

    JUC之Semaphore源碼分析

    這篇文章主要為大家詳細(xì)分析了JUC之Semaphore源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Springboot集成SpringBatch批處理組件

    Springboot集成SpringBatch批處理組件

    這篇文章主要介紹了Springboot集成SpringBatch批處理組件,用于處理大規(guī)模數(shù)據(jù)作業(yè),提供ItemReader/Processor/Writer核心組件,支持任務(wù)持久化與H2數(shù)據(jù)庫(kù)配置,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-06-06
  • Java分布式鎖理論(redis、zookeeper))案例詳解

    Java分布式鎖理論(redis、zookeeper))案例詳解

    zookeeper有個(gè)節(jié)點(diǎn)路徑的概念,節(jié)點(diǎn)路徑不能重復(fù),保證了唯一性,這篇文章給大家介紹Java分布式鎖理論(redis、zookeeper)?案例詳解,感興趣的朋友跟隨小編一起看看吧
    2024-01-01
  • Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    項(xiàng)目中需要導(dǎo)出并合并指定的單元格,下面這篇文章主要給大家介紹了關(guān)于java評(píng)論、回復(fù)功能設(shè)計(jì)與實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 封裝jndi操作ldap服務(wù)器的工具類

    封裝jndi操作ldap服務(wù)器的工具類

    這篇文章主要介紹了封裝JNDI操作LDAP服務(wù)器的工具類,使用者只需要會(huì)使用List,Map 數(shù)據(jù)結(jié)構(gòu),大家參考使用吧
    2014-01-01
  • Spring Boot集成Kafka最佳實(shí)踐與詳細(xì)代碼

    Spring Boot集成Kafka最佳實(shí)踐與詳細(xì)代碼

    Spring Boot作為Java領(lǐng)域的流行框架,提供了與Kafka的無(wú)縫集成,本文將詳細(xì)介紹如何在Spring Boot項(xiàng)目中優(yōu)雅地集成Kafka,并通過(guò)最佳實(shí)踐和代碼示例詳細(xì)講解,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • Spring中的Context你真的懂了嗎

    Spring中的Context你真的懂了嗎

    這篇文章主要給大家介紹了關(guān)于Spring中Context的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • 詳解Java中的日期類

    詳解Java中的日期類

    這篇文章主要介紹了Java中的日期類的相關(guān)資料,幫助大家更好的利用Java處理時(shí)間,感興趣的朋友可以了解下
    2020-10-10
  • MyBatis中關(guān)于resultType和resultMap的區(qū)別介紹

    MyBatis中關(guān)于resultType和resultMap的區(qū)別介紹

    MyBatis中在查詢進(jìn)行select映射的時(shí)候,返回類型可以用resultType,也可以用resultMap,那么MyBatis中關(guān)于resultType和resultMap的區(qū)別是什么呢?下面小編通過(guò)本文給大家解答下
    2016-09-09

最新評(píng)論

佛学| 霸州市| 五原县| 永昌县| 巴彦县| 东山县| 和静县| 太白县| 兴城市| 娄烦县| 宣城市| 吴江市| 分宜县| 封开县| 孝昌县| 抚顺市| 顺平县| 丽江市| 太和县| 斗六市| 灵山县| 垣曲县| 通江县| 五莲县| 扎鲁特旗| 石楼县| 桃园市| 荔波县| 保山市| 开封县| 德令哈市| 兰考县| 遵义县| 微博| 米泉市| 乌兰察布市| 迁安市| 离岛区| 芜湖市| 新营市| 延寿县|