Java Spring MVC中的自定义HttpMessageConverter

Java Spring MVC中的自定义HttpMessageConverter,java,spring,spring-mvc,Java,Spring,Spring Mvc,在实现RESTfulAPI时,我将所有数据包装在一个对象中,使其看起来像这样 {error: null, code: 200, data: {...actual data...}} 这导致我在任何地方都使用重复代码来包装数据: @Transactional @RequestMapping(value = "/", method = RequestMethod.GET) public @ResponseBody Result<List<BookShortDTO>> boo

在实现RESTfulAPI时,我将所有数据包装在一个对象中,使其看起来像这样

{error: null, code: 200, data: {...actual data...}}
这导致我在任何地方都使用重复代码来包装数据:

@Transactional
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody Result<List<BookShortDTO>> books() {

    List<Book> books = booksDao.readBooks();
    return Result.ok(books); // this gets repeated everywhere
}
@Transactional
@RequestMapping(value=“/”,method=RequestMethod.GET)
public@ResponseBody结果书(){
List books=booksDao.readBooks();
返回结果。ok(books);//这会在任何地方重复
}

所以问题是,我如何修改它(可能使用定制的HttpMessageConverter,可能还有其他方式?),只返回booksDao.readBooks(),并自动包装它。

我想,而不是更改消息转换器(这会起作用),我会使用AOP方法——关于所有相关控制器方法的建议都很容易设置。它还将为您提供更好的编程模型,以及对拦截哪些方法的细粒度控制。

您可以使用替换结果

关键点是:在将(修改的)retunr值委托给序列化之前替换返回值


参见本博客:有关如何归档类似(不相同)目标的示例。它还描述了注册
HandlerMethodReturnValueHandler
(另一种方法请参见)

就像@Ralph建议的那样,您可以使用
HandlerMethodReturnValueHandler
包装处理程序返回值

实现这一点的最简单方法是扩展
RequestResponseBodyMethodProcessor
并稍微改变它的行为。最好是创建一个自定义注释来标记处理程序方法。这将确保在默认情况下调用您的
HandlerMethodReturnValueHandler
,而不是
RequestMappingHandlerAdapter
中包含的其他函数

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ResultResponseBody {}
下面是名为
ResultResponseHandlerMethodProcessor
的自定义
HandlerMethodReturnValueHandler
的简单实现,它将支持从带有
ResultResponseBody
注释的方法返回的值。这很简单。只需覆盖
supportsReturnType()
handleReturnValue()
方法,以满足您的需要(将返回值包装成
结果
类型)


我想试着说服你,你所做的是正确的,不需要任何改变

正如您在问题的评论中所说,您有许多不同的
Result
方法来设置错误消息、代码和数据。差不多

Result.ok(data)
Result.forbidden()
Result.badRequest("<Something> caused a syntax error.") 
Result.notModified("The entity was not modified.")
return new ResponseEntity<>(Result.ok(books)); 
在这种情况下,默认状态代码为200

但是如果你想使用

return Result.forbidden();
你会用

return new ResponseEntity<>(Result.forbidden(), HttpStatus.FORBIDDEN);
返回新的响应属性(Result.forbidden(),HttpStatus.forbidden);

Spring将使用相同的
HttpMessageConverter
结果
转换为JSON,但在这里您将对HTTP响应有更多的控制权。

我认为有必要

将默认的RequestResponseBodyMethodProcessor替换为您的所有者 处理机


,否则默认的RequestResponseBodyMethodProcessor将控制返回值的处理。

将jackson 2+添加到类路径中,以使用
MappingJackson2HttpMessageConverter对JSON进行序列化和反序列化。
已经存在。问题是,我希望它自动将我的结果包装在结果对象中,这样我就不必编写返回结果;在每个响应中使用
结果。好的
,我们是否应该假设您有其他
结果
方法来处理不同的错误代码和消息?是的。例如,如果用户没有适当的权限,我可以返回Result.probled(),您可以提供一些示例吗?Spring MVC的
RequestMappingHandlerAdapter
提供了
HandlerMethodReturnValueHandler
的列表,因此您不必求助于AOP。只有当AOP是最后一个可能的解决方案时,我才会使用它。虽然这个链接可以回答这个问题,但最好在这里包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,则“仅链接”答案可能无效。@Martin J-通常您是对的,但是:1)答案是“使用HandlerMethodReturnValueHandler”(而不是HttpMessageConverter)。2) 当我打这个的时候,我只有一个手机phpne:所以只有两种可能的方式:不举一个例子,或者举一个仅仅是博客链接的例子。谢谢,我不知道ResponseEntity,它看起来很方便+1这很有意义。相反,它将注意力集中在想要的解决方案上,而是集中在给定问题的最佳解决方案上。事实上,如果我被要求实现REST控制器,我会像这样做。这应该被标记为答案。这正是我想要的!谢谢您不需要重写
supportsReturnType
,只要它与super类一样,或者我遗漏了什么?@Ralph,如果您想支持您所做的自定义注释。至于其他方面,我想你是对的。@Bart-对不起,你完全正确-你在上面的文本中描述了它“最好是创建一个自定义注释,用…”标记你的处理程序方法。”拉尔夫想起来了。如果
supportsReturnType
RequestResponseBodyMethodProcessor
相同,则
RequestResponseBodyMethodProcessor
将是处理返回值的处理器。不是自定义处理程序。
return Result.forbidden();
return new ResponseEntity<>(Result.forbidden(), HttpStatus.FORBIDDEN);