Contents
削除画面のサンプル
画面デモ
このサンプルコードで、次のような画面を作成します。
削除するだけの簡易な画面になります。
ディレクトリ構成
project-root/src ├── main │ ├── java │ │ └── com │ │ └── springhack │ │ └── okozukaisystem │ │ ├── OkozukaiSystemApplication.java │ │ ├── business │ │ │ └── ChildrenService.java │ │ ├── domain │ │ │ └── Child.java │ │ ├── integration │ │ │ ├── entity │ │ │ │ └── ChildrenEntity.java │ │ │ └── mapper │ │ │ └── ChildrenMapper.java │ │ └── presentation │ │ ├── children │ │ │ ├── ChildrenController.java │ │ │ └── ChildrenControllerHelper.java │ └── resources │ ├── com │ │ └── springhack │ │ └── okozukaisystem │ │ └── integration │ │ └── mapper │ │ └── ChildrenMapper.xml │ └── templates │ ├── children │ │ ├── index.html │ │ └── remove.html
テーブル構造
このサンプルでは下記のテーブルを使用します。
child_id | BIGINT |
name | VARCHAR(50) |
birthday | DATE |
削除のコントローラー層
@Controller
public class ChildrenController {
private final ChildrenService childrenService;
public ChildrenController(ChildrenService childrenService) {
this.childrenService = childrenService;
}
@RequestMapping("/children")
public String index(Model model) {
// 子どもリストを取得
List<Child> children = childrenService.getAll();
// 画面表示
model.addAttribute("children", children);
return "children/index";
}
@GetMapping("/children/remove")
public String remove(Long id, Model model) {
// 削除チェック
Child child = childrenService.get(id);
if (Objects.isNull(child)) {
model.addAttribute("message", "選択した子どもが存在しません。");
return "children/index";
}
// 画面遷移
model.addAttribute("child", child);
return "children/remove";
}
@PostMapping("/children/removeFinish")
public String removeFinish(Long childId, Model model, RedirectAttributes redirectAttributes) {
// 削除チェック
Child child = childrenService.get(childId);
if (Objects.isNull(child)) {
model.addAttribute("message", "選択した子どもが存在しません。");
return "children/index";
}
// 削除実行
childrenService.remove(childId);
// 画面遷移
redirectAttributes.addFlashAttribute("message", "子ども削除しました。");
return "redirect:/children";
}
}
削除のサービス層
@Service
public class ChildrenService {
private final ChildrenMapper childrenMapper;
public ChildrenService(ChildrenMapper childrenMapper) {
this.childrenMapper = childrenMapper;
}
/**
* 全件取得する
*/
public List<Child> getAll() {
// DBから取得
List<ChildrenEntity> allChildren = childrenMapper.selectAll();
var children = allChildren
.stream()
.map(child -> new Child(child.getChildId(), child.getName(), child.getBirthday()))
.collect(Collectors.toList());
return children;
}
/**
* 1件取得する
*/
public Child get(Long childId) {
ChildrenEntity childrenEntity = childrenMapper.findById(childId);
if (Objects.isNull(childrenEntity)) {
return null;
}
return new Child(
childrenEntity.getChildId(),
childrenEntity.getName(),
childrenEntity.getBirthday());
}
/**
* 削除する
*/
public void remove(Long childId) {
childrenMapper.delete(childId);
}
}
削除のインテグレーション層
@Mapper
public interface ChildrenMapper {
List<ChildrenEntity> selectAll();
ChildrenEntity findById(Long childId);
void delete(Long childId);
}
DB接続にはMybatisを使用しました。
そのため、@Repositoryではなく@Mapperを付与したインターフェースを作成し、命名は「テーブル名+Mapper」とします。
<mapper namespace="com.springhack.okozukaisystem.integration.mapper.ChildrenMapper">
<select id="selectAll" resultType="com.springhack.okozukaisystem.integration.entity.ChildrenEntity">
SELECT c.child_id, c.name, c.birthday FROM children c
</select>
<select id="findById" resultType="com.springhack.okozukaisystem.integration.entity.ChildrenEntity">
SELECT c.child_id, c.name, c.birthday FROM children c WHERE c.child_id = #{childId}
</select>
<delete id="delete">
DELETE FROM children WHERE child_id = #{childId}
</delete>
</mapper>
Mybatisの場合は、ネイティブSQLを使用しますので、
MapperのselectAllとinsertに対するSQLを定義しておきます。
@AllArgsConstructor
@Data
public class ChildrenEntity {
private Long childId;
private String name;
private LocalDate birthday;
}
Childrenテーブルに対するエンティティを作成します。
MybatisでSELECT結果を自動で格納させるために、@AllArgsConstructorを付与します。
削除で使用するモデル
@AllArgsConstructor
@Getter
public class Child {
/** ID */
private Long childId;
/** 名前 */
private String name;
/** 誕生日 */
private LocalDate birthday;
}
削除画面のビュー
一覧表示画面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
<header></header>
<main>
<h1>子どもマスタ</h1>
<div th:text="${message}"></div>
<table border="1">
<tr>
<th>名前</th>
<th>生年月日</th>
<th>年齢</th>
<th>操作</th>
</tr>
<tr th:each="child: ${children}">
<td th:text="${child.name}"></td>
<td th:text="${child.birthday}"></td>
<td>TODO</td>
<th>
<button th:attr="onclick='location.href=\'/children/edit?id=' + ${child.childId} + '\''">編集</button>
<button th:attr="onclick='location.href=\'/children/remove?id=' + ${child.childId} + '\''">削除</button>
</th>
</tr>
</table>
<a href="/children/register">子どもを登録</a>
</main>
<footer>
<a href="/">トップページ</a>
</footer>
</body>
</html>
削除確認画面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>子どもマスタ|子どものお小遣い帳アプリ</title>
</head>
<body>
<header></header>
<main>
<h1>子どもを削除</h1>
<div>この子どもを削除します。よろしいですか?</div>
<form method="POST" action="/children/removeFinish" th:object="${child}">
<table border="1">
<tr>
<th>名前</th>
<td th:text="*{name}"></td>
</tr>
<tr>
<th>生年月日</th>
<td th:text="*{birthday}"></td>
</tr>
</table>
<input type="hidden" th:field="*{childId}">
<button onclick="location.href='/children';return false;">キャンセル</button>
<input type="submit" value="削除を確定する" />
</form>
</main>
<footer>
<a href="/">トップページ</a>
</footer>
</body>
</html>