如何在异常处理程序中更改内容类型


问题内容

假设我有一个控制器,该控制器为GET请求提供服务并返回要序列化为JSON的bean,并且还提供了IllegalArgumentException可以在服务中引发的异常处理程序:

@RequestMapping(value = "/meta/{itemId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public MetaInformation getMetaInformation(@PathVariable int itemId) {
    return myService.getMetaInformation(itemId);
}

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleIllegalArgumentException(IllegalArgumentException ex) {
    return ExceptionUtils.getStackTrace(ex);
}

消息转换器是:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
        <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>

现在,当我在浏览器中请求给定的URL时,我会看到正确的JSON答复。但是,如果引发异常,则将字符串化的异常也转换为JSON,但我希望将其处理为StringHttpMessageConverter(导致text/plainmime类型)。我该怎么办?

为了使图片更完整(更复杂),假设我还具有以下处理程序:

@RequestMapping(value = "/version", method = RequestMethod.GET)
@ResponseBody
public String getApplicationVersion() {
    return "1.0.12";
}

这个处理器允许返回串,都被序列化MappingJackson2HttpMessageConverter,并StringHttpMessageConverter根据传入Accept- type客户端。返回类型和值应如下所示:

+----+---------------------+-----------------------+------------------+-------------------------------------+
| NN | URL                 | Accept-type           | Content-type     | Message converter                   |
|    |                     | request header        | response header  |                                     |
+----+---------------------+-----------------------+------------------+-------------------------------------+
| 1. | /version            | text/html; */*        | text/plain       | StringHttpMessageConverter          |
| 2. | /version            | application/json; */* | application/json | MappingJackson2HttpMessageConverter |
| 3. | /meta/1             | text/html; */*        | application/json | MappingJackson2HttpMessageConverter |
| 4. | /meta/1             | application/json; */* | application/json | MappingJackson2HttpMessageConverter |
| 5. | /meta/0 (exception) | text/html; */*        | text/plain       | StringHttpMessageConverter          |
| 6. | /meta/0 (exception) | application/json; */* | text/plain       | StringHttpMessageConverter          |
+----+---------------------+-----------------------+------------------+-------------------------------------+

问题答案:

我想移除produces = MediaType.APPLICATION_JSON_VALUE@RequestMappinggetMetaInformation会给你想要的结果。

响应类型将根据Accept标头中的内容类型值进行协商。


编辑

由于这不涉及场景3,4,因此以下是ResponseEntity.class直接使用的解决方案:

@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleIllegalArgumentException(Exception ex) {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.TEXT_PLAIN);
    return new ResponseEntity<String>(ex.getMessage(), headers, HttpStatus.BAD_REQUEST);
}