Spring MVC Matrix Variables只返回一个参数值

时间:2018-05-31 08:29:16

标签: java spring rest spring-mvc spring-web

我正在构建一个spring-mvc rest API应用程序,我打算在我的某些端点上使用矩阵变量。不幸的是,我无法为每个使用的矩阵变量检索多个值。

我的spring-mvc版本是spring-webmvc:4.3.12.RELEASE

我按照此实施示例中显示的步骤进行操作:http://www.baeldung.com/spring-mvc-matrix-variables

我已启用Spring MVC矩阵变量:

package fr.compagny.project.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.util.UrlPathHelper;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

所以我创建了2个测试端点:

package fr.compagny.project.webservice;

import [...]

@Api
@RefreshScope
@RestController
@RequestMapping(value = "/my_awesome_project")
public class ProjectWS {

    //Services
    private ProjectService projectService;

    //Validator
    private ValidatorService validator;

    @ApiOperation(value = "Matrix Variable Test 1.")
    @GetMapping(value = "/matrix_test_one/{vars}", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public String getMatrixTestOne (@MatrixVariable(pathVar = "vars", required = true) String v1,
                                    @MatrixVariable(pathVar = "vars", required = true) String v2,
                                    @MatrixVariable(pathVar = "vars", required = true) String v3) {
        return v1 + v2 + v3;
    }

    @ApiOperation(value = "Matrix Variable Test 2.")
    @GetMapping(value = "/matrix_test_two/{vars}", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public Map<String, String> getMatrixTestTwo (@MatrixVariable Map<String, String> vars) {
        return vars;
    }

    @Autowired
    public void setProjectService(ProjectService projectService) {
        this.projectService = projectService;
    }

    @Autowired
    public void setValidatorService(ValidatorService validatorService) {
        this.validator = validatorService;
    }
}

当我打电话

GET http://[...]/my_awesome_project/matrix_test_one/v1=toto;v2=titi;v3=tata
OR
GET http://[...]/my_awesome_project/matrix_test_one/v1=toto

我有以下相同的错误消息:

  

出现意外错误(type = Bad Request,status = 400)。失踪   矩阵变量&#39; v2&#39;对于String

类型的方法参数

但是当我打电话时

GET http://[...]/my_awesome_project/matrix_test_one/v2=titi
OR
GET http://[...]/my_awesome_project/matrix_test_one/[anything except "v1=*"]

我有以下相同的错误消息:

  

出现意外错误(type = Bad Request,status = 400)。   缺少矩阵变量&#39; v1&#39;对于String

类型的方法参数

所以Spring似乎可以获得矩阵变量的第一个元素,但那时就停止了。

所以我继续尝试第二个测试功能:

GET http://[...]/my_awesome_project/matrix_test_two/v1=toto;v2=titi;v3=tata
OR
GET http://[...]/my_awesome_project/matrix_test_two/v1=toto

返回:

{
    "v1": "toto"
}

-

GET http://[...]/my_awesome_project/matrix_test_two/v2=titi;v1=toto;v3=tata

返回:

{
    "v2": "titi"
}

所以这种行为似乎证实了我的恐惧。

为了启用矩阵变量支持(可能与分号有关),您是否看到了我遗漏的内容?

1 个答案:

答案 0 :(得分:0)

上面提到的例子是使用Spring Boot。通过Spring Boot启动exmaple按预期工作。如果没有Spring Boot,它就不会开箱即用,正如Q&A中所解释的那样。原因是从UrlPathHelper注入的@Configuration(示例中的第2点)并不用于处理请求。使用了UrlPathHelper的默认实例,因此urlPathHelper.shouldRemoveSemicolonContent()返回true。这将从请求中删除矩阵变量。

编辑:

我调试了它,结果发现有两个类型为RequestMappingHandlerMapping的bean。

Two beans of type RequestMappingHandlerMapping

所以我尝试了这个配置:

@Configuration
@ComponentScan(basePackageClasses = { WebMvcConfiguration.class })
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Bean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")
    @Qualifier("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")
    public RequestMappingHandlerMapping fullyQualifiedRequestMappingHandlerMapping() {
        return requestMappingHandlerMapping();
    }

    @Bean
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping requestMappingHandlerMapping = super.requestMappingHandlerMapping();
        requestMappingHandlerMapping.getUrlPathHelper().setRemoveSemicolonContent(false);
        return requestMappingHandlerMapping;
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = configurer.getUrlPathHelper();
        if (urlPathHelper == null) {
            urlPathHelper = new UrlPathHelper();
        }
        urlPathHelper.setRemoveSemicolonContent(false);
    }

}

但是第一种方法并没有创建完全限定的bean。这个bean正在处理请求。所以矩阵变量仍然被删除。

由于我无法为bean提供工厂方法,我试图修改bean的状态:

@Component
public class Initializer {

    @Autowired
    private ApplicationContext appContext;

    @PostConstruct
    protected void init() {
        initUrlPathHelper("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping");
        initUrlPathHelper("requestMappingHandlerMapping");
    }

    protected void initUrlPathHelper(String beanName) {
        AbstractHandlerMapping b = (AbstractHandlerMapping) appContext.getBean(beanName);
        b.setUrlPathHelper(urlPathHelper());
    }

    public UrlPathHelper urlPathHelper() {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        return urlPathHelper;
    }

}

这对我有用。矩阵变量已经映射。