Spring Framework勉強メモ 2 - FreeMarkerでViewを作成

<img width="239" alt="スクリーンショット 2016-02-07 17.42.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/b8613d1b-321f-f850-68df-4a39ff47fc93.png">

# はじめに
前回は、Spring Bootを用いて、MySQLのデータベースから読み込んだデータを返すRESTful APIを作成しました。

http://qiita.com/yokobonbon/items/064504bc9dca3f0ec7d1

今回は、Web APIではなく、Viewを作成してみます。JavaのViewと言えばJSPが定番ですが、Spring BootではJarへの組み込みのサーブレットを使用する関係上、機能が制限されるためJSPの使用は避けるべきとReferenceに記述されています。

使用できるテンプレートは以下に紹介されています。
http://docs.spring.io/spring-boot/docs/1.2.2.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-template-engines

今回はFreeMarkerを用いて、基本的なViewの作成、ModelデータのViewへの受け渡しといったことを行います。

FreeMarker http://freemarker.incubator.apache.org/

# 基本的な構成
ディレクトリ構成

<img width="372" alt="スクリーンショット 2016-02-07 16.57.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/1e206b44-aff3-c511-da58-e21e65439511.png">

build.gradleに必要なライブラリを追加します。今回はデータベースにアクセスしないのでシンプルに以下の二つだけです。

```java
....

jar {
    baseName = 'spring-web-sample'
    version =  '0.1.0'
}
....

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.springframework.boot:spring-boot-starter-freemarker")
}
```

# Model, Serviceの作成
今回作成するサンプルアプリケーションは、メッセージの入力をフォームから行い、そのリストを表示するというシンプルなものです。まず、メッセージを保持するモデルクラスを作成します。

Message.java

```java
public class Message {
    @NotEmpty
    private String message = "";

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
```
次にメッセージを格納取得するためのサービスを作成します。サービスの実装は、Spring FrameworkらしくDependency Injectionを用いたいのでBean化します。@Serviceアノテーションがそれにあたります。@Serviceは@Component同様、@Autowireアノテーションで変数に割り当てることが可能です。（後で使用します）

MessageService.java

```java
public interface MessageService {
    void addMessage(String message);

    List<Message> getMessages();
}
```

MessageServiceImpl.java

```java
@Service
public class MessageServiceImpl implements MessageService {
    private List<Message> messages;

    public MessageServiceImpl() {
        messages = new ArrayList<Message>();
    }

    @Override
    public void addMessage(String message) {
        Message messageObj = new Message();
        messageObj.setMessage(message);
        messages.add(messageObj);
    }

    @Override
    public List<Message> getMessages() {
        return messages;
    }
}
```

# ControllerおよびViewの作成
Viewを作成するControllerは前回の記事で使用した@RestControllerではなく@Controllerを用います。@ControllerでViewを返す方法はいくつかの方法があります。ここでは、シンプルにページの名前を返します。("index")

```java
@Controller
public class IndexController {
    @Autowired
    private MessageService servie;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String showTopPage() {
        return "index";
    }
}
```
次にViewのテンプレートを作成します。FreeMarkerは本家のページでも記述されているようにテンプレート + Javaのコードからのデータの挿入でHTMLファイルを作成します。テンプレートファイルの置き場所をapplication.propertiesに記述します

```java
spring.freemarker.template-loader-path=/WEB-INF/templates
```

この画面ではフォームを使ってメッセージを入力するだけなので、FreeMarker的な記述はほとんど入っていません。message変数にユーザが入力したメッセージが挿入されてController側にPOSTで渡ります。

index.ftl

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Hello Spring</title>
    </head>
    <body>
        <form role="form" action="" method="post">
            <div>
                <label for="message">message</label>
    	        <input type="message" name="message" id="message" required autofocus/>
            </div>
            <button type="submit">submit</button>
        </form>
    </body>
</html>
```
先ほど作成した、IndexControllerにフォームからのメッセージを受信する部分を作成します。@MdelAttributeを用いて、フォームからの入力メッセージをMessageクラスのオブジェクトとして受け取ることができます。受け取ったメッセージは、@Autowiredで取得したMessageServiceを通して保存します。"redirec:messages"でmessageビューに遷移をします。

```java
@Controller
public class IndexController {
    @Autowired
    private MessageService servie;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String showTopPage() {
        return "index";
    }
    @RequestMapping(method=RequestMethod.POST)
    public String handleMessage(@Valid @ModelAttribute("form") Message message) {
        servie.addMessage(message.getMessage());
        return "redirect:messages";
    }
}
```
messageビューは、今までのメッセージのリストを表示します。<#list messages as message>という記述でmessagesオブジェクトをfor文のように順にmessageオブジェクトとして扱うことができます。

message.ftl

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Messages</title>
    </head>
    <body>
        <hr>
        <#list messages as message>
            ${message.message}
            <hr>
        </#list>
        <a href="/">Back to Home</a>
    </body>
</html>
```
messageビューにmessagesオブジェクトを渡すコントローラーは以下のようになります。ModelAndViewというクラスを返すことで、ビューページ名の指定と引き渡すJavaのオブジェクト（モデル）指定することができます。

```java
@Controller
@RequestMapping("/messages")
public class MessageController {
    @Autowired
    private MessageService service;

    @RequestMapping(method= RequestMethod.GET)
    public ModelAndView showMessagesPage() {
        return new ModelAndView("messages", "messages", service.getMessages());
    }
}
```
最後にApplicationクラス作成します。これは特に通常と変わりません。

```java
@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
```

#動作確認
ビルド、および実行は以下のGradleで以下のように行います

```bash
$ ./gradlew build
$ java -jar build/libs/spring-web-sample-0.1.0.jar
```

http://localhost:8080
にアクセスすると以下のような画面が見れます

<img width="239" alt="スクリーンショット 2016-02-07 17.42.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/bfc33237-2fd6-5fa5-7b12-d85ad41ae0d1.png">

メッセージを入力して、Submitボタンを押すとhttp://locahost:8080/messages
に移動します

<img width="220" alt="スクリーンショット 2016-02-07 17.42.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/46ab0e6c-b3b8-80df-082d-0ad3ba3ca924.png">

http://locahost:8080/messages
<img width="154" alt="スクリーンショット 2016-02-07 17.42.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/57312623-9528-9fc2-81be-61166f3cbf0e.png">

"Back to Home"を押して、再度メッセージを追加するとどんどんリストに表示されます。
<img width="162" alt="スクリーンショット 2016-02-07 17.42.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/e2424c5e-3c45-b909-312e-0472a3641ddd.png">

もちろんデータベースなどを用いて永続化しているわけではないので、起動しなおすとメッセージは全て消えます。