前回の記事は、注文フォームにトランザクションと二重サブミット対策とバリデーションを追加をしました。
今回は、注文フォームの更新と削除の機能を追加していきましょう。
ファイル構成
.
├── .gradle
├── .idea
├── build
├── gradle
└── src
├── main
| ├── java
| | └── com
| | └── example
| | └── practice
| | PracticeApplication.java
| | ├── web
| | | ├── order
| | | | ├── OrderForm.java
| | | | └── OrderController.java
| | | |
| | | └── IndexController.java
| | └── domain
| | └── order
| | └── OrderEntity.java
| | └── OrderService.java
| | └── OrderRepository.java
| |
| └── resources
| ├── static
| ├── templates
| | └── order
| |
├──delete_confirmation.html
| | ├── detail.html
| | ├── form.html
| | └── list.html
| └── index.html
| schema.sql
| data.sql
| application.properties
└── test
.gitignore
build.gradle
gradlew.bat
HELP.md
settings.gradle
今回作成したい完成形を見ていきましょう。
注文番号をクリックすると、注文リストの詳細が表示されます。
注文リストの詳細では、既存のデータを修正または削除できるようにします。
削除ボタンをクリックすると、確認画面が表示され、削除ボタンをクリックすると、削除されます。
Modelの作成
まずは、OrderRepositoryから追加していきます。最初に、注文番号をクリックすると、注文リストの詳細が表示されるように、特定の注文番号のIDを取得します。
@Select("select * from ORDERS where order_id = #{orderId}")
OrderEntity findById(long orderId);
@Update アノテーションは、指定された SQLクエリを使用してデータベース内のデータを更新するためのメソッドを定義する際に使用し、修正する機能ができます。
@Delete アノテーションは、データベースからデータを削除するためのメソッドを定義する際に使用し、削除する機能ができます。
OrderRepository
package com.example.practice.domain.order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Delete;
import java.util.List;
import com.example.practice.web.order.OrderForm;
import org.apache.ibatis.annotations.Options;
@Mapper
public interface OrderRepository {
@Select("select * from orders")
List<OrderEntity> findAll();
@Insert("insert into ORDERS(order_id,order_date,company_no,company_name,item_no,item,quantity,unit_price,price) values (#{orderId}, #{orderDate}, #{companyNo}, #{companyName}, #{itemNo}, #{item}, #{quantity}, #{unitPrice}, #{price})")
void insert(OrderForm orderForm);
@Select("SELECT MAX(CAST(order_id AS SIGNED)) FROM ORDERS")
Integer findMaxOrderId();
@Select("select * from ORDERS where order_id = #{orderId}")
OrderEntity findById(long orderId);
@Update("update ORDERS set order_date = #{orderDate}, company_no = #{companyNo}, company_name = #{companyName}, item_no = #{itemNo}, item = #{item}, quantity = #{quantity}, unit_price = #{unitPrice}, price = #{price} where order_id = #{orderId}")
void update(OrderForm orderForm);
@Delete("delete from ORDERS where order_id = #{orderId}")
void delete(long orderId);
}
次に、OrderRepositoryで追加したコードのロジックを追加します。
OrderService
package com.example.practice.domain.order;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.example.practice.web.order.OrderForm;
import java.util.List;
import org.springframework.ui.Model;
import org.springframework.transaction.annotation.Transactional;
import java.lang.IllegalAccessException;
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository repository;
@Transactional(readOnly = true)
public List<OrderEntity> findAll() {
return repository.findAll();
}
@Transactional
public void create(OrderForm form, Model model) {
int nextOrderId = getNextOrderId(); // 事前にorderIdを取得するメソッド
form.setOrderId(nextOrderId); // OrderFormに次のorderIdを設定
repository.insert(form); // OrderFormをDBに挿入
}
// 最大orderId + 1を計算して返すメソッド
public int getNextOrderId() {
Integer maxOrderId = repository.findMaxOrderId();
if (maxOrderId == null) {
return 1; // 最初の場合、1を返す
}
int nextId = maxOrderId + 1;
System.out.println(nextId);
return nextId;
}
//指定された orderId を使用して、データベースから該当する注文情報を取得するメソッド
public OrderEntity findById(long orderId) {
return repository.findById(orderId);
}
//渡された OrderForm オブジェクトの情報を使用して、データベース内の注文情報を更新するためメソッド
@Transactional
public void update(OrderForm form, Model model) {
repository.update(form);
}
//指定された orderId を使用して、データベース内の注文情報を削除するためメソッド
@Transactional
public void delete(long orderId) {
repository.delete(orderId);
}
}
Controllerの作成
注文情報を詳細表示、更新、削除するためのメソッドを作成します。以下がその内容のコードです。
OrderController
package com.example.practice.web.order;
import com.example.practice.domain.order.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import java.time.LocalDate;
@Controller
@RequestMapping("/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping
public String showList(Model model) {
//orderServiceクラスのfindAllメソッドで取得されたオーダーリストを、orderListでビューに渡す
model.addAttribute("orderList", orderService.findAll());
// "order/list"という名前のThymeleafビューを表示する
return "order/list";
}
@GetMapping("/form")
public String showForm(@ModelAttribute OrderForm form, Model model) {
int nextOrderId = orderService.getNextOrderId();
form.setOrderId(nextOrderId);
form.setOrderDate(LocalDate.now());
model.addAttribute("nextOrderId", nextOrderId);
return "order/form";
}
@PostMapping
public String create(@Validated OrderForm form, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return showForm(form, model);
}
orderService.create(form, model);
return "redirect:/orders";
}
@GetMapping("/{orderId}")
public String showDetail(@PathVariable("orderId") long orderId, Model model) {
// 特定の注文の詳細を表示するためのメソッド
// URLパラメータからorderIdを受け取り、その注文の詳細情報をデータベースから取得してモデルに追加
model.addAttribute("order", orderService.findById(orderId));
return "order/detail"; // 注文の詳細を表示するためのビューにリダイレクト
}
@PostMapping("/update")
public String update(@Validated OrderForm form, BindingResult bindingResult, Model model) {
// 注文情報を更新するためのメソッド
// フォームデータを受け取り、バリデーションエラーがある場合はフォームを再表示
if (bindingResult.hasErrors()) {
return showForm(form, model); // 更新フォームを表示するためのメソッドを呼び出し
}
System.out.println("OrderForm:" + form); // フォームデータをコンソールに出力(デバッグ用)
return "redirect:/orders"; // オーダー一覧画面にリダイレクト
}
@GetMapping("/delete/{orderId}")
public String showDeleteConfirmation(@PathVariable("orderId") long orderId, Model model) {
// 注文の削除確認画面を表示するためのメソッド
// URLパラメータからorderIdを受け取り、削除対象の注文の情報をデータベースから取得してモデルに追加
model.addAttribute("order", orderService.findById(orderId));
return "order/delete_confirmation"; // 削除確認画面を表示するためのビューにリダイレクト
}
@PostMapping("/delete/{orderId}")
public String deleteOrder(@PathVariable("orderId") long orderId) {
// 注文を削除するためのメソッド
orderService.delete(orderId); // 指定されたorderIdに対応する注文をデータベースから削除
return "redirect:/orders"; // オーダー一覧画面にリダイレクト
}
}
Viewの作成
次に、詳細画面と削除詳細画面のViewを作成します。
list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>注文リスト</title>
</head>
<body>
<h1>注文リスト</h1>
<a href="../index.html" th:href="@{/}">トップページ</a>
<a href="./form.html" th:href="@{/orders/form}">作成</a>
<table>
<tr>
<th>注文番号</th>
<th>納入日付</th>
<th>会社番号</th>
<th>会社名</th>
<th>品物番号</th>
<th>品物</th>
<th>数量</th>
<th>単価</th>
<th>金額</th>
</tr>
<!-- orderList の内容をループして表示 -->
<tr th:each="order : ${orderList}">
<td>
<a href="./detail.html" th:href="@{/orders/{orderId}(orderId=${order.orderId})}" th:text="${order.orderId}">
(orderId)
</a>
</td>
<td th:text="${order.orderDate}"></td>
<td th:text="${order.companyNo}"></td>
<td th:text="${order.companyName}"></td>
<td th:text="${order.itemNo}"></td>
<td th:text="${order.item}"></td>
<td th:text="${order.quantity}"></td>
<td th:text="${order.unitPrice}"></td>
<td th:text="${order.price}"></td>
</tr>
</table>
</body>
</html>
detail.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>注文リストフォーム</title>
</head>
<body>
<h1>注文リスト詳細</h1>
<form th:object="${order}" th:action="@{/orders/update}" method="post">
<div>
<input type="hidden" th:field="*{orderId}"> <!-- orderId を hidden フィールドとして追加 -->
<label>注文番号</label>
<span th:text="${order.orderId}"></span>
</div>
<div>
<label for="orderDate">納入日付</label>
<input type="date" id="orderDate" th:field="*{orderDate}">
<p th:if="${#fields.hasErrors('orderDate')}" th:errors="*{orderDate}">(error)</p>
</div>
<div>
<label for="companyNo">会社番号</label>
<input type="number" id="companyNo" th:field="*{companyNo}">
<p th:if="${#fields.hasErrors('companyNo')}" th:errors="*{companyNo}">(error)</p>
</div>
<div>
<label for="companyName">会社名</label>
<input type="text" id="companyName" th:field="*{companyName}">
<p th:if="${#fields.hasErrors('companyName')}" th:errors="*{companyName}">(error)</p>
</div>
<div>
<label for="itemNo">品物番号</label>
<input type="number" id="itemNo" th:field="*{itemNo}">
<p th:if="${#fields.hasErrors('itemNo')}" th:errors="*{itemNo}">(error)</p>
</div>
<div>
<label for="item">品物</label>
<input type="text" id="item" th:field="*{item}">
<p th:if="${#fields.hasErrors('item')}" th:errors="*{item}">(error)</p>
</div>
<div>
<label for="quantity">数量</label>
<input type="number" id="quantity" th:field="*{quantity}">
<p th:if="${#fields.hasErrors('quantity')}" th:errors="*{quantity}">(error)</p>
</div>
<div>
<label for="unitPrice">単価</label>
<input type="number" id="unitPrice" th:field="*{unitPrice}">
<p th:if="${#fields.hasErrors('unitPrice')}" th:errors="*{unitPrice}">(error)</p>
</div>
<div>
<label for="price">金額</label>
<input type="number" id="price" th:field="*{price}">
<p th:if="${#fields.hasErrors('price')}" th:errors="*{price}">(error)</p>
</div>
<button type="submit">更新</button>
<a th:href="@{/orders/delete/{orderId}(orderId=${order.orderId})}">削除</a>
<a href="./order/list.html" th:href="@{/orders}">取消</a>
</form>
</body>
</html>
delete_confirm
<!-- delete_confirmation.html -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>注文リスト削除確認</title>
</head>
<body>
<h1>注文リスト削除確認</h1>
<p>以下の注文を削除しますか?</p>
<p>注文番号: <span th:text="${order.orderId}"></span></p>
<p>納入日付: <span th:text="${order.orderDate}"></span></p>
<p>会社番号: <span th:text="${order.companyNo}"></span></p>
<p>品物番号: <span th:text="${order.itemNo}"></span></p>
<p>品物: <span th:text="${order.item}"></span></p>
<p>数量: <span th:text="${order.quantity}"></span></p>
<p>単価: <span th:text="${order.unitPrice}"></span></p>
<p>金額: <span th:text="${order.price}"></span></p>
<!-- 削除処理を実行するURLを指定 -->
<form th:action="@{/orders/delete/{orderId}(orderId=${order.orderId})}" method="post">
<button type="submit">削除</button>
<a th:href="@{/orders}">キャンセル</a>
</form>
</body>
</html>