web-dev-qa-db-ja.com

Spring MVCフォームのデータバインディングのために文字列からカスタムオブジェクトに変換しますか?

SpringMVCのSimpleFormControllerをSpringMVCのフォームJTLと組み合わせて使用​​して、Genericオブジェクトを編集するためのフォームを作成しています。

私のフォームには、ユーザーがドロップダウンを介してサーバーを指定できるドロップダウンがあります。

<form:form commandName="generic">
    <form:select path="server">
        <form:options items="${servers}" itemValue="id" itemLabel="name"/>
    </form:select>
</form:form>

ここでのサーバーは、使用可能なすべてのサーバーのデータベース呼び出しによって伝播されます。 serverはサーバーORM pojoです。これは、フォームバッキングオブジェクトとして機能する別のORM pojo(Generic)のサブオブジェクトです。

ここでの私の目標は、データベースレベルでサーバーテーブルへの外部キーとして表されるGenericのサーバー参照を変更することです。

永続層としてJPAを使用し、ORMpojoとしてJPAで生成されたエンティティークラスを使用しています。

残念ながら、フォームを送信すると、文字列からサーバーに変換できないため、これは適切にバインドされていないようです。

Field error in object 'generic' on field 'server': rejected value [1]; codes [typeMismatch.generic.server,typeMismatch.server,typeMismatch.com.generic.orm.jpa.Server,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [generic.server,server]; arguments []; default message [server]]; default message [Failed to convert property value of type [Java.lang.String] to required type [com.generic.orm.jpa.Server] for property 'server'; nested exception is Java.lang.IllegalArgumentException: Cannot convert value of type [Java.lang.String] to required type [com.generic.orm.jpa.Server] for property 'server': no matching editors or conversion strategy found], generic=com.generic.orm.jpa.generic[id=3]} and static attributes {}

私はこれを運なしで達成する方法の例を探していました。私は この質問 で行ったように、SimpleFormController内で何かを上書きする必要があると思いますが、Spring MVCのドキュメントは詳細については簡単です。誰かがここで私を助けることができますか?

22
James McMahon

あなたは正しいと思います。文字列をサーバーインスタンスに変換できるように、以前と同じようにバインダーにカスタムエディターを登録する必要があります。 SpringリファレンスドキュメントにカスタムPropertyEditor here の例があります。

MVCのドキュメントが最善ではないことに同意します。 Springフォーラムでグーグルと検索をたくさんしなければなりませんでした。

5
Mark

マークの答えを補足するのと同じように、これが私がコントローラーでやったことです。

@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    binder.registerCustomEditor(Server.class, "serverId", new PropertyEditorSupport() {
        @Override
        public void setAsText(String text) {
            Server type = (Server) em.createNamedQuery("Server.findById")
                .setParameter("id", Short.parseShort(text)).getSingleResult();
            setValue(type);
        }
    });
}

匿名クラスではなく、Springインジェクションを使用してこれを行うこともできます。これは、Markの回答の link で概説されています。

PropertyEditorSupportの代わりにClassEditor(以下を参照)を拡張できる場合もあります。 Javadocは次のように述べています。

Java.lang.Classのプロパティエディタ。Stringクラス名のプロパティをブリッジとして使用する必要なく、Classプロパティの直接入力を可能にします。

私がこれの利点を完全に理解しているかどうかはわかりませんが、覚えておくべきことがあります。

便利なJavadoc

21
James McMahon

「server.id」を使用することが解決策になる可能性があります。つまり、Springは選択された値を自動的にバインドするか、またはその逆です。

<form:form commandName="generic">
    <form:select path="server.id">
        <form:options items="${servers}" itemValue="id" itemLabel="name"/>
    </form:select>
</form:form>
18
Fırat KÜÇÜK

コントローラ内の回答の注釈バージョン:

@org.springframework.web.bind.annotation.InitBinder("yourFormName")
protected void initBinder(
             org.springframework.web.bind.WebDataBinder binder) {
    binder.registerCustomEditor(Server.class, "serverId", new PropertyEditorSupport() {
        @Override
        public void setAsText(String text) {
            Server s = ...; // do whatever needed to convert
            setValue(s);
        }
    });
1
Ean V
1
Kristo Aun