Spring MVCtypes转换:PropertyEditor或Converter?

我正在寻找在MVC中绑定和转换数据的最简单最简单的方法。 如果可能的话,不做任何XMLconfiguration。

到目前为止,我一直在使用PropertyEditor :

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()); } ... } 

很简单:两个转换都是在同一个类中定义的,绑定很简单。 如果我想对所有控制器进行通用绑定,我仍然可以在我的xmlconfiguration中添加3行 。


但是Spring 3.x引入了一个新的方法来使用转换器 :

在一个Spring容器中,这个系统可以用来替代PropertyEditor

所以我们说我想使用转换器,因为它是“最新的select”。 我将不得不创build两个转换器:

 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(); } } 

第一个缺点:我必须做两个class。 好处:不需要感谢通用性。

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

第二个缺点:我没有find任何简单的方法(注释或其他编程设施)在控制器中执行它:没有像someSpringObject.registerCustomConverter(...);

我发现的唯一方法是繁琐的,而不是简单的,只有一般的交叉控制器绑定:

  • XMLconfiguration :

     <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="somepackage.StringToCategory"/> <bean class="somepackage.CategoryToString"/> </set> </property> </bean> 
  • Javaconfiguration ( 仅在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 …绑定更容易,更快捷。

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

不,我认为你已经非常全面地描述了PropertyEditor和Converter,它们是如何声明和注册的。

在我看来,PropertyEditors的范围有限 – 它们帮助将String转换为一个types,这个string通常来自UI,所以使用@InitBinder注册PropertyEditor并使用WebDataBinder是有道理的。

另一方面,转换器更通用,它旨在用于系统中的任何转换 – 不仅仅是与UI相关的转换(string转换为目标types)。 例如,Spring Integration广泛使用转换器将消息有效载荷转换为所需的types。

我认为对于UI相关的streamPropertyEditor仍然适用,尤其是对于需要为特定命令属性进行自定义的情况。 对于其他情况,我会采用Spring引用的build议,而不是写一个转换器(例如,从一个Long id转换为一个实体,例如)。

  1. 对于从/到string转换使用格式化器(实现org.springframework.format.Formatter )而不是转换器。 它有print(…)parse(…)方法,所以你只需要一个类而不是两个。 要注册它们,请使用FormattingConversionServiceFactoryBean ,它可以注册转换器和格式化程序,而不是ConversionServiceFactoryBean
  2. 新的Formatter东西有一些额外的好处:
    • Formatter接口在其print(…)parse(…)方法中提供了Locale对象,所以你的string转换可以是locale-sensitive
    • 除了预先注册的格式化程序外, FormattingConversionServiceFactoryBean还附带了一些方便的预注册的AnnotationFormatterFactory对象,允许您通过注释指定其他格式化参数。 例如: @RequestParam @DateTimeFormat(pattern =“MM-dd-yy”) LocalDate baseDate …创build自己的AnnotationFormatterFactory类并不是很困难,请参阅Spring的NumberFormatAnnotationFormatterFactory 。 我认为这消除了控制器特定的格式化器/编辑器的需要。 为所有控制器使用一个ConversionService并通过注释自定义格式。
  3. 我同意,如果你仍然需要一些控制器特定的string转换,最简单的方法仍然是使用自定义属性编辑器。 (我尝试在我的@InitBinder方法中调用' binder.setConversionService(…) ',但是失败了,因为binder对象带有已经设置好的 'global'转换服务,看起来像每个控制器转换类不鼓励春季3)。

最简单的(假设你正在使用一个持久性框架),但不是完美的方法是通过ConditionalGenericConverter接口实现一个通用的实体转换器,它将使用它们的元数据转换实体。

例如,如果您正在使用JPA,则此转换器可能会查看指定的类是否具有@Entity批注,并使用@Id批注字段来提取信息,并使用提供的String值自动执行查找作为查找的Id。

 public interface ConditionalGenericConverter extends GenericConverter { boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); } 

ConditionalGenericConverter是Spring convertion API的“终极武器”,但是一旦它能够处理大部分的实体转换,节省开发人员的时间就可以实现 – 当你只是指定实体类作为你的控制器的参数,而不用考虑实现一个新的转换器(当然除了自定义和非实体types)。

您可以通过将两个转换器实现为静态内部类来解决两个独立的Converter类的需求。

 public class FooConverter { public static class BarToBaz implements Converter<Bar, Baz> { @Override public Baz convert(Bar bar) { ... } } public static class BazToBar implements Converter<Baz, Bar> { @Override public Bar convert(Baz baz) { ... } } } 

你仍然需要分别注册他们两个,但是至less可以减less你需要修改的文件的数量,如果你做了任何改变的话。