Spring MVC で簡単そうなエコーアプリを作って基本を学ぶ

前回は、プロジェクトに Spring MVC を設定したので簡単なアプリを作ってみます。

ponsuke-tarou.hatenablog.com

環境

ここで作るエコーアプリはこの本のSpring MVCの章にあるものです。

トップ画面から遷移した入力画面で値を入力して出力画面に表示します。
www.shoeisha.co.jp

トップ画面を作ります。

Controllerを作ります。

f:id:ponsuke_tarou:20180618154305p:plain

package example.app;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/** トップ画面用のController. */
@Controller
public class WelcomeController {
    /**
     * トップ画面の表示リクエストをハンドリングするためのメソッド.
     * RequestMappingアノテーションに"/"を指定することで、"/"というパスに対するリクエストがこのメソッドにマッピングされる.
     * @return トップ画面のView名.
     */
    @RequestMapping("/")
    public String home() {
        // トップ画面に表示するView名として"index"を返却すると「/src/main/webapp/index.jsp」が呼び出される。
        return "index";
    }
}

Viewを作成します。

以前、ViewResolverを設定しました。これにより、/WEB-INFディレクトリ配下に格納されているJSPファイルがViewとして扱われます。

index.jspを「/src/main/webapp/index.jsp」へ移動します。

以前、作ったindex.jspを表示できるようにControllerの@RequestMappingに合わせた場所へ移動します。
ponsuke-tarou.hatenablog.com
f:id:ponsuke_tarou:20180618160651p:plain

Tomcatを起動してindex.jspを表示してみます。

ponsuke-tarou.hatenablog.com
f:id:ponsuke_tarou:20180618161841p:plain

index.jspにエコーアプリケーションの入力画面を表示するリクエストを送信するリンクを追加します。

「c: 」は、以前プロジェクトにSpringを設定する中でJSPで使えるように設定しました。

<html>
<body>
    <h2>Hello World!</h2>
    <ul>
        <!--
         JSTL(JSP Standerd Tag Library)の「c:url」を使用して
         {アプリケーションのコンテキストパス} + "/echo"へのリンクを追加しています.
         -->
        <li><a href="<c:url value='/echo' />">エコーアプリケーションへ</a></li>
    </ul>
</body>
</html>
リンクが追加されたことを画面を表示して確認します。

f:id:ponsuke_tarou:20180618163551p:plain

入力画面を作成します。

HTMLのform要素内の入力値を保持するためのフォームクラスを作成します。

package example.app;

import java.io.Serializable;

/**
 * HTMLの<form>要素内で取り扱う入力値を保持するフォームクラス.
 */
public class EchoForm implements Serializable {

    /** serialVersionUID. */
    private static final long serialVersionUID = -3147370534900886671L;

    /** 入力値を保持するプロパティ定義. */
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

Controllerを作成して表示リスクエストをハンドリングするためのメソッドを実装します。

package example.app;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 入力画面のController.
 * RequestMappingアノテーションで指定する"echo"により"/echo"というパスのリクエストがこのControllerにマッピングされます.
 */
@Controller
@RequestMapping("echo")
public class EchoController {
    /**
     * 表示リスクエストをハンドリングするためのメソッド.
     * RequestMappingアノテーションでRequestMethod.GETを指定することで"GET /echo"というリクエストがこのメソッドにマッピングされます.
     * @param model
     * @return 入力画面を表示するJSPのView名.
     */
    @RequestMapping(method = RequestMethod.GET)
    public String viewInput(Model model) {
        // フォームオブジェクトを生成してModelに追加します。
        EchoForm form = new EchoForm();
        // 属性名を省略しているため、クラス名の"echoForm"という属性名で追加されます。
        // Modelに追加したオブジェクトは、HttpServletRequestにエクスポートされる仕組みとなっているため
        // JSPからは、リクエストスコープのオブジェクトとして参照できます。
        model.addAttribute(form);
        return "echo/input";
    }
}

Controllerのメソッドの返却値"echo/input"に合わせて「/WEB-INF/echo/input.jsp」で入力画面のViewを作成します。

<html>
<body>
    <h2>入力画面</h2>
    <!--
     Spring MVCから提供されている「form:form」要素を使用して、HTMLのフォームを作成すします.
     modelAttribute属性にフォームオブジェクトの属性名を指定します.
     「form:form」要素にはmethod/action属性が指定でき、省略すると
     method属性は"post"、action属性は画面表示時URLのアプリケーションのコンテキストパス以降の値 となります.
     ここのaction属性は、"{App名}/echo"となります.
     -->
    <form:form modelAttribute="echoForm">
        <div>テキストを入力してください :</div>
        <div>
            <!--
             Spring MVCから提供されている「form:input」要素を使用して、テキストフィールドを作成します.
             path属性に指定したechoForm(modelAttribute属性で指定)のプロパティが保持する値が初期値として表示されます.
             -->
            <form:input path="text" />
        </div>
        <div>
            <!-- Spring MVCから提供されている「form:button」要素を使用して、HTMLフォームの送信ボタンを作成します。 -->
            <form:button>送信</form:button>
        </div>
    </form:form>
</body>
</html>
トップ画面のリンクを押下して入力画面を表示してみます。

f:id:ponsuke_tarou:20180618173629p:plain

入力画面の入力値を出力画面に表示する処理を作成します。

入力値送信リクエストをハンドリングするためのメソッドをController(EchoController.java)に追加します。

