2013-12-18 27 views
4

当前我正在使用Spring使用标题的mvc请求映射。在Spring中使用标题进行请求映射mvc

以下是两种方法,我有:

方法1:

@RequestMapping(value = "/accounts", method = RequestMethod.GET, 
headers="Accept=application/vnd.se.company1.product1+json; version=2.0") 

@ResponseBody 
public ResponseEntity<String> loginVerionOne(final HttpServletRequest request){} 

方法2:

@RequestMapping(value = "/accounts", method = RequestMethod.GET, 
headers="Accept=application/vnd.se.company1.product1+json; version=3.0") 

@ResponseBody 
public ResponseEntity<String> loginVersionTwo(final HttpServletRequest request) {} 

这里的问题是,当客户端发送接受它的请求头中以下格式: Accept=application/vnd.se.company1.product1+json; version=3.0

然后,弹簧仅映射到第一种方法,即使版本是3.0。
我已阅读其中一篇文章,其中弹簧忽略之后的请求映射;(分号)使用标题进行请求映射。

我们正在使用自定义接受标头,我们需要分别保留内容类型和版本。

映射工作,如果我使用接受以下格式头: Accept=application/vnd.se.company1.product1.v2.0+json

但我不希望使用上述格式。
在这个问题上的任何帮助将不胜感激。

以下是用我的代码:

RequestMappingController 
======================== 
@RequestMapping(value = "/helloworld",method=RequestMethod.GET) 
     @SubdomainMapping(subdomains="application/vnd.se.company1.product1+json;version=2.0") 
    public ModelAndView helloWordNew(HttpServletRequest req){ 
     String message = "Hello World Version 2.0"; 
     return new ModelAndView("helloworld", "message",message); 
    } 
    @RequestMapping(value = "/helloworld",method=RequestMethod.GET) 
    @SubdomainMapping(subdomains="application/vnd.se.company1.product1+json;version=3.0") 
    public ModelAndView helloWord(HttpServletRequest req){ 
      String message = "Hello World Version 3.0"; 
      return new ModelAndView("helloworld", "message",message); 
    } 

RequestCondition: 
================ 

public class SubdomainRequestCondition implements 
     RequestCondition<SubdomainRequestCondition> { 

    private final Set<String> subdomains; 


    public SubdomainRequestCondition(String subdomains) { 
     this(Arrays.asList(subdomains)); 
    } 

    public SubdomainRequestCondition(Collection<String> subdomains) { 
     this.subdomains = Collections.unmodifiableSet(new HashSet<String>(
       subdomains)); 
    } 

    @Override 
    public SubdomainRequestCondition combine(SubdomainRequestCondition other) { 
     Set<String> allRoles = new LinkedHashSet<String>(this.subdomains); 
     allRoles.addAll(other.subdomains); 
     return new SubdomainRequestCondition(allRoles); 
    } 

    @Override 
    public SubdomainRequestCondition getMatchingCondition(
      HttpServletRequest request) { 
      String header = request.getHeader("Accept"); 
      for (String s : subdomains) { 
       if (s.equals(header)) { 
        return this; 
       } 
      } 
     return null; 
    } 

    @Override 
    public int compareTo(SubdomainRequestCondition other, 
      HttpServletRequest request) { 
     return org.apache.commons.collections.CollectionUtils.removeAll(other.subdomains, this.subdomains).size(); 
    } 
} 

HandlerMapping 
============== 

