spring-boot - 处理SpringBoot中绑定到@RequestParam的对象抛出的异常
问题描述
在这篇文章之后: http: //dolszewski.com/spring/how-to-bind-requestparam-to-object/
我创建了以下控制器:
@GetMapping("/highlights")
public ResponseEntity<List<Highlight>> getHighlights(
HighlightFilterCriteria highlightFilterCriteria
) {
//...
其中 HighlightFilterCriteria POJO 具有以下形状:
public class HighlightFilterCriteria {
private LocalDateTime updatedDate;
private UUID userId;
public LocalDateTime getUpdatedDate() {
return updatedDate;
}
public void setUpdatedDate(String updatedDate) {
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
try {
this.updatedDate = LocalDateTime.parse(updatedDate, dateTimeFormat);
} catch (DateTimeParseException exc) {
throw new InvalidInputException("udpatedDate", "should be ISO date");
}
}
public UUID getUserId() {
return userId;
}
public void setUserId(String userId) {
try {
this.userId = UUID.fromString(userId);
} catch (IllegalArgumentException exc) {
throw new InvalidInputException("userId", "should be UUID");
}
}
}
这是我创建的自定义异常的实现InvalidInputException
:
package com.hmhco.rcehighlightspoc.exceptionsHandling;
public class InvalidInputException extends RuntimeException {
private String paramName;
private String message;
public InvalidInputException(String paramName, String message) {
super("\"" + paramName + "\" provided is invalid. It should be " + message);
this.paramName = paramName;
this.message = message;
}
}
然后是带有异常处理程序InvalidInputException
和通用捕获所有Exception
处理程序的 ControllerAdvice 实现:
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = InvalidInputException.class)
public ResponseEntity<Object> handleInvalidInputException(InvalidInputException ex) {
log.info("Handled: Invalid input", ex);
return buildResponseEntity(new ApiErrorResponse(
HttpStatus.BAD_REQUEST,
"Incorrect input",
ex
));
}
@ExceptionHandler(value = Exception.class)
public ResponseEntity<Object> handleException(Exception ex) {
log.error("Handled: Catch all exception", ex);
return buildResponseEntity(new ApiErrorResponse(
HttpStatus.BAD_REQUEST,
"Catch all exception handler",
ex
));
}
private ResponseEntity<Object> buildResponseEntity(ApiErrorResponse errorResponse) {
return new ResponseEntity<>(errorResponse, errorResponse.getStatus());
}
当我使用格式错误的 userId query param (incorrect UUID) 发送请求时http://localhost:8080/v1/highlights?updatedDate=2020-05-18T08:58:33.876Z&userId=badUUID
,try/catch 中的HighlightFilterCriteria
捕获InvalidInputException
并将其作为我的自定义重新抛出,InvalidInputException
但不幸的是,ControllerAdvice 的handleInvalidInputException
处理程序InvalidInputException
由于某种原因没有捕获它。
它被@ExceptionHandler(value = Exception.class)
处理程序捕获,我可以在日志中看到:
ERROR com.hmhco.rcehighlightspoc.exceptionsHandling.GlobalExceptionHandler.handleException - Handled: Catch all exception
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'highlightFilterCriteria' on field 'userId': rejected value [abcacf9b-926a-49c4-b980]; codes [methodInvocation.highlightFilterCriteria.userId,methodInvocation.userId,methodInvocation.java.util.UUID,methodInvocation]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [highlightFilterCriteria.userId,userId]; arguments []; default message [userId]]; default message [Property 'userId' threw exception; nested exception is com.hmhco.rcehighlightspoc.exceptionsHandling.InvalidInputException: "userId" provided is invalid. It should be should be UUID]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:164)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
...
我希望由于控制器使用此 POJO 来解析请求参数,因此可以捕获自定义异常。
如果作为测试,我InvalidInputException
通过以下方式直接从控制器中抛出自定义:
@GetMapping("/highlights")
public ResponseEntity<List<Highlight>> getHighlights(
@Valid HighlightFilterCriteria highlightFilterCriteria
) {
if (true) throw new InvalidInputException("userId", "should be UUID");
...
}
然后我可以看到InvalidInputException
处理程序按预期捕获它。
INFO com.hmhco.rcehighlightspoc.exceptionsHandling.GlobalExceptionHandler.handleInvalidInputException - Handled: Invalid input
com.hmhco.rcehighlightspoc.exceptionsHandling.InvalidInputException: "userId" provided is invalid. It should be should be UUID
at com.hmhco.rcehighlightspoc.controller.HighlightController.getHighlights(HighlightController.java:63)
主要问题是为什么InvalidInputException
没有被异常处理程序捕获但被处理程序捕获ControllerAdvice
?InvalidInputException
Exception
或者,也许我试图以不正确的方式在 POJO 中实现验证,如果是这样,当控制器方法获取 POJO 作为参数时,处理复杂类型(如 ISO 格式的 UUID 和 Date)的解析错误的正确方法是什么?
解决方案
推荐阅读
- python - Jupyter .ipynb 文件在使用 nbformat 包读取时更改字符串格式
- android - 如何读取内部服务器 graphql 消息?
- c# - Youtube Data API C# - 无需请求用户凭据即可使用
- python - Onesignal - 如何使用 python 向 android 设备发送推送通知?
- php - 我对 laravel nova 和 showCreateRelationButton 函数有疑问
- java - 为什么我在 Eclipse 中的 jsp 页面没有将图像显示到 img 标签中?
- c# - 使用查询表达式选择 const 值
- c# - 使用 windows-beacon-library 传输 iBeacon 时如何解决 System.NullReferenceException
- c# - 相机统一性问题
- spring-boot - Spring JPA @Query Anatotion 的缺点