    /**
     * 入力画面の送信リクエストをハンドリンクするためのメソッド.
     * RequestMappingアノテーションでRequestMethod.POSTを指定することで"POST /echo"というリクエストがこのメソッドにマッピングされます.
     * @param form 引数にフォームクラスを指定することでリクエストパラメータの値(入力値)をフォームオブジェクトに格納して受け取れます.
     *        また、フォームオブジェクトはModelにも自動的に追加される仕組みとなっているため、明示的にModelに追加する必要はありません.
     * @return 出力画面を表示するJSPのView名.
     */
    @RequestMapping(method = RequestMethod.POST)
    public String echo(EchoForm form) {
        return "echo/output";
    }

Controllerのメソッドの返却値"echo/output"に合わせて「/WEB-INF/echo/output.jsp」で出力画面のViewを作成します。

<html>
<body>
    <h2>出力画面</h2>
    <div>入力したテキストは・・・</div>
    <div>
        <!--
         JSTL(JSP Standerd Tag Library)の「c:out」を使用してフォームオブジェクト(echoForm)のプロパティ(text)値をHTMLに出力します.
         「c:out」を使用することで、XSS(クロスサイトスクリプティング)攻撃で使用される特殊な文字を単なる文字としてHTMLに出力できます.
         --><span><c:out value="${echoForm.text}" /></span></div>
    <div>です。</div>
    <br>
    <div>
        <!-- トップ画面を表示するリクエスト(GET /)を送信するリンクです. -->
        <a href="<c:url value='/' />">トップ画面へ戻る</a>
    </div>
</body>
</html>
出力画面を表示してみます。

f:id:ponsuke_tarou:20180618180909p:plainf:id:ponsuke_tarou:20180618180917p:plain

Bean Validationを使用した入力チェックを作成します。

Spring MVCでは、Bean Validationの仕組みを利用してフォームオブジェクトのプロパティに入力チェックルールを指定します。

フォームオブジェクト(EchoForm.java)にBean Validationの制約アノテーションを追加します。

Hibernate Validationは、前回pom.xmlで設定しました。

    /**
     * 入力値を保持するプロパティ定義.
     * Hibernate Validationが提供するNotEmptyアノテーションを付加することで入力必須チェックを行います.
     * Bean Validationが提供するSizeアノテーションを付加することで最大文字数のチェックを行います.
     */
    @NotEmpty
    @Size(max = 10)
    private String text;
Springのプロパティでは未入力時にデフォルトで空文字が設定されるため、必須チェックは @NotNull ではなく @NotEmpty を使用します。

Spring以外のプロパティ値に対しては Bean Validation が提供する @java.validation.constraints.NotNull で必須チェックが行えます。

Controllerの送信リクエストをハンドリンクするためのメソッド(EchoController#echo)でSpring MVCの入力チェック機能を有効化してエラーのハンドリング処理を追加します。

    /**
     * 入力画面の送信リクエストをハンドリンクするためのメソッド.
     * RequestMappingアノテーションでRequestMethod.POSTを指定することで"POST /echo"というリクエストがこのメソッドにマッピングされます.
     * @param form 引数にフォームクラスを指定することでリクエストパラメータの値(入力値)をフォームオブジェクトに格納して受け取れます.
     *        また、フォームオブジェクトはModelにも自動的に追加される仕組みとなっているため、明示的にModelに追加する必要はありません.
     *        <<入力チェック>>
     *        パラメータのフォームオブジェクトに Validアノテーションを付与することで、入力チェックを実施してその結果を BindingResult に格納できます.
     * @param result BindingResultは入力チェックするフォームオブジェクトの直後に指定します.
     *        BindingResult もModelに自動的に追加されるため、明示的にModelに追加する必要はありません.
     * @return 出力画面を表示するJSPのView名.
     */
    @RequestMapping(method = RequestMethod.POST)
    public String echo(@Valid EchoForm form, BindingResult result) {
        // BindingResult#hasErrorsを呼び出すことで入力チェックのエラー判定を行います。
        if (result.hasErrors()) {
            // エラーの場合は、入力画面のView名を返却し、入力画面にエラー情報を表示します。
            return "echo/input";
        }
        return "echo/output";
    }

View(input.jsp)にエラー情報を表示するパーツを追加します。

            <form:input path="text" />
            <!--
             Spring MVCが提供する「form:errors」要素を使用して、入力チェックのエラー情報を表示します.
             path属性に指定されたプロパティのエラー情報が表示されます。
             -->
            <form:errors path="text" />
        </div>
エラーになったときの入力画面を表示してみます。

f:id:ponsuke_tarou:20180618231043p:plainf:id:ponsuke_tarou:20180618231046p:plainf:id:ponsuke_tarou:20180618231050p:plainf:id:ponsuke_tarou:20180618231059p:plain

この本を読みながらやりました

www.shoeisha.co.jp