2013-12-18 36 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