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の代替として使用できます
それで、「最新の代替品」であるコンバータを使用したいとしましょう。私はtwoコンバーターを作成する必要があります:
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(...);
のようなものはありません。
私が見つけた唯一の方法は退屈で、単純ではなく、一般的なクロスコントローラバインディングのみです:
<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 config (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を型に変換するのに役立ち、この文字列は通常UIから取得されるため、@ InitBinderとWebDataBinderを使用してPropertyEditorを登録するのは理にかなっています。
一方、コンバータはより汎用的であり、UI関連の変換(文字列からターゲットタイプ)だけでなく、システム内の任意の変換を対象としています。たとえば、Spring Integrationは、メッセージペイロードを目的のタイプに変換するためにコンバーターを広範囲に使用します。
UI関連のフローでは、特に特定のコマンドプロパティに対して何かカスタムを行う必要がある場合、PropertyEditorsが依然として適切だと思います。他の場合には、Springリファレンスから推奨事項を取得し、代わりにコンバーターを作成します(たとえば、サンプルとしてLong idからエンティティーに変換するなど)。
最も簡単な方法(永続フレームワークを使用している場合)ですが、メタデータを使用してエンティティを変換するConditionalGenericConverter
インターフェイスを介して汎用エンティティコンバーターを実装することは完璧な方法ではありません。
たとえば、JPAを使用している場合、このコンバーターは、指定されたクラスに@Entity
注釈があるかどうかを確認し、@Id
注釈付きフィールドを使用して情報を抽出し、指定された文字列値をIdとして自動的にルックアップを実行しますルックアップ用。
public interface ConditionalGenericConverter extends GenericConverter {
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConditionalGenericConverter
はSpring変換APIの「究極の武器」ですが、ほとんどのエンティティ変換を処理できるようになると実装され、開発者の時間を節約できます。コントローラのパラメータとしてエンティティクラスを指定するだけで大いに安心です新しいコンバーターの実装については考えないでください(もちろん、カスタム型および非エンティティ型を除きます)。
2つのConverterを静的内部クラスとして実装することにより、2つの別個の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) { ... }
}
}
それでも両方を別々に登録する必要がありますが、少なくともこれにより、変更を加えた場合に変更する必要があるファイルの数が少なくなります。