Spring MVC @ControllerAdvice 异常行为因异常源而异

Spring MVC @ControllerAdvice exception behavior different based on Exception source

取决于 DuplicateKeyException (DKE) 是通过调用 NamedParameterJdbcTemplate(即 jdbcTemplate.update(sql, namedParameter))还是由我在代码中明确抛出,行为是非常不一样。

当 jdbcTemplate 调用抛出 DKE 时,会发生正确的行为。我的@ControllerAdvice 启动,正确的 HTTP 状态和 ResponseBody 被 returned。但是,当我明确抛出 DKE 时,return 向客户端发送了一个 500 错误,即使我看到我的 @ControllerAdvice class 中的正确代码块正在被访问。

这是处理异常的代码,它应该总是 return HttpStatus.OK 以及一个 RestError:

@ExceptionHandler(DuplicateKeyException.class)
@ResponseStatus(value = HttpStatus.OK)
public @ResponseBody RestError handleDuplicateKey(
    HttpServletRequest request, Exception ex) {     

    logger.error("GlobalExceptionHandler handling exception of type DuplicateKeyException.class: ", ex);
    return new RestError(HttpStatus.CONFLICT, 
                     ErrorCode.DUPLICATE_ENTRY, 
                     ex.getCause().getMessage());
    }

下面是可以抛出 DKE 的代码:

public void insertSubscriber(SubscriberInfo subscriberInfo) {

    if (isAlreadySubscribed(subscriberInfo)) {
        // this will result in a 500 http error to the client
        throw new DuplicateKeyException(
            String.format("This subscriber is already subscribed");
    }

    String sql = "INSERT INTO subscribers (firstname, email, postal_code, subscriber_type) "
               + "VALUES (:firstname, :email, :postal_code, :subscriber_type)";

    HashMap<String, String> namedParameter = Maps.newHashMapWithExpectedSize(4);
    namedParameter.put("email", subscriberInfo.getEmail());
    namedParameter.put("postal_code", subscriberInfo.getPostalCode());
    namedParameter.put("subscriber_type", subscriberInfo.getUserType().getId());
    namedParameter.put("firstname", subscriberInfo.getFirstname());

    // if a DKE is thrown from the below line, everything works fine. 
    jdbcTemplate.update(sql, namedParameter);       
}

我真的很想了解为什么行为会根据异常的来源而有所不同。

我猜你只是在 DKE 中设置消息,而在异常处理程序中你正在做 ex.getCause().getMessage() 我猜这是抛出 NPE。尝试使用 msg 设置 Throwable cause 并试一试。