Spring MVCタイプ変換:PropertyEditorまたはConverter?


129

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コンテナ内では、このシステムをPropertyEditorsの代替として使用できます

「最新の代替手段」であるため、コンバータを使用したいとしましょう。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());
        }
    
    }
    

これらすべての欠点があるため、なぜコンバータを使用するのですか?何か不足していますか?私が知らない他のトリックはありますか?

PropertyEditorsを使い続けたくなります...バインディングははるかに簡単で迅速です。


注(私もつまずいた、Spring 3.2.17を使用):<mvc:annotation-driven />を使用する場合、実際にこのconversionService Beanを参照する必要があります:<mvc:annotation-driven conversion-service = "conversionService" />
mauhiz 2016年

addFormatters(...)はパブリックである必要があります。また、5.0以降、WebMvcConfigurerAdapterは非推奨になりました。
Paco Abato

回答:


55

これらすべての欠点があるため、なぜコンバータを使用するのですか?何か不足していますか?私が知らない他のトリックはありますか?

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

私の考えでは、PropertyEditorsはスコープが制限されています。これらはStringを型に変換するのに役立ちます。この文字列は通常UIから取得されるため、@ InitBinderを使用してPropertyEditorを登録し、WebDataBinderを使用することは意味があります。

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

UIに関連するフローについては、PropertyEditorsは、特定のコマンドプロパティに対して何かカスタムを実行する必要がある場合に特に適しています。他の場合については、Springリファレンスからの推奨を採用し、代わりにコンバーターを作成します(たとえば、サンプルとしてLong IDからエンティティーに変換するためなど)。


5
コンバーターがステートレスであることのもう1つの良い点は、プロパティエディターはステートフルで何度も作成され、多くのapi呼び出しで実装されますが、これがパフォーマンスに大きな影響を与えるとは思いませんが、コンバーターはよりクリーンでシンプルです。
ボリス・トレホフ2012

1
@Borisクリーナーはい、特に初心者にとっては単純ではありません。2つのコンバータークラスを記述し、XML構成またはJava構成に数行追加する必要があります。私は一般的な変換(エンティティだけでなく)を伴うSpring MVCフォームの送信/表示について話しています。
ジェロームダルベルト2012

16
  1. 文字列へ/からの変換には、コンバーターの代わりにフォーマッター(実装org.springframework.format.Formatter)を使用します。それは持っているプリント(...)パース(...)メソッドを、ので、あなただけの1クラスの代わりに、2を必要としています。それらを登録するには、ConversionServiceFactoryBeanの代わりに、コンバータとフォーマッタの両方を登録できるFormattingConversionServiceFactoryBeanを使用します。
  2. 新しいFormatterには、さらにいくつかの利点があります。
    • Formatterインターフェースは、そのprint(...)およびparse(...)メソッドでLocaleオブジェクトを提供するため、文字列変換はロケールに依存する可能性があります
    • 事前登録されたフォーマッタに加えて、FormattingConversionServiceFactoryBeanには便利な事前登録されたAnnotationFormatterFactoryオブジェクトがいくつかあり、アノテーションを介して追加のフォーマットパラメータを指定できます。例: @RequestParam@DateTimeFormat(pattern = "MM-dd-yy")LocalDate baseDate ... 独自のAnnotationFormatterFactoryクラスを作成することはそれほど難しくありません。簡単な例については、SpringのNumberFormatAnnotationFormatterFactoryを参照してください。これにより、コントローラー固有のフォーマッター/エディターが不要になると思います。すべてのコントローラーに対して1つのConversionServiceを使用し、注釈を介してフォーマットをカスタマイズします。
  3. それでもコントローラー固有の文字列変換が必要な場合は、カスタムプロパティエディターを使用するのが最も簡単な方法であることに同意します。(@InitBinderメソッドで「inder.setConversionService(...)」を呼び出そうとしましたが、バインダーオブジェクトには「グローバル」変換サービスがすでに設定されているため、失敗します。コントローラーごとの変換クラスは推奨されていないようです春3)。

7

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

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

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

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


トリックのおかげで、エンティティ変換のみを処理する優れたソリューション。もう1つのクラスを作成する必要があるため、最初は単純ではありませんが、長期的には単純で時間の節約になります。
ジェロームダルバート

ところで、このようなコンバーターは、一般的な規約に準拠するすべての型に実装できます-別の例:列挙型が一般的な逆引き参照インターフェースを実装している場合は、一般的なコンバーターを実装することもできます(stackoverflow.comに似ています)/ questions / 5178622 /…
ボリス・トレホフ2012

@JeromeDalbertはい、初心者が重いことを行うのは少し難しいですが、開発者のチームがある場合は簡単になります)PSそしてとにかくフォームバインディングで毎回同じプロパティエディタを登録するのは退屈になります)
ボリス・トレホフ

1

2つのコンバーターを静的内部クラスとして実装することにより、2つの別個のコンバータークラスを用意する必要性を回避できます。

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) { ... }
    }
}

両方を個別に登録する必要がありますが、少なくとも、変更を加えると、変更する必要のあるファイルの数が減ります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.