1

私はこのクラスを持っています:

@Component
@Scope("session")
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue
    @GenericGenerator(name = "incremental", strategy = "increment")
    private Long userID;

    @Column(nullable = false)
    private String username;

    @Column(nullable = false)
    private String email;

    @Column(nullable = false)
    private String password;
    // getters and setters
}

そしてこのコントローラー:

@Controller
@SessionAttributes("user")
@Scope("request")
public class UserCreationWizard {
    @Autowired
    private User user;

    @ModelAttribute("user")
    private User createUser() {
        return user;
    }

    @RequestMapping(value = "/new/users/page/", method = RequestMethod.GET)
    public String begin(HttpServletRequest request) {
        return "wizard"; 
    }

    @RequestMapping(value = "/new/users/page/{page}", method = RequestMethod.POST) 
    public String step(@ModelAttribute("user") User user,
                       @RequestParam("username") String username,
                       @RequestParam("email") String password,
                       @PathVariable() Integer page) {

        return "wizard" + page;
    }

    @RequestMapping(value = "/new/users/page/end", params = "submit", method = RequestMethod.POST) 
    public String end(@RequestParam("password") String password) {

        user.setPassword(password);
        user.setActive(true);
        user.setLastLoggedIn(Calendar.getInstance());

        Session s = HibernateUtils.getSessionFactory().openSession();
        Transaction t = s.beginTransaction();
        try {
            s.persist(user);
            s.flush();
            t.commit();

            s.close();
        } catch (HibernateException e) {
            t.rollback();
        }
        return "wizard";
    }
}

begin()ユーザー作成ウィザードで最初のビュー(jsp)をロードするだけです。との入力フィールドがusernameありemailます。ビューで、をトリガーするPOSTフォーム送信を行いますstep()。2番目のビュー(wizard + page.jsp)には、passwordをトリガーするフィールドと送信入力がありますend()

  1. デバッグモードではstep()、UserをModelAttributeとして渡した場合、ユーザー名とパスワードのフィールドを設定する必要がないことに気付きました。それらはRequestParams属性から自動的に取得されます。ただしend()、ModelAttributeがない場合は、パスワードを手動で設定する必要があります。Springはこれをどのように管理しますか?
  2. またcreateUser()、コントローラーでメソッドを取得すると、アプリケーションは「ユーザー」のセッション属性が見つからなかったと言って失敗します。このメソッドは、メソッドパラメーターとしてMethodAttributeにどのようにリンクされていますか?
  3. 最後に、@ SessionAttributesを削除しても、アプリケーションは失敗しませんが、問題が発生しているように感じます。ユーザーユーザーはすべてのhttprequestsに対してグローバルになりますか?

私の一般的な質問は次のとおりです。春の豆はその名前にマッピングされていますか?例えば。ここでは、ユーザーとして「user」、セッションに「user」、requestparamとして「password」、Userメンバー変数として「password」があります。

4

1 に答える 1

1

わかりました、多くの質問。見てみましょう。すべての参照は、現在のSpringMVCバージョンのドキュメントを参照しています。

1)属性に表示される動作は、「メソッド引数での@ModelAttributeの使用user」のセクションで説明されています。

メソッド引数の@ModelAttributeは、引数をモデルから取得する必要があることを示します。モデルに存在しない場合は、引数を最初にインスタンス化してから、モデルに追加する必要があります。モデルに存在するようになったら、引数のフィールドは、名前が一致するすべてのリクエストパラメータから入力する必要があります。これは、Spring MVCではデータバインディングと呼ばれ、各フォームフィールドを個別に解析する必要がない非常に便利なメカニズムです。

Springはこれをどのように行いますか?ソースコードが最終的な答えですが、推測するのはそれほど難しいことではありません。Springは、引数がインスタンスであることを認識しており、Userリフレクションを介してクラスのメソッド、特にセッターを読み取ることができます。この場合、それはsetUsername()andを検出しsetEmail()、それらのメソッドの引数はaであるStringため、リクエストのパラメーターと互換性があります。

(ところで:@RequestParam("email") String passwordおそらく間違いです。少なくとも混乱しています)

2)メソッドのcreateUser()前にアノテーションが付き@ModelAttribute("user")ます。これについては、「メソッドでの@ModelAttributeの使用」のセクションで説明しています。

メソッドの@ModelAttributeは、そのメソッドの目的が1つ以上のモデル属性を追加することであることを示します。

したがって、このメソッドは、名前に関連付けられたオブジェクトを"user"モデルに配置し、などの他のメソッドでパラメーターとして使用できるようになりますstep()。注釈は、モデル内のオブジェクトによって使用される識別子を制御することに注意してください。コードをに変更した場合

@ModelAttribute("strangeWeirdIdentifier")
private User createUser() { return user; }

アプリが壊れます。step()ただし、署名を次のように変更すると、再び機能します

public String step(@ModelAttribute("strangeWeirdIdentifier") User user,
                   @RequestParam("username") String username,
                   @RequestParam("email") String password,
                   @PathVariable() Integer page) {

3)1)および2)で説明されているプロセスは、リクエスト中にオブジェクトをモデルに格納します。クラスアノテーション@SessionAttributes("user")を使用すると、オブジェクトの寿命を延ばし、現在のオブジェクトSessionまたは同等のものに追加できます。例として、メソッドControllerと同じように他のオブジェクトを使用できます。step()

最後に明確にするために

  • 質問2に見られる注釈は、質問1に見られる使用法の前に発生します。
  • 質問3の注釈はおそらく必要ありません
  • Springは、BeanをJavaコードの名前にマップするのではなく、アノテーションで使用される名前にマップします。わかりやすくするために、例と同じ名前を繰り返すことは珍しくありません。

これが公式のドキュメントよりも明確になっていることを願っていますが、通常は短すぎます。それをお伝えします。

于 2012-11-23T05:23:06.777 に答える