前回の要点
- http://start.spring.ioでプロジェクトを作成する。
- 処理の流れ
- テンプレートとコントローラを作る。
- テンプレート
- HTMLで記述する。ただし単独で現れるタグは後ろに「/」をつける。
- コントローラから送られてきた値を表示するところで、th:text属性を使う。
- コントローラ
- クラスに@Controllerアノテーションをつける。
- クラスとメソッドにつける@RequestMappingアノテーションで担当するURLを指定する。
- メソッドの返り値で利用するテンプレートを指定する。
- テンプレートに値を送り込みたい場合は、メソッドにModelMap型の引数を加え、そのaddAttributeメソッドで名前と値を指定する。
- その他
- ポート番号を変える: resourcesにあるapplication.propertiesに「server.port = 18080」などと記述する。
ドキュメント
Formの作成と表示
おみくじアプリを作ってみよう。
処理のシーケンスは次のようになる。

名前を入力する(フォームの利用)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>おみくじ</title> </head> <body> <form action="omikuji_output" method="post"> 名前を入力してください <input name="name" /><br/> <button type="submit">おみくじを引く</button> </form> </body> </html> |
- formタグ: どこからどこまでがフォームかを表す。action属性でどこに送るか指定する。method属性でどのような形で送るかを指定する。
- inputタグ: name属性で区別のための名前をつける。この例ではその名前にnameとつけて紛らわしいので注意すること。
- buttonタグ: type属性をsubmitとすることで、formの送信ボタンにすることができる。
コントローラ
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package net.teachingprogramming.webapp; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; /** * 第4回で使うコントローラ */ @Controller @RequestMapping("/lecture04") public class Lecture04Controller { /** * おみくじ: 名前の入力 */ @RequestMapping("/omikuji_input") public String omikujiInput() { return "lecture04/omikuji_input"; } /** * おみくじ: 結果の出力 */ @RequestMapping("/omikuji_output") public String omikujiOutput(ModelMap modelMap, @RequestParam("name") String name) { String result = "吉"; if (Math.random() < 0.5) { result = "大吉"; } modelMap.addAttribute("result", result); modelMap.addAttribute("name", name); return "lecture04/omikuji_output"; } } |
- 18〜21行目:「/lecture04/omikuji_input」にアクセスがあると、「lecture04/omikuji_input」がブラウザに送られる。
- 26〜34行目:「/lecture04/omikuji_output」にアクセスがあると、「lecture04/omikuji_output」がブラウザに送られる。
- 27行目:「フォームから送られてくるパラメータを受け取るための引数」を指定する為に@RequestParamアノテーションをつける。
- 28〜31行目: String型の変数を乱数によって「吉」か「大吉」にする。
- 32行目: 「result」という名前で変数resultをテンプレートに送る。
- 32行目: 「name」という名前で変数nameをテンプレートに送る。
結果の表示
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>おみくじ</title> </head> <body> <p> <span th:text="${name}">nameの値</span>さんの今日の運勢は<span th:text="${result}">resultの値</span>です。 </p> </body> </html> |
- コントローラからは「name」と「result」という名前で値が送られてきている。それぞれ、th:text属性で表示する。
例1: 掲示板
テンプレート
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>掲示板</title> </head> <body> <ul> <li th:each="comment:${commentList}"> <th:block th:text="${comment}">コメント</th:block> </li> <!-- 上とほぼ同じ <li th:each="comment:${commentList}" th:text="${comment}">コメント</li> --> </ul> <hr /> <form method="post"> <input name="comment" /> <button type="submit">書き込む</button> </form> </body> </html> |
- 最初の表示(get)とコメントを書き込む時(post)の両方でこのテンプレートを使う。
- formのaction属性は省略すると、同じURLにアクセスすることになる。
- リストから一つづつ取り出すのは、th:each属性を使う。コロンの左側でつけた名前でアクセスできる(スコープは、属性をつけた要素の内側)。注意しなければならないのは、繰り返し出力されるのは、th:each属性がついた要素(タグ)だということ。例えば、commentListに3つの文字列が入っていたとしたら、li要素が3つ出力される。
- タグ無しで値を出力するのはth:blockタグを使う。
コントローラ
|
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
/** * 掲示板: コメントを保存しておくフィールド */ private List<String> commentList = new ArrayList<>(); // private ArrayList<String> commentList = new ArrayList<String>(); // ListとArrayListの関係がよくわからない人向け /** * 掲示板: get */ @GetMapping("bbs") public String bbsGet(ModelMap modelMap) { modelMap.addAttribute("commentList", commentList); return "lecture04/bbs"; } /** * 掲示板: post */ @PostMapping("bbs") public String bbsGet(ModelMap modelMap, @RequestParam("comment") String comment) { commentList.add(comment); modelMap.addAttribute("commentList", commentList); return "lecture04/bbs"; } |
- @RequestMappingはgetとpostの両方で実行されるが、@GetMappingと@PostMappingを使うことで、同じURLでgetとpostの処理を別のメソッドに分けて書くことができる。
- コントローラ全体
例2: じゃんけん
テンプレート
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>じゃんけん</title> </head> <body> <p th:if="${result != null}" th:text="${result}"> 結果がある場合表示する </p> <form method="post"> <input type="radio" name="janken" value="g" checked="checked"/> グー<br /> <input type="radio" name="janken" value="c" /> チョキ<br /> <input type="radio" name="janken" value="p" /> パー<br /> <button type="submit">じゃんけんする</button> </form> </body> </html> |
- 最初の表示(get)とじゃんけんをした時(post)の両方でこのテンプレートを使う。
- th:ifで条件が真(true)の時だけ要素を表示させることができる。ここでは、コントローラからresultが送られてきた時(つまりresultがnullでない)にそれを表示している。
- input要素のtype属性は「radio」。checked=”checked”をつけた要素がデフォルトで選択される。
- name属性は全て同じにする(nameを同じにすると同一グループとなり排他的選択ができる)。
- 選択されたボタンのvalue属性がコントローラに送られる。
コントローラ
|
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/** * じゃんけん: get */ @GetMapping("janken") public String janken() { return "lecture04/janken"; } /** * じゃんけん: post */ @PostMapping("janken") public String janken(ModelMap modelMap, @RequestParam("janken") String janken) { StringBuilder resultBuilder = new StringBuilder(); resultBuilder.append("あなたは"); if (janken.equals("g")) { resultBuilder.append("グー"); } else if (janken.equals("c")) { resultBuilder.append("チョキ"); } else { resultBuilder.append("パー"); } resultBuilder.append("を出して"); double random = Math.random(); if (random < 0.333) { resultBuilder.append("勝ちました。"); } else if (random < 0.666) { resultBuilder.append("負けました。"); } else { resultBuilder.append("引き分けました。"); } modelMap.addAttribute("result", resultBuilder.toString()); return "lecture04/janken"; } |
- getとpostで同じメソッド名となっているが、これをオーバーロードという(教科書P.132)。
- StringBuilderは文字列を繋げる時に使える(教科書P.82)。
- 律儀にコンピュータの手を決定して結果を出力してもいいが、ここでは選択した手に関わらずランダムで結果を出力している。
- コントローラ全体
例3: アンケート
テンプレート
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>チェックボックス</title> </head> <body> <p> 好きなプログラミング言語はどれですか? </p> <form method="get"> Java <input type="checkbox" name="java" /><br /> Kotlin <input type="checkbox" name="kotlin" /><br /> Scala <input type="checkbox" name="scala" /><br /> <button type="submit">送信</button> </form> <p th:if="${result != null}" th:text="${result}"> チェックボックスを送信した結果。 </p> </body> </html> |
- チェックボックスはname属性で区別する。
コントローラ
|
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
/** * アンケート */ @RequestMapping("questionnaire") public String questionnaire(ModelMap modelMap, @RequestParam(value = "java", required = false) boolean java, @RequestParam(value = "kotlin", required = false) boolean kotlin, @RequestParam(value = "scala", required = false) boolean scala) { StringBuilder resultBuilder = new StringBuilder(); if (java) { resultBuilder.append("Javaがチェックされました。"); } if (kotlin) { resultBuilder.append("Kotlinがチェックされました。"); } if (scala) { resultBuilder.append("Scalaがチェックされました。"); } modelMap.addAttribute("result", resultBuilder.toString()); return "lecture04/questionnaire"; } |
- チェックボックスは、チェックをしたときにしかパラメータが送信されない。そのため、デフォルトの@RequestParamではエラーになる。
- パラメータが送信されなくてもエラーにならないようにするには、「required = false」とする。
- チェックされているときはtrue、チェックされてない時(パラメータが無い時)は、falseになる。
- コントローラ全体