S-JIS[2017-08-27/2017-11-03] 変更履歴

Spring Boot Controller

Spring BootのウェブアプリケーションのControllerクラスのメモ。


概要

Spring BootのウェブアプリケーションのControllerは、画面遷移の制御を行う。

import org.springframework.stereotype.Controller;

クライアント(ブラウザー)から要求されたURI(パス)に対する処理を記述するのがControllerクラス。
パスと処理(メソッド)の対応付けはControllerクラスに@RequestMappingアノテーションを付けることで行う。(対応付けを行うファイルを別途用意する必要は無い)
処理を行うメソッドは、次の処理(htmlの表示とか)を示すパスを返す。


http://ホスト名:8080/」(パスが「/」)のリクエストに対してindex.htmlを返す例。

src/main/java/com/example/demo/IndexController.java:

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に対して値をセットする。


RequestMapping

自分が処理する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";
    }
}

RequestMappingの引数
引数名 説明
path 受け付けるパス
複数のパスを記述することも出来る。
*を使う事も出来る。
@RequestMapping(path = "/hoge")
@RequestMapping(path = { "/hoge", "/hage" })
@RequestMapping(path = "/h*")
value 受け付けるパス(pathの別名) @RequestMapping("/hoge")
method 受け付けるHTTPメソッド @RequestMapping(path = "/hoge", method = RequestMethod.GET)
@RequestMapping(path = "/hoge", method = { RequestMethod.GET, RequestMethod.POST })

パラメーターの取得

Controllerでリクエストを処理するメソッドでパラメーターを取得したい場合は、メソッドの引数を追加する。

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

<!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>

src/main/java/com/example/demo/InputController.java:

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つで済む。

src/main/java/com/example/demo/InputForm.java:

public class InputForm {

	private String param1;

	private String param2;

〜setter, gettter〜
}

src/main/java/com/example/demo/InputController.java:

@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に処理を渡す。クライアント(ブラウザー)からのリクエストとしてはそのまま継続となる。


Model

htmlへ値を渡す場合は、Modelを使用する。
メソッドの引数でModelを定義しておき、そのModelに対して値をセットする。

src/main/java/com/example/demo/IndexController.java:

import org.springframework.ui.Model;
@Controller
public class IndexController {

	@RequestMapping("/")
	public String index(Model model) {
		model.addAttribute("message", "hello IndexController");

		return "index";
	}
}

src/main/resources/templates/index.html:

<!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]

src/main/java/com/example/demo/ForwardController.java:

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";
	}

src/main/java/com/example/demo/ForwardController.java:

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]

src/main/java/com/example/demo/RedirectController.java:

	@RequestMapping(path = "/exampler1")
	public String first(RedirectAttributes redirectAttributes) {
		redirectAttributes.addFlashAttribute("test", "from1");

		return "redirect:/exampler2";
	}

src/main/java/com/example/demo/RedirectController.java:

	@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セッションを介して行うようになっているらしい。


アノテーションのvalueについて

Springのアノテーションは、引数のvalue他の引数の別名(alias)(名前は違うけど同じ機能)になっているものがある。

これは、Javaのアノテーションの仕様によるものだと思われる。
Javaのアノテーションは、引数名がvalueのときは、代入の「value =」を省略できるルールになっている。

例えば、@RequestMappingアノテーションはvalueの別名がpathになっている。
これにより、「@RequestMapping(path = "/hoge")」と「@RequestMapping(value = "/hoge")」は同じ意味になるが、valueに対しては「@RequestMapping("/hoge")」と省略して書くことが出来る。
逆に言えば、「@RequestMapping("/hoge")」と書けるようにする為にわざわざvalueを定義してあるのだろう。

したがって、「value =」が明示的に出てくる書き方は本来の使い方ではないと思われる。


Spring Bootへ戻る / Spring Frameworkへ戻る / 技術メモへ戻る
メールの送信先:ひしだま