java?spring?validation?自動、手動校驗
參數(shù)校驗是一個常見的問題,比如字段非空,字段長度限制,郵箱格式、手機格式驗證等等。
避免校驗規(guī)則,寫一大串步驟,繁瑣重復(fù)。
Hibernate Validator為此提供了一套比較完善、便捷的驗證實現(xiàn)方式。
一、自動校驗
第一步,導(dǎo)入依賴
項目已經(jīng)引入spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依賴。
項目還未引入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ù)校驗出現(xiàn)問題:{},異常類型:{}", e.getMessage(), e.getClass());
Map<String, String> map = new HashMap<>();
//1.獲取校驗錯誤結(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ù)校驗錯誤");
}
}第三步,定義接口接收實體DTO
定義校驗規(guī)則,可以參考
關(guān)于Java Validation (驗證注解) 見文末補充介紹。
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("售后申請接口-接收實體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 = "客戶信息實體不為空")
@ApiModelProperty("客戶信息實體")
private AfterSaleCustomerDTO asCustomerDto;
@Valid
@Size(min = 1, max = 1, message = "只能申請1個商品")
@NotNull(message = "申請單明細列表不為空")
@ApiModelProperty("申請單明細列表")
private List<AfterSaleDetailDTO> asDetailDtos;
}第四步,在Contoller接口中增加參數(shù)注解@Validated
表示只校驗當(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ā)驗證測試

