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面向?qū)ο笤O(shè)計(jì)原則之接口隔離原則示例詳解
這篇文章主要為大家介紹了java面向?qū)ο笤O(shè)計(jì)原則之接口隔離原則的示例詳解,有需要的朋友可以借鑒參考下希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-10-10
java注解實(shí)現(xiàn)websocket服務(wù)的兩種方式
Java WebSocket是一種基于TCP協(xié)議的雙向全雙工消息傳輸技術(shù),它允許服務(wù)器和客戶端之間實(shí)時(shí)通信,具有低延遲和高效率的特點(diǎn),下面這篇文章主要給大家介紹了關(guān)于java注解實(shí)現(xiàn)websocket服務(wù)的兩種方式,需要的朋友可以參考下2024-08-08
Spring @ComponentScan注解使用案例詳細(xì)講解
@ComponentScan注解的作用可以簡(jiǎn)述為:將項(xiàng)目中所有被@Component注解直接或者間接標(biāo)記的類---->組裝成BeanDefinition---->然后以key=beanName, value=BeanDefinition的形式存儲(chǔ),為后續(xù)生成bean對(duì)象做準(zhǔn)備2023-03-03
java模擬http的Get/Post請(qǐng)求,并設(shè)置ip與port代理的方法
下面小編就為大家?guī)?lái)一篇java模擬http的Get/Post請(qǐng)求,并設(shè)置ip與port代理的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
Java利用Swagger2自動(dòng)生成對(duì)外接口的文檔
這篇文章主要介紹了Java利用Swagger2自動(dòng)生成對(duì)外接口的文檔,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Java Web Listener實(shí)現(xiàn)事件監(jiān)聽(tīng)與處理
Java Web開(kāi)發(fā)中的Listener是一種事件機(jī)制,通過(guò)監(jiān)聽(tīng)Web應(yīng)用程序的事件,實(shí)現(xiàn)對(duì)事件的處理,從而實(shí)現(xiàn)更加靈活和高效的應(yīng)用程序開(kāi)發(fā)。Listener能夠監(jiān)聽(tīng)的事件包括應(yīng)用程序啟動(dòng)和關(guān)閉、Session創(chuàng)建和銷毀、請(qǐng)求和響應(yīng)對(duì)象的創(chuàng)建和銷毀等2023-04-04
Spring mvc AJAX技術(shù)實(shí)現(xiàn)原理解析
這篇文章主要介紹了Spring mvc AJAX技術(shù)實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

