使用HttpMessageConverter进行Spring MVC内容协商

时间:2010-08-31 11:03:15

标签: spring-mvc content-negotiation

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

但是,我们无法控制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标头?

2 个答案:

答案 0 :(得分:3)

有一种解决方法,如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>

答案 1 :(得分:0)

更新版本的Spring现在可以执行此操作。 ContentNegotiationManagerFactoryBean可以创建一个内容协商管理器,可以在此处执行您想要的操作。查看我的answer to a related question