Spring @ControllerAdvice消息源不适用于休眠消息参数



我正在尝试在Spring Boot REST控制器中添加一些自定义Bean验证,使用@ControllerAdvice注释扩展ResponseEntityExceptionHandler类并覆盖#handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, HttpStatus status, WebRequest request)方法。在这种方法中,我尝试通过messageSource将给定的FieldError转换为本地化消息。尽管我在尝试使用可以通过 Hibernate 验证器实现的消息参数时收到NumberFormatException

我正在使用以下依赖项:

  • org.hibernate.validator:hibernate-validator(6.0.11.最终版(
  • org.springframework:spring-web(5.0.8.发布(
  • org.springframework:spring-webmvc(5.0.8.发布(

所有这些都通过org.springframework.boot:spring-boot-starter-web(2.0.4.RELEASE(包含在内。

请考虑使用以下 REST 控制器:

@RestController
public class FooController {
@PostMapping(value = "/foo")
public void submitFooRequest(@Validated @RequestBody FooRequest fooRequest) {
// ....
}
}

FooRequest bean 有一个自定义的 Bean 验证注释和约束验证器:

豆福请求:

@Getter
@Setter
@ValidBarRequest
public class FooRequest {
private String fieldFoo;
private BarRequest barRequest;
}

豆吧请求:

@Getter
@Setter
public class BarRequest {
private String fieldBar;
}

验证注释:

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = BarRequestValidator.class)
@Documented
public @interface ValidBarRequest {
String message() default "{org.example.validation.constraints.ValidBarRequest.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String fieldFoo() default "fieldFoo";
String barRequestFieldBar() default "barRequest.fieldBar";
}

验证约束验证程序:

@Log4j2
public class BarRequestValidator implements ConstraintValidator<ValidBarRequest, Object> {
// ....
@Override
public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) {
if (/* some condition */) {
HibernateConstraintValidatorContext hibernateValidatorContext = constraintValidatorContext.unwrap(HibernateConstraintValidatorContext.class);
hibernateValidatorContext.disableDefaultConstraintViolation();
hibernateValidatorContext.addMessageParameter("fieldFoo", "some value...").buildConstraintViolationWithTemplate("{org.example.validation.constraints.ValidBarRequest.message}")
.addPropertyNode("barRequest.fieldBar").addConstraintViolation();
return false;
}
return true;
}
}

但是,通过@ControllerAdvice注释的 bean 并使用 Spring 消息源,在以下消息(在 messages.properties 中(抛出 NumberFormatException:

ValidBarRequest.fooRequest.barRequest.fieldBar=must be lower or equal than {fieldFoo}

豆@ControllerAdvice:

@ControllerAdvice
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
@Autowired private MessageSource messageSource;
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<ErrorDetails> errorDetails = new ArrayList<>();
for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
errorDetails.add(new ErrorDetails(fieldError.getField(), messageSource.getMessage(fieldError, Locale.getDefault())));
}
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
@Getter
@AllArgsConstructor
class ErrorDetails {
private String field;
private String message;
}
}

这会导致以下异常:Caused by: java.lang.NumberFormatException: For input string: "fieldFoo"

我做错了什么?我还在我的@SpringBootApplication中加入了以下豆子:

@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean localValidatorFactory = new LocalValidatorFactoryBean();
localValidatorFactory.setValidationMessageSource(messageSource);
return localValidatorFactory;
}

填充消息源 MessageFormat.format 中的变量,您必须在大括号中使用数字。

ValidBarRequest.fooRequest.barRequest.fieldBar=must be lower or equal than {0}

最新更新