java?spring?validation?自動、手動校驗(yàn)
參數(shù)校驗(yàn)是一個常見的問題,比如字段非空,字段長度限制,郵箱格式、手機(jī)格式驗(yàn)證等等。
避免校驗(yàn)規(guī)則,寫一大串步驟,繁瑣重復(fù)。
Hibernate Validator為此提供了一套比較完善、便捷的驗(yàn)證實(shí)現(xiàn)方式。
一、自動校驗(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 { //如果能精確匹配到該異常就會執(zhí)行這個方法,后續(xù)執(zhí)行下面的方法 @ExceptionHandler(value = MethodArgumentNotValidException.class) public Result handelValidateException(MethodArgumentNotValidException e) { log.error("數(shù)據(jù)校驗(yàn)出現(xiàn)問題:{},異常類型:{}", e.getMessage(), e.getClass()); Map<String, String> map = new HashMap<>(); //1.獲取校驗(yàn)錯誤結(jié)果 BindingResult result = e.getBindingResult(); result.getFieldErrors().forEach(fieldError -> { //獲取每個錯誤的屬性名字 String field = fieldError.getField(); //獲取每個錯誤提示信息 String defaultMessage = fieldError.getDefaultMessage(); map.put(field, defaultMessage); }); return Result.failed(map, "數(shù)據(jù)校驗(yàn)錯誤"); } }
第三步,定義接口接收實(shí)體DTO
定義校驗(yàn)規(guī)則,可以參考
關(guān)于Java Validation (驗(yà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("售后申請接口-接收實(shí)體DTO") public class AfterServiceApplyDTO implements Serializable { @NotBlank(message = "訂單編號不為空") @ApiModelProperty(value = "訂單編號", required = true) private String grandsonOrderCode; @NotNull(message = "申請售后類型不為空") @ApiModelProperty(value = "申請售后類型: 10:退貨 20:換貨 30:維修", required = true) private Integer customerExpect; @NotBlank(message = "產(chǎn)品問題描述不為空") @ApiModelProperty(value = "產(chǎn)品問題描述", required = true) private String questionDesc; @ApiModelProperty("問題描述圖片鏈接地址,多個圖片以“,”分隔") private String questionPic; @Valid @NotNull(message = "客戶信息實(shí)體不為空") @ApiModelProperty("客戶信息實(shí)體") private AfterSaleCustomerDTO asCustomerDto; @Valid @Size(min = 1, max = 1, message = "只能申請1個商品") @NotNull(message = "申請單明細(xì)列表不為空") @ApiModelProperty("申請單明細(xì)列表") private List<AfterSaleDetailDTO> asDetailDtos; }
第四步,在Contoller接口中增加參數(shù)注解@Validated
表示只校驗(yàn)當(dāng)前參數(shù)
@Api(tags = "【售后】訂單售后API接口") @RestController public class AfterServiceApiController { /** * 售后申請接口 * @param afterServiceApplyDTO 售后申請參數(shù) * @return 操作結(jié)果 */ @ApiOperation("售后申請接口") @PostMapping("/afterService/api/apply") public Result apply(@Validated @RequestBody AfterServiceApplyDTO afterServiceApplyDTO) { // todo return null; } }
第五步,測試結(jié)果
Postman發(fā)送錯誤數(shù)據(jù)觸發(fā)驗(yàn)證測試
二、手動校驗(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)是這個模式) // 普通模式(會校驗(yàn)完所有的屬性,然后返回所有的驗(yàn)證失敗信息) validator = Validation.buildDefaultValidatorFactory().getValidator(); } //第二種方式創(chuàng)建Validator // static { // // 1.普通模式(默認(rèn)是這個模式) // // 普通模式(會校驗(yàn)完所有的屬性,然后返回所有的驗(yàn)證失敗信息) // // .failFast(false) // // 或 .addProperty("hibernate.validator.fail_fast", "false") // // // 2.快速失敗返回模式 // // 快速失敗返回模式(只要有一個驗(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)對象,返回校驗(yàn)失敗List信息 * * @param object 對象 * @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)對象,返回校驗(yàn)失敗Map信息 * * @param object 對象 * @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)對象,返回校驗(yàn)失敗Result信息 * * @param object 對象 * @param groups 組 * @return 校驗(yàn)失敗Result,校驗(yàn)失敗返回錯誤信息,成功返回成功信息 */ 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)錯誤!"); } return Result.succeed("數(shù)據(jù)校驗(yàn)成功!"); } public static void main(String[] args) { AfterServiceApplyDTO afterServiceApplyDTO = new AfterServiceApplyDTO(); System.out.println(validateEntityResult(afterServiceApplyDTO)); } }
第二步,測試結(jié)果
Result(datas={questionDesc=產(chǎn)品問題描述不為空, grandsonOrderCode=供應(yīng)鏈三級訂單編號不為空, reason=售后原因不為空, asCustomerDto=客戶信息實(shí)體不為空, asDetailDtos=申請單明細(xì)列表不為空, businessPlatformCode=業(yè)務(wù)商城售后申請單號不為空, customerExpect=申請售后類型不為空}, resp_code=1, resp_msg=數(shù)據(jù)校驗(yàn)錯誤!)
補(bǔ)充:Java Validation (驗(yàn)證注解)
驗(yàn)證注解 | 驗(yàn)證的數(shù)據(jù)類型 | 說明 |
---|---|---|
@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(存儲的是數(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),如字符長度、集合大小 |
@Past | java.util.Date,java.util.Calendar;Joda Time類庫的日期類型 | 驗(yàn)證注解的元素值(日期類型)比當(dāng)前時間早 |
@Future | 與@Past要求一樣 | 驗(yàn)證注解的元素值(日期類型)比當(dāng)前時間晚 |
@NotBlank | CharSequence子類型 | 驗(yàn)證注解的元素值不為空(不為null、去除首位空格后長度為0),不同于@NotEmpty,@NotBlank只應(yīng)用于字符串且在比較時會去除字符串的首位空格 |
@Length(min=下限, max=上限) | CharSequence子類型 | 驗(yàn)證注解的元素值長度在min和max區(qū)間內(nèi) |
@NotEmpty | CharSequence子類型、Collection、Map、數(shù)組 | 驗(yàn)證注解的元素值不為null且不為空(字符串長度不為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,也可以通過regexp和flag指定自定義的email格式 |
@Pattern(regexp=正則表達(dá)式,flag=標(biāo)志的模式) | String,任何CharSequence的子類型 | 驗(yàn)證注解的元素值與指定的正則表達(dá)式匹配 |
@Valid | 任何非原子類型 | 指定遞歸驗(yàn)證關(guān)聯(lián)的對象如用戶對象中有個地址對象屬性,如果想在驗(yàn)證用戶對象時一起驗(yàn)證地址對象的話,在地址對象上加@Valid注解即可級聯(lián)驗(yàn)證 |
到此這篇關(guān)于java spring validation 自動、手動校驗(yàn)的文章就介紹到這了,更多相關(guān)java spring validation校驗(yàn)內(nèi)容請搜索腳本之家以前的文章或繼續(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ǔ)到精通之自動配置底層分析及小技巧
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時也是簡化Spring的一種快速開發(fā)的腳手架,本篇讓我們一起學(xué)習(xí)自動配置的底層分析與一些開發(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ò)通信異常的解決過程
最近一個項(xiàng)目里面出現(xiàn)了一個比較詭異的問題,給大家分享下,這篇文章主要給大家介紹了關(guān)于dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過程,需要的朋友可以參考下2023-02-02Java之?dāng)?shù)組在指定位置插入元素實(shí)現(xiàn)
本文主要介紹了Java之?dāng)?shù)組在指定位置插入元素實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01SpringBoot?+?MyBatis-Plus構(gòu)建樹形結(jié)構(gòu)的幾種方式
在實(shí)際開發(fā)中,很多數(shù)據(jù)都是樹形結(jié)構(gòu),本文主要介紹了SpringBoot?+?MyBatis-Plus構(gòu)建樹形結(jié)構(gòu)的幾種方式,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Java數(shù)組與堆棧相關(guān)知識總結(jié)
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Java數(shù)組與堆棧展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06