java?spring?validation?自動(dòng)、手動(dòng)校驗(yàn)
參數(shù)校驗(yàn)是一個(gè)常見(jiàn)的問(wèn)題,比如字段非空,字段長(zhǎng)度限制,郵箱格式、手機(jī)格式驗(yàn)證等等。
避免校驗(yàn)規(guī)則,寫一大串步驟,繁瑣重復(fù)。
Hibernate Validator為此提供了一套比較完善、便捷的驗(yàn)證實(shí)現(xiàn)方式。
一、自動(dòng)校驗(yàn)
第一步,導(dǎo)入依賴
項(xiàng)目已經(jīng)引入spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依賴。
項(xiàng)目還未引入spring-boot-starter-web包可以引入以下依賴:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.3.1.Final</version> </dependency>
第二步,統(tǒng)一異常處理
ValidateExceptionController
import com.central.common.model.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.validation.BindingResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; /** * 統(tǒng)一異常處理 */ @Slf4j @RestControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) public class ValidateExceptionController { //如果能精確匹配到該異常就會(huì)執(zhí)行這個(gè)方法,后續(xù)執(zhí)行下面的方法 @ExceptionHandler(value = MethodArgumentNotValidException.class) public Result handelValidateException(MethodArgumentNotValidException e) { log.error("數(shù)據(jù)校驗(yàn)出現(xiàn)問(wèn)題:{},異常類型:{}", e.getMessage(), e.getClass()); Map<String, String> map = new HashMap<>(); //1.獲取校驗(yàn)錯(cuò)誤結(jié)果 BindingResult result = e.getBindingResult(); result.getFieldErrors().forEach(fieldError -> { //獲取每個(gè)錯(cuò)誤的屬性名字 String field = fieldError.getField(); //獲取每個(gè)錯(cuò)誤提示信息 String defaultMessage = fieldError.getDefaultMessage(); map.put(field, defaultMessage); }); return Result.failed(map, "數(shù)據(jù)校驗(yàn)錯(cuò)誤"); } }
第三步,定義接口接收實(shí)體DTO
定義校驗(yàn)規(guī)則,可以參考
關(guān)于Java Validation (驗(yàn)證注解) 見(jiàn)文末補(bǔ)充介紹。
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.io.Serializable; import java.util.List; @Data @ApiModel("售后申請(qǐng)接口-接收實(shí)體DTO") public class AfterServiceApplyDTO implements Serializable { @NotBlank(message = "訂單編號(hào)不為空") @ApiModelProperty(value = "訂單編號(hào)", required = true) private String grandsonOrderCode; @NotNull(message = "申請(qǐng)售后類型不為空") @ApiModelProperty(value = "申請(qǐng)售后類型: 10:退貨 20:換貨 30:維修", required = true) private Integer customerExpect; @NotBlank(message = "產(chǎn)品問(wèn)題描述不為空") @ApiModelProperty(value = "產(chǎn)品問(wèn)題描述", required = true) private String questionDesc; @ApiModelProperty("問(wèn)題描述圖片鏈接地址,多個(gè)圖片以“,”分隔") private String questionPic; @Valid @NotNull(message = "客戶信息實(shí)體不為空") @ApiModelProperty("客戶信息實(shí)體") private AfterSaleCustomerDTO asCustomerDto; @Valid @Size(min = 1, max = 1, message = "只能申請(qǐng)1個(gè)商品") @NotNull(message = "申請(qǐng)單明細(xì)列表不為空") @ApiModelProperty("申請(qǐng)單明細(xì)列表") private List<AfterSaleDetailDTO> asDetailDtos; }
第四步,在Contoller接口中增加參數(shù)注解@Validated
表示只校驗(yàn)當(dāng)前參數(shù)
@Api(tags = "【售后】訂單售后API接口") @RestController public class AfterServiceApiController { /** * 售后申請(qǐng)接口 * @param afterServiceApplyDTO 售后申請(qǐng)參數(shù) * @return 操作結(jié)果 */ @ApiOperation("售后申請(qǐng)接口") @PostMapping("/afterService/api/apply") public Result apply(@Validated @RequestBody AfterServiceApplyDTO afterServiceApplyDTO) { // todo return null; } }
第五步,測(cè)試結(jié)果
Postman發(fā)送錯(cuò)誤數(shù)據(jù)觸發(fā)驗(yàn)證測(cè)試
二、手動(dòng)校驗(yàn)
第一步,校驗(yàn)工具類
ValidatorUtils
import com.central.business.afterService.dto.AfterServiceApplyDTO; import com.central.common.model.Result; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * 校驗(yàn)工具類 */ public class ValidatorUtils { private static final Validator validator; // 第一種方式創(chuàng)建Validator static { // 普通模式(默認(rèn)是這個(gè)模式) // 普通模式(會(huì)校驗(yàn)完所有的屬性,然后返回所有的驗(yàn)證失敗信息) validator = Validation.buildDefaultValidatorFactory().getValidator(); } //第二種方式創(chuàng)建Validator // static { // // 1.普通模式(默認(rèn)是這個(gè)模式) // // 普通模式(會(huì)校驗(yàn)完所有的屬性,然后返回所有的驗(yàn)證失敗信息) // // .failFast(false) // // 或 .addProperty("hibernate.validator.fail_fast", "false") // // // 2.快速失敗返回模式 // // 快速失敗返回模式(只要有一個(gè)驗(yàn)證失敗,則返回) // // .addProperty("hibernate.validator.fail_fast", "true") // // 或 .failFast(true) // ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) // .configure() // .failFast(true) .addProperty("hibernate.validator.fail_fast", "true") // .buildValidatorFactory(); // validator = validatorFactory.getValidator(); // } /** * 校驗(yàn)對(duì)象,返回校驗(yàn)失敗List信息 * * @param object 對(duì)象 * @param groups 組 * @return 校驗(yàn)失敗List信息 */ public static List<String> validateEntity(Object object, Class<?>... groups) { List<String> list = new ArrayList<>(); Set<ConstraintViolation<Object>> validate = validator.validate(object, groups); for (ConstraintViolation<Object> violation : validate) { list.add(violation.getMessage()); } return list; } /** * 校驗(yàn)對(duì)象,返回校驗(yàn)失敗Map信息 * * @param object 對(duì)象 * @param groups 組 * @return 校驗(yàn)失敗Map信息,key為屬性(字段名),value為校驗(yàn)失敗信息 */ public static Map<String, String> validateEntityProperty(Object object, Class<?>... groups) { Map<String, String> map = new HashMap<>(); Set<ConstraintViolation<Object>> validate = validator.validate(object, groups); for (ConstraintViolation<Object> violation : validate) { map.put(violation.getPropertyPath().toString(), violation.getMessage()); } return map; } /** * 校驗(yàn)對(duì)象,返回校驗(yàn)失敗Result信息 * * @param object 對(duì)象 * @param groups 組 * @return 校驗(yàn)失敗Result,校驗(yàn)失敗返回錯(cuò)誤信息,成功返回成功信息 */ public static Result<Map<String, String>> validateEntityResult(Object object, Class<?>... groups) { Map<String, String> map = new HashMap<>(); Set<ConstraintViolation<Object>> validate = validator.validate(object, groups); for (ConstraintViolation<Object> violation : validate) { map.put(violation.getPropertyPath().toString(), violation.getMessage()); } if (map.size() > 0) { return Result.failed(map, "數(shù)據(jù)校驗(yàn)錯(cuò)誤!"); } return Result.succeed("數(shù)據(jù)校驗(yàn)成功!"); } public static void main(String[] args) { AfterServiceApplyDTO afterServiceApplyDTO = new AfterServiceApplyDTO(); System.out.println(validateEntityResult(afterServiceApplyDTO)); } }
第二步,測(cè)試結(jié)果
Result(datas={questionDesc=產(chǎn)品問(wèn)題描述不為空, grandsonOrderCode=供應(yīng)鏈三級(jí)訂單編號(hào)不為空, reason=售后原因不為空, asCustomerDto=客戶信息實(shí)體不為空, asDetailDtos=申請(qǐng)單明細(xì)列表不為空, businessPlatformCode=業(yè)務(wù)商城售后申請(qǐng)單號(hào)不為空, customerExpect=申請(qǐng)售后類型不為空}, resp_code=1, resp_msg=數(shù)據(jù)校驗(yàn)錯(cuò)誤!)
補(bǔ)充:Java Validation (驗(yàn)證注解)
驗(yàn)證注解 | 驗(yàn)證的數(shù)據(jù)類型 | 說(shuō)明 |
---|---|---|
@AssertFalse | Boolean,boolean | 驗(yàn)證注解的元素值是false |
@AssertTrue | Boolean,boolean | 驗(yàn)證注解的元素值是true |
@NotNull | 任意類型 | 驗(yàn)證注解的元素值不是null |
@Null | 任意類型 | 驗(yàn)證注解的元素值是null |
@Min(value=值) | BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存儲(chǔ)的是數(shù)字)子類型 | 驗(yàn)證注解的元素值大于等于@Min指定的value值 |
@Max(value=值) | 和@Min要求一樣 | 驗(yàn)證注解的元素值小于等于@Max指定的value值 |
@DecimalMin(value=值) | 和@Min要求一樣 | 驗(yàn)證注解的元素值大于等于@ DecimalMin指定的value值 |
@DecimalMax(value=值) | 和@Min要求一樣 | 驗(yàn)證注解的元素值小于等于@ DecimalMax指定的value值 |
@Digits(integer=整數(shù)位數(shù), fraction=小數(shù)位數(shù)) | 和@Min要求一樣 | 驗(yàn)證注解的元素值的整數(shù)位數(shù)和小數(shù)位數(shù)上限 |
@Size(min=下限, max=上限) | 字符串、Collection、Map、數(shù)組等 | 驗(yàn)證注解的元素值的在min和max(包含)指定區(qū)間之內(nèi),如字符長(zhǎng)度、集合大小 |
@Past | java.util.Date,java.util.Calendar;Joda Time類庫(kù)的日期類型 | 驗(yàn)證注解的元素值(日期類型)比當(dāng)前時(shí)間早 |
@Future | 與@Past要求一樣 | 驗(yàn)證注解的元素值(日期類型)比當(dāng)前時(shí)間晚 |
@NotBlank | CharSequence子類型 | 驗(yàn)證注解的元素值不為空(不為null、去除首位空格后長(zhǎng)度為0),不同于@NotEmpty,@NotBlank只應(yīng)用于字符串且在比較時(shí)會(huì)去除字符串的首位空格 |
@Length(min=下限, max=上限) | CharSequence子類型 | 驗(yàn)證注解的元素值長(zhǎng)度在min和max區(qū)間內(nèi) |
@NotEmpty | CharSequence子類型、Collection、Map、數(shù)組 | 驗(yàn)證注解的元素值不為null且不為空(字符串長(zhǎng)度不為0、集合大小不為0) |
@Range(min=最小值, max=最大值) | BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子類型和包裝類型 | 驗(yàn)證注解的元素值在最小值和最大值之間 |
@Email(regexp=正則表達(dá)式,flag=標(biāo)志的模式) | CharSequence子類型(如String) | 驗(yàn)證注解的元素值是Email,也可以通過(guò)regexp和flag指定自定義的email格式 |
@Pattern(regexp=正則表達(dá)式,flag=標(biāo)志的模式) | String,任何CharSequence的子類型 | 驗(yàn)證注解的元素值與指定的正則表達(dá)式匹配 |
@Valid | 任何非原子類型 | 指定遞歸驗(yàn)證關(guān)聯(lián)的對(duì)象如用戶對(duì)象中有個(gè)地址對(duì)象屬性,如果想在驗(yàn)證用戶對(duì)象時(shí)一起驗(yàn)證地址對(duì)象的話,在地址對(duì)象上加@Valid注解即可級(jí)聯(lián)驗(yàn)證 |
到此這篇關(guān)于java spring validation 自動(dòng)、手動(dòng)校驗(yàn)的文章就介紹到這了,更多相關(guān)java spring validation校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Base64算法實(shí)際應(yīng)用之郵件發(fā)送實(shí)例分析
這篇文章主要介紹了Java Base64算法實(shí)際應(yīng)用之郵件發(fā)送,結(jié)合實(shí)例形式分析了java字符編碼與郵件發(fā)送相關(guān)操作技巧,需要的朋友可以參考下2019-09-09SpringBoot2零基礎(chǔ)到精通之自動(dòng)配置底層分析及小技巧
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說(shuō)是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開(kāi)發(fā)的腳手架,本篇讓我們一起學(xué)習(xí)自動(dòng)配置的底層分析與一些開(kāi)發(fā)中的小技巧2022-03-03Java8函數(shù)式接口java.util.function速查大全
因?yàn)镴ava8引入了函數(shù)式接口,在java.util.function包含了幾大類函數(shù)式接口聲明,這篇文章主要給大家介紹了關(guān)于Java8函數(shù)式接口java.util.function速查的相關(guān)資料,需要的朋友可以參考下2021-08-08dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過(guò)程
最近一個(gè)項(xiàng)目里面出現(xiàn)了一個(gè)比較詭異的問(wèn)題,給大家分享下,這篇文章主要給大家介紹了關(guān)于dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過(guò)程,需要的朋友可以參考下2023-02-02Java之?dāng)?shù)組在指定位置插入元素實(shí)現(xiàn)
本文主要介紹了Java之?dāng)?shù)組在指定位置插入元素實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01SpringBoot?+?MyBatis-Plus構(gòu)建樹(shù)形結(jié)構(gòu)的幾種方式
在實(shí)際開(kāi)發(fā)中,很多數(shù)據(jù)都是樹(shù)形結(jié)構(gòu),本文主要介紹了SpringBoot?+?MyBatis-Plus構(gòu)建樹(shù)形結(jié)構(gòu)的幾種方式,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Java數(shù)組與堆棧相關(guān)知識(shí)總結(jié)
今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java數(shù)組與堆棧展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06springboot 基于Tomcat容器的自啟動(dòng)流程分析
這篇文章主要介紹了springboot 基于Tomcat容器的自啟動(dòng)流程分析,Spring通過(guò)注解導(dǎo)入Bean大體可分為四種方式,我們主要來(lái)說(shuō)Import的兩種實(shí)現(xiàn)方法,需要的朋友可以參考下2020-02-02