我有一些旧 Controller ,它将一些数据放入 Model
中对象(Thymeleaf 模板所需)。
现在我必须在 REST 服务中返回与 JSON 相同的数据。
出于这些目的,我将数据准备 block 包装到单独的方法中以在两个地方使用:在用于 thymeleaf 模板的旧方法中和在新方法中:
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index(Model model) {
prepareIndexModel(model);
return "index";
}
@RequestMapping(value = "/index/model", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> indexModel(Model model) {
prepareIndexModel(model);
return model.asMap();
}
private void prepareIndexModel(Model model) {
model.addAttribute("prop1", ...);
...
}
但是,当我尝试通过 GET /index/model
访问时我收到以下错误:
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "/WEB-INF/templates/index/model.html")
所以它只是认为我的方法不是 REST 方法。我想,这是因为方法实际上返回 ExtendedModelMap
的实例实现两个接口(interface)的类:Model
和Map
.
因此,修改后/index/model
方法:
@RequestMapping(value = "/index/model", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Map<String, Object> indexModel(Model model) {
prepareIndexModel(model);
return new LinkedHashMap<>(model.asMap());
}
一切都按预期开始工作:GET /index/model
返回我想要的 JSON。所以基本上我只是将模型包装成 LinkedHashMap
.
我的问题是:这是一个指定的行为还是仅仅是一个错误?我希望通过使用 @ResponseBody
注释一个方法来实现这一点。注解,Spring应该忽略返回对象是 Model
的实例这一事实。不应该吗?
更新:@Sotirios Delimanolis 提供了非常相似的 question 的链接。 ,大约是 3.2 版本。但我的问题是不是关于为什么,而是它是Spring的bug还是在文档中的某个地方指定了?
UPDATE-2:另请注意,在链接的问题中,方法有 Model
返回类型,及其行为进行了描述。就我而言,我有 Map<...>
返回类型,在我看来是什么让这种行为变得奇怪和不一致!
最佳答案
is this a specified behaviour or simply a bug?
我想说这是未定义行为。
Spring Framework Reference定义返回类型 Model
表示带有模型的 View 。它还定义了返回类型 Map
表示以 map 为模型的 View 。这些都是明确定义的。
它还指定对于用 @ResponseBody
注释的方法,返回值写入响应 HTTP 主体。同样,这是明确定义的。
它没有指定,当 @ResponseBody
时会发生什么?返回 Model
或Map
.
返回 Map
是很常见的编码为 JSON,并且可以正常工作,即 @ResponseBody
优先于返回类型 Map
。这是有道理的。
但是,Model
专门用于 View 的模型属性,因此返回类型 Model
优先于@ResponseBody
有一定道理。但正如我所说,这不是指定的行为,但也不是错误。它未定义。
如果你问我它应该做什么,我会保留它未定义,因为 Model
如@ResponseBody
对我来说没有任何意义。
此外,文档没有区分声明的返回类型和实际返回类型,因此使用的是未定义。
该实现使用实际返回类型,其优点是您的处理程序方法可以返回 Object
然后返回例如一个ModelAndView
或HttpEntity
,取决于条件。这种灵 active 是有道理的,但据我所知,它并没有明确定义。
所以,@ResponseBody
组合的结果,声明返回类型为Map
,但实际返回类型为 Model
,未定义。
如果你问我(你确实这么做了),我会说你的代码有问题。如果你想返回Map
要作为响应正文发送,为什么不直接创建 Map
你自己。向 Spring 框架请求 View Model
对我来说毫无意义。
考虑到使用 Model
的混合信号,即使阅读代码,我也不确定您的真正意图是什么。并指定 @ResponseBody
.
结论:不要偷懒,创建Map
你自己。
关于java - 使用 ResponseBody 并返回 Model 类实例的 Controller 方法上的奇怪 Spring MVC 4.2.x 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44440229/