プログラマーの調べ物

プログラマーが調べ物をするときに役に立つサイトを作ります。

Spring BootでThymeleafを使ってViewを実装してみる。

ThymeleafはWebアプリケーションと親和性の高いテンプレートエンジンです。 テンプレートエンジンとは、雛形となるドキュメントに対し、可変データを埋め込むことで動的にドキュメントを生成する仕組みのことです。

Themeleafを使ってViewを作ってみます。

pom.xmlは以下のように書きます。

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

コントローラーは以下のように書きます。

src/main/java/com/example/EchoController.java

package com.example;

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

import com.example.form.EchoForm;

@Controller
@RequestMapping("echo")
public class EchoController {

    @RequestMapping(method = RequestMethod.GET)
    public String viewInput(Model model) {
        EchoForm form = new EchoForm();
        model.addAttribute(form);
        return "echo/input";
    }
    
    @RequestMapping(method = RequestMethod.POST)
    public String echo(EchoForm form) {
        return "echo/output";
    }
}

フォームクラスを作成します。

src/main/java/com/example/form/EchoForm.java

package com.example.form;

import java.io.Serializable;

public class EchoForm implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String text;

    public String getText() {
        return text;
    }

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

次にViewの部分です。

src/main/resources/templates/echo/input.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h2>Echo Application</h2>
<form action="./output.html" th:action="@{/echo}"
  th:object="${echoForm}" method="POST">
  <div>Input Text</div>
  <div>
    <input type="text" name="text" th:field="*{text}"/><br/>
    <span th:if="${#fields.hasErrors('text')}"
        th:errors="*{text}">error message</span>
  </div>  
  <div>
    <button type="submit">Submit</button>
  </div>
</form>
</body>
</html>

src/main/resources/templates/echo/output.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
      
<body>
    <h2>出力画面</h2>
    <div>入力したテキストは...</div>
    <div><span th:text="*{echoForm.text}">ここに入力した値が表示される</span></div>
    <br/>
    <div>です</div>
    <div>
        <a href="../index.html" th:href="@{/}">トップ画面に戻る</a>
    </div>
</body>
      
</html>

テキストの出力

式の構文

名称 意味
変数式 ${echoForm.text} Thymeleafが管理する変数へアクセスしたり、メソッドを実行できる。プロパティ名を指定することで、フォームオブジェクトなどのModelに格納された情報にアクセスできる。
選択変数式 *{echoForm.text} 特定のオブジェクトに対するプロパティに連続してアクセスしたい時、th:object="${echoForm}"などと組み合わせて使う。
メッセージ式 #{status.reserved.message} メッセージをkey-valueで管理するための仕組み
リンクURL式 @{/echo} 指定したURLへのリンクを貼ることができる

Spring Bootでフォームアプリケーションを作成する

Spring Bootでフォームアプリケーションを作ります。

テキストボックスに値を入力

それをコントローラーで受け取って、モデルオブジェクトに突っ込む

モデルオブジェクトの内容を別のHTMLに表示する

というありがちな流れを作ってみます。

まずは、フォームの情報を格納するbeanを作成します。

こいつにフォームで入力した情報をぶち込みます。 src/main/java/com/example/form/Search.java

package com.example.form;

public class Search {
    private String userName;
    private String tagName;
    private String location;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getTagName() {
        return tagName;
    }
    public void setTagName(String tagName) {
        this.tagName = tagName;
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
    
    
}

次に、フォームを作りましょう。

src/main/resource/templates/search.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Search Form</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>Form</h1>
    <form action="#" th:action="@{/search}" th:object="${search}" method="post">
        <p>User Name: <input type="text" th:field="*{userName}" /></p>
        <p>Tag Name: <input type="text" th:field="*{tagName}" /></p>
        <p>Location: <input type="text" th:field="*{location}" /></p>
        <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
    </form>
</body>
</html>

これが送信フォームです。 Submitボタン(送信ボタン)を押すと、リクエストが投げられます。

では、そのリクエストを処理するコントローラーを作りましょう。

src/main/java/com/example/SearchController.java

package com.example;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.form.Search;

@Controller
public class SearchController {

    @GetMapping("/search")
    public String searchForm(Model model) {
        model.addAttribute("search", new Search());
        return "search";
    }
    
    @PostMapping("/search")
    public String searchSubmit(@ModelAttribute Search search) {
        return "result";
    }
}

これで飛ばされたリクエストを処理することができます。 最後に、結果を表示するHTMLです。

src/main/resource/templates/result.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title>Result</title>
</head>
<body>
<h1>Result</h1>
    <p th:text="'user name: ' + ${search.userName}" />
    <p th:text="'tag name: ' + ${search.tagName}" />
    <p th:text="'location: ' + ${search.location}" />
    <a href="/search">another search</a>
</body>
</html>

これで、送信した内容を表示することができます。

https://spring.io/guides/gs/handling-form-submission/

Spring Bootでフォームを送って結果を返す

とりあえずって感じですが、formタグで囲まれた情報をJava側に送りつけて、その結果をHTMLで返すサンプルです。

まずは、HTTP GETで情報を送信するHTMLです。

account.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title>SAMPLE</title>
</head>
<body>
<form action="/result">
  <fieldset>
    <input type="text" name="name" />
    <input type="submit" value="Subscribe me!" />
  </fieldset>
</form>
</body>
</html>

これを受け取るJavaを書きます。

package com.example;

import java.util.ArrayList;
import java.util.List;

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

@Controller
public class RestaurantController {
    
