中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring?Boot之Validation自定義實現的方法

發布時間:2022-07-04 13:45:51 來源:億速云 閱讀:252 作者:iii 欄目:開發技術

這篇“Spring Boot之Validation自定義實現的方法”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Spring Boot之Validation自定義實現的方法”文章吧。

    Validation自定義實現方式

    Spring Boot Validation定制

    雖然在Spring Boot中已經提供了非常多的預置注解,用以解決在日常開發工作中的各類內容,但是在特定情況仍然存在某些場景,無法滿足需求,需要自行定義相關的validator。

    自定義的注解

    這里的場景設置為進行IP地址的驗證,通過注解的方式,讓用戶使用驗證規則。注解定義如下:

    @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字段上,運行時生效,觸發的是IPAddressValidator這個驗證類。

    • message

    • 定制化的提示信息,主要是從ValidationMessages.properties里提取,也可以依據實際情況進行定制

    • groups

    • 這里主要進行將validator進行分類,不同的類group中會執行不同的validator操作

    • payload

    • 主要是針對bean的,使用不多。

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

    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;
            }
        }
    }

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

    使用自定義的注解

    定義了實體類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);
        }
    }

    自定義執行Validator

    如果不希望由系統自行觸發Validator的驗證邏輯,則可以由開發者自行進行驗證。在Spring Boot已經內置了Validator實例,直接將其加載進來即可。

    使用示例如下:

    @Autowired
    private Validator validator;

    自定義執行的單元測試

    測試代碼如下:

    @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很好用,但是有時不能滿足稍微復雜一些的業務校驗。為了不在業務代碼中寫校驗邏輯,以及讓代碼更優雅,故而采用了自定義校驗注解的方式。

    場景說明

    本例注解應用場景: 填寫表單時,某一項數據存在時,對應的一類數據都應存在,一同提交。

    源碼

    1.類注解

    主注解用于標記要在校驗的實體類

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

    2.輔助注解

    輔助注解用于標注于要校驗的字段,isMaster區分為主注解和從注解。

    主注解是關鍵字段,存在才進行校驗從注解對應字段的有效性;主注解的value()屬性可以設置默認值,當字段對應值對應value()時才開啟校驗。

    從注解為等待校驗的值,默認為從注解。

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

    3.校驗類

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

    要設置為校驗類,首先要實現ConstraintValidator類的isValid方法。

    @Slf4j  // @Slf4j是lombok的注解
    public class RelateOtherValidator implements ConstraintValidator<RelateOther, Object> {
        // 要校驗的個數
        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 {
                // 總共需要校驗的字段數
                int totalValidateNum = validateNum;
                for (Field field : declaredFields) {
                    // 校驗是否進行過標注
                    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異常。這里可以采用全局異常處理的方法,進行捕獲處理。捕獲之后的異常可以獲取BindingResult 對象,后面就跟hibernate-validator處理方式一致了。

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

    5.使用demo

    注解的使用類似下面,首先在請求實體類上標注類注解,再在對應的字段上標注輔助注解。

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

    以上就是關于“Spring Boot之Validation自定義實現的方法”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    丰宁| 瓮安县| 鄄城县| 辽宁省| 巴中市| 丹凤县| 镇安县| 西昌市| 双桥区| 彭泽县| 中西区| 雅江县| 榆树市| 山阳县| 凤台县| 特克斯县| 岚皋县| 柳林县| 大渡口区| 尖扎县| 鞍山市| 宣汉县| 华阴市| 抚宁县| 西乌珠穆沁旗| 沙坪坝区| 民勤县| 元江| 常熟市| 象山县| 涞源县| 宣城市| 巴林左旗| 临漳县| 泸定县| 定陶县| 达拉特旗| 勐海县| 宝应县| 哈密市| 东方市|