読者です 読者をやめる 読者になる 読者になる

M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

「Getting Started - フォーム送信を処理する」を読む

Java Spring

引き続きSpring Bootについて調べて回っていて、今回はフォームから送信されたデータを処理する方法について書かれた公式ガイドを見てみます。

このドキュメントは、いわゆる"form-backed object"とか"command object"と呼ばれるオブジェクト──FORM要素の子孫要素であるINPUT要素やSELECT要素などの入力フィールドの値を、みずからのインスタンス・フィールドに格納するオブジェクト──と@ModelAttributeアノテーションを使用して、フォームに入力されたデータを処理する方法を簡潔に示しています。

原典は、"Getting Started - Handling Form Submission"です(2014/11/25現在)。

          * * *

フォーム送信を処理する

このガイドではSpringを使ってWebフォームを作成し送信する処理を見ていきます。

何をつくるのか

このガイドのなかで、あなたはWebフォームをつくります。フォームのページには次のURLでアクセスします:

http://localhost:8080/greeting

このページをブラウザで表示するとフォームが表示されます。idcontentの入力欄に値を設定してあいさつ文を送信できます。フォームからの送信がなされると、結果ページが表示されます。

何をする必要があるか

  • だいたい15分くらいの時間
  • お好きなテキスト・エディタもしくはIDE
  • JDK のバージョン1.6もしくはそれ以降
  • Gradle 1.11以降 もしくは Maven 3.0以降
  • 今見ているこのページからSpring Tool Suite(STS)に直接コードをインポートして、そこから作業を開始することもできます。

どうすればこのガイドは完了できるか

Springの「Getting Startedガイド」系ドキュメントのご多分に漏れず、このガイドも一からコードを書いてステップごとに完了していくことも、すでに理解している基本的な準備のステップを端折って進むこともできます。

一からはじめる方は「Gradleでビルドする」〔訳注:あるいはその後続のセクション〕に進んでください。

基本をスキップする方は次のステップを踏んでください:

  • このガイドのソースコードリポジトリからZipファイルをダウンロードして解凍するか、Gitコマンドでクローンを行います:git clone https://github.com/spring-guides/gs-handling-form-submission.git
  • cdコマンドでgs-handling-form-submission/initialに移動します
  • 「Webコントローラをつくる」のセクションに移動します

作業が終わったらgs-handling-form-submission/completeのコードと比較することで結果をチェックすることができます。.

Gradleでビルドする

(・・・興味がないので中略・・・)

Mavenでビルドする

まず基本的なビルド・スクリプトを準備します。Springでアプリケーションを構築するにあたり、あなたは好みのビルド・システムを使用できます。しかしここで示すコードはMavenでビルドする必要があります。もしMavenについてあまり詳しくないのであれば、「MavenでJavaプロジェクトをビルドする」を参照してみてください。

ディレクトリ構造をつくる

プロジェクトのディレクトリとしてあなたの選んだ場所で、次のサブディレクトリ構造をつくります。例えばUnix/Linux環境であればmkdir -p src/main/java/hello というコマンドを実行します:

└── src
    └── main
        └── java
            └── hello

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-handling-form-submission</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.1.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>hello.Application</start-class>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>

Spring Boot Mavenプラグインは多くの便利な機能を提供しています:

  • クラスパス上のすべてのjarファイルを1つのjarにビルドします。この実行可能な「含み込みのjar」〔"über-jar"。英語的に言えば”over jar”。開発者自身が作成したコードのみならず、そのコードが依存するjarの内容を内包したjarで、それ単体で実行が可能。〕はあなたが開発したアプリケーションの実行と移動をより容易にしてくれます。
  • 実行可能クラスの目印としてpublic static void main()メソッドを検索します。
  • 組み込みの依存性解決メカニズムにより、Spring Bootの依存するライブラリのバージョンを設定します。いずれのバージョンもあなた自身で設定することもできますが、デフォルトではSpring Bootが選択したバージョンが利用されます。
Spring Tool Suiteでビルドする

