【问题标题】:Add new field in body exception spring rest在身体异常弹簧休息中添加新字段
【发布时间】:2017-11-06 14:40:33
【问题描述】:

我想在我的 Rest spring boot 应用程序中处理异常。我知道使用 @ControllerAdvice 和 ResponseEntity 我可以返回一个自定义对象来代表我的错误,但我想要的是在现有异常的主体中添加一个新字段。

我创建了一个自定义异常,它继承了带有额外属性的 RuntimeException,一个字符串列表:

@ResponseStatus(HttpStatus.CONFLICT)
public class CustomException extends RuntimeException {

    private List<String> errors = new ArrayList<>();

    public CustomException(List<String> errors) {
        this.errors = errors;
    }

    public CustomException(String message) {
        super(message);
    }

    public CustomException(String message, List<String> errors) {
        super(message);
        this.errors = errors;
    }

    public List<String> getErrors() {
        return errors;
    }

    public void setErrors(List<String> errors) {
        this.errors = errors;
    }
}

在我的控制器中,我只是以这种方式抛出这个自定义异常:

@GetMapping("/appointment")
public List<Appointment> getAppointments() {
    List<String> errors = new ArrayList<>();
    errors.add("Custom message");
    throw new CustomException("This is my message", errors);
}

当我用邮递员测试我的 Rest 端点时,似乎 spring boot 没有编组我的错误字段,响应是:

{
  "timestamp": "2017-06-05T18:19:03",
  "status": 409,
  "error": "Conflict",
  "exception": "com.htech.bimaristan.utils.CustomException",
  "message": "This is my message",
  "path": "/api/agenda/appointment"
}

如果我可以从异常中获取“路径”和“时间戳”字段,我可以使用 @ControllerAdvice 获取自定义对象,但是这两个属性没有 getter。

谢谢。

【问题讨论】:

    标签: java spring rest spring-boot exception-handling


    【解决方案1】:

    好吧!这是 DefaultErrorAttributes 中“路径”和“时间戳”的实现,您也可以在自定义实现中实现:

    路径:

    String path = getAttribute(requestAttributes, "javax.servlet.error.request_uri");
    if (path != null) {
        errorAttributes.put("path", path);
    }
    

    时间戳:

    errorAttributes.put("timestamp", new Date());
    

    spring boot 中错误定制的文档是here

    @Bean
    public ErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes() {
            @Override
            public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
                Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
                // customize here
                return errorAttributes;
            }
    
       };
    }
    

    或者您可以编写自定义实现:

    @Component
    public class CustomErrorAttributes extends DefaultErrorAttributes {
    
        @Override
        public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
            Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
            // customize here
            return errorAttributes;
        }
    }
    

    ErrorAttributes bean 自定义错误响应如下:

    {
       "timestamp": 1413883870237,
       "status": 500,
       "error": "Internal Server Error",
       "exception": "org.example.ServiceException",
       "message": "somthing goes wrong",
       "path": "/index"
    }
    

    "exception" 属性可以使用@ExceptionHandler 进行自定义。 @ControlerAdvice 可用于跨控制器自定义异常。要在控制器级别进行自定义,您可以将它们放在控制器中。

    在你的情况下:

       @ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Invalid Inputs")
        @ExceptionHandler(CustomException.class)
        private void errorHanlder() {
            //Log exception
        }
    
    
      public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
        Throwable error = getError(requestAttributes);
        if (error instanceof CustomException) {
            errorAttributes.put("errorList", ((CustomException)error).getErrors());
        }
        return errorAttributes;
    }
    

    【讨论】:

    • 我尝试将此功能集成到我的控制器中,但每次调用我的端点时都会出现此异常:org.thymeleaf.exceptions.TemplateInputException: Error resolve template "generic/error", template任何配置的模板解析器可能不存在或可能无法访问
    • 我认为您正在实现 REST 端点。所以,使用 ResponseEntity。
    • 这个解决方案是我在问题帖子中谈到的。我可以使用它,但是如何从异常主体中获取路径和时间戳属性,以便我可以将它们添加到自定义错误对象中?
    • 对不起!我忽略了。更新了答案。
    • 谢谢@YuVi。方法errorAttributes应该在控制器类中声明吗?这个声明将为所有异常添加一个新的键值对,还是我应该在每个异常处理程序中单独自定义它?
    【解决方案2】:

    以前的答案确实有这一切,但不知何故我花了一段时间才弄明白,所以总的来说,实现这一点的最简单方法是拥有这样的 bean:

    @Bean
    public ErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes() {
            @Override
            public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
                    boolean includeStackTrace) {
                Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
                Throwable error = getError(requestAttributes);
                if (error instanceof CustomExceptionthere) {
                    errorAttributes.put("errorList", ((CustomException)error).getErrors());
                }
                return errorAttributes;
            }
    
        };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多