削除機能を作成していきましょう。
2.設計で検討した一覧機能をおさらい
機能一覧
4.タスクの削除
ユーザーが既存タスクを削除できる機能。物理削除。
画面遷移
一覧画面 → 削除確認画面 → 完了画面(→ 一覧画面)
画面一覧
- 完了画面
- 削除確認画面
画面項目
- 削除確認画面
タイトル 出力
説明 出力
期限 出力 yyyy/mm/dd
ステータス 出力 変更のときのみ
完了 ボタン 削除処理を実行し、完了画面に遷移
もどる ボタン 確認画面に遷移
- 完了画面
完了メッセージ 出力
"The data was successfully deleted."削除したときのみ表示
go to list ボタン 一覧画面に遷移
削除機能は、削除内容を確認して削除を実行します。画面のUIとしては、既存の画面イメージとよく似ているようです。
*
ユーザーからの見られ方を想像してみます。
- ブラウザから一覧画面にアクセス
- 一覧画面が表示される
- タスクの削除ボタンを押下
- 確認画面で内容を確認し、完了ボタンを押下
- 完了画面で削除できたメッセージを確認し、go to listボタンを押下
- 一覧画面で登録済タスクが一覧に表示される
*
URL設計で検討したもので、変更機能で関係があるのは以下のものでしょうか
画面名: タスク削除確認画面
URL: /task/delete
HTTPメソッド: GET
画面名: (リダイレクト先が存在しないため、リダイレクトされないため画面名は不明)
URL: /task/delete
HTTPメソッド: POST
画面名: タスク完了画面
URL: /task/complete
HTTPメソッド: GET
実装方針(箇条書き)
-
Controllerクラス
- HTTPリクエストを受け取り、適切なServiceクラスのメソッドを呼び出す。
- 必要なデータを取得し、ビューに渡して適切なHTMLファイルを返す。
-
Serviceクラス
- ビジネスロジックを実装。
- データの操作や処理を行い、Repositoryクラスを介してデータベースとのやり取りを行う。
- ビジネスロジックをControllerクラスから切り離し、コードの再利用性や保守性を向上。
-
Repositoryクラス
- データベースとのやり取りを担当。
- Mapperクラスを介してSQLクエリを定義し、Repositoryクラスから呼び出す。
-
Mapperクラス
- MyBatisを使用してSQLクエリを実行し、データの永続化や取得、更新、削除などの操作を行う。
実装の流れ
- まずControllerクラスから始めて、リクエストに対する処理を実装。
- 次にServiceクラスでビジネスロジックを実装し、必要なデータの操作を行う。
- Repositoryクラスを実装し、Mapperクラスを呼び出す。
- Mapperクラスを実装し、MyBatisを使用してSQLクエリを実行するメソッドを定義。
- 最後にHTMLファイルを作成し、ThymeleafでHTMLにマージする。
URL設計をベースに削除確認画面~完了画面と画面遷移をしながらタスクを削除する処理を書いていきます。今回は、削除確認画面のhtmlを新設して作成します。完了画面は登録処理、変更処理で使ったものと同じhtmlを使用します。
それでは、Javaの実装を行いましょう。
controllerクラスを書いてみよう
URL設計で検討したURLをもとにcontrollerクラスのメソッドを書いていきましょう。
今回、controllerクラスに追記するメソッドは2つです。削除確認画面を表示するためのメソッドと、削除処理を実行するためのメソッドです。
削除確認画面を表示するためのメソッドはタスクIDをもとにDBから指定のタスク情報を取得し、画面に表示するものです。「タスクIDをもとにDBから指定のタスク情報を取得」処理は、変更処理で書いているので流用しましょう。また、削除処理を実行するメソッドは、タスクIDをもとにタスクをdeleteするものです。こちらもフォームの再送信を防止するために、リダイレクトさせます。
@GetMapping(value = "/task/delete")
public String showDeleteForm(@RequestParam("taskId") int taskId, Model model) {
// タスクIDに基づいてタスクを取得
TaskForm taskForm = taskService.getTask(taskId);
model.addAttribute("taskForm", taskForm);
return "task/deleteConfirm";
}
@PostMapping(value = "/task/delete")
public String deleteTask(@RequestParam("taskId") int taskId, RedirectAttributes redirectAttributes,Model model) {
//保存処理
String completeMessage =taskService.delete(taskId);
//redirect先に値を渡す
redirectAttributes.addFlashAttribute("completeMessage", completeMessage);
return "redirect:/task/complete";
}
serviceクラスを書いてみよう
削除確認画面を表示されるメソッド(タスクIDをもとにタスク情報を取得する)はすでに書いていますので、今回追加するものは、削除処理のメソッドを追加していきます。
まず、taskService.javaにserviceのインターフェースを書きます。
String delete(int taskId);
*
次に実装クラスの記述を行っていきます。トランザクションのアノテーションをつけて、削除処理のメソッドを書いていきます。完了のメッセージもセットします。
@Override
@Transactional
public String delete(int taskId) {
//削除処理
taskRepository.delete(taskId);
//完了メッセージをセット
String completeMessage = Constants.DELETE_COMPLETE;
return completeMessage;
}
repositoryクラスを書いてみよう
repositoryクラスで削除のメソッドを書いていきましょう。
以下のように記載します。
public int delete(int taskId) {
return taskMapper.delete(taskId);
}
mybatisを書いてみよう
ます、mapperのインターフェースを書いていきます。
削除のインターフェースを書いていきましょう。
int delete(int taskId);
次に、mapper.xmlの中にSQLを書いていきます。
<delete id ="delete">
DELETE FROM task where taskId = #{taskId} and deleteFlg = 0;
</delete>
htmlマージをしてみよう
次に、htmlを書いていきましょう。変更機能では、設計より以下のように画面遷移します。
画面遷移
一覧画面 → 削除確認画面 → 完了画面(→ 一覧画面)
まずは、一覧画面を修正します。ボタンに修正を入れます。
deleteボタンの記述は以下のようになっているかと思います。
<td><a class="btn btn-primary" href="/task/delete/1">delete</a></td>
taskIdをクエリとして持たせるようにhrefを書き換えます。
<td><a class="btn btn-primary" th:href="@{/task/delete(taskId=${taskList.taskId})}">delete</a></td>
*
次は、削除確認画面を書いていきましょう。コードはこちらです。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DeleteConfirm</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<body>
<nav class="navbar bg-body-tertiary">
<div class="container-fluid">
<span class="navbar-brand mb-0 h1">Practice</span>
</div>
</nav>
<div class="container">
<h1>Delete Confirm</h1>
<form action="/task/delete" method="post" class="mb-3">
<div class="px-4 pt-3 my-3">
<div class="mb-3">
<label>Title</label>
<p>title</p>
</div>
<div class="mb-3">
<label>Description</label>
<p>description</p>
</div>
<div class="mb-3">
<label>Deadline</label>
<p>Formatted Deadline</p>
</div>
<div class="mb-3">
<label>Status</label>
<p>Status</p>
</div>
</div>
<input type="hidden" name="title">
<input type="hidden" name="description">
<input type="hidden" name="deadline">
<input type="hidden" name="taskId">
<input type="hidden" name="status">
<input type="hidden" name="updatedAt">
<button type="submit" class="btn btn-primary" value="submit">submit</button>
<a type="button" class="btn btn-outline-secondary" href="/task/list">back</a>
</form>
</div>
<footer class="py-3 my-4">
<p class="text-center text-body-secondary">© 2023 Company, Inc</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
</body>
</html>
まず、上記コードで、deleteConfirm.htmlというファイルを作ります。場所は、template>task配下です。index.htmlと同じ階層ですね。
このdeleteConfirm.htmlに対して、行うことは以下の通りです。
- タグにThymeleafの名前空間を追加する。
- タグの th:action 属性と th:object 属性を追加し、action 属性を修正する。
- 各< p>タグの th:text 属性を追加
- 各 タグの th:field 属性を追加
では、書いていきます。
- タグにThymeleafの名前空間を追加する。
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2.< form> タグの th:action 属性と th:object 属性を追加し、action 属性を修正する。
<form th:action="@{/task/delete}" , method="post" th:object="${taskForm}"class="mb-3">
3.各< p> タグの th:text 属性を追加
<p th:text="*{title}">title</p>
<p th:text="*{description}">description</p>
<p th:text="${#temporals.format(taskForm.deadline, 'yyyy/MM/dd HH:mm')}">Formatted Deadline</p>
<p th:text="*{status == 1 ? '未着手' : status == 2 ? '作業中' : '完了'}">Status</p>
4.各< input type="hidden"> タグの th:field 属性を追加
<input type="hidden" name="title" th:field="*{title}">
<input type="hidden" name="description" th:field="*{description}">
<input type="hidden" name="deadline" th:field="*{deadline}">
<input type="hidden" name="taskId" th:field="*{taskId}">
<input type="hidden" name="status" th:field="*{status}">
<input type="hidden" name="updatedAt" th:value="*{updatedAt}">
動作確認
ここまで、一覧画面から削除確認画面、完了画面に遷移し、指定のタスクを削除するコードを書きました。
削除機能で確認すべきポイントは1点です。
1.画面に沿って遷移して、DBに登録されている値が削除されるか
1.について、削除されるかは、ブラウザ上で削除操作をした後に、MySQLworkbenchで以下のSQLを打ってDBに値が入っているかを確認して、チェックします。
select * from tutorialtodoapplication.task;
次の投稿では、戻る処理を実装しています。
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-①イントロダクション-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-②設計-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-③実装方針と環境構築-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-④一覧機能の作成-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-⑤新規登録機能の作成-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-⑥変更機能の作成-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-⑦削除機能の実装-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-⑧戻る機能の実装-
【Java】Spring Bootを使ったToDoアプリケーションを作成しよう-⑨例外処理の実装-
ここまでで書いたコードの全量
コメントも入れています。
controllerクラス
package com.example.demo.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.example.demo.entity.Task;
import com.example.demo.form.TaskForm;
import com.example.demo.service.TaskService;
/**
* Webアプリケーションのタスク関連機能を担当するControllerクラスです。
* タスクの一覧表示、登録、変更などの機能が含まれています。
*
*/
@Controller
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
/**
* タスクの一覧を表示するメソッドです。
*
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "task/index" - タスク一覧表示用のHTMLテンプレートのパス
*/
@RequestMapping(value = "/task/list", method = RequestMethod.GET)
public String showTask(Model model) {
//タスクの一覧を取得
List<Task> taskList = taskService.findAll();
model.addAttribute("taskList", taskList);
return "task/index";
}
/**
* タスクの新規登録画面を表示するメソッドです。
*
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "task/edit" - タスク新規登録画面のHTMLテンプレートのパス
*/
@GetMapping(value = "/task/add")
public String showForm(Model model) {
// タスクフォームを作成
TaskForm taskForm = new TaskForm();
model.addAttribute("taskForm", taskForm);
return "task/edit";
}
/**
* タスクの変更画面を表示するメソッドです。
*
* @param taskId タスクのID
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "task/edit" - タスク変更画面のHTMLテンプレートのパス
*/
@GetMapping(value = "/task/edit")
public String showEditForm(@RequestParam("taskId") int taskId,Model model) {
// タスクIDに基づいてタスクを取得
TaskForm taskForm = taskService.getTask(taskId);
model.addAttribute("taskForm", taskForm);
return "task/edit";
}
/**
* タスクの確認画面を表示するメソッドです。
*
* @param taskForm タスクのフォームデータ
* @param bindingResult バリデーション結果を保持するオブジェクト
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "task/confirm" - タスク確認画面のHTMLテンプレートのパス
*/
@GetMapping(value = "/task/confirm")
public String showConfirmForm(@Validated TaskForm taskForm, BindingResult bindingResult, Model model) {
// バリデーションチェックでエラーがある場合は変更画面に戻る
if (bindingResult.hasErrors()) {
return "task/edit";
}
model.addAttribute("taskForm", taskForm);
return "task/confirm";
}
/**
* タスクを保存するメソッドです。
*
* @param taskForm タスクのフォームデータ
* @param bindingResult バリデーション結果を保持するオブジェクト
* @param redirectAttributes リダイレクト時に属性を渡すためのSpringのRedirectAttributesオブジェクト
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "redirect:/task/complete" - タスク確認画面へのリダイレクト
*/
@PostMapping(value = "/task/save")
public String saveTask(@Validated TaskForm taskForm, BindingResult bindingResult, RedirectAttributes redirectAttributes,Model model) {
//バリデーションチェック
if (bindingResult.hasErrors()) {
// バリデーションエラーがある場合は変更画面に遷移
return "task/edit";
}
//保存処理
String completeMessage =taskService.save(taskForm);
//redirect先に値を渡す
redirectAttributes.addFlashAttribute("completeMessage", completeMessage);
return "redirect:/task/complete";
}
/**
* タスク完了画面を表示するメソッドです。
*
* @return "task/complete" - タスク完了画面のHTMLテンプレートのパス
*/
@GetMapping("/task/complete")
public String showCompletePage() {
return "task/complete";
}
/**
* タスクの削除確認画面を表示するメソッドです。
*
* @param taskForm タスクのフォームデータ
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "task/confirm" - タスク確認画面のHTMLテンプレートのパス
*/
@GetMapping(value = "/task/delete")
public String showDeleteForm(@RequestParam("taskId") int taskId, Model model) {
// タスクIDに基づいてタスクを取得
TaskForm taskForm = taskService.getTask(taskId);
model.addAttribute("taskForm", taskForm);
return "task/deleteConfirm";
}
/**
* タスクを削除するメソッドです。
*
* @param taskForm タスクのフォームデータ
* @param bindingResult バリデーション結果を保持するオブジェクト
* @param redirectAttributes リダイレクト時に属性を渡すためのSpringのRedirectAttributesオブジェクト
* @param model タスク一覧をViewに渡すためのSpringのModelオブジェクト
* @return "redirect:/task/complete" - タスク確認画面へのリダイレクト
*/
@PostMapping(value = "/task/delete")
public String deleteTask(@RequestParam("taskId") int taskId, RedirectAttributes redirectAttributes,Model model) {
//保存処理
String completeMessage =taskService.delete(taskId);
//redirect先に値を渡す
redirectAttributes.addFlashAttribute("completeMessage", completeMessage);
return "redirect:/task/complete";
}
}
serviceクラス
package com.example.demo.service;
import java.util.List;
import com.example.demo.entity.Task;
import com.example.demo.form.TaskForm;
/**
* タスク関連のサービスを提供するインターフェースです。
*/
public interface TaskService {
/**
* すべてのタスクを取得します。
*
* @return タスクのリスト
*/
List<Task> findAll();
/**
* タスクを保存します。
*
* @param taskForm タスクのフォームデータ
* @return 保存完了メッセージ
*/
String save(TaskForm taskForm);
/**
* 指定されたタスクIDに対応するタスクを取得します。
*
* @param taskId タスクID
* @return タスクのフォームデータ
*/
TaskForm getTask(int taskId);
/**
* タスクを削除します。
*
* @param taskForm タスクのフォームデータ
* @return 削除完了メッセージ
*/
String delete(int taskId);
/**
* タスクのフォームデータをタスクエンティティに変換します。
*
* @param taskForm タスクのフォームデータ
* @return タスクエンティティ
*/
Task convertToTask(TaskForm taskForm);
/**
* タスクエンティティをタスクのフォームデータに変換します。
*
* @param task タスクエンティティ
* @return タスクのフォームデータ
*/
TaskForm convertToTaskForm(Task task);
}
package com.example.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.common.Constants;
import com.example.demo.entity.Task;
import com.example.demo.form.TaskForm;
import com.example.demo.repository.TaskRepository;
/**
* タスク関連のビジネスロジックを担当するサービスクラスです。
* タスクの検索、保存、更新などの機能を提供します。
*/
@Service
public class TaskServiceImpl implements TaskService{
@Autowired
TaskRepository taskRepository;
/**
* タスク一覧を取得するメソッドです。
*
* @return List<Task> タスク一覧。
*/
@Override
public List<Task> findAll() {
return taskRepository.findAll();
}
/**
* タスクを保存するメソッドです。
*
* @param task タスクエンティティ
* @return String 完了メッセージ
* @throws OptimisticLockingFailureException 楽観ロックエラーが発生した場合
*/
@Override
@Transactional
public String save(TaskForm taskForm) {
//変換処理
Task task = convertToTask(taskForm);
//完了メッセージを宣言
String completeMessage = null;
if(task.getTaskId() != 0) {
//変更処理の場合
//楽観ロック
int updateCount =taskRepository.update(task);
if (updateCount == 0) {
throw new OptimisticLockingFailureException("楽観ロックエラー");
}
//完了メッセージをセット
completeMessage = Constants.EDIT_COMPLETE;
return completeMessage;
}else {
//登録処理の場合
taskRepository.save(task);
//完了メッセージをセット
completeMessage = Constants.REGISTER_COMPLETE;
return completeMessage;
}
}
/**
* タスクIDに基づいて1件のタスクを取得し、対応するタスクフォームに変換するメソッドです。
*
* @param taskId タスクID
* @return 対応するタスクフォーム
*/
@Override
public TaskForm getTask(int taskId) {
//タスクを取得
Task task =taskRepository.getTask(taskId);
//変換処理
TaskForm taskForm =convertToTaskForm(task);
return taskForm;
}
/**
* タスクを削除するメソッドです。
*
* @param task タスクエンティティ
* @return String 完了メッセージ
* @throws OptimisticLockingFailureException 楽観ロックエラーが発生した場合
*/
@Override
@Transactional
public String delete(int taskId) {
//削除処理
taskRepository.delete(taskId);
//完了メッセージをセット
String completeMessage = Constants.DELETE_COMPLETE;
return completeMessage;
}
/**
* タスクフォームをタスクエンティティに変換するメソッドです。
*
* @param taskForm タスクフォーム
* @return 変換されたタスクエンティティ
*/
@Override
public Task convertToTask(TaskForm taskForm) {
Task task = new Task();
task.setTaskId(taskForm.getTaskId());
task.setTitle(taskForm.getTitle());
task.setDescription(taskForm.getDescription());
task.setDeadline(taskForm.getDeadline());
task.setStatus(taskForm.getStatus());
task.setUpdatedAt(taskForm.getUpdatedAt());
return task;
}
/**
* タスクエンティティをタスクフォームに変換するメソッドです。
*
* @param task タスクエンティティ
* @return 変換されたタスクフォーム
*/
@Override
public TaskForm convertToTaskForm(Task task) {
TaskForm taskForm = new TaskForm();
taskForm.setTaskId(task.getTaskId());
taskForm.setTitle(task.getTitle());
taskForm.setDescription(task.getDescription());
taskForm.setDeadline(task.getDeadline());
taskForm.setStatus(task.getStatus());
taskForm.setUpdatedAt(task.getUpdatedAt());
return taskForm;
}
}
repositoryクラス
package com.example.demo.repository;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.Task;
import com.example.demo.mapper.TaskMapper;
/**
* タスク情報にアクセスするためのリポジトリクラスです。
*/
@Repository
public class TaskRepository {
private final TaskMapper taskMapper;
/**
* コンストラクタ
*
* @param taskMapper タスクデータへのマッパー
*/
public TaskRepository(TaskMapper taskMapper) {
this.taskMapper = taskMapper;
}
/**
* 全てのタスクを取得します。
*
* @return タスクのリスト
*/
public List<Task> findAll() {
return taskMapper.findAll();
}
/**
* タスクを保存します。
*
* @param task 保存するタスク
*/
public void save(Task task) {
taskMapper.save(task);
}
/**
* 指定されたタスクIDに対応するタスクを取得します。
*
* @param taskId タスクID
* @return タスク
*/
public Task getTask(int taskId) {
return taskMapper.getTask(taskId);
}
/**
* タスクを更新します。
*
* @param task 更新するタスク
* @return 更新された行数
*/
public int update(Task task) {
return taskMapper.update(task);
}
/**
* タスクを削除します。
*
* @param task 削除するタスク
* @return 削除された行数
*/
public int delete(int taskId) {
return taskMapper.delete(taskId);
}
}
mapperクラス
package com.example.demo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.example.demo.entity.Task;
/**
* タスクエンティティにアクセスするための MyBatis マッパーインターフェースです。
*/
@Mapper
public interface TaskMapper {
/**
* 全てのタスクを取得します。
*
* @return タスクのリスト
*/
List<Task> findAll();
/**
* タスクを保存します。
*
* @param task 保存するタスク
*/
void save(Task task);
/**
* 指定されたタスクIDに対応するタスクを取得します。
*
* @param taskId タスクID
* @return タスク
*/
Task getTask(int taskId);
/**
* タスクを更新します。
*
* @param task 更新するタスク
* @return 更新された行数
*/
int update(Task task);
/**
* タスクを削除します。
*
* @param task 削除するタスク
* @return 削除された行数
*/
int delete(int taskId);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.TaskMapper">
<!-- タスクの全件取得 -->
<select id="findAll" resultType="com.example.demo.entity.Task">
SELECT * FROM task where deleteFlg = 0;
</select>
<!-- 新規タスクの登録 -->
<insert id="save">
INSERT INTO task
(title, description, deadline, status,created_at,updated_at, deleteFlg)
VALUES
(#{title}, #{description}, #{deadline}, 1,CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,0);
</insert>
<!-- タスクIDを指定してタスクを取得 -->
<select id="getTask" resultType="com.example.demo.entity.Task">
SELECT * FROM task where taskId = #{taskId} and deleteFlg = 0;
</select>
<!-- タスクの削除 -->
<delete id ="delete">
DELETE FROM task where taskId = #{taskId} and deleteFlg = 0;
</delete>
<!-- タスクの更新 -->
<update id="update" parameterType="com.example.demo.entity.Task">
UPDATE task SET title = #{title}, description = #{description},deadline = #{deadline},status = #{status}, updated_at = CURRENT_TIMESTAMP WHERE taskId = #{taskId} and updated_at = #{updatedAt};
</update>
</mapper>
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DeleteConfirm</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<body>
<nav class="navbar bg-body-tertiary">
<div class="container-fluid">
<span class="navbar-brand mb-0 h1">Practice</span>
</div>
</nav>
<div class="container">
<h1>Delete Confirm</h1>
<form th:action="@{/task/delete}" , method="post" th:object="${taskForm}"class="mb-3">
<div class="px-4 pt-3 my-3">
<div class="mb-3">
<label>Title</label>
<p th:text="*{title}">title</p>
</div>
<div class="mb-3">
<label>Description</label>
<p th:text="*{description}">description</p>
</div>
<div class="mb-3">
<label>Deadline</label>
<p th:text="${#temporals.format(taskForm.deadline, 'yyyy/MM/dd HH:mm')}">Formatted Deadline</p>
</div>
<div class="mb-3">
<label>Status</label>
<p th:text="*{status == 1 ? '未着手' : status == 2 ? '作業中' : '完了'}">Status</p>
</div>
</div>
<input type="hidden" name="title" th:field="*{title}">
<input type="hidden" name="description" th:field="*{description}">
<input type="hidden" name="deadline" th:field="*{deadline}">
<input type="hidden" name="taskId" th:field="*{taskId}">
<input type="hidden" name="status" th:field="*{status}">
<input type="hidden" name="updatedAt" th:value="*{updatedAt}">
<button type="submit" class="btn btn-primary" value="submit">submit</button>
<a type="button" class="btn btn-outline-secondary" href="/task/list">back</a>
</form>
</div>
<footer class="py-3 my-4">
<p class="text-center text-body-secondary">© 2023 Company, Inc</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
</body>
</html>