如何防止在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
组合的输出:
-
/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 (同样的事情正在发生),并不希望重新实现绑定function。 我希望有人可以通过转义或其他机制提供一个简单的方法来防止这种行为。
TIA
更新:我在Twitter上发布了这个Q,并得到了一个答复,说Spring 3.0.4.RELEASE的预期输出 。 我现在已经证实这是事实,因此是一个临时的解决办法。 我将继续并将其logging为Spring JIRA系统上的一个错误。 如果任何人都可以提供解决或修复3.0.5,我会接受他们的答案。
我testing了你的代码:这是令人难以置信的,但我不能重现你的问题。 我已经下载了最新版本的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; } }
这是我简单的弹簧configuration:
<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中testing了我的代码; 当我inputhttp://localhost:8080/testweb/test/params.htm?fq=foo,bar
我可以在我的日志文件中读取这一行: DEBUG fq = foo,bar
。 从我的代码到你的代码有什么区别? 难道我做错了什么? 我想帮助你,所以如果你有任何疑问,或者我可以为你做一些其他的testing,这将是一件乐事。
更新/解决scheme
随着你的代码,我已经转载了这个问题。 您在调度程序servletconfiguration中有<mvc:annotation-driven />
标记,因此您默认使用默认转换服务,即FormattingConversionService
实例,该实例包含从String
到String[]
的默认转换器,该转换器使用逗号作为分隔符。 你必须使用一个不同的转换服务bean,包含你自己的转换器,从String
到String[]
。 你应该使用不同的分隔符,我select使用“;” 因为它是查询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, ";"); } }
那么你必须在你的configuration中指定这个转换服务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将String转换为String []而不使用分隔符( null
参数)。 如果同一个项目中的某个人将使用新的默认转换方式,那么就可以。
正如菲利普·波特(Philip Potter)所build议的那样,我将“更新”作为答案发布在我的问题上,因为它可能很容易错过…
从3.0.5.RELEASE降级到3.0.4.RELEASE 修正了这个问题,使用@RequestParam
注解时,提示这是一个3.0.5的bug。
但是,当绑定到一个form-backing bean时,它不能解决相关的问题 – 这正是我的web应用程序所具有的。 我已经testing了所有版本到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
。
如果有人解决这个问题,我会很乐意接受他们的回答。
javanna已经指出了正确的根源。 我只是想进一步指出,你也可以完全删除StringToArrayConverter ,如这里和这里 所示 。
它是一个黑客,但是,你有没有考虑通过你的参数分隔“ – ”
/test?fq=foo-bar results in fq = foo-bar /test?fq=foo-bar&fq=bash results in fq = foo-bar|bash
或者任何其他分隔符可能〜,或!,或^,或?