136

Spring MVC でデータをバインドして変換する最も簡単で簡単な方法を探しています。可能であれば、xml 構成を行わずに。

これまでのところ、私はPropertyEditorsを次のように使用してきました:

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 config に 3 行追加できます。


しかし、Spring 3.x では、 Convertersを使用してそれを行う新しい方法が導入されました。

Spring コンテナー内では、このシステムを PropertyEditor の代替として使用できます。

それで、「最新の代替手段」であるため、コンバーターを使用したいとしましょう。2 つのコンバーターを作成する必要があります。

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

}

最初の欠点: 2 つのクラスを作成する必要があります。利点 : 汎用性のおかげでキャストする必要がありません。

次に、コンバーターを単純にデータバインドするにはどうすればよいですか?

2番目の欠点:コントローラーでそれを行う簡単な方法(注釈またはその他のプログラム機能)が見つかりませんでした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());
        }
    
    }
    

これらすべての欠点があるのに、なぜ Converters を使用するのでしょうか? 何か不足していますか?私が気付いていない他のトリックはありますか?

私は PropertyEditors を使い続けたいと思っています... バインディングははるかに簡単で迅速です。

4

4 に答える 4

59

これらすべての欠点があるのに、なぜ Converters を使用するのでしょうか? 何か不足していますか?私が気付いていない他のトリックはありますか?

いいえ、PropertyEditor と Converter の両方について、それぞれがどのように宣言および登録されるかを非常に包括的に説明したと思います。

私の考えでは、PropertyEditors は範囲が限られています。String を型に変換するのに役立ちます。この文字列は通常 UI から取得されるため、@InitBinder を使用して PropertyEditor を登録し、WebDataBinder を使用することは理にかなっています。

一方、コンバーターはより一般的であり、UI 関連の変換 (文字列からターゲット型へ) だけでなく、システム内のあらゆる変換を対象としています。たとえば、Spring Integration はコンバーターを広範囲に使用して、メッセージ ペイロードを目的の型に変換します。

UI 関連のフローでは、PropertyEditor は、特に特定のコマンド プロパティに対して何かカスタムを行う必要がある場合に適していると思います。他のケースでは、Spring リファレンスからの推奨事項を参考にして、代わりにコンバーターを作成します (たとえば、サンプルとして、Long id からエンティティーに変換するため)。

于 2012-09-22T20:26:45.303 に答える
8

最も簡単な方法 (永続化フレームワークを使用していると仮定) ですがConditionalGenericConverter、メタデータを使用してエンティティを変換するインターフェイスを介して汎用エンティティ コンバーターを実装するのが完璧な方法ではありません。

たとえば、JPA を使用している場合、このコンバーターは、指定されたクラスに@Entity注釈があるかどうかを調べ、@Id注釈付きフィールドを使用して情報を抽出し、提供された文字列値をルックアップの Id として使用して自動的にルックアップを実行します。

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

ConditionalGenericConverterは、Spring 変換 API の「究極の武器」ですが、一度実装すると、ほとんどのエンティティ変換を処理できるようになり、開発者の時間を節約できます。エンティティ クラスをコントローラーのパラメーターとして指定するだけで、実装について考えない場合は非常に安心です。新しいコンバーター (もちろん、カスタムおよび非エンティティ型を除く)。

于 2012-09-22T15:14:53.330 に答える