Spring MVC,将@ExceptionHandler迁移到HandlerExceptionResolver以获取RESTful服务

mat*_*sev 9 java rest spring content-type spring-mvc

背景

我有一个错误消息类:

@XmlRootElement
public class ErrorMessage {
    private String message;

    public ErrorMessage() {
    }

    public ErrorMessage(String message) {
        this.message = message;
    }

    public String getError() {
        return message;
    }

    public void setError(String message) {
        this.message = message;
    }
}
Run Code Online (Sandbox Code Playgroud)


此类已被指定为Spring MVC REST控制器中@ExceptionHandler的返回值:

@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
ErrorMessage handleException(RuntimeException e) {
    return new ErrorMessage("something went wrong");
}
Run Code Online (Sandbox Code Playgroud)

每当客户端触发RuntimeException发出一个请求后application/json,为Accept报头,它接收用正确的状态码和匹配JSON体的响应:

{"error":"something went wrong"}
Run Code Online (Sandbox Code Playgroud)

或者,如果Accept标头是application/xml:则接收XML主体:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errorMessage><error>something went wrong</error></errorMessage>
Run Code Online (Sandbox Code Playgroud)


问题

现在,我想通过实现一个HandlerExceptionResolver来使这个解决方案变得更好,所以我不必复制/粘贴@ExceptionHandler到每个控制器(或创建一个其他控制器可以扩展的公共"父控制器").

但是,AbstractHandlerExceptionResolver.doResolveException()方法返回一个ModelAndView而不是我的适当性ErrorMessage,所以我尝试了以下方法:

public class RuntimeExceptionHandlerExceptionResolver extends AbstractHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (ex instanceof RuntimeException) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            ModelAndView mav = new ModelAndView();
            mav.addObject("error", "something went wrong");
            return mav;
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

调试时,我可以看到mav.addObject()调用该方法.客户端的响应具有预期的状态代码,但内容类型text/html在正文中使用html,而不是Accept原始请求中的标头指定的JSON或XLM内容.

(旁注,上面示例中的实际异常,响应代码和文本消息并不重要,它们只是用作简单示例.)

Spring版本:3.1.1.RELEASE

mat*_*sev 4

我花了一些时间调查这个问题,并写了一篇博客文章,其中提出了该问题的解决方案。

更新:如果您使用 Spring 3.2,则可以利用@ControllerAdvice注释。更多详细信息可以在我的第二篇博文中找到。