如何防止参数绑定解释Spring 3.0.5中的逗号?

nic*_*dos 53 java data-binding spring spring-mvc

考虑以下控制器方法:

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

以下是不同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, "|"));
Run Code Online (Sandbox Code Playgroud)

它打印预期的输出:fqs = foo,bar.所以"问题"在于Spring数据绑定.

我可以绕过Spring的绑定和使用,HttpServletRequest但我真的不想,因为我在我的实际代码中使用了支持bean(同样的事情正在发生),并且不希望重新实现绑定功能.我希望有人可以提供一种通过转义或其他机制来防止这种行为的简单方法.

TIA

更新:我在Twitter上发布了这个Q并得到了一个回复说,预期输出出现在Spring 3.0.4.RELEASE.我现在已经证实了这种情况,因此是一个临时修复.我将继续将此作为Spring JIRA系统上的错误记录下来.如果有人可以提供解决方案或修复3.0.5,我会接受他们的回答.

jav*_*nna 33

我已经测试了你的代码:它令人难以置信,但我无法重现你的问题.我已经下载了最新版本的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(), "|"));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的SearchRequestParams类:

package test;

public class SearchRequestParams {
    private String[] fq;

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

    public void setFq(String[] fq) {
    this.fq = fq;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我简单的弹簧配置:

<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>
Run Code Online (Sandbox Code Playgroud)

我在tomcat 7.0.8中测试了我的代码; 当我输入时,我http://localhost:8080/testweb/test/params.htm?fq=foo,bar能够在我的日志文件中读到这一行:DEBUG fq = foo,bar.我的代码与你的代码有什么不同?难道我做错了什么?我想帮助你,所以如果你有任何疑问,或者我可以为你做一些其他测试,那将是一种乐趣.

更新/解决方案
使用您的代码我重现了这个问题; 你必须标记<mvc:annotation-driven />你的调度servlet配置,让你悄无声息使用默认的转换服务,实例FormattingConversionService,其中包含从默认的转换器StringString[]使用逗号作为分隔符.您必须使用含有自己的转换器不同的转换服务的bean StringString[].您应该使用不同的分隔符,我选择使用";" 因为它是常用于查询字符串的分隔符("?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, ";");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您必须在配置中指定此转换服务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>
Run Code Online (Sandbox Code Playgroud)

问题已解决,现在你应该检查是否有任何副作用.我希望您在应用程序中不需要将原始转换StringString[](使用逗号作为分隔符).;-)


Tac*_*aGT 25

我找到了最优雅,最短的方式 - 添加@InitBinder@Controller:

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

它将String转换为String []而不使用separator(nullparam),使用Spring类org.springframework.beans.propertyeditors.StringArrayPropertyEditor.如果同一项目中的某个人将使用新的默认转换方式,那就没问题了.

  • 对我来说最好的答案。@beaudet,它是 StringArrayPropertyEditor,所以它自然不适用于列表。尝试“binder.registerCustomEditor(List.class, new CustomCollectionEditor(List.class));” (5认同)

Jam*_*ins 7

rougou 的评论是唯一对我有用的解决方案,因为我使用的是List<String>而不是String[].

将其添加到您的控制器中以消除解析逗号分隔值:

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(List.class, new CustomCollectionEditor(List.class));
    }
Run Code Online (Sandbox Code Playgroud)