可以在DTO中放入业务(自定义)验证吗


@Getter
public class PolicyRequestDto {
@Getter
@Builder
@AllArgsConstructor
public static class InsertPolicyRequest {
@NotNull(message = "need typeNo")
private Integer typeNo;
private String typeDescription;
private Long volume;
private Integer retryCnt;
private Integer authTime;
public InsertPolicyRequest insertValidate() {
PolicyTypeEnum policyEnumList = new PolicyTypeEnum();
Stream<Integer> volumeList = policyEnumList.getVolumeList().stream();
Stream<Integer> authTimeList = policyEnumList.getAuthTimeList().stream();
Stream<Integer> retryCntList = policyEnumList.getRetryCntList().stream();
switch (Objects.requireNonNull(typeNo, "no typeNo")) {
case 0 :
// case 0
break;
case 1 :
// case 1
break;
case 2 :
// case 2
break;
default : throw new IllegalArgumentException("Error");
}
return this;
}
public PolicyEntity toEntity () {
return PolicyEntity.builder()
.typeNo(typeNo)
.volume(volume)
.retryCnt(retryCnt)
.authTime(authTime)
.build();
}
}
}
public PolicyResponseDto.CommonResponse addWifiServicePolicy(@Valid PolicyRequestDto.InsertPolicyRequest insertRequest) {
insertRequest.insertValidate();
PolicyEntity policyEntity = insertRequest.toEntity();
...
return ...
}

如果该服务需要的验证无法使用@Validated注释完成,那么可以在DTO中完成吗?

目前,验证过程处于一个根据输入参数(例如代码(而变化的级别。该服务希望仅对通过此验证的数据执行业务逻辑。验证代码被放在每个方法的顶部很烦人,但我认为这是必要的代码。

在DTO中这样做有问题吗?

p.s我想让一个服务对象独立于控制器,这样即使只分离服务也不会有问题。

您可以创建自定义验证注释。

@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint {
String message() default "default error message";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

此注释适用于字段或方法级别。验证器必须实现ConstraintValidator。

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Integer> {
@Override
public boolean isValid(Integer typeNo, ConstraintValidatorContext context) {
PolicyTypeEnum policyEnumList = new PolicyTypeEnum();
Stream<Integer> volumeList = policyEnumList.getVolumeList().stream();
Stream<Integer> authTimeList = policyEnumList.getAuthTimeList().stream();
Stream<Integer> retryCntList = policyEnumList.getRetryCntList().stream();
switch (Objects.requireNonNull(typeNo, "no typeNo")) {
case 0 :
// case 0
break;
case 1 :
// case 1
break;
case 2 :
// case 2
break;
default :
return false;
}
return true;
}
}

如果您需要访问其他字段的数据,则需要更新注释以适用于类型级别-@Target( { ElementType.TYPE }),并相应地更改验证器以使用类型-InsertPolicyRequest:

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, InsertPolicyRequest> {
@Override
public boolean isValid(InsertPolicyRequest request, ConstraintValidatorContext context) {
PolicyTypeEnum policyEnumList = new PolicyTypeEnum();
Stream<Integer> volumeList = policyEnumList.getVolumeList().stream();
Stream<Integer> authTimeList = policyEnumList.getAuthTimeList().stream();
Stream<Integer> retryCntList = policyEnumList.getRetryCntList().stream();
switch (Objects.requireNonNull(request.getTypeNo(), "no typeNo")) {
case 0 :
// case 0
break;
case 1 :
// case 1
break;
case 2 :
// case 2
break;
default :
return false;
}
return true;
}
}

也可以查看此指南。

编辑:只需一个注释即可实现。有一个负责提取公共数据的接口,我们称之为PolicyRequestData

public interface PolicyRequestData {
Integer getTypeNo();
String getTypeName();
}

然后将上面的注释更改为在类型级别上工作,并将其重命名为MyCommonConstraint。更新ConstraintValidator以使用PolicyRequestData而不是具体类。

public class MyCommonConstraintValidator implements ConstraintValidator<MyCommonConstraint, PolicyRequestData> {
@Override
public boolean isValid(PolicyRequestData request, ConstraintValidatorContext constraintValidatorContext) {
PolicyTypeEnum policyEnumList = new PolicyTypeEnum();
Stream<Integer> volumeList = policyEnumList.getVolumeList().stream();
Stream<Integer> authTimeList = policyEnumList.getAuthTimeList().stream();
Stream<Integer> retryCntList = policyEnumList.getRetryCntList().stream();
switch (Objects.requireNonNull(request.getTypeNo(), "no typeNo")) {
case 0 :
// case 0
break;
case 1 :
// case 1
break;
case 2 :
// case 2
break;
default :
return false;
}
return true;
}
}

与此类似,注释将适用于任何实现PolicyRequestData类。

@MyCommonConstraint
public class InsertPolicyRequest implements PolicyRequestData {
private Integer typeNo;
private String typeName;
@Override
public Integer getTypeNo() {
return this.typeNo;
}
@Override
public String getTypeName() {
return this.typeName;
}
//setters, if needed
}

除了类名之外,UpdatePolicyRequest是完全相同的。

如果需要使用特定数据验证类,请扩展接口。

public interface SpecificPolicyRequestData extends PolicyRequestData {
String getOtherData();
}

让特定的类实现它,并创建注释来使用这个接口。然后在类上应用两个注释(如果需要两个验证(:

@MyCommonConstraint
@MySpecificConstraint
public class SomeSpecificPolicyRequest implements SpecificPolicyRequestData {
@Override
public Integer getTypeNo() {
return null;
}
@Override
public String getTypeName() {
return null;
}
@Override
public String getOtherData() {
return null;
}
}

最新更新