Spring Web Flux + Thymeleaf で画面出力する
過去に同じことやろうとしてダメだったので、リベンジ。
Spring Web Flux + Thymeleaf で画面出力したかった
内容に間違いなどがあれば指摘をお願いします。
やりたいこと
前回と同じく、SpringWebFlux
と Thymeleaf
で GetWild する。
ルーティングはアノテーションベースと、RouterFunctionsの2パターンで実施。
結論
先に結論を書くと、
- RouterFunctionsの場合には、
ServerResponse.BodyBuilder#render
メソッドに、表示するビュー名を渡す。- 表示に必要なデータは、
render
メソッドの第二引数に指定する。
- 表示に必要なデータは、
- アノテーションベースの場合にはメソッドの戻り値を
Mono<String>
にして、ビュー名をMono
でラップする。- 表示に必要なデータは、
SpringWebMvc
の時と同じようにModel
等に設定する。
- 表示に必要なデータは、
です。
環境
準備
Spring Inisyaraizaで雛形を作成し、 MavenプロジェクトとしてIDE等にインポートしてください。
- Spring Boot:2.0.0(SNAPSHOT)
- Dependencies
- Reactive Web
- Thymeleaf
- Project Metadata
- Group:任意(デフォルトの
com.example
でOK) - Artifact:任意(
webflux-thymeleaf-demo
とか)
- Group:任意(デフォルトの
pom.xml
以下のような pom.xml
が定義されていると思います。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>webflux-thymeleaf-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>webflux-thymeleaf-demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.BUILD-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
ルーティング定義
アノテーションベース(@GetMapping
、@PostMapping
)と、RouterFunctions
の2パターンでルーティング定義を行います。
RouterFunctions
RouterFunctionsで画面出力を行う場合には、ServerResponse.BodyBuilder#render
メソッドを用いればいいようです。
render
メソッドの第一引数にはビュー名、第二引数には画面出力に必要なデータを渡します。
今回の場合、ビュー名は hello
で、画面に出力するタイトルと現在日時を渡しています。
@Component public class HelloHandler { /** ルーティング定義 */ public RouterFunction<ServerResponse> routes(){ return RouterFunctions.route(RequestPredicates.GET("/get"), this::get); } /** /get へアクセスした場合の処理 */ public Mono<ServerResponse> get(final ServerRequest request) { Map<String, Object> attributes = new HashMap<>(); attributes.put("title", "Get Wild!!"); attributes.put("now", LocalDateTime.now()); return ServerResponse.ok().contentType(MediaType.TEXT_HTML).render("hello", attributes); } }
このままではルーティング定義が反映されないので、RouterFunction
をコンテナに登録します。
@SpringBootApplication public class WebfluxThymeleafDemoApplication { public static void main(String[] args) { SpringApplication.run(WebfluxThymeleafDemoApplication.class, args); } @Bean RouterFunction<ServerResponse> routes(HelloHandler handler) { return handler.routes(); } }
アノテーションベース
アノテーションベースで画面出力する場合は、SpringWebMvc
とほぼ同じでした。
SpringWebMvc
の場合、メソッドの戻り値は String
でしたが SpringWebFlux
では、Mono<String>
となります。
表示させたいビュー名(文字列)を、Mono
でラップして返却するだけです。
返却するビュー名と、他のデータは RouterFunctions で定義したものと同様です。
@Controller public class HelloController { @GetMapping(path = "/wild") public Mono<String> wild(final Model model){ model.addAttribute("title", "Get Wild!!"); model.addAttribute("now", LocalDateTime.now()); return Mono.just("hello"); // ビュー名を設定する。 } }
テンプレート
今回は src/main/resources/template/
配下に hello.html
を作成しました。
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"/> <title>Get Wild</title> </head> <body> <h1 th:utext="${title}">タイトル</h1> <p th:utext="${now}">現在日時</p> <form th:action="@{/get}" method="get"> <input type="submit" value="get" /> </form> <form th:action="@{/wild}" method="get"> <input type="submit" value="wild" /> </form> </body> </html>
起動してアクセスしてみる
@SpringBootApplication
が注釈されたクラスを実行して、localhost:8080/get
または localhost:8080/wild
にアクセスして画面表示されていれば成功です。