如何return响应体中的ConstraintViolationException消息?
How to return the ConstraintViolationException messages in the response body?
我正在开发 Spring 基于引导的 REST API。我正在使用自定义 ConstraintValidator 注释验证输入实体。我的问题是我无法在响应中 return ConstraintViolationException 消息。我的异常处理程序没有捕获异常(可能是因为它们包含在其他类型的异常中)。
我能得到一些关于如何处理这种情况的建议吗?
我在整个 Internet 上进行了搜索,但找不到适合我的解决方案,而且我还浪费了一些时间。
示例注释:
@Documented
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
@Constraint(validatedBy = BirthDateValidator.class)
public @interface ValidBirthDate {
String message() default "The birth date is not valid.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
验证者class:
public class BirthDateValidator extends FieldValidationBase implements ConstraintValidator<ValidBirthDate, LocalDate> {
private static final Logger LOGGER = LoggerFactory.getLogger(BirthDateValidator.class);
@Override
public void initialize(ValidBirthDate constraintAnnotation) {
}
@Override
public boolean isValid(LocalDate birthDate, ConstraintValidatorContext constraintValidatorContext) {
constraintValidatorContext.disableDefaultConstraintViolation();
LOGGER.info("Starting the validation process for birth date {}.", birthDate);
if(birthDate == null) {
constraintValidatorContext.buildConstraintViolationWithTemplate("The birth date is null.")
.addConstraintViolation();
return false;
}
//other validations
return true;
}
型号class:
public class Manager extends BaseUser {
//other fields
@Valid
@ValidBirthDate
private LocalDate birthDate;
//setters & getters
异常处理程序:
@ExceptionHandler(value = ConstraintViolationException.class)
public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + ": " + violation.getMessage());
}
Error response = new Error(errors);
return new ResponseEntity<Object>(response, new HttpHeaders(), BAD_REQUEST);
}
控制器:
@RestController
@RequestMapping(value = "/register", consumes = "application/json", produces = "application/json")
public class RegistrationController {
@Autowired
private RegistrationService registrationService;
@PostMapping(value = "/manager")
public ResponseEntity registerManager(@RequestBody @Valid Manager manager) {
registrationService.executeSelfUserRegistration(manager);
return new ResponseEntity<>(new Message("User " + manager.getEmailAddress() + " registered successfully!"), CREATED);
}
}
我收到 400 响应代码,但我没有看到任何包含违反约束消息的响应正文。
经过更多调试后,我发现所有违反约束的行为都包含在 MethodArgumentNotValidException
中(因为有 @Valid
注释)——我不得不在该异常中深入挖掘一下才能得到我的信息。
我已经覆盖了 ResponseEntityExceptionHandler
中的 handleMethodArgumentNotValid()
方法,这就是我如何让它工作的:
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> errorMessages = new ArrayList<>();
BindingResult bindingResult = ex.getBindingResult();
List<ObjectError> errors = bindingResult.getAllErrors();
for(ObjectError error : errors) {
String message = error.getDefaultMessage();
errorMessages.add(message);
}
return new ResponseEntity<>(new Error(errorMessages), new HttpHeaders(), BAD_REQUEST);
}
也许这对某人有帮助。
当目标参数未通过验证时,Spring Boot 抛出 MethodArgumentNotValidException
异常。我已经从这个异常的 bindingResult
中提取了错误消息,如下所示:
@RestControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
//to extract the default error message from a diagnostic
// information about the errors held in MethodArgumentNotValidException
Exception exception = new Exception(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return this.createResponseEntity(HttpStatus.BAD_REQUEST, exception, request);
}
private ResponseEntity<Object> createResponseEntity(
HttpStatus httpStatus, Exception ex, WebRequest request) {
ErrorResponse errorResponse = ErrorResponse.builder()
.timestamp(LocalDateTime.now())
.status(httpStatus.value())
.error(httpStatus.getReasonPhrase())
.message(ex.getMessage())
.path(request.getDescription(true))
.build();
return handleExceptionInternal(ex, errorResponse,
new HttpHeaders(), httpStatus, request);
}
}
错误响应class:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
响应将是 400,主体采用 JSON 格式,如下所示:
{
"timestamp": "2021-01-20T10:30:15.011468",
"status": 400,
"error": "Bad Request",
"message": "Due date should not be greater than or equal to Repeat Until Date.",
"path": "uri=/api/tasks;client=172.18.0.5;user=109634489423695603526"
}
希望对您有所帮助。如果您需要 class 级约束的详细说明,请查看 this video.
我正在开发 Spring 基于引导的 REST API。我正在使用自定义 ConstraintValidator 注释验证输入实体。我的问题是我无法在响应中 return ConstraintViolationException 消息。我的异常处理程序没有捕获异常(可能是因为它们包含在其他类型的异常中)。
我能得到一些关于如何处理这种情况的建议吗?
我在整个 Internet 上进行了搜索,但找不到适合我的解决方案,而且我还浪费了一些时间。
示例注释:
@Documented
@Retention(RUNTIME)
@Target({FIELD, PARAMETER})
@Constraint(validatedBy = BirthDateValidator.class)
public @interface ValidBirthDate {
String message() default "The birth date is not valid.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
验证者class:
public class BirthDateValidator extends FieldValidationBase implements ConstraintValidator<ValidBirthDate, LocalDate> {
private static final Logger LOGGER = LoggerFactory.getLogger(BirthDateValidator.class);
@Override
public void initialize(ValidBirthDate constraintAnnotation) {
}
@Override
public boolean isValid(LocalDate birthDate, ConstraintValidatorContext constraintValidatorContext) {
constraintValidatorContext.disableDefaultConstraintViolation();
LOGGER.info("Starting the validation process for birth date {}.", birthDate);
if(birthDate == null) {
constraintValidatorContext.buildConstraintViolationWithTemplate("The birth date is null.")
.addConstraintViolation();
return false;
}
//other validations
return true;
}
型号class:
public class Manager extends BaseUser {
//other fields
@Valid
@ValidBirthDate
private LocalDate birthDate;
//setters & getters
异常处理程序:
@ExceptionHandler(value = ConstraintViolationException.class)
public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + ": " + violation.getMessage());
}
Error response = new Error(errors);
return new ResponseEntity<Object>(response, new HttpHeaders(), BAD_REQUEST);
}
控制器:
@RestController
@RequestMapping(value = "/register", consumes = "application/json", produces = "application/json")
public class RegistrationController {
@Autowired
private RegistrationService registrationService;
@PostMapping(value = "/manager")
public ResponseEntity registerManager(@RequestBody @Valid Manager manager) {
registrationService.executeSelfUserRegistration(manager);
return new ResponseEntity<>(new Message("User " + manager.getEmailAddress() + " registered successfully!"), CREATED);
}
}
我收到 400 响应代码,但我没有看到任何包含违反约束消息的响应正文。
经过更多调试后,我发现所有违反约束的行为都包含在 MethodArgumentNotValidException
中(因为有 @Valid
注释)——我不得不在该异常中深入挖掘一下才能得到我的信息。
我已经覆盖了 ResponseEntityExceptionHandler
中的 handleMethodArgumentNotValid()
方法,这就是我如何让它工作的:
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> errorMessages = new ArrayList<>();
BindingResult bindingResult = ex.getBindingResult();
List<ObjectError> errors = bindingResult.getAllErrors();
for(ObjectError error : errors) {
String message = error.getDefaultMessage();
errorMessages.add(message);
}
return new ResponseEntity<>(new Error(errorMessages), new HttpHeaders(), BAD_REQUEST);
}
也许这对某人有帮助。
当目标参数未通过验证时,Spring Boot 抛出 MethodArgumentNotValidException
异常。我已经从这个异常的 bindingResult
中提取了错误消息,如下所示:
@RestControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
//to extract the default error message from a diagnostic
// information about the errors held in MethodArgumentNotValidException
Exception exception = new Exception(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return this.createResponseEntity(HttpStatus.BAD_REQUEST, exception, request);
}
private ResponseEntity<Object> createResponseEntity(
HttpStatus httpStatus, Exception ex, WebRequest request) {
ErrorResponse errorResponse = ErrorResponse.builder()
.timestamp(LocalDateTime.now())
.status(httpStatus.value())
.error(httpStatus.getReasonPhrase())
.message(ex.getMessage())
.path(request.getDescription(true))
.build();
return handleExceptionInternal(ex, errorResponse,
new HttpHeaders(), httpStatus, request);
}
}
错误响应class:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
private LocalDateTime timestamp;
private int status;
private String error;
private String message;
private String path;
}
响应将是 400,主体采用 JSON 格式,如下所示:
{
"timestamp": "2021-01-20T10:30:15.011468",
"status": 400,
"error": "Bad Request",
"message": "Due date should not be greater than or equal to Repeat Until Date.",
"path": "uri=/api/tasks;client=172.18.0.5;user=109634489423695603526"
}
希望对您有所帮助。如果您需要 class 级约束的详细说明,请查看 this video.