【问题标题】:Spring MVC, Migrate @ExceptionHandler to HandlerExceptionResolver for a RESTful serviceSpring MVC,将@ExceptionHandler 迁移到 HandlerExceptionResolver 以获得 RESTful 服务
【发布时间】:2012-06-08 18:59:22
【问题描述】:

背景

我有一个错误消息类:

@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;
    }
}

这个类已作为返回值分配给我的 Spring MVC REST 控制器中的 @ExceptionHandler:

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

每当客户端在发出带有application/json 作为Accept 标头的请求后触发RuntimeException 时,它都会收到带有正确状态代码和匹配JSON 正文的响应:

{"error":"something went wrong"}

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

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errorMessage><error>something went wrong</error></errorMessage>

问题

现在,我想通过实现 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;
    }
}

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

(旁注,上例中的实际异常、响应代码和短信并不重要,它们只是作为简单示例。)

春季版:3.1.1.RELEASE

【问题讨论】:

    标签: java spring rest spring-mvc content-type


    【解决方案1】:

    要让@ExceptionHandlers 使用内容协商,AnnotationMethodHandlerExceptionResolver 有一个setMessageConverters() 方法,该方法必须随消息转换器一起提供,例如:

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
        <property name="messageConverters">
            <list>
                <ref bean="xmlConverter"/>
                <ref bean="jsonConverter"/>
            </list>
        </property>
    </bean>
    

    但由于您使用的是自定义方法,因此您可能必须自己实现此功能。最简单的方法可能是从AnnotationMethodHandlerExceptionResolver sourceCtrl-C Ctrl-V,特别是handleResponseBody() 方法。

    【讨论】:

    • 通过使用@EnableWebMvc or <mvc:annotation-driven /> 并在类路径中添加Jackson,您无需配置消息转换器。默认情况下,Spring 将为您提供 JSON、XML(和一些其他转换器)。我再仔细看看AnnotationMethodHandlerExceptionResolver的源码。
    • 贾哈;我从来没有在没有明确指定转换器的情况下使用@ExceptionHandlers 进行内容协商,但这可能取决于我配置的另一个方面。不幸的是,setMessageConverters() 似乎不是接口的一部分,因此消息转换器不太可能自动注入。另外,你好,来自马尔默。
    【解决方案2】:

    我花了一些时间调查此事,并写了一封blog post,在其中我提出了问题的解决方案。

    更新:如果您使用的是 Spring 3.2,则可以利用 @ControllerAdvice 注释。更多详情可以在我的second blog post找到。

    【讨论】:

      猜你喜欢
      • 2021-12-11
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 1970-01-01
      • 2015-12-20
      • 1970-01-01
      • 2015-02-20
      相关资源
      最近更新 更多