    @RequestMapping("/account")
    public String account(Model model) {
        return "account";
    }
    
    @RequestMapping(value = "/result", method = RequestMethod.GET)
    public String form(Model model,@RequestParam String name) {
        model.addAttribute("name", name);
        return "result";
    }
    
}

結果を表示するHTMLです。

result.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title>結果</title>
</head>
<body>
結果:
<span th:text="${name}"></span>
</body>
</html>

「結果: test」とブラウザに表示されます。

とりあえずExpressを動かしてみる。

Node.jsのフレームワーク「Express」を動かしてみます。

package.jsonには以下のように記述します。

{
  "name" : "MEAN",
    "version" : "0.0.1",
    "dependencies" : {
        "express" : "latest",
        "glup" : "latest"
  }
}

で、server.jsを書きます。

var express = require('express');


var hasName = function(req, res, next) {
    if (req.param('name')) {
        next();
    } else {
        res.send('What is your name?');
    }
};

var sayHello = function(req, res, next) {
    res.send('Hello ' + req.param('name'));
};

//create new Express application object
var app = express();

app.get('/', hasName, sayHello);

//user() method to mount a middleware funtion with a specific path
/*
app.use('/', function(req, res) {
   res.send('Hello World');
});
*/

app.listen(3000);
console.log('Server running at http://localhost:3000');

module.exports = app;

これをnode serverで実行します。

NPMでGlobalモードでインストールしたパッケージはどこにインストールされるのか?

NPMには2つのインストールモードがあります。 ローカルモードとグローバルモードです。

Unixベースのシステムの場合、/usr/local/lib/node_modules/にインストールされます。 Windowsの場合、C:¥Users¥%USERNAME%¥AppData¥Roaming¥npm¥node_modules にインストールされます。

何か不安があるときは、とりあえずローカルモードでインストールするのがいいと思います。

npmでパッケージをインストールするときは、以下のコマンドを使います。

npm install express

バージョンを指定するときは、

npm install express@2.2

のようにコマンドを打ちます。

その他に、

npm uninstall

や、

npm update

コマンドがあります。

複数のパッケージを管理するには、package.jsonを使うのが一般的です。

アプリケーションのルートディレクトリに置きます。

こんな感じで書いておけば、npm installで依存ファイルをまとめてインストールできます。

{
  "name" : "MEAN",
  "version" : "0.0.1",
  "dependencies" : {
    "express" : "latest",
    "grunt" : "latest"
  }
}

npm init で作成するのが一般的です。

npmで手動インストールした情報をpackage.jsonに自動追加したいときは、

npm install <package> --save

としてください。

Macで8080番ポートでLISTENしているプロセスをkillするコマンド

以下のコマンドで、8080番ポートでLISTENしているプロセスをkillすることができます。

$ kill $(lsof -t -i:8080)

http://stackoverflow.com/questions/11583562/how-to-kill-a-process-running-on-particular-port-in-linux/11596144

Spring Bootで画面遷移型アプリケーションを作成する

Spring Bootを使えば画面遷移型のアプリケーションも簡単に作ることができます。

テンプレートエンジンとして、次のライブラリがサポートされています。

  • Thymeleaf
  • FreeMarker
  • Groovy templates
  • Velocity
  • Mustache

JSPの利用はさまざまな制約があるため、推奨されていないようです。

Spring Bootで画面遷移型アプリケーション

pom.xmlに以下の依存モジュールを追加します。

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

次に、src/main/javaに以下のクラスを配置します。

RestaurantController.java

package com.example;

import java.util.ArrayList;
import java.util.List;

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

import con.example.tw.RestaurantBean;

@Controller
public class RestaurantController {
    final List<RestaurantBean> restaurantList = new ArrayList<RestaurantBean>();

    
    public List<RestaurantBean> getRestaurants() {
        RestaurantBean bean = new RestaurantBean();
        bean.setTagName("sampleTag");
        bean.setTabelogUrl("https://www.google.com");
        bean.setUserName("takashi");
        bean.setTweet("this is nice restaurant!");
        restaurantList.add(bean);
        return restaurantList;
    }
    
    @RequestMapping("/info")
    public String info(Model model) {
        model.addAttribute("title", "おいしいレストラン情報");
        model.addAttribute("info", "This is Restaurant Infomation");
        return "info";
    }
    
    
}

TemplateResolverがビュー名につけるプレフィックスとサフィックスのデフォルト値はそれぞれ"classpath:/templates/"と".html"になるため、 /src/main/resources/templates/info.htmlを配置します。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title th:text="${title}"></title>
</head>
<body>
<p>
<span th:text="${info}">Hello!</span>
</p>
</body>
</html>

これで、localhost:8080/info にアクセスすると、

「This is Restaurant Infomation」

と表示されます。