自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Validation不是只能用注解,還可以通過編程方式實(shí)現(xiàn)參數(shù)校驗(yàn)

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

在項(xiàng)目中集成Hibernate-Validation,定義注解,實(shí)現(xiàn)參數(shù)的校驗(yàn),相信大家都會。

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

接下來,我們一起看下如何實(shí)現(xiàn)。

一、用例描述

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

import lombok.Data;

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

我們需要驗(yàn)證User類的id和name字段,id必須是正數(shù)、name不能為空。

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

為了驗(yàn)證User的id字段,我們創(chuàng)建了一個名為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字段不能為空,我們直接復(fù)用NotNull注解和NotNullDef約束定義。

二、驗(yàn)證器設(shè)置

現(xiàn)在,讓我們來研究一下驗(yàn)證器配置:

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字段,以實(shí)現(xiàn)對應(yīng)的約束定義。

為了保障測試用例的準(zhǔn)確,這里有個小細(xì)節(jié):

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

我們在定義NotNullDef時,設(shè)置了message屬性。這是因?yàn)樵诋?dāng)前的hibernate-validation版本中,內(nèi)置了很多的錯誤信息,存儲在 ValidationMessages*.properties文件族中,不同語言的錯誤信息不同。

為了實(shí)現(xiàn)測試用例的穩(wěn)定性,統(tǒng)一設(shè)置為“must not be null”。

三、應(yīng)用驗(yàn)證邏輯

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

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傳入?yún)?shù),就會執(zhí)行校驗(yàn)邏輯。

四、測試約束

編寫測試用例,看看執(zhí)行效果:

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

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

五、總結(jié)

本文中,我們討論了以編程方式為實(shí)體類添加驗(yàn)證的方式??梢孕薷脑创a時,我們可以使用注解,不能修改時,我們使用編程式校驗(yàn),幾乎可以覆蓋絕大部分場景了。

責(zé)任編輯:武曉燕 來源: 看山的小屋
相關(guān)推薦

2015-04-02 11:25:39

2020-12-28 08:36:30

C語言編程泛型

2024-06-13 08:19:08

Controller接口參數(shù)

2024-08-06 09:51:21

SpringHTTPJSON

2021-03-03 08:05:53

C++項(xiàng)目函數(shù)

2023-10-18 18:38:44

數(shù)據(jù)校驗(yàn)業(yè)務(wù)

2025-01-06 09:51:51

2022-10-09 10:02:09

Python3.12

2022-07-30 23:45:09

內(nèi)存泄漏檢測工具工具

2020-11-04 07:36:06

Redis二進(jìn)制數(shù)據(jù)庫

2022-04-21 14:50:50

Python農(nóng)歷命令

2009-12-09 17:37:36

PHP函數(shù)isset(

2022-04-21 09:59:53

Nest參數(shù)校驗(yàn)

2024-12-02 00:59:30

Spring

2022-07-29 16:50:30

網(wǎng)絡(luò)帶寬

2021-02-01 13:35:28

微信Python技巧

2022-12-06 17:30:04

2022-11-10 07:53:54

Spring參數(shù)校驗(yàn)

2015-02-11 09:41:02

土豪APP

2018-08-08 14:25:17

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號