【问题标题】:Spring boot handle type mismatch errorsSpring Boot 句柄类型不匹配错误
【发布时间】:2020-01-16 13:08:08
【问题描述】:

我使用的是 Spring Boot 2.1.5,并且我有一个映射到从表单提交的数据的类。该类有一个整数字段:

class FormData {
   private Integer id;
   ...
}

当我发送错误类型的有效负载时,例如:

{
  id: "aaaa"
}

Spring 静默返回 400 状态,不抛出异常,控制台也不会打印任何内容。当这种情况发生时,我想以某种方式捕捉到这一点,以便能够返回正确的自定义错误。我基本上对所有其他验证都使用 bean 验证,但我找不到将其应用于类型不匹配的方法。

谢谢。

【问题讨论】:

  • 也分享你的控制器

标签: spring spring-boot bean-validation


【解决方案1】:

这种无效的参数类型转换会抛出一个TypeMismatchException,您可以使用带有@ExceptionHandler 注释的方法来处理它,例如,像这样:

@ExceptionHandler(TypeMismatchException.class)
@ResponseBody
public MyErrorResponse handleTypeMismatchException(TypeMismatchException typeMismatchException) {
    // create my error response
}

您可以将此方法放置在一个控制器中(在这种情况下,它将仅处理此控制器抛出的异常),或放置在带有 @ControllerAdvice 注释的类中(因此它将推广到您的所有控制器)。

【讨论】:

  • 它对我不起作用 - 我的 ControllerAdvice 中没有捕获 TypeMismatchException
  • @Matley ControllerAdvice 是否被组件扫描获取?它是否针对具有“basePackages”或“注释”等选项的控制器子集?
  • 当然!您确定反序列化期间引发的异常(在我的情况下将 String 转换为 Long)应该在 ExceptionHandler 的 ControllerAdvice 中捕获吗?
【解决方案2】:

Spring Controller 将为您的情况抛出 TypeMismatchException

要在控制器级别处理任何异常,您可以使用 @ExceptionHandler 注释方法

像这样的

@ExceptionHandler(TypeMismatchException.class)
@ResponseBody
public SampleObject handleTypeMismatchException(TypeMismatchException typeMismatchException) {
    ...
}

您还可以使用@ControllerAdvice. 配置全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {

    /** Provides handling for exceptions throughout this service. */
    @ExceptionHandler({ TypeMismatchException.class })
    public final ResponseEntity<ApiError> handleException(Exception ex, WebRequest request) {
        HttpHeaders headers = new HttpHeaders();

        HttpStatus status = HttpStatus.BAD_REQUEST;
        TypeMismatchException tme = (TypeMismatchException) ex;
        return handleTypeMismatchException(tme, headers, status, request);

    }


    /** Customize the response for TypeMismatchException. */
    protected ResponseEntity<ApiError> handleTypeMismatchException(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<String> errorMessages = ex.getErrors()
                .stream()
                .map(contentError -> contentError.getObjectName() + " " + contentError.getDefaultMessage())
                .collect(Collectors.toList());

        return handleExceptionInternal(ex, new ApiError(errorMessages), headers, status, request);
    }

    /** A single place to customize the response body of all Exception types. */
    protected ResponseEntity<ApiError> handleExceptionInternal(Exception ex, ApiError body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
            request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
        }

        return new ResponseEntity<>(body, headers, status);
    }
}

【讨论】:

    【解决方案3】:

    尝试 HttpMessageNotReadableException

    为我工作

    【讨论】:

    • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
    【解决方案4】:

    创建自己的@ControllerAdvice 类并像这样处理TypeMismatchException

    @ExceptionHandler({
            MethodArgumentTypeMismatchException.class,
            TypeMismatchException.class
    })
    public ResponseEntity<Map<String, String>> handleException(TypeMismatchException e) {
        Map<String, String> errorResponse = new HashMap<>();
    
        errorResponse.put("message", e.getLocalizedMessage());
        errorResponse.put("status", HttpStatus.BAD_REQUEST.toString());
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
    }
    

    更多信息请参考Custom Error Messages in Spring REST API

    【讨论】:

      【解决方案5】:

      如果您使用的是复杂的 JSON,则可能会出现另一个错误。就我而言,我与List&lt;BigDecimal&gt; 有类似的东西,我有HttpMessageNotReadableException 而不是TypeMismatchException

      我使用了带有@RestControllerAdvice 的自定义验证处理程序(实际上您也可以使用@ControllerAdvice)。这两个注解有什么区别你可以在这里找到:https://stackoverflow.com/a/43124517/5631885

      如果您使用extends 策略,例如:

      @ControllerAdvice    
      public class ValidationExceptionHandler extends ResponseEntityExceptionHandler
      

      只需要重写handleHttpMessageNotReadable方法

      @Override
      protected ResponseEntity<Object> handleHttpMessageNotReadable(
              HttpMessageNotReadableException ex,
              HttpHeaders headers,
              HttpStatus status,
              WebRequest request) {
      
          Map<String, Object> body = new LinkedHashMap<>();
          body.put(TIMESTAMP_KEY, new Date());
          body.put(STATUS_KEY, status.value());
          body.put(ERROR_KEY, ex.getCause().getMessage());
          return new ResponseEntity<>(body, headers, status);
      }
      

      否则,在方法上方加上@ExceptionHandler(HttpMessageNotReadableException.class)注解。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-19
        • 2017-03-04
        • 1970-01-01
        • 2013-01-16
        • 2014-09-23
        • 2014-02-05
        相关资源
        最近更新 更多