在SpringBoot中怎么验证输入请求的自定义注解
这篇文章主要介绍了在SpringBoot中怎么验证输入请求的自定义注解,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
在我们的日常编程中,我们会使用许多可用于验证的 Spring Boot 默认注解,如@NotNull、@Size、@NotBlank、@Digits等等,这是验证任何传入的一种很酷的方式要求。
考虑一个场景,默认情况下有一些字段是可选的,如果其他一些字段由特定值填充,则它必须是强制性的。
Spring 没有为这种验证预定义注释。
让我们举一些例子,看看我们如何简化验证过程,使其代码可重用,并在注释级别引入抽象。
在一个典型的销售平台中,会有销售操作和无效销售操作。该金额在销售操作中是强制性的,在销售操作无效的情况下,冲销类型将是强制性的。
我们的 dto 类如下:
public class IncomingRequestDto { public TransactionType transactionType; public ReversalType reversalType; public String reversalId; public AmountDto amountDto;}
IncomingRequestDto 有几个属性,如 transactionType、reversalType 作为 ENUMS。
public enum TransactionType { SALE { public String toString() { return "Sale"; } }, VOIDSALE { public String toString() { return "VoidSale"; } },}
public enum ReversalType { TIMEDOUT { public final String toString() { return "Timedout"; } }, CANCELLED { public final String toString() { return "Cancelled"; } }}
和 amountDto 为:
public class AmountDto { public String value;}
场景一: amountDto.value 是有条件的。当我们收到一个具有 transactionType="SALE" 的请求时,amountDto.value 应该是强制性的。
场景 2: reversalType 是有条件的。当我们收到一个具有 transactionType="VOIDSALE" 的请求时,reversalType 应该是强制性的。
让我们首先定义一个带有验证过程所需属性的注释:
@Target({TYPE, ANNOTATION_TYPE})@Retention(RUNTIME)@Documentedpublic @interface NotNullIfAnotherFieldHasValue { String fieldName(); String fieldValue(); String dependFieldName(); String message(); Class>[] groups() default {}; Class extends Payload>[] payload() default {}; @Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Documented @interface List { NotNullIfAnotherFieldHasValue[] value(); }}
fieldName 和 fieldValue 将被定义,我们必须在其上搜索特定值。这里是"销售"。
将定义dependFieldName,我们必须在其上搜索值。
现在让我们实现上面的接口:
public class NotNullIfAnotherFieldHasValueValidator implements ConstraintValidator { private String fieldName; private String expectedFieldValue; private String dependFieldName; @Override public void initialize(NotNullIfAnotherFieldHasValue annotation) { fieldName = annotation.fieldName(); expectedFieldValue = annotation.fieldValue(); dependFieldName = annotation.dependFieldName(); } @Override public boolean isValid(Object value, ConstraintValidatorContext ctx) { String fieldValue = ""; String dependFieldValue = ""; if (value == null) { return true; } try { fieldValue = BeanUtils.getProperty(value, fieldName); dependFieldValue = BeanUtils.getProperty(value, dependFieldName); return validate(fieldValue, dependFieldValue, ctx); } catch (NestedNullException ex) { dependFieldValue = StringUtils.isNotBlank(dependFieldValue) ? dependFieldValue : ""; try { return validate(fieldValue, dependFieldValue, ctx); } catch (NumberFormatException exception) { return false; } } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NumberFormatException | NullPointerException ex) { return false; } } private boolean validate(String fieldValue, String dependFieldValue, ConstraintValidatorContext ctx) { if (!StringUtils.isBlank(fieldValue)) { if (expectedFieldValue.equals(fieldValue) && (StringUtils.isBlank(dependFieldValue))) { ctx.disableDefaultConstraintViolation(); ctx.buildConstraintViolationWithTemplate(ctx.getDefaultConstraintMessageTemplate()) .addNode(dependFieldName) .addConstraintViolation(); return false; } } else { return false; } return true; }}
在这里,我们需要返回并使用其实现类装饰我们的界面,如下所示:
@Target({TYPE, ANNOTATION_TYPE})@Retention(RUNTIME)@Constraint(validatedBy = NotNullIfAnotherFieldHasValueValidator.class)@Documentedpublic @interface NotNullIfAnotherFieldHasValue {
就是这样!我们已经完成了!让我们用我们的自定义注解装饰我们的 IncomingRequestDto 类:
@JsonDeserialize(as = IncomingRequestDto.class)@NotNullIfAnotherFieldHasValue.List({ @NotNullIfAnotherFieldHasValue( fieldName = "transactionType", fieldValue = "Sale", dependFieldName = "amountDto.value", message = " - amount is mandatory for Sale requests"), })@JsonInclude(JsonInclude.Include.NON_NULL)public class IncomingRequestDto { public TransactionType transactionType; public ReversalType reversalType; public String reversalId; public AmountDto amountDto;}
通过添加上述注释,请求将被拒绝为BAD,HTTP 400不为 Sale 类型请求填充 amountDto.value。我们可以在 List 中添加任意数量的验证,而无需更改任何代码,如下所示:
@JsonDeserialize(as = IncomingRequestDto.class)@NotNullIfAnotherFieldHasValue.List({@NotNullIfAnotherFieldHasValue( fieldName = "transactionType", fieldValue = "Sale", dependFieldName = "amountDto.value", message = " - amount is mandatory for Sale requests"), @NotNullIfAnotherFieldHasValue( fieldName = "transactionType", fieldValue = "VoidSale", dependFieldName = "reversalType", message = " - Reversal Type is mandatory for VoidSale requests"),})@JsonInclude(JsonInclude.Include.NON_NULL)public class IncomingRequestDto { public TransactionType transactionType; public ReversalType reversalType; public String reversalId; public AmountDto amountDto;}
感谢你能够认真阅读完这篇文章,希望小编分享的"在SpringBoot中怎么验证输入请求的自定义注解"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!