次のコントローラーメソッドを考えます。
@RequestMapping(value = "/test", method = RequestMethod.GET)
public void test(@RequestParam(value = "fq", required = false) String[] filterQuery) {
logger.debug(fq = " + StringUtils.join(filterQuery, "|"));
}
次に、さまざまなfq
の組み合わせの出力を示します。
/test?fq=foo
結果はfq = foo
になります/test?fq=foo&fq=bar
結果はfq = foo|bar
になります/test?fq=foo,bar
結果はfq = foo|bar
になります/test?fq=foo,bar&fq=bash
結果はfq = foo,bar|bash
になります/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で回避策や修正を提供できる場合は、その答えを受け入れます。
私はあなたのコードをテストしました:それは信じられないほどですが、あなたの問題を再現することはできません。 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[]
への元の変換(区切り文字としてコンマを使用)が必要ないことを願っています。 ;-)
私は最もエレガントで最短の方法を見つけました-@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 []に変換します。同じプロジェクトの誰かが新しいデフォルトの変換方法を使用する場合、それは問題ありません。
フィリップ・ポッターが提案したように、私は見逃していたかもしれないので、私の質問への「更新」を回答として投稿しています...
Spring 3.0.5.RELEASEから3.0.4.RELEASEへのダウングレードfixed@RequestParam
アノテーションを使用する場合の問題で、3.0.5のバグであることを示唆しています。
ただし、フォームバッキングBeanにバインドする場合、関連する問題は修正されません。これは、私のWebアプリケーションにあるものです。 3.0.0.RELEASEまでのすべてのバージョンをテストし、同じ結果を得ました(/test?fq=foo,bar
はfq = 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
が含まれます。
誰かがこれを修正できれば、私は喜んで彼らの答えを受け入れます。
以下は、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;
}
};
}
}
それはハックですが、「-」で区切られたパラメータを渡すことを検討しましたか
/test?fq=foo-bar results in fq = foo-bar
/test?fq=foo-bar&fq=bash results in fq = foo-bar|bash
または、他の区切り文字である〜、または!、または^、または???