SpringMVCの流れ

それでは、SpringMVCの流れを、login処理に沿って説明していきます。
ログイン画面に関連する動きが、SpringMVCの全てのコツを集約しています。
キーワードは、「HTTP/GET」時と「HTTP/POST」時の、LoginCtrl.javaの動きの違い です。
本ページを最後まで読み終わったときに、この違いが理解できていることが、目標です。

ログイン画面表示

はっきり言います。ここが重要です。
「ログイン画面表示するぐらい簡単じゃん、login.jspを表示するんだろ」と思う気持ちをぐっとこらえて、
SpringMVC の最大の特色であり、使いこなすための最重要ポイントだと思って読んでください。

SpringWeb2/index.jsp

先週のサンプルでは、http://localhost:8080/SpringWeb2/ をTomcatに送信すると、
ログイン画面が表示されました。この流れを 順番に追っかけていきます。

http://localhost:8080/SpringWeb2/ をTomcatに送信すると、Tomcatは、自動的に以下の
ファイルのうち、見つかったものを表示します。

  • http://localhost:8080/SpringWeb2/index.html
  • http://localhost:8080/SpringWeb2/index.htm
  • http://localhost:8080/SpringWeb2/index.jsp( 今回はこれ )

なんでそんな動きを自動でするのか、秘密は、web.xmlというファイルにあります。
といっても、SpringWeb2/WEB-INF/web.xmlには、そんな動きをする記述は書いていません。
逆に、書いていないので、Tomcatのデフォルト設定である、TOMCAT/conf/web.xml に書いている
内容をデフォルトの動作として解釈します。
 (注) TOMCAT は、Tomcatをインストールしたディレクトリを示すものとします。

TOMCAT/conf/web.xml には最後の方に、以下のような記述があります。

これは、URLの末尾がファイル名でない場合に、自動的に補完するファイル名の候補を
列挙しています。この設定により
http://localhost:8080/SpringWeb2は http://localhost:8080/SpringWeb2/index.jsp に
読み替えられました。

さて、その SpringWeb2/index.jsp ですが、中身は下記の1行です。

簡単にいうと、http://localhost:8080/SpringWeb2/index.jsp をブラウザが表示すると
直ぐに http://localhost:8080/SpringWeb2/action/login.html に HTTP/GETを要求しなさい
という意味になります。

action/login.html

さて、このactionというキーワードですが、SpringWeb2/WEB-INF/web.xmlに下記のように記述しています。

この指定は、大雑把にいうと、http://localhost:8080/SpringWeb2/action/ で始まる URL が
Tomcat に送信されてきたら、全て「SpringWeb2/WEB-INF/SpringWeb2-servlet.xml の指示に従え」という
意味だと思ってください。

SpringWeb2-servlet.xml

では、SpringWeb2-servlet.xml ではどのような指示を記述しているのでしょうか。
まずは、http://localhost:8080/SpringWeb2/action/○○ の○○を解釈する箇所を紹介します。
末尾の方に、以下の記述があります。

これは、○○が login.html のとき、つまり http://localhost:8080/SpringWeb2/action/login.html
というURLが届いたら、loginCtrl という処理を実行せよと書いています。
では、loginCtrl とは何者でしょうか。答えは、SpringWeb2-servlet.xmlのちょっと上に書いている
以下の記述にあります。

id="loginCtrl"がその接着材の役割を果たしています。そして loginCtrlの実体とは、
com.jxpath.springweb.login.LoginCtrl のインスタンスということになり、やっと、LoginCtrl.java にやってきます。

この定義では、4つのpropertyをDIでセットしています。

loginCtrl の property
property名 説明
formView menu 継承元クラス SimpleFormControllerのメンバ変数(String型)
successView login 継承元クラス SimpleFormControllerのメンバ変数(String型)
commandName login 継承元クラス SimpleFormControllerのメンバ変数
loginLogic loginLogicMap 自分で追加した、Login判定用 LoginInterface型のメンバ変数

formView, successView, commandName は、SpringMVCに含まれている SimpleFormControllerの
メンバ変数で、ログイン操作の画面遷移を行う重要な値ですので、これから説明していきます。
loginLogicは、先週説明しましたので、今週は省略します。

HTTP/GET時の SimpleFormController

さて、これからSpringMVCが用意している SimpleFormController の HTTP/GET 時の振る舞いに
ついて説明します。
SimpleFormControllerは HTTP/GET で呼び出されると、下記の動作をします。
(厳密には少し違いますが、今のところは、流れを理解するため、分かりやすく書いています。)

  1. formBackingObject() メソッドをコールして、
  2. formBackingObject() の戻り値( Object型 )を commandNameで HttpServletRequest.setAttribute()して
  3. formViewが示すJSPを表示する

で、LoginCtrl.javaの formBackingObject() って、以下のようにコーディングしており、
http://localhost:8080/SpringWeb2/action/login.html に HTTP/GET が届くと、このメソッドが呼ばれます。

