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

Spring?Boot之Validation自定義實現(xiàn)方式的總結(jié)

 更新時間:2022年07月04日 11:19:46   作者:bladestone  
這篇文章主要介紹了Spring?Boot之Validation自定義實現(xiàn)方式的總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Validation自定義實現(xiàn)方式

Spring Boot Validation定制

雖然在Spring Boot中已經(jīng)提供了非常多的預(yù)置注解,用以解決在日常開發(fā)工作中的各類內(nèi)容,但是在特定情況仍然存在某些場景,無法滿足需求,需要自行定義相關(guān)的validator。本節(jié)將針對自定義的validator進(jìn)行介紹。

自定義的注解

這里的場景設(shè)置為進(jìn)行IP地址的驗證,通過注解的方式,讓用戶使用驗證規(guī)則。注解定義如下:

@Target({ElementType.FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = IPAddressValidator.class)
public @interface IPAddress {
? ? String message() default "{ipaddress.invalid}";
? ? Class<?>[] groups() default {};
? ? Class<? extends Payload>[] payload() default {};
}

這個注解是作用在Field字段上,運行時生效,觸發(fā)的是IPAddressValidator這個驗證類。

  • message
  • 定制化的提示信息,主要是從ValidationMessages.properties里提取,也可以依據(jù)實際情況進(jìn)行定制
  • groups
  • 這里主要進(jìn)行將validator進(jìn)行分類,不同的類group中會執(zhí)行不同的validator操作
  • payload
  • 主要是針對bean的,使用不多。

然后自定義Validator,這個是真正進(jìn)行驗證的邏輯代碼:

public class IPAddressValidator implements ConstraintValidator<IPAddress, String> {
? ? @Override
? ? public boolean isValid(String value, ConstraintValidatorContext context) {
? ? ? ? Pattern pattern = compile("^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$");
? ? ? ? Matcher matcher = pattern.matcher(value);
? ? ? ? try {
? ? ? ? ? ? if (!matcher.matches()) {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? for (int i = 1; i <= 4; i++) {
? ? ? ? ? ? ? ? ? ? int octet = Integer.valueOf(matcher.group(i));
? ? ? ? ? ? ? ? ? ? if (octet > 255) {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? return false;
? ? ? ? }
? ? }
}

關(guān)于IP地址的驗證規(guī)則是通用的,具體邏輯不用太在意,主要是需要這里Validator這個接口,以及其中的兩個泛型參數(shù),第一個為注解名稱,第二個為實際字段的數(shù)據(jù)類型。

使用自定義的注解

定義了實體類CustomFieldBean.java

@Data
public class CustomFieldBean {
? ? @IPAddress
? ? private String ipAddr;
}

使用方法非常簡約,基于注解,無侵入邏輯。

單元測試用例

測試代碼:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomFieldValidatorTest {
? ? @Autowired
? ? private ProductService productService;
? ? @Test(expected = ConstraintViolationException.class)
? ? public void testInvalid() {
? ? ? ? CustomFieldBean customFieldBean = new CustomFieldBean();
? ? ? ? customFieldBean.setIpAddr("1.2.33");
? ? ? ? this.productService.doCustomField(customFieldBean);
? ? }
? ? @Test
? ? public void testValid() {
? ? ? ? CustomFieldBean customFieldBean = new CustomFieldBean();
? ? ? ? customFieldBean.setIpAddr("1.2.33.123");
? ? ? ? this.productService.doCustomField(customFieldBean);
? ? }
}

自定義執(zhí)行Validator

如果不希望由系統(tǒng)自行觸發(fā)Validator的驗證邏輯,則可以由開發(fā)者自行進(jìn)行驗證。在Spring Boot已經(jīng)內(nèi)置了Validator實例,直接將其加載進(jìn)來即可。

使用示例如下:

@Autowired
private Validator validator;

自定義執(zhí)行的單元測試

測試代碼如下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CodeValidationTest {
? ? @Autowired
? ? private Validator validator;
? ? @Test(expected = ConstraintViolationException.class)
? ? public void testValidator() {
? ? ? ? CustomFieldBean input = new CustomFieldBean();
? ? ? ? input.setIpAddr("123.3.1");
? ? ? ? Set<ConstraintViolation<CustomFieldBean>> violations = validator.validate(input);
? ? ? ? if (!violations.isEmpty()) {
? ? ? ? ? ? throw new ConstraintViolationException(violations);
? ? ? ? }
? ? }
}

自定義Validation注解

最近新開了一個項目,雖然hibernate-validator很好用,但是有時不能滿足稍微復(fù)雜一些的業(yè)務(wù)校驗。為了不在業(yè)務(wù)代碼中寫校驗邏輯,以及讓代碼更優(yōu)雅,故而采用了自定義校驗注解的方式。

場景說明

本例注解應(yīng)用場景: 填寫表單時,某一項數(shù)據(jù)存在時,對應(yīng)的一類數(shù)據(jù)都應(yīng)存在,一同提交。

源碼

1.類注解

主注解用于標(biāo)記要在校驗的實體類

@Target( { TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = RelateOtherValidator.class)
@Documented
public @interface RelateOther {
? ? String message() default "";
? ? /**
? ? ?* 校驗數(shù)量
? ? ?*/
? ? int num() default 2;
? ? Class<?>[] groups() default {};
? ? Class<? extends Payload>[] payload() default {};
}

2.輔助注解

輔助注解用于標(biāo)注于要校驗的字段,isMaster區(qū)分為主注解和從注解。

主注解是關(guān)鍵字段,存在才進(jìn)行校驗從注解對應(yīng)字段的有效性;主注解的value()屬性可以設(shè)置默認(rèn)值,當(dāng)字段對應(yīng)值對應(yīng)value()時才開啟校驗。

從注解為等待校驗的值,默認(rèn)為從注解。

@Target( { FIELD })
@Retention(RUNTIME)
@Documented
public @interface RelateOtherItem {
? ? /**
? ? ?* 是否為主字段,主字段存在才進(jìn)行校驗
? ? ?*/
? ? boolean isMaster() default false;
? ? /**
? ? ?* 用于開啟對指定值校驗判斷,master字段有效
? ? ?* 當(dāng)前為master且value與標(biāo)注字段值相等才進(jìn)行校驗,
? ? ?*/
? ? String value() default "";
}

3.校驗類

校驗類為實際執(zhí)行校驗邏輯的類,在類注解的@Constraint的validatedBy屬性上設(shè)置。

要設(shè)置為校驗類,首先要實現(xiàn)ConstraintValidator類的isValid方法。

@Slf4j ?// @Slf4j是lombok的注解
public class RelateOtherValidator implements ConstraintValidator<RelateOther, Object> {
?? ?// 要校驗的個數(shù)
? ? private int validateNum;
? ? @Override
? ? public void initialize(RelateOther constraintAnnotation) {
? ? ? ? validateNum = constraintAnnotation.num();
? ? }
? ? @Override
? ? public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
? ? ? ? if (o == null) {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? Field[] declaredFields = o.getClass().getDeclaredFields();
? ? ? ? boolean mater = false;
? ? ? ? int emptyNum = 0;
? ? ? ? try {
? ? ? ? ? ? // 總共需要校驗的字段數(shù)
? ? ? ? ? ? int totalValidateNum = validateNum;
? ? ? ? ? ? for (Field field : declaredFields) {
? ? ? ? ? ? ? ? // 校驗是否進(jìn)行過標(biāo)注
? ? ? ? ? ? ? ? if (!field.isAnnotationPresent(RelateOtherItem.class)) {
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (validateNum > 0 && totalValidateNum-- < 0) {
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? field.setAccessible(true);
? ? ? ? ? ? ? ? Object property = field.get(o);
? ? ? ? ? ? ? ? RelateOtherItem relateOtherItem = field.getAnnotation(RelateOtherItem.class);
? ? ? ? ? ? ? ? // 主字段不存在,則校驗通過
? ? ? ? ? ? ? ? if (relateOtherItem.isMaster()) {
? ? ? ? ? ? ? ? ? ? if (property==null) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? // 與指定值不一致,校驗通過
? ? ? ? ? ? ? ? ? ? if (!StringUtils.isEmpty(relateOtherItem.value()) && !relateOtherItem.value().equals(property)) {
? ? ? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? mater = true;
? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (null == property) {
? ? ? ? ? ? ? ? ? ? emptyNum++;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // 主字段不存在,則校驗通過
? ? ? ? ? ? if (!mater) {
? ? ? ? ? ? ? ? log.info("RelateOther注解主字段不存在");
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? ? ? return emptyNum==0;
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? log.info("RelateOther注解,解析異常 {}", e.getMessage());
? ? ? ? ? ? return false;
? ? ? ? }
? ? }
}

4.校驗失敗

注解校驗不同時會拋出一個MethodArgumentNotValidException異常。這里可以采用全局異常處理的方法,進(jìn)行捕獲處理。捕獲之后的異??梢垣@取BindingResult 對象,后面就跟hibernate-validator處理方式一致了。

BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();

5.使用demo

注解的使用類似下面,首先在請求實體類上標(biāo)注類注解,再在對應(yīng)的字段上標(biāo)注輔助注解。

@RelateOther(message = "xx必須存在!",num=2)
public class MarkReq ?{
?? ?@RelateOtherItem (isMaster= true,value="1")
?? ?private Integer ?girl;
?? ?@RelateOtherItem?
?? ?private Integer sunscreen;
?? ?private String remarks;
}

總結(jié)

自定義注解在開發(fā)中還是很好用的,本文主要起到拋磚引玉的作用。對于首次使用的朋友應(yīng)該還是有些用處的。

這些僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • IntelliJ IDEA中出現(xiàn)

    IntelliJ IDEA中出現(xiàn)"PSI and index do not match"錯誤的解決辦法

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA中出現(xiàn)"PSI and index do not match"錯誤的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • 一文教你學(xué)會如何使用MyBatisPlus

    一文教你學(xué)會如何使用MyBatisPlus

    本篇文章,我們通過 MyBatis Plus 來對一張表進(jìn)行 CRUD 操作,來看看是如何簡化我們開發(fā)的,文中通過代碼示例介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-05-05
  • SpringCloud2020整合Nacos-Bootstrap配置不生效的解決

    SpringCloud2020整合Nacos-Bootstrap配置不生效的解決

    這篇文章主要介紹了SpringCloud2020整合Nacos-Bootstrap配置不生效的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • JAVA?Springboot配置i18n國際化語言詳細(xì)步驟

    JAVA?Springboot配置i18n國際化語言詳細(xì)步驟

    國際化(Internationalization,縮寫為i18n)是指根據(jù)來展示不同的內(nèi)容,使應(yīng)用程序能夠適應(yīng)不同的語言和文化習(xí)慣,下面這篇文章主要給大家介紹了關(guān)于JAVA?Springboot配置i18n國際化語言的詳細(xì)步驟,需要的朋友可以參考下
    2024-08-08
  • Maven中的SnapShot版本和正式版本的區(qū)別

    Maven中的SnapShot版本和正式版本的區(qū)別

    在Nexus倉庫中,一個倉庫一般分為public(Release)倉和SNAPSHOT倉,本文詳細(xì)的介紹了SnapShot版本和正式版本的區(qū)別,感興趣的可以了解一下
    2021-06-06
  • 詳解Java線程中斷知識點

    詳解Java線程中斷知識點

    在本篇文章中我們給大家分享了關(guān)于Java線程中斷的相關(guān)知識點內(nèi)容以及相關(guān)代碼實例,有興趣的朋友們可以學(xué)習(xí)下。
    2018-09-09
  • Java Socket編程(五) 簡單的WEB服務(wù)器

    Java Socket編程(五) 簡單的WEB服務(wù)器

    Java Socket編程(五) 簡單的WEB服務(wù)器...
    2006-12-12
  • try catch finally的執(zhí)行順序深入分析

    try catch finally的執(zhí)行順序深入分析

    首先執(zhí)行try,如果有異常執(zhí)行catch,無論如何都會執(zhí)行finally,當(dāng)有return以后,函數(shù)就會把這個數(shù)據(jù)存儲在某個位置,然后告訴主函數(shù),我不執(zhí)行了,接下來你執(zhí)行吧,所以函數(shù)就會推出
    2013-09-09
  • 責(zé)任鏈模式在spring security過濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在spring security過濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在SpringSecurity過濾器鏈中的應(yīng)用,通過一系列的過濾器按順序處理請求,每個過濾器負(fù)責(zé)特定的安全功能,實現(xiàn)靈活且可擴(kuò)展的請求處理機(jī)制,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • JavaScript中棧和隊列應(yīng)用詳情

    JavaScript中棧和隊列應(yīng)用詳情

    這篇文章主要介紹了JavaScript中棧和隊列應(yīng)用詳情,棧如果用數(shù)組模擬的話是類似于一個U形桶狀堆??臻g,文章圍繞制圖展開詳細(xì)的內(nèi)容展開更多相關(guān)內(nèi)容,需要的小伙伴可以參考一下
    2022-06-06

最新評論

黄石市| 莲花县| 太康县| 大方县| 广河县| 保康县| 贵定县| 伽师县| 高邮市| 永宁县| 敖汉旗| 西和县| 筠连县| 镇远县| 独山县| 历史| 青海省| 涞水县| 来凤县| 丹江口市| 六枝特区| 永德县| 怀化市| 太原市| 昌图县| 攀枝花市| 光泽县| 宁阳县| 江安县| 色达县| 水富县| 收藏| 荆门市| 共和县| 马公市| 巴东县| 临潭县| 东台市| 宣恩县| 子洲县| 马公市|