目次
はじめに
Javaの人気フレームワーク「Spring Boot」と「Spring Boot」と相性の良いテンプレートエンジン「Thymeleaf」を使用して編集画面を作成し、編集画面から更新処理を行う方法を紹介します。
本記事で作成する「ユーザー情報編集」画面のイメージは以下のとおり。
「保存」または「キャンセル」ボタン押下で「ユーザー情報詳細」画面に戻るようにします。
入力項目
項目 | チェック内容 |
名前 | 必須、100桁以内 |
住所 | 255桁以内 |
電話番号 | 必須、電話番号形式 |
スポンサーリンク
各イベント処理
「キャンセル」リンク押下:詳細画面へ戻る
「保存」ボタン押下時:下記の挙動とする
- 入力チェックOK:データを更新し詳細画面へ遷移
- 入力チェックNG:ユーザー編集画面の画面上部にエラー内容を表示する
詳細画面については「Spring Boot + Thymeleafで詳細画面を作成する」の記事をご覧ください。
テーブル定義
物理名 | 論理名 | データ型 | NOT NULL | 説明 |
id | ID | BIGINT | 〇 | 主キー(AUTO_INCREMENT) |
name | 名前 | VARCHAR(100) | 〇 | ユーザーの名前 |
address | 住所 | VARCHAR(255) | ユーザーの住所 | |
phone | 電話番号 | VARCHAR(50) | ユーザーの電話番号 | |
update_date | 更新日時 | DATETIME | 〇 | 最終更新日時 |
create_date | 作成日時 | DATETIME | 〇 | 登録日時 |
delete_date | 削除日時 | DATETIME | 論理削除した日時 |
ディレクトリ構成
ディレクトリ構成は次のとおり。
springSample | |___src.main.java | |___com.example.demo | | | |___controller | | | | | |__UserController.java | | | |___entity | | | | | |___User.java | | | |___dto | | | | | |___UserRequest.java | | | | | |___UserUpdateRequest.java | | | |___repository | | | | | |___UserRepository.java | | | |___service | | | |___UserService.java | |___src.main.resources | |___templates | | | |___common | | | | | |___head.html | | | |___user | | | |___add.html | | | |___edit.html | | | |___list.html | | | |___view.html | |___application.properties
バックエンド(サーバー)側のソースコード
コントローラークラス(UserController.java)
コントローラクラスの内容は以下のとおり。
package com.example.demo.controller; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.example.demo.dto.UserUpdateRequest; import com.example.demo.entity.User; import com.example.demo.service.UserService; /** * ユーザー情報 Controller */ @Controller public class UserController { /** * ユーザー情報 Service */ @Autowired private UserService userService; /** * ユーザー情報一覧画面を表示 * @param model Model * @return ユーザー情報一覧画面 */ @GetMapping(value = "/user/list") public String displayList(Model model) { List<User> userlist = userService.searchAll(); model.addAttribute("userlist", userlist); return "user/list"; } /** * ユーザー新規登録画面を表示 * @param model Model * @return ユーザー情報一覧画面 */ @GetMapping(value = "/user/add") public String displayAdd(Model model) { return "user/add"; } /** * ユーザー情報詳細画面を表示 * @param id 表示するユーザーID * @param model Model * @return ユーザー情報詳細画面 */ @GetMapping("/user/{id}") public String displayView(@PathVariable Long id, Model model) { User user = userService.findById(id); model.addAttribute("userData", user); return "user/view"; } /** * ユーザー編集画面を表示 * @param id 表示するユーザーID * @param model Model * @return ユーザー編集画面 */ @GetMapping("/user/{id}/edit") public String displayEdit(@PathVariable Long id, Model model) { User user = userService.findById(id); UserUpdateRequest userUpdateRequest = new UserUpdateRequest(); userUpdateRequest.setId(user.getId()); userUpdateRequest.setName(user.getName()); userUpdateRequest.setPhone(user.getPhone()); userUpdateRequest.setAddress(user.getAddress()); model.addAttribute("userUpdateRequest", userUpdateRequest); return "user/edit"; } /** * ユーザー更新 * @param userRequest リクエストデータ * @param model Model * @return ユーザー情報詳細画面 */ @RequestMapping(value = "/user/update", method = RequestMethod.POST) public String update(@Validated @ModelAttribute UserUpdateRequest userUpdateRequest, BindingResult result, Model model) { if (result.hasErrors()) { List<String> errorList = new ArrayList<String>(); for (ObjectError error : result.getAllErrors()) { errorList.add(error.getDefaultMessage()); } model.addAttribute("validationError", errorList); return "user/edit"; } // ユーザー情報の更新 userService.update(userUpdateRequest); return String.format("redirect:/user/%d", userUpdateRequest.getId()); } }
ユーザー編集画面の初期表示は「displayEdit」メソッドでおこなっています。処理の流れは下記のとおり
処理の流れ
- リクエストデータ(HTTP GET)から表示対象のIDを取得
- データベースからIDをキーにデータを抽出
- 抽出したデータを「User」クラスに設定する
- ユーザー編集画面を表示する
ユーザーデータの更新は「update」メソッドでおこなっています。処理の流れは下記のとおり
処理の流れ
- リクエストデータの入力チェックをおこなう
- 入力チェックNGの場合は、エラーメッセージを設定しユーザー編集画面へ
- 入力チェックOKの場合は、入力データの内容をデータベースに反映する
- ユーザー詳細画面へ遷移する
スポンサーリンク
サービスクラス(UserService.java)
データベース接続はJPA、トランザクション管理は「@Transactional」のアノテーションを使用、「@Transactional」を使う事で「create」メソッドの登録に成功すればコミット、失敗してExceptionが発生すればロールバックを自動でおこなってくれます。
package com.example.demo.service; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.example.demo.dto.UserUpdateRequest; import com.example.demo.entity.User; import com.example.demo.repository.UserRepository; /** * ユーザー情報 Service */ @Service @Transactional(rollbackFor = Exception.class) public class UserService { /** * ユーザー情報 Repository */ @Autowired private UserRepository userRepository; /** * ユーザー情報 全検索 * @return 検索結果 */ public List<User> searchAll() { return userRepository.findAll(); } /** * ユーザー情報 主キー検索 * @return 検索結果 */ public User findById(Long id) { return userRepository.findById(id).get(); } /** * ユーザー情報 更新 * @param user ユーザー情報 */ public void update(UserUpdateRequest userUpdateRequest) { User user = findById(userUpdateRequest.getId()); user.setAddress(userUpdateRequest.getAddress()); user.setName(userUpdateRequest.getName()); user.setPhone(userUpdateRequest.getPhone()); user.setUpdateDate(new Date()); userRepository.save(user); } }
エンティティクラス(User.java)
データベースから取得したデータを格納するエンティティクラスの内容は以下のとおり。「@Data」アノテーションを使用して「getter」「setter」の定義を省略しています。
package com.example.demo.entity; import java.io.Serializable; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.Data; /** * ユーザー情報 Entity */ @Entity @Data @Table(name = "user") public class User implements Serializable { /** * ID */ @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 名前 */ @Column(name = "name") private String name; /** * 住所 */ @Column(name = "address") private String address; /** * 電話番号 */ @Column(name = "phone") private String phone; /** * 更新日時 */ @Column(name = "update_date") private Date updateDate; /** * 登録日時 */ @Column(name = "create_date") private Date createDate; /** * 削除日時 */ @Column(name = "delete_date") private Date deleteDate; }
リポジトリクラス(UserRepository.java)
データベースにアクセスする為のリポジトリクラスの内容は以下の通り。
package com.example.demo.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.example.demo.entity.User; /** * ユーザー情報 Repository */ @Repository public interface UserRepository extends JpaRepository<User, Long> {}
Data Transfer Object(UserRequest.java)
ユーザー編集画面からのリクエストデータを格納するオブジェクトクラスは以下のとおり。
ユーザー編集画面はユーザー新規登録と項目がほぼ同じため(ユーザーIDが追加されるだけ)、「UserUpdateRequest」クラスは「UserRequest」クラスを継承して作成しています。
ユーザー新規登録の作成手順はこちら
入力チェックは「Bean Validation」を使用しています。「@NotEmpty」や「@Size」などを定義することで入力チェックを実装することができます。
package com.example.demo.dto; import java.io.Serializable; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import lombok.Data; /** * ユーザー情報 リクエストデータ */ @Data public class UserRequest implements Serializable { /** * 名前 */ @NotEmpty(message = "名前を入力してください") @Size(max = 100, message = "名前は100桁以内で入力してください") private String name; /** * 住所 */ @Size(max = 255, message = "住所は255桁以内で入力してください") private String address; /** * 電話番号 */ @Pattern(regexp = "0\\d{1,4}-\\d{1,4}-\\d{4}", message = "電話番号の形式で入力してください") private String phone; }
package com.example.demo.dto; import java.io.Serializable; import javax.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; /** * ユーザー情報更新リクエストデータ * */ @Data @EqualsAndHashCode(callSuper=false) public class UserUpdateRequest extends UserRequest implements Serializable { /** * ユーザーID */ @NotNull private Long id; }
Bean ValidationはSpring Bootのバージョンが2.3.1以降の場合、依存関係に「spring-boot-starter-validation」の追加が必要です。
gradleの場合は「build.gradle」に以下を追加。
dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' }
mavenの場合は「pom.xml」に以下を追加。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
スポンサーリンク
フロントエンド(クライアント)側のソースコード
HTML(edit.html)
共通ヘッダ(head.html)、ユーザー情報一覧画面(list.html)のHTMLは一覧画面作成の記事、ユーザー情報詳細画面(view.html)のHTMLはユーザー情報詳細画面作成の記事で紹介していますので、そちらの記事をご覧ください。
一覧と詳細画面のHTMLはこちら
ユーザー編集画面のHTMLは以下のとおり。※デザインは「Bootstrap」を使用しています。
入力チェックエラーが発生した場合は、画面上部にエラー内容を出力しています。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head th:replace="common/head :: head_fragment(title = 'ユーザー情報編集', scripts = ~{::script}, links = ~{::link})"></head> <body> <div class="container"> <div th:if="${validationError}" th:each="error : ${validationError}"> <label class="text-danger" th:text="${error}"></label> </div> <h1>ユーザー情報編集</h1> <form th:action="@{/user/update}" th:object="${userUpdateRequest}" th:method="post"> <input type="hidden" th:field="*{id}" /> <div> <div class="row mx-md-n5"> <div class="col-2 pt-3 border bg-light">名前<span class="text-danger">※</span></div> <div class="col py-2 border"> <input type="text" class="form-control" th:field="*{name}"> </div> </div> <div class="row mx-md-n5"> <div class="col-2 pt-3 border bg-light">住所</div> <div class="col py-2 border"> <input type="text" class="form-control" th:field="*{address}"> </div> </div> <div class="row mx-md-n5"> <div class="col-2 pt-3 border bg-light">電話番号<span class="text-danger">※</span></div> <div class="col py-2 border"> <input type="text" class="form-control" th:field="*{phone}"> </div> </div> </div> <br /> <div class="text-center"> <input type="submit" class="btn btn-primary" value=" 保存 "> <a th:href="@{/user/{id}(id=*{id})}" class="btn btn-secondary">キャンセル</a> </div> </form> </div> </body> </html>
動作確認
Spring Bootプロジェクトを実行して http://localhost:8080/user/list へアクセスします。
ユーザー情報一覧画面が表示されるので、一覧から対象ユーザーの「詳細」ボタンを押下。
ユーザー詳細画面が表示されるので「編集」ボタンを押下、ユーザー情報編集画面が表示され、ユーザー情報が編集できればOKです。