spring-mvc - Spring mvc 中使用 header 进行请求映射

标签 spring-mvc

目前我正在使用带有 header 的 Spring mvc 请求映射。

以下是我有的两种方法:

方法一:

@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) {}

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

那么即使版本是3.0,spring也只映射到第一个方法。
我在一篇文章中读到,在使用 header 的请求映射中,spring 会忽略 ; (分号)之后的请求映射。

我们正在使用自定义接受 header ,我们需要单独保留内容类型和版本。

如果我使用以下格式的 Accept header ,则映射有效: 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;
        }
}

最佳答案

内容协商有一些特殊属性:consumesproducts。在你的情况下,它会是

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

但这并不能解决你的问题。 Spring 在寻找匹配时仅考虑媒体类型和子类型。这是一种硬编码行为。

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

解决方案1

仅映射到媒体类型并具有单独的私有(private)方法。类似的东西

@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

实现您自己的映射条件。这并不难,但是官方文档中没有引用。您必须在 google 上搜索 org.springframework.web.servlet.mvc.condition.RequestCondition

关于spring-mvc - Spring mvc 中使用 header 进行请求映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20655614/

相关文章:

java - 在我的(java spring mvc + mysql应用程序,thymeleaf)中实现spring security后,身份验证发生了一些奇怪的事情

java - 在真实的基于 Java 的企业应用程序中,应该在哪一层进行验证?

spring - 为什么我无法在此 Spring Boot 应用程序中处理分段上传?我得到 "no matching editors or conversion strategy found"

jsp - 在 Spring MVC 中不显示图像

Css 和 js 未在 spring mvc 应用程序中加载

java - spring mvc中如何更新mysql数据?

java - 用spring安排任务

java - 向 ResponseBody 对象添加附加属性

java - Spring bean java.lang.NoSuchMethodError 错误

java - 轮询字段中的空值时删除