在自定义对象中包装默认REST错误响应

时间:2018-08-31 12:05:28

标签: json rest spring-boot exception-handling

我正在构建用于集成目的的简单REST api,并且我希望响应尽可能一致(无论错误如何都相同)。

我过去曾经使用过@ExceptionHandler方法-因此,如果我没记错的话,我很可能会使用该类的版本……@ControllerAdvice

我知道它是可行的,在帮助我之前我已经使用过SO,它只需要进行设置即可。 这不是我的问题...

API允许创建消息和搜索消息(两个单独的请求),因此可以接受内部验证的日期值。经过测试,我收到了一个格式非常好且非常详细的错误响应:

{
    "timestamp": "2018-08-31T10:35:10.748+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "typeMismatch.IntegrationMessageFilter.fromDate",
                "typeMismatch.fromDate",
                "typeMismatch.java.util.Date",
                "typeMismatch"
            ],
            "arguments": [
                {
                    "codes": [
                        "IntegrationMessageFilter.fromDate",
                        "fromDate"
                    ],
                    "arguments": null,
                    "defaultMessage": "fromDate",
                    "code": "fromDate"
                }
            ],
            "defaultMessage": "Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'fromDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@com.fasterxml.jackson.annotation.JsonFormat java.util.Date] for value '213-456-45'; nested exception is java.lang.IllegalArgumentException",
            "objectName": "IntegrationMessageFilter",
            "field": "fromDate",
            "rejectedValue": "213-456-45",
            "bindingFailure": true,
            "code": "typeMismatch"
        }
    ],
    "message": "Validation failed for object='IntegrationMessageFilter'. Error count: 1",
    "path": "/Integration/get"
}

我要做的是拦截此错误并将其包装在我自己的响应对象中,该对象将是每个可用API方法的响应对象: 例如

{
    "success": Boolean,
    "messageId": Integer, (null on search, int on successful create)
    "messages": Array, (searched IntegrationMessage objects)
    "errorMessage": String, (error message during manual validation (e.g. range validation depending on the field))
    "error" [SPRING DEFAULT ERROR] (this is what i want to intercept from spring-boot and include in this response object)
}

当系统已经执行完手动创建详细的错误消息时,手动操作似乎有点无意义...我不知道它用来创建上面的第一条JSON消息的对象是什么,即使我可以拦截它。

注意:这纯粹是为了给API用户带来便利,他们不必区分不同的响应对象,也为我带来方便,而不必重新开发轮子(可以这么说)

1 个答案:

答案 0 :(得分:0)

好的,所以我找到了实现(想要)我想要的东西的方法。

给我的印象是,无论异常类型如何,我都可以拦截完整的异常响应消息并将其放入对象中。事实证明,我可以得到最多个默认信息,但这是特定于每种错误类型的(显然)。

第一次尝试:
我的第一个尝试是使用以下命令简单地“测试”默认错误响应。这是为了确定spring在做什么(它正在使用哪个错误-我确实认为这是handleTypeMismatch异常)-下面的方法只是该类中的一种(我正在处理的一种)与):

@ControllerAdvice
public class IntegrationExceptionHandler extends ResponseEntityExceptionHandler
{
    @Override
    public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
    {
        return super.handleBindException(ex, headers, status, request);
    }
}

我希望得到与默认错误消息完全相同的错误消息,但是这没有响应(或响应为空)。

我的“解决方案”:
虽然我不必重新开发轮子,但我必须做一些箍跳动作:

    @Override
    public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
    {               

        IntegrationResponse response = new IntegrationResponse(ex.getMessage());
        response.setErrors(ex.getBindingResult().getAllErrors());

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

错误为private List<ObjectError> errors;org.springframework.validation.ObjectError

因此,我将不得不尝试在ResponseEntityExceptionHandler(适用于我的情况)中复制每个可覆盖的错误,并对其进行稍微不同的处理,现在您可以看到为什么我只想包装现有的错误响应

仅作为旁注,我确实尝试在响应对象中添加:private Object error;private BindingResult error;作为变量,但是这两次尝试似乎都拒绝了我的响应对象并仅显示默认消息(好像没有控制器建议),也没有任何提示。

如果有人发现如何跳过ResponseEntityExceptionHandler步骤并仅包装默认的异常响应对象,我将很乐意接受该答案。