代码之家  ›  专栏  ›  技术社区  ›  Juraj Blahunka

如何在SpringMVC中定义基于URL扩展的消息转换器?

  •  2
  • Juraj Blahunka  · 技术社区  · 14 年前

    如何影响在中选择消息转换器的过程 AnnotationMethodHandlerAdapter 通过URL扩展得到的POJO? 我希望对一个数据对象有更多的表示,而数据表示应该由请求的URL扩展来选择,例如。 /users/2.xml /users/2.json .

    应根据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() 提供对生成的HTTP状态代码定义的细粒度控制(确定、未找到、无内容等)。我找不到一种方法来使用ResponseEntity和ContentNegotiatingViewResolver,这也能满足我的需求。

    另一种方法是修改请求 accept 报头到 application/xml application/json 基于URL扩展名。这样,所有处理都应该直接转到配置的消息转换器。但是,我不知道一种合理的方法来篡改请求头。

    谢谢。

    2 回复  |  直到 12 年前
        1
  •  3
  •   axtavt    14 年前

    既然选择了 HttpMessageConverter S使用 Accept 请求头,也许实现内容协商的最简单方法是用URL扩展指定的所需媒体类型替换此头。

    这可以实现为 Filter (使用) HttpServletRequestWrapper 替换标题值)或重写 AnnotationMethodHanlderAdapter.createHttpInputMessage() 如建议 SPR-7517 (需要弹簧3.0.2)。

    也见 SPR-6993 .

        2
  •  2
  •   antyrat Andy    12 年前

    我也有同样的需求,我设计了一个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);
            }
        }
    }
    }