前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【hibernate validator】(六)创建自定义约束

【hibernate validator】(六)创建自定义约束

作者头像
程序员朱永胜
发布于 2023-08-27 07:36:45
发布于 2023-08-27 07:36:45
20000
代码可运行
举报
运行总次数:0
代码可运行

首发博客地址

https://blog.zysicyj.top/

一、创建一个简单的约束

1. 约束注释

  • 枚举表示大小写
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public enum CaseMode {
    UPPER,
    LOWER;
}
  • 定义@CheckCase约束
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
@Repeatable(List.class)
public @interface CheckCase {
    String message() default "{org.hibernate.validator.referenceguide.chapter06.CheckCase." +
            "message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    CaseMode value();
    @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        CheckCase[] value();
    }
}
  • 测试一下吧
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Severity {
    public interface Info extends Payload {
    }
    public interface Error extends Payload {
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ContactDetails {
    @NotNull(message = "Name is mandatory", payload = Severity.Error.class)
    private String name;
    @NotNull(message = "Phone number not specified, but not mandatory",
            payload = Severity.Info.class)
    private String phoneNumber;
    // ...
}

用法

@Target 定义约束所支持的目标元素类型
@Retention(RUNTIME):指定此类型的注释将在运行时通过反射方式提供
@Constraint(validatedBy = CheckCaseValidator.class):将注释类型标记为约束注释,并指定用于验证元素的验证器
@CheckCase。如果可以在几种数据类型上使用约束,则可以指定几个验证器,每种数据类型一个。
@Repeatable(List.class):表示注释可以在同一位置重复多次,通常使用不同的配置

2. 约束验证器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
    private CaseMode caseMode;
    @Override
    public void initialize(CheckCase constraintAnnotation) {
        this.caseMode = constraintAnnotation.value();
    }
    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        if ( object == null ) {
            return true;
        }
        if ( caseMode == CaseMode.UPPER ) {
            return object.equals( object.toUpperCase() );
        }
        else {
            return object.equals( object.toLowerCase() );
        }
    }
}
  • 自定义错误消息
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
    private CaseMode caseMode;
    @Override
    public void initialize(CheckCase constraintAnnotation) {
        this.caseMode = constraintAnnotation.value();
    }
    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        if ( object == null ) {
            return true;
        }
        boolean isValid;
        if ( caseMode == CaseMode.UPPER ) {
            isValid = object.equals( object.toUpperCase() );
        }
        else {
            isValid = object.equals( object.toLowerCase() );
        }
        if ( !isValid ) {
            constraintContext.disableDefaultConstraintViolation();
            constraintContext.buildConstraintViolationWithTemplate(
                    "{org.hibernate.validator.referenceguide.chapter06." +
                    "constraintvalidatorcontext.CheckCase.message}"
            )
            .addConstraintViolation();
        }
        return isValid;
    }
}
  • HibernateConstraintValidator(对原版进行扩展)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyFutureValidator implements HibernateConstraintValidator<MyFuture, Instant> {
    private Clock clock;
    private boolean orPresent;
    @Override
    public void initialize(ConstraintDescriptor<MyFuture> constraintDescriptor,
            HibernateConstraintValidatorInitializationContext initializationContext) {
        this.orPresent = constraintDescriptor.getAnnotation().orPresent();
        this.clock = initializationContext.getClockProvider().getClock();
    }
    @Override
    public boolean isValid(Instant instant, ConstraintValidatorContext constraintContext) {
        //...
        return false;
    }
}

将有效负载传递给约束验证器

- 在ValidatorFactory初始化期间定义约束验证器有效载荷

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .constraintValidatorPayload( "US" )
        .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
  • 使用Validator上下文定义约束验证器有效载荷
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HibernateValidatorFactory hibernateValidatorFactory = Validation.byDefaultProvider()
        .configure()
        .buildValidatorFactory()
        .unwrap( HibernateValidatorFactory.class );
Validator validator = hibernateValidatorFactory.usingContext()
        .constraintValidatorPayload( "US" )
        .getValidator();
