如何进行spring请求参数转换

时间:2011-07-26 19:43:44

标签: spring spring-mvc

在基于Spring 3的Web(portlet)应用程序中,我有一个控制器,其方法如下:

@RenderMapping
public ModelAndView handleRenderRequest(...,@RequestParam MyClass myObject)
{
    ...
}

现在我想知道:我如何告诉spring如何将请求参数转换为MyClass。我找到了有关属性编辑器和Converter接口的信息,似乎有一些影响,转换器是属性编辑器的继承者,但似乎没有人愿意明确它。

我实现了String到MyClass转换的转换器接口。但是我如何告诉Spring呢?我尽可能使用基于注释的配置,所以我检查spring是否会自动从类路径中检测到Converter,但事实并非如此。

所以认为手册中的Configuring a ConversionService部分想告诉我,我必须将以下内容添加到我的applicationContext.xml中:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="some.package.MyConverter"/>
        </list>
    </property>
</bean>

仍然:

  

org.springframework.beans.ConversionNotSupportedException:失败   转换价值[...]

那我错过了什么?有没有办法,只需配置一个包,让Spring扫描这个包转换器并自动注册?并且说,在某种方法中,我想使用与所有其他方法不同的转换器。例如,我想要一个检查Luhn-Checksum的整数并删除校验和,我该怎么做?像@RequestParam(converter = some.package.MyConverter.class)这样的东西会很棒。

修改

好的,我刚刚收到了文档:

  

在客户端环境中工作时使用Formatter SPI,   例如Web应用程序,需要解析和打印本地化字段   值

所以我想这意味着我应该使用Formatter SPI,然后是属性编辑器和转换器旁边的第三种可能性(我想我可以使用比较表等)。我也实现了Parser接口,并尝试使用以下方式注册我的转换器:

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="some.package.SortOrderEnumConverterSpring"/>
        </set>
    </property>
</bean> 

如您所见,我使用“set”而不是“list”来指定转换器。我在FormattingConversionServiceFactoryBean.setConverters方法中设置了一个调试断点,该方法在使用list时没有触发,但它确实触发了使用set。

另外我添加了

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

我的applicationContext的mvc-prefix的命名空间。但我仍然得到转换不支持的异常。

我还尝试回到转换器方法,并在applicationContext.xml文件中更改了从列表到设置的转换器的参数列表,但这也没有改变任何内容。

EDIT2

正如digitaljoel所指出的,可以使用initBinder方法为每个控制器设置不同的转换器。我将它应用于我的控制器:

@Autowired
private ConversionService conversionService;

@InitBinder
public void initBinder(WebDataBinder binder)
{
    binder.setConversionService(conversionService);
}

在我的applicationContext.xml中:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="some.package.with.MyConverter"/>
        </set>
    </property>
</bean>

所有突然转换工作正常:-)。但我不太高兴不得不将其应用于我的每一个控制器。必须有一种方法可以在我的applicationContext中为每个人设置它,不是吗?很高兴知道我可以覆盖默认,如果我需要(毕竟我要求),但我仍然想设置默认值。

那格式化程序的东西呢。我不应该使用它而不是转换器吗?

5 个答案:

答案 0 :(得分:3)

Spring Portlet MVC 3.0不支持

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

访问https://jira.springsource.org/browse/SPR-6817了解更多相关信息。

但是,您可以将此添加到常用的applicationContext

<bean
    class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <bean
            class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService">
                <list>
                    <ref bean="conversionService" />
                </list>
            </property>
        </bean>
    </property>
</bean>

这样您就不需要将@InitBinder添加到每个控制器

当然

<bean id="conversionService"
    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <!-- converter implementations here -->
        </list>
    </property>
</bean>

答案 1 :(得分:1)

您认为Converter(和ConverterFactory)是属性编辑器的后继者是正确的。您的问题可能是您没有接受适当的类型作为转换器的参数,但如果没有看到转换器代码,很难说。如果您期望Long或Integer,您可能实际上是从Spring获取字符串并且需要首先自己执行该键转换。

至于配置,我相信你需要列出xml中bean配置中的所有转换器。如果使用@Component注释转换器实现,则可能可以通过bean名称而不是完全限定的路径来引用它,但我只尝试使用ConverterFactory,而不是转换器。

最后,在特定转换器上,看起来您可以在控制器级别配置转换服务(请参阅Javi在Setting up a mixed configuration for annotation-based Spring MVC controllers上的答案),然后您可以放置​​该方法(以及其他需要该方法的方法)控制器)进入一个使用二级转换服务的控制器,您应该能够通过@Resource注释按名称注入。

答案 2 :(得分:1)

实施WebArgumentResolver:

public class MyArgumentResolver implements WebArgumentResolver
{
    @Override
    public Object resolveArgument(MethodParameter methodParameter,
            NativeWebRequest webRequest) throws Exception
    {
        Class<?> paramType = methodParameter.getParameterType();
        if (paramType == MyClass.class)
        {
            String parameterName = methodParameter.getParameterName();
            String stringParameter = webRequest.getParameter(parameterName);
            return convert(stringParameter);
        }
        return UNRESOLVED;
    }
}

并在applicationContext.xml中注册:

<bean class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="customArgumentResolver">
        <bean class="com.dshs.eakte.util.MyArgumentResolver" />
    </property>
</bean>

这有效,甚至可以允许基于多个方法参数的参数转换。

答案 3 :(得分:0)

为了实现类似于你正在做的事情,我发现this blog entry很有用。

答案 4 :(得分:-1)

我认为你需要使用像

这样的东西
public ModelAndView handleRenderRequest(...,@ModelAttribute("myObject") MyClass myObject)