(・・・興味がないので中略・・・)

Webコントローラをつくる

SpringがWebサイトを構築するアプローチにおいて、HTTPリクエストを処理するのはコントローラの役目です。このコンポーネント@Controllerアノテーションにより簡単に識別されます。下記のGreetingControllerは/greetingというパスへのGETリクエストを処理して、ビュー〔View〕の名前──ここでは「greeting」を返します。ビューはHTMLコンテンツをレンダリングする役目を持つコンポーネントです:

src/main/java/hello/GreetingController.java

package hello;

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

@Controller
public class GreetingController {

    @RequestMapping(value="/greeting", method=RequestMethod.GET)
    public String greetingForm(Model model) {
        model.addAttribute("greeting", new Greeting());
        return "greeting";
    }

    @RequestMapping(value="/greeting", method=RequestMethod.POST)
    public String greetingSubmit(@ModelAttribute Greeting greeting, Model model) {
        model.addAttribute("greeting", greeting);
        return "result";
    }

}

このコントローラは簡潔でシンプルですが、多くのことをしています。1つずつ見て行きましょう。
@RequestMappingアノテーションは、HTTPリクエストを特定のコントローラのメソッドに結びつけるものです。このコントローラのなかで宣言されている2つのメソッドはいずれも、/greetingというパスに結び付けられています。デフォルトでは@RequestMappingはGETやPOSTその他のあらゆるHTTP操作をパスの一致したメソッドに結びつけます。しかし上記のコードでは、 greetingForm()メソッド@RequestMapping(method=GET)という指定によって、とくに GETに結び付けられています。対して greetingSubmit()メソッド @RequestMapping(method=POST) という指定によって、とくにPOSTに結び付けられています。このマッピング指定により、コントローラは/greeting というエンドポイントへのリクエストを分別できるようになるのです。

greetingForm()メソッドは新しいGreetingインスタンスをビュー・テンプレートに呈示するために、Modelオブジェクトを使用しています。次のコードでは、Greetingオブジェクトにidcontentといったフィールドが宣言されていますが、これらはgreetingビューのなかのフォームの入力欄に対応しています。そしてこのオブジェクトはフォームから情報を取得するのに使用されます。

src/main/java/hello/Greeting.java

package hello;

public class Greeting {

    private long id;
    private String content;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

}

メソッドの中側のコードの実装はビュー・テクノロジー次第で変わります。今回のケースではサーバ側でHTMLをレンダリングするのにThymeleafが使用されています。Thymeleafは下記のgreeting.htmlテンプレートをパースし、フォームをレンダリングするために種々のテンプレート式を評価します。

src/main/resources/templates/greeting.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Getting Started: Handing Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Form</h1>
    <form action="#" th:action="@{/greeting}" th:object="${greeting}" method="post">
    	<p>Id: <input type="text" th:field="*{id}" /></p>
        <p>Message: <input type="text" th:field="*{content}" /></p>
        <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
    </form>
</body>
</html>

th:action="@{/greeting}"という記述はフォームがデータを送信する向き先を /greetingというエンドポイントに設定します。一方、 th:object="${greeting}"という記述はフォーム・データをまとめて保持しているモデル・オブジェクトを宣言します。2つのフォームの入力欄には、 th:field="*{id}"th:field="*{content}"という記述があり、このそれぞれが上述のGreeting オブジェクトのフィールドに対応しています。

これでフォームを表示するためのコントローラ、モデル、そしてビューを説明し終えました。さて、それでは送信されたフォームの情報を処理するところを見て行きましょう。先に述べたとおり、フォームはPOSTメソッドを用いて/greetingエンドポイントにデータを送信します。 greetingSubmit()メソッドは、フォームに入力された内容をもとに初期化された Greetingオブジェクトを受け取ります。そして送信されたデータをresultビュー(後述)で画面に表示できるよう、 Greetingオブジェクトをモデルに追加します。id<p th:text="'id: ' + ${greeting.id}" />という記述のなかで使用されています。同様に、content<p th:text="'content: ' + ${greeting.content}" />という記述のなかで使用されています。