public class CustomRequestMappingHandlerMapping extends 
     RequestMappingHandlerMapping { 
    @Override 
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) { 
     SubdomainMapping typeAnnotation = AnnotationUtils.findAnnotation(
       handlerType, SubdomainMapping.class); 
     return createCondition(typeAnnotation); 
    } 

    @Override 
    protected RequestCondition<?> getCustomMethodCondition(Method method) { 
     SubdomainMapping methodAnnotation = AnnotationUtils.findAnnotation(
       method, SubdomainMapping.class); 
     return createCondition(methodAnnotation); 
    } 

    private RequestCondition<?> createCondition(SubdomainMapping accessMapping) { 
     return (accessMapping != null) ? new SubdomainRequestCondition(accessMapping.subdomains()) : null; 
    } 
} 



    applicationContext.xml 
    ====================== 
    <context:component-scan base-package="com.net.controllers"/> 

     <bean id="viewResolver" 
      class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 

      <property name="prefix"> 
       <value>/WEB-INF/views/</value> 
      </property> 
      <property name="suffix"> 
       <value>.jsp</value> 
      </property> 
     </bean> 

     <bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> 
      <property name="webBindingInitializer"> 
      <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"> 
       <property name="validator"> 
        <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> 
       </property> 
      </bean> 
     </property> 
     <property name="messageConverters"> 
      <list> 
       <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean> 
       <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean> 
      </list> 
     </property> 
     </bean> 
<bean id="re" class="com.net.controllers.WebConfig"/> 
</beans> 

WebConfig.java 
============== 

@Configuration 
public class WebConfig extends WebMvcConfigurationSupport { 

    @Autowired 

    @Override 
    @Bean 
    public RequestMappingHandlerMapping requestMappingHandlerMapping() { 
     CustomRequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping(); 
     handlerMapping.setOrder(0); 
     handlerMapping.setInterceptors(getInterceptors()); 
     return handlerMapping; 
    } 

    @Bean 
     @Override 
     public FormattingConversionService mvcConversionService() { 

      // Use the DefaultFormattingConversionService but do not register defaults 
      DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false); 
      return conversionService; 
     } 
} 

回答

0

两个头用逗号分隔:

headers = {"Accept=application/vnd.se.company1.product1+json", "version=3.0"}) 
+0

但Accept = application/vnd.se.company1.product1 + json;版本= 2.0“这是一个标题的一部分,这些不是两个不同的标题 – ManasiD

+0

@ManasiD不,它不是 – NimChimpsky

+0

我得到下面的错误:org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException:没有匹配通过使用上面的标题找到servlet请求的路径处理方法:路径'/ accounts',方法'GET',参数map [[empty]]。 – ManasiD

1

有对内容协商的特殊属性:consumesproduces。在你的情况下,它将是

@RequestMapping(value = "/accounts", method = RequestMethod.GET, 
produces="application/vnd.se.company1.product1+json; version=2.0") 

虽然这并不能解决您的问题。 Spring在查找匹配时仅考虑媒体类型和子类型。这是一个硬编码的行为。

我可以提供两种解决方案:

解决方案1 ​​

仅映射到的介质类型,并具有独立的私有方法。像

@RequestMapping(value = "/accounts", method = RequestMethod.GET, 
produces="application/vnd.se.company1.product1+json") 
@ResponseBody 
public ResponseEntity<String> login(final HttpServletRequest request){ 
    if(getVersion(request).equals(VERSION_2)) { 
    loginVersion2(request); 

解决方案2

一些实施自己的映射条件。这并不困难,但官方文档中没有提及。您将不得不谷歌org.springframework.web.servlet.mvc.condition.RequestCondition

+0

我已经经历了一些更多的帖子,发现使用RequestMappingHandlerMapping类,我们可以为请求映射编写自己的条件。但为此,我需要使用Spring MVC基于Java的配置,我们使用applicationContext.xml而不是基于Java的配置。任何想法我怎么能继续呢? – ManasiD

+0

@ManasiD你可以编写你自己的扩展'RequestMappingHandlerMapping'的类,并在你的xml中配置bean,比如'' – zeroflagL

+0

所以同时会有xml配置作为基于java的配置权?我已经这样做了,并且我得到了错误导致:java.lang.NoSuchMethodError:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getUrlPathHelper()Lorg/springframework/web/util/UrlPathHelper; – ManasiD