Матричные переменные Spring MVC получают только одно значение параметра - PullRequest
0 голосов
/ 31 мая 2018

Я создаю приложение API rest-mvc rest и намереваюсь использовать матричные переменные для некоторых моих конечных точек.К сожалению, я не могу получить более одного значения для каждой используемой матричной переменной.

Моя версия spring-mvc - spring-webmvc: 4.3.12.RELEASE

Я выполнил шаги, показанные вэтот пример реализации: http://www.baeldung.com/spring-mvc-matrix-variables.

Я включил Spring MVC Matrix Variables:

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

У меня появляется следующее сообщение об ошибке:

Произошла непредвиденная ошибка (тип = Плохой запрос, статус = 400).Отсутствует матричная переменная 'v2' для параметра метода типа String

Но когда я вызываю

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

, у меня появляется следующее сообщение об ошибке:

Произошла непредвиденная ошибка (тип = неверный запрос, статус = 400).Отсутствует матричная переменная 'v1' для параметра метода типа 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

Return:

{
    "v1": "toto"
}

-

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

Return:

{
    "v2": "titi"
}

Так что такое поведениеподтвердите мои опасения.

Вы видели что-то, что я пропустил, чтобы включить поддержку матричных переменных (возможно, связанных с точкой с запятой)?

1 Ответ

0 голосов
/ 31 мая 2018

В приведенном примере используется Spring Boot.Запуск exmaple через Spring Boot работает, как и ожидалось.Без Spring Boot это не работает из коробки, как объясняется в этом Q & A .Причина в том, что UrlPathHelper, введенный из @Configuration (точка 2 в примере), не используется для обработки запроса.Используется экземпляр по умолчанию UrlPathHelper, поэтому urlPathHelper.shouldRemoveSemicolonContent() возвращает true.Это удаляет матричные переменные из запроса.

РЕДАКТИРОВАТЬ:

Я отладил в нем, и оказалось, что есть два bean-типа типа RequestMappingHandlerMapping.

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);
    }

}

Но полностью квалифицированный компонент не был создан первым методом.Этот бин обрабатывает запрос.Таким образом, переменные матрицы все еще были удалены.

Поскольку я не смог предоставить фабричный метод для компонента, я попытался изменить состояние компонента:

@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;
    }

}

Это сделало это для меня,Матричные переменные были сопоставлены.

...