2

对于最近的一个项目,我们希望为我们的响应支持 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 标头?

4

2 回答 2

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>
于 2010-09-02T10:45:34.190 回答
0

较新版本的 Spring 现在可以做到这一点。可以创建一个内容协商管理器,在ContentNegotiationManagerFactoryBean此处精确执行您想要的操作。请参阅我对相关问题的回答

于 2013-06-19T18:31:26.893 回答