弹簧MVC类型转换:属性编辑器还是转换器?

我正在寻找在Spring MVC中绑定和转换数据的最简单,最简单的方法。如果可能,无需执行任何 xml 配置。

到目前为止,我一直在使用属性编辑器,如下所示:

public class CategoryEditor extends PropertyEditorSupport {

    // Converts a String to a Category (when submitting form)
    @Override
    public void setAsText(String text) {
        Category c = new Category(text);
        this.setValue(c);
    }

    // Converts a Category to a String (when displaying form)
    @Override
    public String getAsText() {
        Category c = (Category) this.getValue();
        return c.getName();
    }

}

...
public class MyController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Category.class, new CategoryEditor());
    }

    ...

}

这很简单:两个转换都在同一个类中定义,并且绑定很简单。如果我想在所有控制器上进行常规绑定,我仍然可以在 xml 配置中添加 3 行


但是Spring 3.x引入了一种新的方法,使用转换器

在Spring容器中,该系统可以用作PropertyEditors的替代品

因此,假设我想使用转换器,因为它是“最新的替代方案”。我必须创建两个转换器:

public class StringToCategory implements Converter<String, Category> {

    @Override
    public Category convert(String source) {
        Category c = new Category(source);
        return c;
    }

}

public class CategoryToString implements Converter<Category, String> {

    @Override
    public String convert(Category source) {
        return source.getName();
    }

}

第一个缺点:我必须上两节课。优点 :由于通用性,无需铸造。

那么,我如何简单地数据绑定转换器?

第二个缺点:我还没有找到任何简单的方法(注释或其他编程工具)在控制器中执行此操作:没有像.someSpringObject.registerCustomConverter(...);

我发现的唯一方法是乏味的,不简单,而且只是关于一般的交叉控制器绑定:

  • XML 配置

    <bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="somepackage.StringToCategory"/>
                <bean class="somepackage.CategoryToString"/>
            </set>
        </property>
    </bean>
    
  • Java 配置仅在 Spring 3.1+中):

    @EnableWebMvc
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        protected void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToCategory());
            registry.addConverter(new CategoryToString());
        }
    
    }
    

有了所有这些缺点,为什么要使用转换器 ?我错过了什么吗?还有其他我不知道的技巧吗?

我很想继续使用PropertyEditors...绑定更容易、更快捷。


答案 1

有了所有这些缺点,为什么要使用转换器 ?我错过了什么吗?还有其他我不知道的技巧吗?

不,我认为您已经非常全面地描述了属性编辑器和转换器,每个转换器是如何声明和注册的。

在我看来,PropertyEditors的范围是有限的 - 它们有助于将String转换为类型,并且此字符串通常来自UI,因此使用@InitBinder和使用WebDataBinder注册PropertyEditor是有意义的。

另一方面,转换器更通用,它适用于系统中的任何转换 - 而不仅仅是与UI相关的转换(字符串到目标类型)。例如,Spring Integration广泛使用转换器将消息有效负载转换为所需的类型。

我认为对于与UI相关的流,PropertyEditor仍然适合,特别是对于需要为特定命令属性进行自定义的情况。对于其他情况,我会从Spring参考中获取建议并编写一个转换器(例如,从Long id转换为实体,作为示例)。


答案 2
  1. 对于 to/from String 转换,请使用格式化程序(实现 org.springframework.format.Formatter)而不是转换器。它具有 print(...)parse(...) 方法,因此您只需要一个类而不是两个类。要注册它们,请使用FormatationConversionServiceFactoryBean,它可以同时注册转换器和格式化程序,而不是ConvertationServiceFactoryBean
  2. 新的格式化程序内容有几个额外的好处:
    • 格式化程序接口在其 print(...)parse(...) 方法中提供 Locale 对象,因此字符串转换可以区分区域设置
    • 除了预注册的格式化程序之外,FormattingConversionServiceFactoryBean还附带了几个方便的预注册NotestinFormatterFactory对象,允许您通过注释指定其他格式设置参数。例如:@RequestParam @DateTimeFormat(pattern=“MM-dd-yy”) LocalDate baseDate ...创建自己的NotementFormatterFactory类并不难,请参阅Spring的NumberFormatAnnotationFormatterFactory以获取一个简单的示例。我认为这消除了对特定于控制器的格式化程序/编辑器的需求。对所有控制器使用一个转换服务,并通过注释自定义格式。
  3. 我同意,如果您仍然需要一些特定于控制器的字符串转换,最简单的方法仍然是使用自定义属性编辑器。(我试图在我的@InitBinder方法中调用'binder.setConversionService(...)',但它失败了,因为binder对象附带了已经设置的'global'转换服务。似乎不鼓励在 Spring 3 中使用每个控制器的转换类)。

推荐