web-dev-qa-db-ja.com

Spring 3.0.5でパラメータバインディングがカンマを解釈しないようにするにはどうすればよいですか?

次のコントローラーメソッドを考えます。

@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を使用することもできますが、バッキングBeanを使用しているので、本当に使いたくない私の実際のコード(同じことが起こっています)で、バインディング機能を再実装したくありません。誰かがエスケープや他のメカニズムを介してこの動作を防ぐ簡単な方法を提供できることを願っています。

TIA

UPDATE:私はこのQをTwitterに投稿し、Spring 3.0.4で期待される出力が表示されるという返信を得ました。 RELEASE。これが事実であり、一時的な修正であることが確認できました。 Spring JIRAシステムのバグとしてこれをログに記録します。誰かが3.0.5で回避策や修正を提供できる場合は、その答えを受け入れます。

53
nickdos

私はあなたのコードをテストしました:それは信じられないほどですが、あなたの問題を再現することはできません。 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[]への独自のコンバーターを含む別の変換サービスBeanを使用する必要があります。別のセパレータを使用する必要があります。「;」を使用することにしました。これは、クエリ文字列で一般的に使用されるセパレータであるため( "?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, ";");
    }
}

次に、この変換サービスBeanを構成で指定する必要があります。

<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[]への元の変換(区切り文字としてコンマを使用)が必要ないことを願っています。 ;-)

32
javanna

私は最もエレガントで最短の方法を見つけました-@InitBinder@Controllerに追加します。

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

Springクラスorg.springframework.beans.propertyeditors.StringArrayPropertyEditorを使用して、セパレーター(null param)を使用せずにStringをString []に変換します。同じプロジェクトの誰かが新しいデフォルトの変換方法を使用する場合、それは問題ありません。

24
TachikomaGT

フィリップ・ポッターが提案したように、私は見逃していたかもしれないので、私の質問への「更新」を回答として投稿しています...

Spring 3.0.5.RELEASEから3.0.4.RELEASEへのダウングレードfixed@RequestParamアノテーションを使用する場合の問題で、3.0.5のバグであることを示唆しています。

ただし、フォームバッキングBeanにバインドする場合、関連する問題は修正されません。これは、私のWebアプリケーションにあるものです。 3.0.0.RELEASEまでのすべてのバージョンをテストし、同じ結果を得ました(/test?fq=foo,barfq = foo|barを生成します)。

例えば。

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

ここで、SearchRequestParamsにはフィールドString[] fqが含まれます。

誰かがこれを修正できれば、私は喜んで彼らの答えを受け入れます。

4
nickdos

javannaはすでに正しい根本原因を指摘しています。 StringToArrayConverterを ここに示すようにここに を一緒に削除することもできることをさらに指摘したかっただけです。

3

以下は、MVCリクエストでカンマ区切りをバイパスする私の旅です

これは、これらのタイプのソリューションのSpringsの進化に関する私の理解です。ドキュメントは、最新のソリューションが何であるかについて非常にあいまいです。

最初は、インターフェースWebMvcConfigを実装するWebMvcConfigAdapterでした。これは最終的に廃止されました

これは、WebMvcConfigSupportに置き換えられました。これは最終的に廃止されましたが、最初のソリューションよりも優れていました。主な問題は、MVCの自動構成がオフになっていて、swagger.htmlが機能しない、アクチュエーター情報がかなりの形式で欠けているなどの副次的な問題があり、日付が大きな10進数になったことです。

最新は、Java 8機能を使用してデフォルトのメソッドを実装する、改訂されたインターフェースWebMvcConfigです。

私の場合はクラスを作成します。WebConfigUUIDはAnyClassで、WebMvcConfigの新しいバージョンを実装します。

これにより、他のものに影響を与えたり、他のものをオーバーライドしてSwaggerを機能させたり、アクチュエーター情報出力を処理したりすることなく、必要なもの(この場合はカスタムコンバーター)を変更できます

以下は、MVCリクエストの処理時にリストへの文字列のカンマ区切りをバイパスするための変更を実装した2つのクラスです。
それでも文字列のリストを生成しますが、値は1つだけです。

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
Joseph Rogers

それはハックですが、「-」で区切られたパラメータを渡すことを検討しましたか

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

または、他の区切り文字である〜、または!、または^、または???

0
Sumit