【问题标题】:Spring 3.2 @ResponseBody not working with a Model return valueSpring 3.2 @ResponseBody 不使用模型返回值
【发布时间】:2013-12-29 18:53:44
【问题描述】:

以下映射适用于 Spring 3.1,但不适用于 Spring 3.2。 我收到一个 404 错误,说明 table.jsp 文件丢失。相反,“模型”应该序列化为 json。

    @RequestMapping(value = {"/table"}, method = RequestMethod.GET, produces="application/json")
    public @ResponseBody Model table(Model model, @RequestParam(defaultValue = "1") Integer pg) {
        fillListModel(model, pg);
        return model;
    }

有没有办法在不影响现有代码的情况下解决这个问题?

以下代码可以正常工作:

    @RequestMapping(value = {"/table"}, method = RequestMethod.GET, produces="application/json")
    public @ResponseBody Model table(Model model, @RequestParam(defaultValue = "1") Integer pg) {
        return new User();
    }

所以看起来 Spring 无法识别返回模型的目的是为了将其转换为 json 而不是在视图中呈现。

【问题讨论】:

  • Model 是 Spring 类还是您的自定义类?
  • Model为spring模型:org.springframework.ui.Model
  • 这仍然是Spring 4.2.x的实际问题

标签: java json spring spring-mvc


【解决方案1】:

这是 Spring 3.2+(我不记得 3.1 是如何做到的)处理 @RequestMapping 方法的返回值的结果。 Spring 使用HandlerMethodReturnValueHandler 类型的实例来解决应该如何处理返回的值。浏览 javadoc 也可以看到不同的类型。

在配置 MVC 环境时,如果使用默认的 @EnableWebMVC<mvc:annotation-driven>,Spring 会按特定顺序注册这些实例。这发生在RequestMappingHandlerAdapter#getDefaultReturnValueHandlers() 方法中,如下所示

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
    List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

    // Single-purpose return value types
    handlers.add(new ModelAndViewMethodReturnValueHandler());
    handlers.add(new ModelMethodProcessor());
    handlers.add(new ViewMethodReturnValueHandler());
    handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
    handlers.add(new CallableMethodReturnValueHandler());
    handlers.add(new DeferredResultMethodReturnValueHandler());
    handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

    // Annotation-based return value types
    handlers.add(new ModelAttributeMethodProcessor(false));
    handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));

    // Multi-purpose return value types
    handlers.add(new ViewNameMethodReturnValueHandler());
    handlers.add(new MapMethodProcessor());

    // Custom return value types
    if (getCustomReturnValueHandlers() != null) {
        handlers.addAll(getCustomReturnValueHandlers());
    }

    // Catch-all
    if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
        handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
    }
    else {
        handlers.add(new ModelAttributeMethodProcessor(true));
    }

    return handlers;
}

当您的方法返回一个值时,Spring 会遍历这些处理程序,调用它们的 supportsReturnType() 方法并选择它找到的第一个返回 true 的方法。

在这种情况下,处理Model 返回值的ModelMethodProcessor 具有更高的优先级(在之前注册)处理@ResponseBodyRequestResponseBodyMethodProcessor

因此,您不能返回 Model 并通过 @ResponseBody 将其转换为 JSON。在我看来,你根本不应该这样做。 Model 可供DispatcherServlet 堆栈的大多数部分访问,因此许多模块可以添加/删除最终 JSON 中可能不需要的属性。

只需像在第二个示例中那样使用 DTO。

【讨论】:

  • 打我一拳。不过,您可以设置自己的列表,从而根据需要定义默认处理程序的顺序。
  • @zero 是的,您必须使用 RequestMappingHandlerAdapter bean 进行一些自定义配置。我觉得不值得。
  • 感谢各位的帮助。 @Sotirios,很好的解释,正是我需要的。我不会重新配置 spring,我会采用 Sotirios 推荐的 DTO 方法。
  • 可能不是,但每个解决方案都有问题 ;)
  • @Sotirios Delimanolis: HandlerMethodReturnValueHandler 应该在 spring 3.1 中以相同的方式工作(但从 3.0 到 3.1 发生了变化)
猜你喜欢
  • 2014-10-22
  • 2014-10-28
  • 2013-06-21
  • 2013-01-20
  • 1970-01-01
  • 2023-03-19
  • 2011-06-18
  • 2014-12-12
  • 2013-06-15
相关资源
最近更新 更多