「親クラスの formBackingObject() を継承しただけじゃん」。はい、先週まではこれでよいです。
今週の「データバインディング」の記事で少し改造します。
また、来週、login.jspをカスタムタグで改造するときに、さらに改造します。
今は、login.jsp は、HttpServletRequest.setAttribute()しても、その値を利用する作りになっていないので
まだ説明する準備ができていないのです。

では、「formViewが示す JSP を表示する」を説明します。formViewの値、login という Stringを
Springはどのように解釈しているのでしょうか?

その設定は、SpringWeb2-servlet.xml の下記の場所にあります。

またもや大雑把に言うと、formViewが示す login という String について、下記のように書いています。

  • prefix( 前 )に、/WEB-INF/jsp/ を付与しなさい
  • suffix( 後 )に、.jsp を付与しなさい
つまり、formViewに login と書いていれば、「/WEB-INF/jsp/」+ login + 「.jsp」と文字列を付与して
/WEB-INF/jsp/login.jsp を表示しろと解釈しているわけです。

やっと、login.jspがブラウザ上に表示されました

たかが、login.jspを表示するために、えらく長い道のりでしたね。「SpringMVCって面倒だなあ」と
感じている方も多いと思います。

この長い道のりは、3つの意味を持っています。
1つ目は、login.jsp を /WEB-INF の下に配置して、直接はブラウザに見せないようにするためです。実際、
http://localhost:8080/SpringWeb2/WEB-INF/jsp/login.jsp というアドレスを直打ちしても、
ログイン画面は出現しません。これにより、jspの前に、formBackingObject() メソッドが
呼ばれることが保証され、初期化やエラーチェックを確実に組み込むことができる訳です。

2つ目は、利用者に Webアプリの実装方法を隠す目的があります。
ログイン画面を表示する URLはhttp://localhost:8080/SpringWeb2/action/login.htmlでしたよね。
末尾が html なので、まるで静的 HTML を表示しているだけのようです。
何か動いているとしても、拡張子からは、JavaなのかPHPなのかASPなのか、簡単には予測できません。
悪意ある利用者( クラッカー )に対して、「このサイトは jsp、つまり Javaで作っていますよ」と最初から
教えてしまうより、何も情報を与えないほうが、サイトのセキュリティが高まるという訳です。

ログイン判定

では本ページの後半戦です。ログイン画面で、「送信」ボタンを押した時の処理の流れを説明します。
login.jspでは、「送信」ボタンを押すということは、http://localhost:8080/SpringWeb2/action/login.html に
HTTP/POST を送信するという意味になります。( パラメータは、account と password )。
SpringMVCは /action/login.htmlから、id="loginCtrl"を起動させます。( ここは上で説明した通り )。 ところが、同じ loginCtrl でも、HTTP/POSTの場合は、下記の動作になります。

  1. formBackingObject() メソッドをコールして、
  2. formBackingObject() の戻り値( Object型 )を commandNameで HttpServletRequest.setAttribute()して
  3. 自動的にデータバインディングして
  4. onSubmit() メソッドをコールして、
  5. onSubmit()の戻り値である ModelAndView を表示します

太字で書いたところが、HTTP/GET との違いです。「データバインディング」は今週の
別のページの記事で紹介しますので、「onSubmit()」の挙動について説明します。

onSubmit() は、簡単に言うと、「ログインに成功したら、new ModelAndView( getSuccessView() )」、
「ログインに失敗したら new ModelAndView( getFormView() )」を戻り値にする、という動きをします。
DIの設定を思い出すと、下記のように読み替えられます。

  • new ModelAndView( getSuccessView() ) → new ModelAndView( "menu" )
  • new ModelAndView( getFormView() ) → new ModelAndView( "login" )

ModelAndViewというクラスの詳細は、今はまだ深入りせず、"menu" と "login" という String型に
着目してください。これ、HTTP/GET で「ログイン画面を表示」するときも似たようなものを見ましたね。
下記のように prefix と suffix を付与して、jsp と読み替えます。

  • "menu" → /WEB-INF/jsp/menu.jsp
  • "login" → /WEB-INF/jsp/login.jsp

やっと意味が通じました。「ログインに成功したら、menu.jspを表示しろ」
「ログインに失敗したら、login.jspに戻れ」という動作を実現しているのです。

まとめ

お疲れ様でした。ログインという最もシンプルな流れの中で、SpringMVC の設定ファイルの書き方と
その挙動について説明してきました。
HTTP/GET と HTTP/POST で挙動を変えるという特色は、strutsの経験が長い方には理解しにくいものだと思います。
(やつは HttpServlet.doPost(), HttpServlet.doGet() を隠蔽しますからねえ..)

とにかく、SpringMVC を使う上で、覚えておかねばならぬことは、onSubmit()メソッドを起動するには、
HTTP/POST を送りましょうということです。