java - 使用 ResponseBody 并返回 Model 类实例的 Controller 方法上的奇怪 Spring MVC 4.2.x 行为

标签 java spring spring-mvc model-view-controller

我有一些旧 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)的类:ModelMap .

因此,修改后/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 时会发生什么?返回 ModelMap .

返回 Map 是很常见的编码为 JSON,并且可以正常工作,即 @ResponseBody优先于返回类型 Map 。这是有道理的。

但是,Model专门用于 View 的模型属性,因此返回类型 Model优先于@ResponseBody有一定道理。但正如我所说,这不是指定的行为,但也不是错误。它未定义

如果你问我它应该做什么,我会保留它未定义,因为 Model@ResponseBody对我来说没有任何意义。

<小时/>

此外,文档没有区分声明的返回类型和实际返回类型,因此使用的是未定义

该实现使用实际返回类型,其优点是您的处理程序方法可以返回 Object然后返回例如一个ModelAndViewHttpEntity ,取决于条件。这种灵 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/

相关文章:

Java:比较 3 个正整数时出现问题

java - 了解 spring mvc 中 enctype = multipart/form-data 的工作原理

spring - Spring MVC-HttpSession.setAttribute和model.addObject之间的区别

java - Spring mvc 4 hello world 示例抛出 javax.servlet.ServletException : Failed to instantiate WebApplicationInitializer class

java - JavaScript 和 JMS 的集成

java - 为什么 java.sql.DriverManager.getConnection(...) 挂起?

java - 使用 JAX-RS 处理异步 http 请求?

java - 如何在 Spring @Value 注解中正确指定默认值?

java - 如果返回类型为 java.sql.Timestamp,则基于接口(interface)的投影 getter 方法给出异常

规范中的 spring-data 子查询