src/main/resources/templates/result.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Getting Started: Handing Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Result</h1>
    <p th:text="'id: ' + ${greeting.id}" />
    <p th:text="'content: ' + ${greeting.content}" />
    <a href="/greeting">Submit another message</a>
</body>
</html>

この例では明瞭さのため、フォームの画面表示と送信されたデータの表示とに2つの異なるビュー・テンプレートを使用しました。しかし2つの目的のために1つのビューを使用することもできます。

実行可能ファイルをつくる

アプリケーションを独立したアプリケーション・サーバにデプロイするために、伝統的なwarファイルとしてパッケージすることはもちろん可能なのですが、より簡単なアプローチは以下で示すようにスタンドアローンのアプリケーションをつくってしまうというものです。あなたはすべてを1つの、実行可能jarファイル──懐かしのmain()メソッドにより駆動する──のなかにパッケージ化することができるのです。外部の〔独立した〕サーブレット・コンテナにデプロイする代わりにこの方法をとることで、HTTPランタイムとしての組み込みのTomcatサーブレット・コンテナに対するSpringフレームワークの支援機能が利用できます。

src/main/java/hello/Application.java

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

main()メソッドは、SpringApplication ヘルパー・クラスのrun()メソッドの引数として、 Application.classを渡して処理を委譲します。このコードは、Springに対して「Applivationからアノテーションメタデータを読み取り、それをコンポーネントとして、Springアプリケーション・コンテキストのなかで管理しなさい」と述べていることになります。

@ComponentScanアノテーションはSpringに対して「helloパッケージとそのサブパッケージのなかを検索し、直接もしくは間接にSpringの@Componentアノテーションにより印付けされているクラスを見つけ出せ」という指示になります。このディレクティブはSpringが GreetingControllerを見つけて〔Springのアプリケーション・コンテキストに〕登録するよう仕向けます。なぜならこのクラスには@Controllerアノテーションが付与されており、このアノテーションには @Componentアノテーションが付与されているからです。

@EnableAutoConfiguration アノテーションは、クラスパス上に存在するクラス情報に基づき、適切なデフォルトの動作を行うようスイッチを入れます。例えば、アプリケーションが組み込みバージョンのTomcattomcat-embed-core.jar)に依存しているので、Tomcatサーバはあなた自身が設定の手間を労せずとも、適切なデフォルトの設定と構成で起動されます。あるいはまた、アプリケーションがSpring MVC(spring-webmvc.jar)に依存しているので、Spring MVCのDispatcherServlet があなたのために設定され登録されます──もはや web.xmlは不要なのです! 自動コンフィギュレーションはパワフルで柔軟性に富むメカニズムです。より詳しい情報についてはJavadocを参照してください。

実行可能jarファイルをつくる

Gradleを使っている場合(・・・興味が無いので中略・・・)

Mavenを使っている場合、 mvn spring-boot:runコマンドでアプリケーションを実行することができます。あるいはまた mvn clean packageコマンドでjarファイルをつくり、続いて次のようにタイプしてjarを実行します:

java -jar target/gs-handling-form-submission-0.1.0.jar


[NOTE] 上記の手順では実行可能jarファイルが作成されます。Springはwarファイルをビルドする方法も提供しています。


ログ出力が画面に現れ、コンポーネントが組み立てられて数秒のうちにアプリケーションが起動します。

サービスをテストする

さあ、もうWebサイトは動いています。http://localhost:8080/greetingにアクセスしてみましょう。次のような入力フォームが表示されるはずです:

f:id:m12i:20141126231712p:plain

IDとメッセージを送信すると結果が表示されます:

f:id:m12i:20141126231722p:plain

まとめ

おめでとうございます! Springを使ってフォームを作成し送信するプログラムができあがりました。

          * * *

原典は、"Getting Started - Handling Form Submission"です(2014/11/25現在)。


Spring関連の訳出記事まとめ - M12i.