Memo

メモ > 技術 > フレームワーク: SpringBoot > プログラムの整理

■プログラムの整理
■EntityのGetter/Setterを自動作成 【Spring Boot】Lombokの導入 https://b1san-blog.com/post/spring/spring-lombok/ SpringBootのプロジェクトにlombok導入する - Qiita https://qiita.com/kihara-takahiro/items/f616d01be6bf7384dbfc pom.xml
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
src/main/java/com/example/demo/entity/Task.java
package com.example.demo.entity; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Table; import jakarta.persistence.Id; import lombok.Data; @Entity @Table(name="tasks") @Data public class Task { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String title; private String text; }
lombok.Dataを使用すると、初回実行時に「アノテーションを有効にするか」を確認されるみたい ■フォームからの値取得とバリデーション pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
src/main/java/com/example/demo/request/TaskRequest.java
package com.example.demo.request; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Size; import lombok.Data; import java.io.Serializable; @Data public class TaskRequest implements Serializable { @NotEmpty(message = "タイトルを入力してください。") @Size(max = 80, message = "タイトルは80文字以内で入力してください。") private String title; @NotEmpty(message = "テキストを入力してください。") @Size(max = 80, message = "テキストは80文字以内で入力してください。") private String text; }
src/main/java/com/example/demo/service/TaskService.java
public void create(TaskRequest taskRequest) { Task task = new Task(); task.setId(null); task.setTitle(taskRequest.getTitle()); task.setText(taskRequest.getText()); taskRepository.save(task); }
src/main/java/com/example/demo/controller/TaskController.java
@GetMapping(value = "/task/add") String add(Model model) { model.addAttribute("taskRequest", new Task()); return "task/add"; } @PostMapping(value = "/task/create") String create(@Validated @ModelAttribute TaskRequest taskRequest, BindingResult result) { if (result.hasErrors()) { return "task/add"; } taskService.create(taskRequest); return "redirect:/task/"; }
src/main/resources/templates/task/add.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Spring Boot</title> </head> <body> <h1>Spring Boot</h1> <p>タスクを登録します。</p> <form th:action="@{/task/create}" th:object="${taskRequest}" method="post"> <dl> <dt>タイトル</dt> <dd><input type="text" th:field="*{title}"><div th:if="${#fields.hasErrors('title')}" th:errors="*{title}" class="error">Title Error</div></dd> <dt>テキスト</dt> <dd><input type="text" th:field="*{text}"><div th:if="${#fields.hasErrors('text')}" th:errors="*{text}" class="error">Text Error</div></dd> </dl> <p><input type="submit" value="登録"></p> </form> </body> </html>
「@{}」はURLパスを生成するもの 上の場合は「action="/task/create"」としても同じだが、パラメータを埋め込む場合はシンプルに書くことができる 「th:object」は、その要素内で使用するオブジェクトを設定できる このオブジェクトからは「*{プロパティ名}」で値を取得できる ここでは「*{title}」は「taskRequest.getTitle()」と解釈される 「#fields.hasErrors('プロパティ名')」でエラーの有無をチェックできる 「th:errors」はエラーメッセージを取得する。「*{プロパティ名}」の形式で、どのプロパティに対するエラーメッセージなのかを指定できる http://localhost:8080/task/add にアクセスすると、タスクの登録画面が表示される http://localhost:8080/task/ にアクセスすると、タスクが一覧表示される バリデーションは「登録画面用」「編集画面用」など画面ごとに用意する方がいいかと思ったが、 以下によるとバリデーションのグループ化によって「登録時だけ実行するバリデーション」といった制御ができるみたい 【Spring Boot】バリデーション https://b1san-blog.com/post/spring/spring-validation/ ■共通レイアウトの作成 pom.xml
<dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> </dependency>
src/main/resources/templates/layout/frontend.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title>Demo</title> </head> <body> <header th:fragment="header"> <h1>Demo</h1> </header> <th:block layout:fragment="content"></th:block> <footer th:fragment="footer"> <p><small>This is demo site.</small></p> </footer> </body> </html>
src/main/resources/templates/home/index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/frontend}"> <head> <title>Demo</title> </head> <body> <th:block layout:fragment="content"> <main> <p>ホーム。</p> </main> </th:block> </body> </html>
src/main/resources/templates/home/now.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/frontend}"> <head> <title>現在時刻 | Demo</title> </head> <body> <th:block layout:fragment="content"> <main> <p>現在時刻は<span th:text="${time}"></span>です。</p> </main> </th:block> </body> </html>
src/main/resources/templates/task/index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/frontend}"> <head> <title>タスク | Demo</title> </head> <body> <th:block layout:fragment="content"> <main> <p>タスクは以下のとおりです。</p> <table> <tr> <th>ID</th> <th>タイトル</th> <th>テキスト</th> </tr> <tr th:each="task : ${tasks}"> <td th:text="${task.id}"></td> <td th:text="${task.title}"></td> <td th:text="${task.text}"></td> </tr> </table> </main> </th:block> </body> </html>
src/main/resources/templates/task/add.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/frontend}"> <head> <title>タスク登録 | Demo</title> </head> <body> <th:block layout:fragment="content"> <main> <p>タスクを登録します。</p> <form th:action="@{/task/create}" th:object="${taskRequest}" method="post"> <dl> <dt>タイトル</dt> <dd><input type="text" th:field="*{title}"><div th:if="${#fields.hasErrors('title')}" th:errors="*{title}" class="error">Title Error</div></dd> <dt>テキスト</dt> <dd><input type="text" th:field="*{text}"><div th:if="${#fields.hasErrors('text')}" th:errors="*{text}" class="error">Text Error</div></dd> </dl> <p><input type="submit" value="登録"></p> </form> </main> </th:block> </body> </html>
共通レイアウトの詳細は、後述の「テンプレート(Thymeleaf)」を参照

Advertisement