在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;
    }
}

然后这是ControllerAdvice实现,其中包含InvalidInputException的异常处理程序和泛型捕获所有Exception处理程序:

@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","Catch all exception handler",ex
        ));
    }

    private ResponseEntity<Object> buildresponseEntity(ApiErrorResponse errorResponse) {
        return new ResponseEntity<>(errorResponse,errorResponse.getStatus());
    }

当我发送带有格式不正确的userId查询参数(不正确的UUID)http://localhost:8080/v1/highlights?updatedDate=2020-05-18T08:58:33.876Z&userId=badUUID的请求时,HighlightFilterCriteria中的try / catch捕获InvalidInputException并将其作为我的自定义{{1} },但不幸的是,由于某些原因,ControllerAdvice的InvalidInputException的{​​{1}}处理程序无法捕获它。

它被handleInvalidInputException处理程序捕获,我可以在日志中看到它:

InvalidInputException

我希望由于控制器使用此POJO来解析请求参数,因此可以捕获自定义异常。

如果要测试,我可以通过以下方式直接从控制器中抛出自定义@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)
    ...

然后我可以看到InvalidInputException处理程序按预期捕获了它。

    @GetMapping("/highlights")
    public ResponseEntity<List<Highlight>> getHighlights(
            @Valid HighlightFilterCriteria highlightFilterCriteria
            ) {
        if (true) throw new InvalidInputException("userId","should be UUID");
        ...
    }

主要问题是为什么InvalidInputException的{​​{1}}异常处理程序未捕获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异常处理程序却捕获了它?

或者也许我正试图以一种不正确的方式在POJO中进行验证,如果是这样,那么当控制器方法获得POJO时,处理诸如ISO格式的UUID和Date之类的复杂类型的解析错误的正确方法是什么?作为论点?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)