// [...] US specific validation checks
validator = hibernateValidatorFactory.usingContext()
        .constraintValidatorPayload( "FR" )
        .getValidator();
// [...] France specific validation checks
  • 在约束验证器中使用约束验证器有效载荷
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ZipCodeValidator implements ConstraintValidator<ZipCode, String> {
    public String countryCode;
    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        if ( object == null ) {
            return true;
        }
        boolean isValid = false;
        String countryCode = constraintContext
                .unwrap( HibernateConstraintValidatorContext.class )
                .getConstraintValidatorPayload( String.class );
        if ( "US".equals( countryCode ) ) {
            // checks specific to the United States
        }
        else if ( "FR".equals( countryCode ) ) {
            // checks specific to France
        }
        else {
            // ...
        }
        return isValid;
    }
}

3. 错误讯息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
org.hibernate.validator.referenceguide.chapter06.CheckCase.message = 案例模式必须为{value}

4. 使用约束

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Car {
    @NotNull
    private String manufacturer;
    @NotNull
    @Size(min = 2, max = 14)
    @CheckCase(CaseMode.UPPER)
    private String licensePlate;
    @Min(2)
    private int seatCount;
    public Car(String manufacturer, String licencePlate, int seatCount) {
        this.manufacturer = manufacturer;
        this.licensePlate = licencePlate;
        this.seatCount = seatCount;
    }
    //getters and setters ...
}
  • 使用约束验证对象
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//invalid license plate
Car car = new Car( "Morris", "dd-ab-123", 4 );
Set<ConstraintViolation<Car>> constraintViolations =
        validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
        "Case mode must be UPPER.",
        constraintViolations.iterator().next().getMessage()
);
//valid license plate
car = new Car( "Morris", "DD-AB-123", 4 );
constraintViolations = validator.validate( car );
assertEquals( 0, constraintViolations.size() );

二、类级别约束

  • 实现一个类级别约束
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { ValidPassengerCountValidator.class })
@Documented
public @interface ValidPassengerCount {
    String message() default "{org.hibernate.validator.referenceguide.chapter06.classlevel." +
            "ValidPassengerCount.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ValidPassengerCountValidator
        implements ConstraintValidator<ValidPassengerCount, Car> {
    @Override
    public void initialize(ValidPassengerCount constraintAnnotation) {
    }
    @Override
    public boolean isValid(Car car, ConstraintValidatorContext context) {
        if ( car == null ) {
            return true;
        }
        return car.getPassengers().size() <= car.getSeatCount();
    }
}

自定义属性路径

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ValidPassengerCountValidator
        implements ConstraintValidator<ValidPassengerCount, Car> {
    @Override
    public void initialize(ValidPassengerCount constraintAnnotation) {
    }
    @Override
    public boolean isValid(Car car, ConstraintValidatorContext constraintValidatorContext) {
        if ( car == null ) {
            return true;
        }
        boolean isValid = car.getPassengers().size() <= car.getSeatCount();
        if ( !isValid ) {
            constraintValidatorContext.disableDefaultConstraintViolation();
            constraintValidatorContext
                    .buildConstraintViolationWithTemplate( "{my.custom.template}" )
                    .addPropertyNode( "passengers" ).addConstraintViolation();
        }
        return isValid;
    }
}

三、交叉级别约束

