成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Validation不是只能用注解,還可以通過編程方式實現參數校驗

開發 前端
本文中,我們討論了以編程方式為實體類添加驗證的方式。可以修改源碼時,我們可以使用注解,不能修改時,我們使用編程式校驗,幾乎可以覆蓋絕大部分場景了。

在項目中集成Hibernate-Validation,定義注解,實現參數的校驗,相信大家都會。

但如果我們需要校驗的類是第三方提供的,由于種種原因無法替換參數類。根據業務邏輯,我們又需要對參數執行特定的校驗規則,應該怎么做呢?當注解沒有辦法使用時,我們就可以使用編程式約束了。

接下來,我們一起看下如何實現。

一、用例描述

我們先引入一個User實體類,假設這個類是由第三方提供的:

import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
}

我們需要驗證User類的id和name字段,id必須是正數、name不能為空。

如果能夠修改User類,我們只需要@NotNull和@Range(min = 1)兩個注解就解決問題了。現在,我們需要迂回一下。

為了驗證User的id字段,我們創建了一個名為UserId的自定義注解:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.hibernate.validator.constraints.Range;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.ReportAsSingleViolation;
import jakarta.validation.constraints.NotNull;

@Documented
@NotNull
@Range(min = 1)
@ReportAsSingleViolation
@Constraint(validatedBy = {})
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
public @interface UserId {

    String message() default "${validatedValue} must be a positive long";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

有了注解,還需要有約束定義類:

import org.hibernate.validator.cfg.ConstraintDef;

public class UserIdDef extends ConstraintDef<UserIdDef, UserId> {

    public UserIdDef() {
        super(UserId.class);
    }
}

這里說個題外話,有朋友留言說我不寫明引用的包,想想也是,Java棧同名類那么多,不寫包名,很容易引起歧義。

此外,User的name字段不能為空,我們直接復用NotNull注解和NotNullDef約束定義。

二、驗證器設置

現在,讓我們來研究一下驗證器配置:

import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.cfg.ConstraintMapping;
import org.hibernate.validator.cfg.context.TypeConstraintMappingContext;
import org.hibernate.validator.cfg.defs.NotNullDef;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;

import cn.howardliu.effective.spring.constraint.UserIdDef;
import cn.howardliu.effective.spring.entity.User;
import jakarta.validation.Validation;
import jakarta.validation.Validator;

@Configuration
class ValidationConf {

    @Bean
    Validator validator(AutowireCapableBeanFactory autowireCapableBeanFactory) {
        final HibernateValidatorConfiguration conf = Validation.byProvider(HibernateValidator.class).configure();
        final ConstraintMapping constraintMapping = conf.createConstraintMapping();

        final TypeConstraintMappingContext<User> context = constraintMapping.type(User.class);
        context.field("id").constraint(new UserIdDef());
        final NotNullDef notNullDef = new NotNullDef();
        notNullDef.message("must not be null");
        context.field("name").constraint(notNullDef);

        return conf.allowOverridingMethodAlterParameterConstraint(true)
                .addMapping(constraintMapping)
                .constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
                .buildValidatorFactory()
                .getValidator();
    }
}

我們使用TypeConstraintMappingContext,將必要的注解分配給User的id和name字段,以實現對應的約束定義。

為了保障測試用例的準確,這里有個小細節:

final NotNullDef notNullDef = new NotNullDef();
notNullDef.message("must not be null");

我們在定義NotNullDef時,設置了message屬性。這是因為在當前的hibernate-validation版本中,內置了很多的錯誤信息,存儲在 ValidationMessages*.properties文件族中,不同語言的錯誤信息不同。

為了實現測試用例的穩定性,統一設置為“must not be null”。

三、應用驗證邏輯

接下來我們定義一個接收User參數的組件:

import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import cn.howardliu.effective.spring.entity.User;
import jakarta.validation.Valid;

@Validated
@Service
public class UserService {

    public void handleUser(@Valid User user) {
        System.out.println("Got validated user " + user);
    }
}

此時,如果向UserService的handleUser傳入參數,就會執行校驗邏輯。

四、測試約束

編寫測試用例,看看執行效果:

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import cn.howardliu.effective.spring.entity.User;
import jakarta.validation.ConstraintViolationException;

@SpringBootTest
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    void provideInvalidUser() {
        final User user = new User();
        user.setId(-1L);
        user.setName(null);

        Assertions.assertThatThrownBy(() -> userService.handleUser(user))
                .isInstanceOf(ConstraintViolationException.class)
                .hasMessageContaining("handleUser.arg0.id: -1 must be a positive long")
                .hasMessageContaining("handleUser.arg0.name: must not be null");
    }

    @Test
    void provideValidUser() {
        final User user = new User();
        user.setId(1L);
        user.setName("howardliu.cn");

        assertDoesNotThrow(() -> userService.handleUser(user));
    }
}

我們寫了兩個測試用例,一個是非法的參數、一個是合法參數。非法參數傳入時,會被攔截,并返回定義好的異常信息。

五、總結

本文中,我們討論了以編程方式為實體類添加驗證的方式。可以修改源碼時,我們可以使用注解,不能修改時,我們使用編程式校驗,幾乎可以覆蓋絕大部分場景了。

責任編輯:武曉燕 來源: 看山的小屋
相關推薦

2015-04-02 11:25:39

2020-12-28 08:36:30

C語言編程泛型

2024-06-13 08:19:08

Controller接口參數

2024-08-06 09:51:21

SpringHTTPJSON

2021-03-03 08:05:53

C++項目函數

2009-12-09 17:37:36

PHP函數isset(

2022-07-29 16:50:30

網絡帶寬

2021-02-01 13:35:28

微信Python技巧

2022-12-06 17:30:04

2022-07-30 23:45:09

內存泄漏檢測工具工具

2020-11-04 07:36:06

Redis二進制數據庫

2022-10-09 10:02:09

Python3.12

2022-04-21 14:50:50

Python農歷命令

2025-01-06 09:51:51

2023-10-18 18:38:44

數據校驗業務

2022-04-21 09:59:53

Nest參數校驗

2024-12-02 00:59:30

Spring

2009-06-15 10:40:14

2022-05-17 07:26:33

動畫CSS前端

2018-08-08 14:25:17

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产高清视频在线播放 | 国产精品久久久久久中文字 | 久久伊人在 | 国产成人精品999在线观看 | 一区二区三区在线免费观看 | 天堂av在线影院 | 久久久久久久国产精品视频 | 欧美国产日韩在线观看 | 在线观看av中文字幕 | 日韩在线精品 | 黄色av一区 | 超碰精品在线观看 | 正在播放国产精品 | 精品久久国产 | 欧美一区二区三区在线免费观看 | 日韩精品一区二区三区中文字幕 | 91精品一区二区三区久久久久久 | 久久亚洲综合 | 亚洲精品乱码久久久久久按摩观 | 精久久久久| 久久综合久 | 国产九九精品 | 亚洲视频在线看 | 中文字幕视频三区 | 国产免费一二三区 | 成人亚洲| 国产精品美女久久久久久免费 | 伊人久久麻豆 | 99精品视频在线观看 | 亚洲国产情侣自拍 | 中文字幕 国产精品 | 91亚洲国产亚洲国产 | 国产精品视频一区二区三区 | 亚洲成人精选 | 污视频免费在线观看 | 久久蜜桃av一区二区天堂 | 精品www| 91精品国产综合久久小仙女图片 | 99免费视频 | 亚洲综合网站 | 欧美极品在线 |