【问题标题】:Spring MVC Content Negotiation with HttpMessageConverter使用 HttpMessageConverter 的 Spring MVC 内容协商
【发布时间】:2011-04-06 05:16:23
【问题描述】:

对于最近的一个项目,我们希望支持 XML 和另一种格式的响应。

但是,我们无法控制 Accept 标头。因此我们配置了一个 ContentNegotiatingViewResolver 来使用请求参数:

<bean id="viewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="favorParameter" value="true" />
    <property name="parameterName" value="format" />
    <property name="ignoreAcceptHeader" value="true" />
    <property name="defaultContentType" value="application/xml" />
    <property name="mediaTypes">
        <map>
            <entry key="xml" value="application/xml" />
            <entry key="foo" value="application/x-foo" />
       </map>
    </property>
    <property name="viewResolvers">
        <list>
            <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver" >
                <property name="basename" value="views-xml" />
            </bean>
            <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver" >
                <property name="basename" value="views-foo" />
            </bean>
        </list>
    </property>
</bean>

不过,现在我想知道是否可以转而使用 @ResponseBody 和 HttpMessageConverter 实现来简化我需要维护的代码量。

但是,是否有类似的方法来确保使用 reqeust 参数而不是 Accept 标头进行内容协商?

【问题讨论】:

    标签: spring-mvc content-negotiation


    【解决方案1】:

    有一种解决方法,如 https://jira.springframework.org/browse/SPR-7517 所述

    创建AnnotationMethodHandlerAdapter的子类:

    package org.nkl.spring;
    
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.MediaType;
    import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
    
    public class MyAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {
    
       private Logger logger = LoggerFactory.getLogger(MyAnnotationMethodHandlerAdapter.class);
       private String requestParam = "accept";
       private Map<String, MediaType> mediaTypesMap;
    
       @Override protected HttpInputMessage createHttpInputMessage(HttpServletRequest request) throws Exception {
          HttpInputMessage message = super.createHttpInputMessage(request);
          String accept = request.getParameter(requestParam);
          if (accept == null || accept.isEmpty()) {
             logger.info(String.format("Request parameter [%s] not found. Using standard HttpInputMessage", requestParam));
             return message;
          } else {
             logger.info(String.format("Request parameter [%s] was [%s]", requestParam, accept));
             MediaType mediaType = mediaTypesMap.get(accept);
             if (mediaType == null) {
                logger.info(String.format("Suitable MediaType not found. Using standard HttpInputMessage"));
                return message;
             } else {
                logger.info(String.format("Suitable MediaType [%s] found. Using custom HttpInputMessage", mediaType));
                return new MyHttpInputMessage(message, mediaTypesMap.get(accept));
             }
          }
       }
    
       public void setMediaTypesMap(Map<String, MediaType> mediaTypesMap) {
          this.mediaTypesMap = mediaTypesMap;
       }
    
       public void setRequestParam(String requestParam) {
          this.requestParam = requestParam;
       }
    }
    

    创建一个HttpInputMessage的装饰器:

    package org.nkl.spring;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Arrays;
    
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.MediaType;
    
    public class MyHttpInputMessage implements HttpInputMessage {
    
       private HttpInputMessage delegate;
    
       public MyHttpInputMessage(HttpInputMessage delagate, MediaType mediaType) {
          this.delegate = delagate;
          this.delegate.getHeaders().setAccept(Arrays.asList(mediaType));
       }
    
       @Override public InputStream getBody() throws IOException {
          return this.delegate.getBody();
       }
    
       @Override public HttpHeaders getHeaders() {
          return this.delegate.getHeaders();
       }
    }
    

    像这样配置你的bean:

       <bean class="org.nkl.spring.MyAnnotationMethodHandlerAdapter">
          <property name="requestParam" value="format" />
          <property name="mediaTypesMap">
             <util:map>
                <entry key="plain" value="text/plain" />
                <entry key="xml" value="text/xml" />
             </util:map>
          </property>
          <property name="messageConverters">
             <util:list>
                ... converters go here ...
             </util:list>
          </property>
       </bean>
    

    【讨论】:

      【解决方案2】:

      较新版本的 Spring 现在可以做到这一点。 ContentNegotiationManagerFactoryBean 可以创建一个内容协商管理器,该管理器正是您想要的。见我的answer to a related question

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-15
        • 1970-01-01
        • 1970-01-01
        • 2016-03-12
        • 1970-01-01
        • 1970-01-01
        • 2019-03-01
        • 1970-01-01
        相关资源
        最近更新 更多