Spring @ExceptionHandler 不适用于 @ResponseBody
Posted
技术标签:
【中文标题】Spring @ExceptionHandler 不适用于 @ResponseBody【英文标题】:Spring @ExceptionHandler does not work with @ResponseBody 【发布时间】:2011-07-03 02:23:11 【问题描述】:我尝试为休息控制器配置一个弹簧异常处理程序,该处理程序能够根据传入的接受标头将映射呈现到 xml 和 json。它现在抛出一个 500 servlet 异常。
这行得通,它拿起了 home.jsp:
@ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request, Writer writer)
return "home";
这不起作用:
@ExceptionHandler(IllegalArgumentException.class)
public @ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)
final Map<String, Object> map = new HashMap<String, Object>();
map.put("errorCode", 1234);
map.put("errorMessage", "Some error message");
return map;
在同一控制器中,通过相应的转换器将响应映射到 xml 或 json:
@RequestMapping(method = RequestMethod.GET, value = "/book/id", headers = "Accept=application/json,application/xml")
public @ResponseBody
Book getBook(@PathVariable final String id)
logger.warn("id=" + id);
return new Book("12345", new Date(), "Sven Haiges");
【问题讨论】:
ExceptionHandler returning JSON or XML not working in spring mvc 3的可能重复 【参考方案1】:我遇到了类似的问题,当您的 Controller 方法返回类型和 ExceptionHandler 返回类型不相同时会出现此问题。确保您具有完全相同的返回类型。
控制器方法:
@RequestMapping(value = "/id", produces = "application/json", method = RequestMethod.POST)
public ResponseEntity<?> getUserById(@PathVariable String id) throws NotFoundException
String response = userService.getUser(id);
return new ResponseEntity(response, HttpStatus.OK);
建议方法:
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<?> notFoundException(HttpServletRequest request, NotFoundException e)
ExceptionResponse response = new ExceptionResponse();
response.setSuccess(false);
response.setMessage(e.getMessage());
return new ResponseEntity(response, HttpStatus.NOT_FOUND);
如您所见,两个类中的返回类型相同 ResponseEntity<?>
。
【讨论】:
【参考方案2】:我使用的是 Spring 3.2.4。我对这个问题的解决方案是确保我从异常处理程序返回的对象具有 getter。
没有 getter,Jackson 无法将对象序列化为 JSON。
在我的代码中,对于以下 ExceptionHandler:
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public List<ErrorInfo> exceptionHandler(Exception exception)
return ((ConversionException) exception).getErrorInfos();
我需要确保我的 ErrorInfo 对象有 getter:
package com.pelletier.valuelist.exception;
public class ErrorInfo
private int code;
private String field;
private RuntimeException exception;
public ErrorInfo()
public ErrorInfo(int code, String field, RuntimeException exception)
this.code = code;
this.field = field;
this.exception = exception;
public int getCode()
return code;
public String getField()
return field;
public String getException()
return exception.getMessage();
【讨论】:
【参考方案3】:AnnotationMethodHandlerExceptionResolver 也需要 MappingJacksonHttpMessageConverter
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper"
class="iacm.cemetery.framework.web.servlet.rest.JacksonObjectMapper" />
【讨论】:
我没有意识到 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 的 messageConverters 需要复制到 org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver。我想你知道的越多。【参考方案4】:谢谢,看来我读多了。这很糟糕......任何想法如何提供 自动以 xml/json 格式出现异常?
Spring 3.0 中的新功能 MappingJacksonJsonView 可以用来实现:
private MappingJacksonJsonView jsonView = new MappingJacksonJsonView();
@ExceptionHandler(Exception.class)
public ModelAndView handleAnyException( Exception ex )
return new ModelAndView( jsonView, "error", new ErrorMessage( ex ) );
【讨论】:
自 Spring 4.0.0 MappingJacksonJsonView 已弃用其构造函数。见:docs.spring.io/spring/docs/4.0.5.RELEASE/javadoc-api/org/… @borjab 不是因为这是一种无效的方法,而是因为他们正在推动迁移到MappingJackson2JsonView【参考方案5】:如果您使用消息转换器将错误对象编组为响应内容,则以下可能是一种解决方法
@ExceptionHandler(IllegalArgumentException.class)
public String handleException(final Exception e, final HttpServletRequest request)
final Map<String, Object> map = new HashMap<String, Object>();
map.put("errorCode", 1234);
map.put("errorMessage", "Some error message");
request.setAttribute("error", map);
return "forward:/book/errors"; //forward to url for generic errors
//set the response status and return the error object to be marshalled
@SuppressWarnings("unchecked")
@RequestMapping(value = "/book/errors", method = RequestMethod.POST, RequestMethod.GET)
public @ResponseBody Map<String, Object> showError(HttpServletRequest request, HttpServletResponse response)
Map<String, Object> map = new HashMap<String, Object>();
if(request.getAttribute("error") != null)
map = (Map<String, Object>) request.getAttribute("error");
response.setStatus(Integer.parseInt(map.get("errorCode").toString()));
return map;
【讨论】:
这绝对应该被选为这个话题的答案!谢谢你,伙计!【参考方案6】:这似乎是一个已确认的错误 (SPR-6902 @ResponseBody 不适用于 @ExceptionHandler)
https://jira.springsource.org/browse/SPR-6902
虽然已在 3.1 M1 中修复...
【讨论】:
【参考方案7】:你的方法
@ExceptionHandler(IllegalArgumentException.class)
public @ResponseBody Map<String, Object> handleException(final Exception e, final HttpServletRequest request, Writer writer)
不起作用,因为它具有错误的返回类型。 @ExceptionHandler 方法只有两种有效的返回类型:
字符串 模型和视图。请参阅http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html 了解更多信息。以下是链接中的具体文字:
返回类型可以是字符串, 被解释为视图名称或 ModelAndView 对象。
回应评论
谢谢,看来我读多了。那是 坏...任何想法如何提供 在 xml/json 中自动出现异常 格式? – Sven Haiges 7 小时前
这是我所做的(我实际上是在 Scala 中完成的,所以我不确定语法是否完全正确,但你应该明白要点)。
@ExceptionHandler(Throwable.class)
@ResponseBody
public void handleException(final Exception e, final HttpServletRequest request,
Writer writer)
writer.write(String.format(
"\"error\":\"java.class\":\"%s\", \"message\":\"%s\"",
e.getClass(), e.getMessage()));
【讨论】:
谢谢,看来我读多了。这很糟糕......有什么想法如何以 xml/json 格式自动提供异常? 您好,只是为了评论@ExceptionHandler 方法的返回类型非常广泛。根据文档,它可以是 ModelAndView、Model 对象、java.util.Map、org.springframework.web.servlet.View、String 或 void 请注意,由于您没有返回类型 (void
),因此 @ResponseBody
没有意义,可以省略。
是的,从 Spring 3.1 开始,@ResponseBody 方法可以返回一个对象,这将被传递给一个 HttpMessageConverter 以转换为一个表示。以上是关于Spring @ExceptionHandler 不适用于 @ResponseBody的主要内容,如果未能解决你的问题,请参考以下文章
如何在@ExceptionHandler(Spring REST)中获取@RequestBody
@ExceptionHandler 用于 Spring 中的包装异常 / getCause()
spring 新版本 ExceptionHandler 了解
Spring的 @ExceptionHandler注解无效问题