Webアプリ作成 Spring Boot
⑦日記編集・削除

日記の編集と削除できるよう実装していきます。

編集

編集は詳細画面から編集ボタンを選択することで編集できるようにします。
編集画面は新規登録と同じなので、同じHTMLを利用していきます。

form

編集用のFormを「PutForm.java」作成していきます。
※PostFormとほぼ同じです。役割が異なるのでわけています。

package diary.form;

import java.util.Date;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class PutForm {
	private boolean updateFlag;
	
	private int id;

	private String categoryForm;

	@NotNull (message = "日付を入力してください。")
	private Date dateForm;

	@NotNull (message = "題名を入力してください。")
	@Size(min = 1, max = 25, message="25文字以内で入力してください。")
	private String titleForm;

	private String contentForm;

	public boolean getUpdateFlag() {
		return updateFlag;
	}

	public void setUpdateFlag(boolean updateFlag) {
		this.updateFlag = updateFlag;
	}

	public String getCategoryForm() {
		return categoryForm;
	}

	public void setCategoryForm(String categoryForm) {
		this.categoryForm = categoryForm;
	}

	public Date getDateForm() {
		return dateForm;
	}

	public void setDateForm(Date dateForm) {
		this.dateForm = dateForm;
	}

	public String getTitleForm() {
		return titleForm;
	}

	public void setTitleForm(String titleForm) {
		this.titleForm = titleForm;
	}

	public String getContentForm() {
		return contentForm;
	}

	public void setContentForm(String contentForm) {
		this.contentForm = contentForm;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}
ポイント

updateFlag
 updateFlagを設定して、新規登録なのか編集なのかを区別できるようにします。

Repository

「IDiaryDao.java」にメソッドを追加します。

	// 日記を更新する
	int update(PutForm form);


「DairyDao.java」にメソッドを追加します。

	// 日記を編集する
	@Override
	public int update(PutForm form) {
		int count = 0;
		String sql = "UPDATE diary "
				+ "SET category=:category, title=:title, content=:content, date=:date, update_datetime=:update_datetime "
				+ "WHERE id=:id";
		// パラメータ設定用Map
		Map<String, Object> param = new HashMap<>();
		param.put("id", form.getId());
		param.put("category", form.getCategoryForm());
		param.put("title", form.getTitleForm());
		param.put("content", form.getContentForm());
		param.put("date", form.getDateForm());
		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
		param.put("update_datetime", timestamp);
		count = jdbcTemplate.update(sql, param);
		return count;
	}
ポイント

パラメータ設定
 検索時と同様登録する内容はMapに格納し、キー値とValues内の変数は紐づいています。

Service

「DiaryService.java」にメソッドを追加していきます。

    public int update(PutForm form) {
		return dao.update(form);
	}

Controller

「DiaryController.java」にメソッドを追加していきます。
実施していることは日記登録で記載した内容とほとんど同じになります。

   /**
     * 日記を編集
     * @param putForm
     * @param model
     * @return
     */
    @PostMapping(path="/update", params="update")
    public String update(
    	@ModelAttribute PutForm form,
    	BindingResult result,
    	Model model
    ) {
    	if(result.hasErrors()) {
    		model.addAttribute("error", "パラメータエラーが発生しました。");
    		return "form";
    	}
    	int count = diaryservice.update(form);
        return "redirect:/diary";
    }

編集の場合フォーム画面へ遷移する際に多くのパラメータを渡すため、formPageメソッドを「@GetMapping」から「@PostMapping」に変更します。
また、新規登録か編集なのかで分岐しています。「updateFlag」の値はHTML内で設定します。

    /**
     * 新規登録へ遷移
     * @param model
     * @return resources/templates/form.html
     */
    @PostMapping("/form")
    public String formPage(
    	@ModelAttribute PutForm form,
    	Model model
    ) {
    	model.addAttribute("putForm", form);
        //新規登録か編集で分岐
        if (form.getUpdateFlag()) {
        	model.addAttribute("update", true);
        } else {
        	model.addAttribute("update", false);
        }
        return "form";
    }


一覧ページへ戻る用のbackPage(メソッドにも修正を加えます。
pathにupdateを追加しています。

    @PostMapping(path={"/insert", "/form", "/update"}, params="back")
    public String backPage(
    	Model model
    ) {
    	return "redirect:/diary";
    }

画面修正

まずは「detail.html」を修正します。
formタグ内の末部に以下2行を追加します。

          <input type="hidden" name="updateFlag" th:value=true>
          <input type="hidden" name="id" th:value="${diary.id}">
          <input type="hidden" name="categoryForm" th:value="${diary.category}">
          <input type="hidden" name="titleForm" th:value="${diary.title}">
          <input type="hidden" name="dateForm" th:value="${diary.date}">
          <input type="hidden" name="contentForm" th:value="${diary.content}">
ポイント

<input type=”hidden” name=”updateFlag” th:value=true>
 遷移元が詳細画面なことがわかるように設定しています。
 Controllerでこの値を利用し分岐しています。

<input type=”hidden” name=”diary” th:value=”${diary.値}”>
 編集なのでフォーム画面に遷移した際変更前の状態を初期値として設定します。

つぎに「form.html」修正をします。
変更箇所が多いためformタグ内全てを記載しています。

        <form id="form" class="needs-validation" novalidate method="POST" th:action="${update}? @{/diary/update}: @{/diary/insert}" th:object="${putForm}" onsubmit="return check()">
          <p class="p-1 h4" th:text="${update}? 編集: 新規作成"></p>
          <div class="row justify-content-center">
            <div class="form-group col-8">
              <label for="dateForm">日付</label>
              <input type="text" class="form-control" name="dateForm" id="date_sample" th:value="${#dates.format(putForm.dateForm, 'yyyy/MM/dd')}" required>
              <div class="invalid-feedback">必須入力です</div>
            </div>
          </div>
          <div class="row justify-content-center">
            <div class="form-group col-8">
              <label for="categoryForm">分類</label>
              <select id="categoryForm" class="form-select col-8" name="categoryForm" th:value="*{categoryForm}" required>
                <option selected></option>
                <option value="1" th:selected="*{categoryForm} == 1">仕事</option>
                <option value="2" th:selected="*{categoryForm} == 2">趣味</option>
                <option value="3" th:selected="*{categoryForm} == 3">その他</option>
              </select>
              <div class="invalid-feedback">必須入力です</div>
            </div>
          </div>
          <div class="row justify-content-center">
            <div class="form-group col-8">
              <label for="title">題名</label>
              <input type="text" class="form-control" name="titleForm" id="title" th:value="*{titleForm}" required>
              <div class="invalid-feedback">25文字以内で入力してください</div>
            </div>
          </div>
          <div class="row justify-content-center">
            <div class="form-group col-8">
              <label for="floatingTextarea">内容</label>
              <textarea class="form-control" placeholder="日記の内容" name="contentForm" th:text="*{contentForm}"  style="height: 200px"></textarea>
            </div>
          </div>
          <input type="hidden"  name="id" th:value="*{id}">
          <div class="row justify-content-end">
            <div class="col-1">
              <button type="submit" class="btn btn-primary" th:name="${update}? update: insert" th:text="${update}? 更新: 登録" onClick="btn='insert'"></button>
            </div>
            <div class="col-1">
              <button type="submit" class="btn btn-light" name="back" onClick="btn='back'">一覧へ</button>
            </div>
          </div>
        </form>
ポイント

th:action=”${update}? @{/diary/update}: @{/diary/insert}”
th:text=”${update}? 編集時の値: 新規作成時の値”
th:name=”${update}? update: insert”

 編集なのか新規登録なのかで文言やaction時の実行URL等を変更をしています。

form値
 th:value=”*{form値}”、th:selected=”*{categoryForm}のように編集の場合は元の値が設定されるようにしています。

th:value=”${#dates.format(putForm.dateForm, ‘yyyy/MM/dd’)}”
 tymeleafのユーティリティオブジェクトを利用しています。
 そのまま設定すると「yyyy/mm/dd」の値にならないので変換をかけています。
 ↓詳細はこちら
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#%E6%97%A5%E4%BB%98

<input type=”hidden”  name=”id” th:value=”*{id}”>
 updateする際はidを条件に更新するため、idも渡すようにしています。

動作確認

編集の動作確認をしていきます。
①「詳細」→「編集」と画面遷移し、変更前の値が設定されていることを確認

②値を変更して各項目が更新されていることを確認
 DBを確認して更新日も実施時間に更新されているかも含めて確認

③新規登録できるかを確認
 新規登録に影響のあるform.htmlやControllerを修正したため、念の為確認

④「一覧へ」ボタンを選択し一覧画面へ戻れるかを確認


ここまでうまくいけば編集機能の完了となります。

削除

一覧画面に削除ボタンをつくっていました。
ボタンを押すと日記を削除できる機能を実装します。
削除なので、ボタン選択した後に確認ダイアログを表示しようと思います。

Repository

「IDiaryDao.java」にメソッドを追加します。

	// 日記を削除する
	int delete(int id);

「DiaryDao.java」にメソッドを追加します。

	// 日記を削除する
	@Override
	public int delete(int id) {
		int count = 0;
		String sql = "DELETE FROM diary "
				+ "WHERE id = :id";
		// パラメータ設定用Map
		Map<String, Object> param = new HashMap<>();
		param.put("id", id);
		count = jdbcTemplate.update(sql, param);
		return count;
	}

Service

「DiaryService.java」にメソッドを追加していきます。

    public int delete(int id) {
		return dao.delete(id);
	}

Controller

「DiaryController.java」にメソッドを追加していきます。

    /**
     * 日記を削除
     * @param id
     * @param model
     * @return
     */
    @PostMapping("/delete")
    public String delete(
    	@RequestParam int id,
    	Model model
    ) {
    	int count = diaryservice.delete(id);
        return "redirect:/diary";
    }
ポイント

@RequestParam
 POST時のパラメータを受け取るが可能です。
 URLに含まれるパラメータも受け取ることが可能みたいです。

return “redirect:/diary”;
 リクエストの二重送信防止となります。
 (新規登録等でも使用)

画面修正

「list.html」を修正していきます。
変更箇所は3つです。
・「delete」用のformタグを作成
・idをControllerに渡せるように「input type=”hidden”」を利用
・モーダルを作成
tbodyタグ内を抜粋しております。

       <tbody>
            <tr th:each="item: ${list}">
              <td th:text=${item.date}></td>
              <td th:text=${item.name}></td>
              <td th:text=${item.title}></td>
              <td>
                <a class="btn btn-primary" th:href="@{/diary/{id}(id=${item.id})}">詳細</a>
              </td>
              <td>
                <form method="POST" th:action="@{/diary/delete}">
                  <input type="hidden" th:value="${item.id}" name="id">
                  <button type="button" class="btn btn-danger" data-bs-toggle="modal" th:data-bs-target="'#id' + ${item.id}">削除</button>
                  <!-- Modal -->
                  <div class="modal fade" th:id="'id' + ${item.id}" tabindex="-1" aria-hidden="true">
                    <div class="modal-dialog">
                      <div class="modal-content">
                        <div class="modal-header">
                          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">
                          削除してもよろしいですか?
                        </div>
                        <div class="modal-footer">
                          <button type="submit" class="btn btn-danger">削除</button>
                          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉じる</button>
                        </div>
                      </div>
                    </div>
                   </div>
                </form>
              </td>
            </tr>
          </tbody>
ポイント

<form method=”POST” th:action=”@{/diary/delete}”>
 delete用にformを作成

モーダル作成
 buttonタグ内にモーダルと紐づける用の「data-bs-toggle=”modal” 」「th:data-bs-target=”‘#id’ + ${item.id}”」を指定しています。
 <!– Modal –>以降に実際に表示されるモーダルの内容を記載しています。
 詳細は↓をご確認ください。
https://getbootstrap.jp/docs/5.0/components/modal/

動作確認

動作確認していきます。
①モーダルが開くことを確認
削除ボタンを選択して、モーダルを開きます。

②削除を選択するとデータが削除されることを確認

③モーダルの「閉じる」「✖️」を選択すると
 モーダルが閉じることを確認

最後に

ここまで終えることでSpringを利用して「CRUD機能」を実装することができました。
思ったよりだいぶながくなってしまいました。。。

次回はSpringの機能を利用して、ログイン画面を実装していきます。

タイトルとURLをコピーしました