简体   繁体   English

Spring 3.2 @ResponseBody无法与Model返回值一起使用

[英]Spring 3.2 @ResponseBody not working with a Model return value

The following mapping was working with Spring 3.1, but is not working with Spring 3.2. 以下映射适用于Spring 3.1,但不适用于Spring 3.2。 I get a 404 error with an explanation that the table.jsp file is missing. 我收到404错误,并说明table.jsp文件丢失。 Instead, the "model" should be serialized to json. 相反,“模型”应序列化为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;
    }

Is there a way to fix this without any impact to the existing code? 有没有办法解决此问题而又不影响现有代码?

The following code works fine: 以下代码可以正常工作:

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

So it looks like Spring cannot recognize that the model is returned with a purpose to be turned into json instead to be rendered in a view. 因此,看起来Spring不能识别出返回该模型的目的是将其转换为json而不是呈现在视图中。

This is a consequence of how Spring 3.2+ (I don't remember how 3.1 does it) handles @RequestMapping methods' return values. 这是Spring 3.2+(我不记得它是如何做到的)如何处理@RequestMapping方法的返回值的结果。 Spring uses instances of type HandlerMethodReturnValueHandler to resolve how the value returned should be handled. Spring使用HandlerMethodReturnValueHandler类型的实例来解决应如何处理返回的值。 Go through the javadoc too see the different types. 遍历javadoc也可以看到不同的类型。

When you configure your MVC environment, if you use the default @EnableWebMVC or <mvc:annotation-driven> , Spring registers these instances in a specific order. 当您配置MVC环境时,如果使用默认的@EnableWebMVC<mvc:annotation-driven> ,Spring将以特定顺序注册这些实例。 This happens in the RequestMappingHandlerAdapter#getDefaultReturnValueHandlers() method as shown below 发生在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;
}

When your method returns a value, Spring iterates through these handlers, calling their supportsReturnType() method and picking the first it finds that returns true . 当您的方法返回值时,Spring遍历这些处理程序,调用它们的supportsReturnType()方法,并选择第一个发现返回true

In this case, the ModelMethodProcessor which handles Model return values has higher priority (is registered before) the RequestResponseBodyMethodProcessor which handles @ResponseBody . 在这种情况下,处理Model返回值的ModelMethodProcessor具有更高的优先级(在之前注册),该RequestResponseBodyMethodProcessor处理@ResponseBody

As such, you can't return a Model and have it be converted to JSON through the @ResponseBody . 因此,您无法返回Model并通过@ResponseBody将其转换为JSON。 In my opinion, you shouldn't do this at all. 我认为,您根本不应该这样做。 The Model is accessible to most parts of the DispatcherServlet stack and therefore many modules can add/remove attributes which you may not want in the final JSON. Model可供DispatcherServlet堆栈的大部分访问,因此许多模块可以添加/删除最终JSON中可能不需要的属性。

Just use a DTO like you have in your second example. 就像在第二个示例中一样使用DTO。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM