Как запретить привязке параметров интерпретировать запятые в Spring 3.0.5? - PullRequest
50 голосов
/ 15 февраля 2011

Рассмотрим следующий метод контроллера:

@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(@RequestParam(value = "fq", required = false) String[] filterQuery) {
    logger.debug(fq = " + StringUtils.join(filterQuery, "|"));
}

Вот выходные данные для различных комбинаций fq:

  1. /test?fq=foo приводит к fq = foo
  2. /test?fq=foo&fq=bar приводит к fq = foo|bar
  3. /test?fq=foo,bar приводит к fq = foo|bar
  4. /test?fq=foo,bar&fq=bash приводит к fq = foo,bar|bash
  5. /test?fq=foo,bar&fq= приводит к fq = foo,bar|

Пример 3 - проблема.Я ожидаю (хочу / нужно), чтобы он вывел fq = foo,bar.

Я пытался экранировать запятую с помощью \ и использовать %3C, но лучше не работать.

Если я посмотрю на версию объекта HttpServletRequest:

String[] fqs = request.getParameterValues("fq");
logger.debug(fqs = " + StringUtils.join(fqs, "|"));

Выводит ожидаемый результат: fqs = foo,bar.Таким образом, «проблема» связана с привязкой данных Spring.

Я мог бы обойти привязку Spring и использовать HttpServletRequest, но я действительно не хочу этого, так как использую backing bean в моем реальном коде (то же самое происходит) и не хочу повторно реализовывать функциональность привязки.Я надеюсь, что кто-то может предоставить простой способ предотвращения этого поведения через экранирование или с помощью другого механизма.

TIA

ОБНОВЛЕНИЕ: Я разместил этот вопрос в Твиттере и получилв ответном сообщении ожидаемый результат появляется с Spring 3.0.4.RELEASE .Теперь я подтвердил, что это так, и поэтому это временное исправление.Я продолжу и буду регистрировать это как ошибку в системе Spring JIRA.Если кто-нибудь может предоставить обходной путь или исправить с помощью 3.0.5, я приму их ответ.

Ответы [ 6 ]

31 голосов
/ 09 марта 2011

Я проверил ваш код: это невероятно, но я не могу воспроизвести вашу проблему.Я скачал последнюю версию Spring (3.0.5), это мой контроллер:

package test;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/test/**")
public class MyController {

    private static final Logger logger = Logger.getLogger(MyController.class);

    @RequestMapping(value = "/test/params", method = RequestMethod.GET)
    public void test(SearchRequestParams requestParams, BindingResult result) {
    logger.debug("fq = " + StringUtils.join(requestParams.getFq(), "|"));
    }
}

, это мой класс SearchRequestParams:

package test;

public class SearchRequestParams {
    private String[] fq;

    public String[] getFq() {
    return fq;
    }

    public void setFq(String[] fq) {
    this.fq = fq;
    }
}

, и это моя простая пружинаконфигурация:

<bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

<bean class="test.MyController" />

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

Я тестировал свой код в tomcat 7.0.8;когда я набираю http://localhost:8080/testweb/test/params.htm?fq=foo,bar, я могу прочитать в моем файле журнала следующую строку: DEBUG fq = foo,bar.Чем отличается мой код от вашего?Я делаю что-то неправильно?Я хотел бы помочь вам, поэтому, если у вас есть какие-либо сомнения или если я смогу провести для вас какие-то другие тесты, это будет удовольствие.

ОБНОВЛЕНИЕ / РЕШЕНИЕ
Ствой код я воспроизвел проблему;у вас есть тег <mvc:annotation-driven /> в конфигурации вашего сервлет-диспетчера, поэтому вы молча используете службу преобразования по умолчанию, экземпляр FormattingConversionService, который содержит конвертер по умолчанию из String в String[], в котором в качестве разделителя используется запятая.Вы должны использовать другой компонент службы преобразования, содержащий ваш собственный преобразователь от String до String[].Вы должны использовать другой разделитель, я решил использовать ";"поскольку этот разделитель обычно используется в строке запроса ("? first = 1; second = 2; third = 3"):

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;

public class CustomStringToArrayConverter implements Converter<String, String[]>{
   @Override
    public String[] convert(String source) {
        return StringUtils.delimitedListToStringArray(source, ";");
    }
}

Затем вы должны указать этот компонент службы преобразования в вашей конфигурации:

<mvc:annotation-driven conversion-service="conversionService" />

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="au.org.ala.testspringbinding.CustomStringToArrayConverter" />
        </list>
    </property>
</bean>

Проблема исправлена, теперь вам следует проверить наличие побочных эффектов.Я надеюсь, что вам не нужно исходное преобразование из String в String[] (с запятой в качестве разделителя).;-)

21 голосов
/ 04 декабря 2013

Я нашел самый элегантный и самый короткий путь для меня - добавьте @InitBinder к @Controller:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}

. Он преобразует строку в строку [] без использования разделителя (nullparam), с классом Spring org.springframework.beans.propertyeditors.StringArrayPropertyEditor.Если кто-то в том же проекте будет использовать новый способ конвертации по умолчанию, все будет в порядке.

4 голосов
/ 07 марта 2011

По предложению Филиппа Поттера я отправляю "обновление" на мой вопрос в качестве ответа, так как его легко было пропустить ...

Понижение версии Spring 3.0.5.RELEASE до 3.0.4.RELEASE исправлена ​​ проблема при использовании аннотации @RequestParam, предполагающая, что это ошибка 3.0.5.

Однако это НЕ устраняет проблему, связанную с , при привязке к компоненту, поддерживающему форму - это то, что у меня есть в моем веб-приложении. Я протестировал все версии обратно до 3.0.0.RELEASE и получил тот же результат (/test?fq=foo,bar производит fq = foo|bar).

* 1014 Е.Г. *

@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(SearchRequestParams requestParams, BindingResult result) {
    logger.debug("fq = " + StringUtils.join(requestParams.getFq(), "|"));
}

, где SearchRequestParams содержит поле String[] fq.

Если у кого-нибудь есть исправление, я с радостью приму их ответ.

3 голосов
/ 21 ноября 2012

Яванна уже указала правильную причину.Я просто хотел еще раз подчеркнуть, что вы также можете полностью удалить StringToArrayConverter , как показано здесь и здесь .

0 голосов
/ 15 марта 2019

Ниже описан мой путь обхода разграничения запятых в запросе MVC

Это мое понимание эволюции Springs решений такого типа: документация очень расплывчата относительно того, что является новейшим решением.

Сначала был WebMvcConfigAdapter, реализующий интерфейс WebMvcConfig.Это в конечном итоге устарело

Это было заменено WebMvcConfigSupport.Это в конечном итоге устарело, но это было лучше, чем первое решение.Основная проблема заключалась в том, что он отключил автоконфигурацию MVC и имел побочные проблемы, такие как swagger.html, не работающий и информация привода отсутствовала в довольно хорошем формате, а дата стала большой десятичной дробью

Последним является переработанный интерфейс WebMvcConfigкоторый реализует методы по умолчанию с использованием функций Java 8.

Создайте класс в моем случае, WebConfigUUID может быть AnyClass, который реализует более позднюю версию WebMvcConfig

Это позволяет вам изменить то, что вам нужно, вв нашем случае пользовательский преобразователь, не влияющий на что-либо другое или не требующий переопределения другого, чтобы заставить работать чванство, или иметь дело с выводом информации привода

Ниже приведены два класса, которые реализовали мое изменение, чтобы обойти разделение запятыми строк всписок при обработке запроса MVC:
По-прежнему создается список строк, но только с одним значением.

import java.util.Collection;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfigUUID implements WebMvcConfigurer {
  @Override
  public void addFormatters(FormatterRegistry registry)  {
    registry.removeConvertible(String.class,Collection.class);
    registry.addConverter(String.class,Collection.class,BypassCommaDelimiterConfiguration.commaDelimiterBypassedParsingConverter());
  }
}

import java.util.ArrayList;
import java.util.List;
import org.springframework.core.convert.converter.Converter;

public class BypassCommaDelimiterConfiguration  {
    public static Converter<String, List<String>> commaDelimiterBypassedParsingConverter() {
        return new Converter<String, List<String>>() {
            @Override
            public List<String> convert(final String source) {
                final List<String> classes = new ArrayList<String>();
                classes.add(source);
                return classes;
            }
        };
    }
}
0 голосов
/ 07 марта 2011

Это хак, но вы рассматривали возможность передачи своих параметров, разделенных '-'

/test?fq=foo-bar results in fq = foo-bar
/test?fq=foo-bar&fq=bash results in fq = foo-bar|bash 

Или любой другой разделитель, может быть ~, или!, Или ^, или ???

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...