Spring BootのウェブアプリケーションのControllerクラスのメモ。
|
Spring BootのウェブアプリケーションのControllerは、画面遷移の制御を行う。
import org.springframework.stereotype.Controller;
クライアント(ブラウザー)から要求されたURI(パス)に対する処理を記述するのがControllerクラス。
パスと処理(メソッド)の対応付けはControllerクラスに@RequestMappingアノテーションを付けることで行う。(対応付けを行うファイルを別途用意する必要は無い)
処理を行うメソッドは、次の処理(htmlの表示とか)を示すパスを返す。
「http://ホスト名:8080/
」(パスが「/」)のリクエストに対してindex.htmlを返す例。
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class IndexController { @RequestMapping("/") public String index() { return "index"; } }
Controllerクラスには@Controllerアノテーションを付ける。
どのパスの処理を行うかについては@RequestMappingアノテーションで指定する。
メソッド名は自由に付けてよい。
パラメーターを受け取りたい場合は引数を追加する。
戻り値は「次の処理」を示すパスを返す。
「index」を返した場合、「index.html」が表示される。
htmlで表示する値を渡したい場合は、メソッドの引数にModelを追加し、Modelに対して値をセットする。
自分が処理するURI(パス)を指定するのが@RequestMappingアノテーション。
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMappingアノテーションはクラスとメソッドに付けられる。
「http://ホスト名:8080/hoge/zzz
」のリクエストを処理する場合は以下のような書き方が出来る。
@RequestMapping("/hoge") @Controller public class HogeController { @RequestMapping("zzz") public String zzz() { return "zzz"; } } |
@RequestMapping("/hoge/zzz") @Controller public class HogeController { @RequestMapping public String zzz() { return "zzz"; } } |
@Controller public class HogeController { @RequestMapping("/hoge/zzz") public String zzz() { return "zzz"; } } |
引数名 | 説明 | 例 |
---|---|---|
path | 受け付けるパス 複数のパスを記述することも出来る。 *を使う事も出来る。 |
@RequestMapping(path = "/hoge") |
value | 受け付けるパス(pathの別名) | @RequestMapping("/hoge") |
method | 受け付けるHTTPメソッド | @RequestMapping(path = "/hoge",
method = RequestMethod.GET) |
Controllerでリクエストを処理するメソッドでパラメーターを取得したい場合は、メソッドの引数を追加する。
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Input Thymeleaf</title> </head> <body> <h1>Input Thymeleaf</h1> <form action="#" th:action="@{/input}" method="post"> <p><input name="param1" type="text" /></p> <p><input name="param2" type="text" /></p> <p><input type="submit" value="submit"/></p> </form> </body> </html>
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class InputController { @RequestMapping(path = "/input") public String submit(@ModelAttribute("param1") String param1, @ModelAttribute("param2") String param2) { return "input"; } }
HTMLのformのinputの値を受け取る場合は、引数に@ModelAttributeアノテーションを付ける。
→HTTPリクエストのパラメーターを取得したい場合は@RequestParamアノテーションを付ける
HTMLのformの内容を表すJavaBeanを作れば、引数はそれ1つで済む。
public class InputForm { private String param1; private String param2; 〜setter, gettter〜 }
@Controller public class InputController { @RequestMapping(path = "/input") public String submit(@ModelAttribute InputForm form) { String param1 = form.getParam1(); String param2 = form.getParam2(); return "input"; } }
Controllerでリクエストを処理するメソッドの戻り値は、「次の処理(のパス)」を示す。
例えば"index"を返すと、「index.htmlを表示する」ことになる。
参考: tag1216さんのSpring MVCのコントローラでの戻り値いろいろ
遷移方法 | 説明 | 例 |
---|---|---|
htmlの表示 | htmlを表示する。"hoge/foo" は、src/main/resources/templates/hoge/foo.htmlを指す。 |
return "index"; |
フォワード | 次の処理(Controller)へフォワードする。→フォワードのデータ渡し | return "forward:/login"; |
リダイレクト | 次のURLへリダイレクトする。→リダイレクトのデータ渡し | return "redirect:/login"; |
フォワードとリダイレクトの違いは、Struts1の時代から変わっていないw
リダイレクトは、クライアント(ブラウザー)にリダイレクト先のURLを返す。クライアントは改めてそのURLをリクエストする。つまりリクエストが別になる。
フォワードは、別のControllerに処理を渡す。クライアント(ブラウザー)からのリクエストとしてはそのまま継続となる。
htmlへ値を渡す場合は、Modelを使用する。
メソッドの引数でModelを定義しておき、そのModelに対して値をセットする。
import org.springframework.ui.Model;
@Controller public class IndexController { @RequestMapping("/") public String index(Model model) { model.addAttribute("message", "hello IndexController"); return "index"; } }
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>index Thymeleaf</title> </head> <body> <h1>index Thymeleaf</h1> <p th:text="${message}">hello</p> </body> </html>
フォワード先へデータを渡したい場合は、Modelにデータを追加し、HTTPリクエストのattributeから取得する。[2017-11-01]
import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping(path = "/examplef1") public String first(Model model) { model.addAttribute("test", "from1"); return "forward:/examplef2"; }
HttpServletRequestを使う方法
import javax.servlet.http.HttpServletRequest;
@RequestMapping(path = "/examplef2") public String second(HttpServletRequest request, Model model) { String test = (String) request.getAttribute("test"); model.addAttribute("message", test); return "index"; }
RequestAttributeを使う方法[2017-11-03]
import java.util.Optional; import org.springframework.web.bind.annotation.RequestAttribute;
@RequestMapping(path = "/examplef2") public String second(@RequestAttribute("test") Optional<String> test, Model model) { test.ifPresent(s -> model.addAttribute("message", s)); return "index"; }
フォワードはクライアント(ブラウザー)からのリクエスト内の一連の処理なので、フォワード前に作ったデータ(インスタンス)がそのままフォワード先に渡される。
リダイレクト先へデータを渡したい場合は、RedirectAttributesにデータを追加し、Modelから取得する。[2017-11-01]
@RequestMapping(path = "/exampler1") public String first(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("test", "from1"); return "redirect:/exampler2"; }
@RequestMapping(path = "/exampler2") public String second(Model model) { String test = (String) model.asMap().get("test"); model.addAttribute("message", test); return "index"; }
RedirectAttributesに追加されたデータはリダイレクト先のModelに入ってくる。
なので、上記の例では「test」という名前で保存してリダイレクト先で「message」というデータとして保存し直しているが、
RedirectAttributesに「message」という名前で保存しておけば、リダイレクト先でModelに詰め直す必要は無い。
リダイレクトは、一旦クライアント(ブラウザー)に制御を戻し、指定したURLに改めてアクセスさせる。
このため、RedirectAttributesを使った実際のデータの受け渡しは、HTTPセッションを介して行うようになっているらしい。
Springのアノテーションは、引数のvalueが他の引数の別名(alias)(名前は違うけど同じ機能)になっているものがある。
これは、Javaのアノテーションの仕様によるものだと思われる。
Javaのアノテーションは、引数名がvalueのときは、代入の「value =」を省略できるルールになっている。
例えば、@RequestMappingアノテーションはvalueの別名がpathになっている。
これにより、「@RequestMapping(path = "/hoge")
」と「@RequestMapping(value
= "/hoge")
」は同じ意味になるが、valueに対しては「@RequestMapping("/hoge")
」と省略して書くことが出来る。
逆に言えば、「@RequestMapping("/hoge")
」と書けるようにする為にわざわざvalueを定義してあるのだろう。
したがって、「value =」が明示的に出てくる書き方は本来の使い方ではないと思われる。