二、手動校驗
第一步,校驗工具類
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;
/**
* 校驗工具類
*/
public class ValidatorUtils {
private static final Validator validator;
// 第一種方式創(chuàng)建Validator
static {
// 普通模式(默認是這個模式)
// 普通模式(會校驗完所有的屬性,然后返回所有的驗證失敗信息)
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
//第二種方式創(chuàng)建Validator
// static {
// // 1.普通模式(默認是這個模式)
// // 普通模式(會校驗完所有的屬性,然后返回所有的驗證失敗信息)
// // .failFast(false)
// // 或 .addProperty("hibernate.validator.fail_fast", "false")
//
// // 2.快速失敗返回模式
// // 快速失敗返回模式(只要有一個驗證失敗,則返回)
// // .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();
// }
/**
* 校驗對象,返回校驗失敗List信息
*
* @param object 對象
* @param groups 組
* @return 校驗失敗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;
}
/**
* 校驗對象,返回校驗失敗Map信息
*
* @param object 對象
* @param groups 組
* @return 校驗失敗Map信息,key為屬性(字段名),value為校驗失敗信息
*/
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;
}
/**
* 校驗對象,返回校驗失敗Result信息
*
* @param object 對象
* @param groups 組
* @return 校驗失敗Result,校驗失敗返回錯誤信息,成功返回成功信息
*/
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ù)校驗錯誤!");
}
return Result.succeed("數(shù)據(jù)校驗成功!");
}
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=客戶信息實體不為空, asDetailDtos=申請單明細列表不為空, businessPlatformCode=業(yè)務(wù)商城售后申請單號不為空, customerExpect=申請售后類型不為空}, resp_code=1, resp_msg=數(shù)據(jù)校驗錯誤!)補充:Java Validation (驗證注解)
| 驗證注解 | 驗證的數(shù)據(jù)類型 | 說明 |
|---|---|---|
| @AssertFalse | Boolean,boolean | 驗證注解的元素值是false |
| @AssertTrue | Boolean,boolean | 驗證注解的元素值是true |
| @NotNull | 任意類型 | 驗證注解的元素值不是null |
| @Null | 任意類型 | 驗證注解的元素值是null |
| @Min(value=值) | BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存儲的是數(shù)字)子類型 | 驗證注解的元素值大于等于@Min指定的value值 |
| @Max(value=值) | 和@Min要求一樣 | 驗證注解的元素值小于等于@Max指定的value值 |
| @DecimalMin(value=值) | 和@Min要求一樣 | 驗證注解的元素值大于等于@ DecimalMin指定的value值 |
| @DecimalMax(value=值) | 和@Min要求一樣 | 驗證注解的元素值小于等于@ DecimalMax指定的value值 |
| @Digits(integer=整數(shù)位數(shù), fraction=小數(shù)位數(shù)) | 和@Min要求一樣 | 驗證注解的元素值的整數(shù)位數(shù)和小數(shù)位數(shù)上限 |
| @Size(min=下限, max=上限) | 字符串、Collection、Map、數(shù)組等 | 驗證注解的元素值的在min和max(包含)指定區(qū)間之內(nèi),如字符長度、集合大小 |
| @Past | java.util.Date,java.util.Calendar;Joda Time類庫的日期類型 | 驗證注解的元素值(日期類型)比當(dāng)前時間早 |
| @Future | 與@Past要求一樣 | 驗證注解的元素值(日期類型)比當(dāng)前時間晚 |
| @NotBlank | CharSequence子類型 | 驗證注解的元素值不為空(不為null、去除首位空格后長度為0),不同于@NotEmpty,@NotBlank只應(yīng)用于字符串且在比較時會去除字符串的首位空格 |
| @Length(min=下限, max=上限) | CharSequence子類型 | 驗證注解的元素值長度在min和max區(qū)間內(nèi) |
| @NotEmpty | CharSequence子類型、Collection、Map、數(shù)組 | 驗證注解的元素值不為null且不為空(字符串長度不為0、集合大小不為0) |
| @Range(min=最小值, max=最大值) | BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子類型和包裝類型 | 驗證注解的元素值在最小值和最大值之間 |
| @Email(regexp=正則表達式,flag=標(biāo)志的模式) | CharSequence子類型(如String) | 驗證注解的元素值是Email,也可以通過regexp和flag指定自定義的email格式 |
| @Pattern(regexp=正則表達式,flag=標(biāo)志的模式) | String,任何CharSequence的子類型 | 驗證注解的元素值與指定的正則表達式匹配 |
| @Valid | 任何非原子類型 | 指定遞歸驗證關(guān)聯(lián)的對象如用戶對象中有個地址對象屬性,如果想在驗證用戶對象時一起驗證地址對象的話,在地址對象上加@Valid注解即可級聯(lián)驗證 |
到此這篇關(guān)于java spring validation 自動、手動校驗的文章就介紹到這了,更多相關(guān)java spring validation校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Base64算法實際應(yīng)用之郵件發(fā)送實例分析
這篇文章主要介紹了Java Base64算法實際應(yīng)用之郵件發(fā)送,結(jié)合實例形式分析了java字符編碼與郵件發(fā)送相關(guān)操作技巧,需要的朋友可以參考下2019-09-09
SpringBoot2零基礎(chǔ)到精通之自動配置底層分析及小技巧
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時也是簡化Spring的一種快速開發(fā)的腳手架,本篇讓我們一起學(xué)習(xí)自動配置的底層分析與一些開發(fā)中的小技巧2022-03-03
Java8函數(shù)式接口java.util.function速查大全
因為Java8引入了函數(shù)式接口,在java.util.function包含了幾大類函數(shù)式接口聲明,這篇文章主要給大家介紹了關(guān)于Java8函數(shù)式接口java.util.function速查的相關(guān)資料,需要的朋友可以參考下2021-08-08
dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過程
最近一個項目里面出現(xiàn)了一個比較詭異的問題,給大家分享下,這篇文章主要給大家介紹了關(guān)于dm.jdbc.driver.DMException網(wǎng)絡(luò)通信異常的解決過程,需要的朋友可以參考下2023-02-02
Java之?dāng)?shù)組在指定位置插入元素實現(xiàn)
本文主要介紹了Java之?dāng)?shù)組在指定位置插入元素實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
SpringBoot?+?MyBatis-Plus構(gòu)建樹形結(jié)構(gòu)的幾種方式
在實際開發(fā)中,很多數(shù)據(jù)都是樹形結(jié)構(gòu),本文主要介紹了SpringBoot?+?MyBatis-Plus構(gòu)建樹形結(jié)構(gòu)的幾種方式,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Java數(shù)組與堆棧相關(guān)知識總結(jié)
今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Java數(shù)組與堆棧展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下2021-06-06