  • 交叉级别约束
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Constraint(validatedBy = ConsistentDateParametersValidator.class)
@Target({ METHOD, CONSTRUCTOR, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
public @interface ConsistentDateParameters {
    String message() default "{org.hibernate.validator.referenceguide.chapter04." +
            "crossparameter.ConsistentDateParameters.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}
  • 通用和交叉级别约束
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class ConsistentDateParametersValidator implements
        ConstraintValidator<ConsistentDateParameters, Object[]> {
    @Override
    public void initialize(ConsistentDateParameters constraintAnnotation) {
    }
    @Override
    public boolean isValid(Object[] value, ConstraintValidatorContext context) {
        if ( value.length != 2 ) {
            throw new IllegalArgumentException( "Illegal method signature" );
        }
        //leave null-checking to @NotNull on individual parameters
        if ( value[0] == null || value[1] == null ) {
            return true;
        }
        if ( !( value[0] instanceof Date ) || !( value[1] instanceof Date ) ) {
            throw new IllegalArgumentException(
                    "Illegal method signature, expected two " +
                            "parameters of type Date."
            );
        }
        return ( (Date) value[0] ).before( (Date) value[1] );
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Constraint(validatedBy = {
        ScriptAssertObjectValidator.class,
        ScriptAssertParametersValidator.class
})
@Target({ TYPE, FIELD, PARAMETER, METHOD, CONSTRUCTOR, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
public @interface ScriptAssert {
    String message() default "{org.hibernate.validator.referenceguide.chapter04." +
            "crossparameter.ScriptAssert.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    String script();
    ConstraintTarget validationAppliesTo() default ConstraintTarget.IMPLICIT;
}
  • 指定通用和交叉参数约束的目标
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@ScriptAssert(script = "arg1.size() <= arg0", validationAppliesTo = ConstraintTarget.PARAMETERS)
public Car buildCar(int seatCount, List<Passenger> passengers) {
    //...
    return null;
}

四、约束构成

  • 创建一个合成约束 @ValidLicensePlate
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@NotNull
@Size(min = 2, max = 14)
@CheckCase(CaseMode.UPPER)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
public @interface ValidLicensePlate {
    String message() default "{org.hibernate.validator.referenceguide.chapter06." +
            "constraintcomposition.ValidLicensePlate.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}
  • 组合约束的应用 ValidLicensePlate
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Car {
    @ValidLicensePlate
    private String licensePlate;
    //...
}
  • 使用@ReportAsSingleViolation
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@ReportAsSingleViolation
public @interface ValidLicensePlate {
    String message() default "{org.hibernate.validator.referenceguide.chapter06." +
            "constraintcomposition.reportassingle.ValidLicensePlate.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}
```ayload() default { };
}

本文由 mdnice 多平台发布

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
自定义Hibernate Validator校验注解
写代码的时候发现:如果Controller层返回的对象没有getter和setter会抛出 org.springframework.web.HttpMediaTypeNotAcceptableException:Couldnotfind acceptable representation异常
喜欢天文的pony站长
2020/06/29
1.2K0
自定义Hibernate Validator校验注解
自定义校验
1)编写一个指定要的校验注解 @Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.
一个风轻云淡
2022/11/15
2500
自定义校验
使用hibernate validate做参数校验
​ 在开发http接口的时候,参数校验是必须有的一个环节,当参数校验较少的时候,一般是直接按照校验条件做校验,校验不通过,返回错误信息。比如以下校验用户名不为空的校验:
代码改变世界-coding
2020/08/02
9420
Java Bean Validation自定义注解
前面介绍了Java Bean Validation的使用,本文进一步介绍一下当标准的校验注解不满足要求时,可以自定义校验注解满足特定需求。比如@In,要求参数数据某个固定的集合(类似于枚举值) 自定义注解 @In import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention
十毛
2019/05/14
2.7K0
从源码到实践:构建个性化Spring Boot参数校验器
想要自定义,先找个官方提供的注解看看它是怎么实现的,然后我们就照葫芦画瓢写一个呗。
索码理
2024/03/22
3780
从源码到实践:构建个性化Spring Boot参数校验器
java 入参枚举类型,自定义注解
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
时光_赌徒
2023/07/20
2510
Java 参数校验(Validator)
应用在执行业务逻辑之前,必须通过校验保证接受到的输入数据是合法正确的,但很多时候同样的校验出现了多次,在不同的层,不同的方法上,导致代码冗余,浪费时间,违反DRY原则。
郭顺发
2021/12/17
1.5K0
Spring Security(使用hibernate-validator)
hibernate-validator是Hibernate项目中的一个数据校验框架,是Bean Validation 的参考实现。使用hibernate-validator能够将数据校验从业务代码中脱离出来,增加代码可读性,同时也让数据校验变得更加方便、简单。如果参数不能通过校验,报400错误,请求格式不正确。
用户7386338
2020/05/29
1.1K0
Spring Boot 使用 JSR303 实现参数验证
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。
程序员果果
2020/05/19
6730
Spring Boot 使用 JSR303 实现参数验证
springboot实现Validator校验
在开发中,我们实际不这么干,我们使用Hibernate Validator来进行参数校验
阿超
2022/08/16
4100
springboot实现Validator校验
枚举的使用及校验
今天聊聊枚举咋用 先定义一个枚举 package com.ruben.enumration; import com.alibaba.fastjson.annotation.JSONType; import com.fasterxml.jackson.annotation.JsonFormat; /** * @ClassName: GenderEnum * @Description: * @Date: 2020/8/18 19:03 * * * @author: achao<achao14414
阿超
2022/08/16
5580
枚举的使用及校验
SpringBoot中实现自定义注解用于文件验证(大小、扩展名、MIME类型)
首先在Spring Boot中定义一个注解,用于标记需要校验的文件字段。这个注解包含验证所需的参数:允许的扩展名、MIME类型和最大文件大小。
公众号:码到三十五
2024/09/05
2670
Bean Validation完结篇:你必须关注的边边角角(约束级联、自定义约束、自定义校验器、国际化失败消息...)【享学Spring】
一般来说,对于web项目我们都有必要对请求参数进行校验,有的前端使用JavaScript校验,但是为了安全起见后端的校验都是必须的。因此数据校验不仅仅是在web下,在方方面面都是一个重要的点。前端校验有它的JS校验框架(比如我之前用的jQuery Validation Plugin),后端自然也少不了。
YourBatman
2019/09/03
1.7K0
Bean Validation完结篇:你必须关注的边边角角(约束级联、自定义约束、自定义校验器、国际化失败消息...)【享学Spring】
Hibernate Validator 数据校验框架
JSR303是专家组成员向JCP提交的第1版Bean Validation,即针对bean数据校验提出的一个规范,使用注解方式实现数据校验。后面有升级版本JSR349及JSR380。
冬天vs不冷
2025/01/21
1930
Hibernate Validator 数据校验框架
Spring Boot实现用户注册验证全过程
首先,我们需要一个DTO来囊括用户的注册信息。这个对象应该包含我们在注册和验证过程中所需要的基本信息。
翊君
2022/03/08
1.3K0
java 自定义注解之ElementType.PARAMETER
需求:controller方法获取数据列表,orderPackagePayedAmount等于desc时按照packagePayedAmount字段倒叙排序,等于asc时按照packagePayedAmount字段正叙排序. @Api("项目管理") @RestController @RequestMapping("/project") @Validated public class ProjectController extends BaseController { @ApiOperation(valu
qubianzhong
2018/09/19
4.6K0
一文教你实现 SpringBoot 中的自定义 Validator 和错误信息国际化配置
本文通过示例说明,在 Springboot 中如何自定义 Validator,以及如何实现国际化的错误信息返回。注意,本文代码千万别直接照抄,有可能会出大事情的。先留个悬念,读者朋友们能从中看出有什么问题吗?
程序猿石头
2020/07/14
4.2K0
一文教你实现 SpringBoot 中的自定义 Validator 和错误信息国际化配置
【hibernate validator】(五)分组约束
程序员朱永胜
2023/08/27
1970
自定义valida验证注解
自定义注解 @Target({ElementType.METHOD,ElementType.FIELD}) //注解作用域 @Retention(RetentionPolicy.RUNTIME) //注解作用时间 @Constraint(validatedBy = MyConstriantValidator.class) //执行校验逻辑的类 public @interface MyConstraint { //校验不过时候的信息 String message() default
Meet相识
2018/09/12
6160
自定义valida验证注解
Hibernate Validator校验
1. 参数校验 ---- 官网地址 spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依赖。 2. hibernate validator校验demo ---- 1. 导入包 import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.AssertFalse; import javax
山海散人
2021/03/03
9200
相关推荐
自定义Hibernate Validator校验注解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文