我正在嘗試使用自定義驗證器驗證列舉,在我的自定義驗證器中,當列舉值中不存在引數時,我試圖回傳自定義訊息。
咆哮我的列舉
public enum Type {
MISSING_SITE,
INACTIVE_SITE;
}
吼吼我的PostMapping方法
@PostMapping(value = "/line-kpi", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Find Kpis by one or more customer property")
public ResponseEntity<List<KpiDTO>> findKPILineByCustomer(@RequestBody @ValidCustomerParameter CustomerParameter customerParameter, @RequestParam @ValidExtractionDate String extractionDate) {
var linesKpi = Optional.ofNullable(
kpiService.findKPILineByCustomer(
Optional.ofNullable(customerParameter.getEntityPerimeter()).orElse(List.of()),
Optional.ofNullable(customerParameter.getName()).orElse(List.of()),
Optional.ofNullable(customerParameter.getIc01()).orElse(List.of()),
Optional.ofNullable(customerParameter.getSiren()).orElse(List.of()),
Optional.ofNullable(customerParameter.getEnterpriseId()).orElse(List.of()),
LocalDate.parse(extractionDate)
)
);
return linesKpi.map(ResponseEntity::ok).orElseThrow(() -> new ResourceNotFoundException(KPIS));
}
我無法在方法本身中將列舉型別切換為字串,因為我使用的是 swagger,它顯示了一個不錯的列舉選擇串列。
不幸的是,當我嘗試為 Type 提供不同的值時,它回傳一個錯誤的請求并且我的驗證器沒有被觸發。
所以我試圖序列化我的列舉以在它到達控制器時被解釋為字串,為此我需要使用杰克遜,我試圖尋找一個解決方案,但我找不到適合我的案例的解決方案。
下面是我的驗證器
public class ReportTypeValidator implements ConstraintValidator<ValidReportType, Type> {
private String globalMessage;
@Override
public void initialize(ValidReportType constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
globalMessage = constraintAnnotation.message();
}
@Override
public boolean isValid(Type type, ConstraintValidatorContext constraintValidatorContext) {
if (Arrays.stream(Type.values()).filter(type1 -> type1.equals(type)).toList().isEmpty()) {
constraintValidatorContext
.buildConstraintViolationWithTemplate(globalMessage ", report type does not exist")
.addConstraintViolation();
return false;
}
return true;
}
}
@Constraint(validatedBy = ReportTypeValidator.class)
@Target( { ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Valid
public @interface ValidReportType {
String message() default "Invalid value for report type";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
誰能告訴我如何將我的列舉轉換為字串以便我的驗證器可以處理它?
uj5u.com熱心網友回復:
添加一個特殊的列舉常量,指示請求 JSON 包含無效的列舉常量名稱。請求 JSON 不應實際包含此列舉常量的名稱。還添加一個方法,Jackson 將在反序列化時呼叫該方法以將 JSON 字串轉換為列舉常量。如果 JSON 字串不是已知的列舉常量名稱,則此方法回傳特殊的列舉常量。
public enum Type {
MISSING_SITE,
INACTIVE_SITE,
@JsonProperty("SHOULD NEVER ACTUALLY APPEAR IN REQUEST JSON")
INVALID;
/**
* Converts enum constant name to enum constant.
*
* @param name
* enum constant name
* @return enum constant, or {@link #INVALID} if there is no enum constant with that name
*/
@JsonCreator
public static Type valueOfOrInvalid(String name) {
try {
return Type.valueOf(name);
} catch (IllegalArgumentException e) {
return INVALID;
}
}
}
在ReportTypeValidator.isValid(方法內部,檢查列舉常量 is INVALID。
if (type == Type.INVALID) {
// Add constraint violation.
uj5u.com熱心網友回復:
我找到了它,我能夠通過實作一個新的轉換器來做到這一點,它將字串轉換為有效的列舉值或 INVALID 值:
public class TypeConverter implements Converter<String, Type> {
@Override
public Type convert(String source) {
if (Arrays.stream(Type.values()).filter(type -> Objects.equals(type.toString(), source)).toList().isEmpty()) {
return Type.INVALID;
}
return Type.valueOf(source.toUpperCase());
}
}
之后,我為我的轉換器添加了一個新配置:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new TypeConverter());
}
}
此外,我不得不通過添加 @Schema 注釋來隱藏我的列舉的 INVALID 值,以免招搖撞騙:
@Schema(allowableValues = {"MISSING_SITE","INACTIVE_SITE"}, type = "String")
public enum Type {
MISSING_SITE,
INACTIVE_SITE,
INVALID
}
最后在驗證器中,我應該拒絕 INVALID 值并顯示一條自定義訊息:
public class ReportTypeValidator implements ConstraintValidator<ValidReportType, Type> {
private String globalMessage;
@Override
public void initialize(ValidReportType constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
globalMessage = constraintAnnotation.message();
}
@Override
public boolean isValid(Type type, ConstraintValidatorContext constraintValidatorContext) {
if (type == Type.INVALID) {
constraintValidatorContext
.buildConstraintViolationWithTemplate(globalMessage)
.addConstraintViolation();
return false;
}
return true;
}
}
前一個驗證器的注解:
@Constraint(validatedBy = ReportTypeValidator.class)
@Target( { ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Valid
public @interface ValidReportType {
String message() default "Invalid value for report type";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/365057.html
