2010-09-08 18 views
2

如何通過網址擴展影響在AnnotationMethodHandlerAdapter中選擇消息轉換器的過程以生成POJO? 我想有一個數據對象的更多表示,而數據表示應該通過請求的URL擴展來選擇,例如, /users/2.xml/users/2.json如何在Spring MVC中基於url擴展定義消息轉換器?

當前消息處理程序,應根據URL擴展選擇的配置:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> 
    <property name="messageConverters"> 
     <list> 
      <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> 
      <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter" 
       p:marshaller-ref="xmlMarshaller" p:unmarshaller-ref="xmlMarshaller" /> 
     </list> 
    </property> 
</bean> 

有一種方式,這我幾乎舒服,就是用ContentNegotiatingViewResolver,但是我想繞過視圖解析過程並直接使用消息轉換器。另外,在創建動作時,在public ResponseEntity<User> showUser()中使用ResponseEntity可對結果http狀態代碼定義(OK,NOT_FOUND,NO_CONTENT,..)進行細粒度控制。我無法找到使用ContentNegotiatingViewResolver的ResponseEntity的方式,這也可以滿足我的需求。

另一種方式可能是通過將請求accept標頭修改爲基於url擴展名的application/xmlapplication/json。通過這種方式,所有的處理都應該直接進入配置的消息轉換器。但是,我不知道一個合理的方式來篡改請求標頭。

謝謝。

回答

3

由於HttpMessageConverter的選擇使用Accept請求標頭,所以實現內容協商的最簡單方法是用URL擴展指定的所需媒體類型替換該標頭。

這可以被實現爲一個Filter(使用HttpServletRequestWrapper取代標頭值),或通過重寫AnnotationMethodHanlderAdapter.createHttpInputMessage()SPR-7517建議(需要彈簧3.0.2)。請參閱SPR-6993

+1

謝謝,你救了我的一天:)去'SPR-7517'方式 – 2010-09-08 19:02:11

2

我有這個相同的需求,一起攻擊一個servlet過濾器來完成任務。不是一件藝術品,但完成工作:

public class UrlExtensionFilter implements Filter { 

public void init(FilterConfig filterConfig) throws ServletException { 
} 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 
    HttpServletRequest httpServletRequest = (HttpServletRequest)request; 
    if (httpServletRequest.getRequestURI().endsWith(".json")) { 
     MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest); 
     acceptHeaderRequest.setAcceptHeader("application/json"); 
     filterChain.doFilter(acceptHeaderRequest, response); 
    } else if (httpServletRequest.getRequestURI().endsWith(".xml")) { 
     MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest); 
     acceptHeaderRequest.setAcceptHeader("text/xml"); 
     filterChain.doFilter(acceptHeaderRequest, response); 
    } else { 
     filterChain.doFilter(request, response); 
    } 
} 

public void destroy() { 
} 

public class MyAcceptHeaderRequest extends HttpServletRequestWrapper { 

    private String accept = "application/json"; 

    public MyAcceptHeaderRequest(HttpServletRequest request) throws IOException { 
     super(request); 
    } 

    public void setAcceptHeader(String value) { 
     accept = value; 
    } 

    @Override 
    public String getHeader(String name) { 
     if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) { 
      return accept; 
     } else { 
      return super.getHeader(name); 
     } 
    } 

    @Override 
    public Enumeration getHeaders(String name) { 
     if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) { 
      Enumeration enumeration = new StringTokenizer(accept); 
      return enumeration; 
     } else { 
      return super.getHeaders(name); 
     } 
    } 

    @Override 
    public String getContentType() { 
     return accept; 
    } 

    @Override 
    public String getParameter(String name) { 
     // When we're using this class and it is a POST operation then the body is JSON or XML so don't allow 
     // attempts to retrieve parameter names to consume the input stream 
     if (this.getMethod().equals("POST")) { 
      return null; 
     } else { 
      return super.getParameter(name); 
     } 
    } 

    @Override 
    public String[] getParameterValues(String name) { 
     // When we're using this class and it is a POST operation then the body is JSON or XML so don't allow 
     // attempts to retrieve parameter names to consume the input stream 
     if (this.getMethod().equals("POST")) { 
      return null; 
     } else { 
      return super.getParameterValues(name); 
     } 
    } 
} 
}