Spring boot ＋ Ajax　簡易掲示板作成 (編集機能)

# 最初に
今回の記事は前回投稿した[Spring boot ＋ Ajax　簡易掲示板作成 (投稿機能)](https://qiita.com/Sesoniso/items/a3c2b2c32bff09bfbbd5)に編集機能を追加するための記事となります。
環境構築などは前回の記事に記載していますので先にそちらをご覧ください。

・本記事の完成ページ

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2645309/538cc764-3fb6-b5a2-78c5-0c9efe85b356.png)

# 1. サンプルコード
## 1.1 HTMLファイル
```html:/src/main/resources/templates/top.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>TOP画面</title>

		<link href="/css/style.css" rel="stylesheet" type="text/css">

		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

		<script src="/js/note.js"></script>
	</head>
	<body>
		<form method="post" action="/add" style="margin: 20px 0;" id="addContent">
		    <input type="text" name="content" size="20" maxlength="200" class="content"/>
		    <button type="button" id="submit">投稿</button>
		</form>

		<div th:each="content : ${contents}" th:class="'addContent' + ${content.id}">

			<div th:id="'content' + ${content.id}" style="margin: 1rem 0;">
				<h4 th:text="${content.content}"></h4>
			</div>

			<!-- 追加 -->
			<!-- 編集ボタン -->
			<div  style="display:inline;" th:class="'edit' + ${content.id}">
				<a th:action="@{/Edit/{id}(id=${content.id})}" method="get">
					<button type="button" th:onclick="|getEditFunk('__${content.id}__')|">編集</button>
				</a>
			</div>
			<!-- 追加 -->
		</div>

	</body>
</html>
```

＜補足＞
今回の編集機能実装にあたって追加したコードは`<!-- 追加 -->`の間に記載されているものになります。

## 1.2 JavaScriptファイル
```js:/src/main/resources/static/js/note.js
$(document).ready(function(){
	$('#submit').on('click', function(){
		var content = $(".content").val();

		$.ajax({
			url: "/add",  // リクエストを送信するURLを指定（action属性のurlを抽出）
			type: "POST",  // HTTPメソッドを指定（デフォルトはGET）
			data: {
				"content" : content
			},
			dataType: "json"
		})
		.done(function(data) {
			var data_stringify = JSON.stringify(data);
			var data_json = JSON.parse(data_stringify);

			var data_id = data_json["id"];
			var content = data_json["content"];

			// 追加１
			$("#addContent").after(`
			<div class="addContent${data_id}">
				<h4>${content}</h4>

				<!-- 編集ボタン -->
				<div  style="display:inline;" class="edit${data_id}">
					<a action="/Edit/${data_id}" method="get">
						<button type="button"　onclick="getEditFunk('${data_id}')">編集</button>
					</a>
				</div>
			</div>`);
            // 追加１

			$(".content").val("");
		})
		.fail(function(jqXHR, textStatus, errorThrown) {
			alert("error!");  //
			console.log("jqXHR          : " + jqXHR.status);
			console.log("textStatus     : " + textStatus);
			console.log("errorThrown    : " + errorThrown.message);
		})
	})
})

// 追加２

// 編集機能 情報取得
function getEditFunk(id) {

	var edit_url = "/Edit/" + id;

	$.ajax({
		url: edit_url,
		type: "GET",
		data: {
			"id": id
		},
		dataType: "json"
	})
	.done(function(data) {

		var data_id = data["id"];
		var content = data["content"];
		// 追加、削除先を指定
		var edit_btn = ".edit" + data_id;

		// 更新ボタンを追加
		$(edit_btn).before(`
		<div style="display:inline;" class="update${data_id}">
			<a action="/Update/${data_id}" method="put">
				<button type="button" onclick="UpdateFunk('${data_id}')">更新</button>
			</a>
		</div>`);

		// 編集ボタンを削除
		$(edit_btn).remove();

		var content_edit = "#content" + data_id;
		// 編集欄を表示
		$(content_edit).after(`
		    <div id="content${data_id}" style="margin: 1rem 0;">
				<input type="text" name="content" size="20" maxlength="200" id="update_content${data_id}"
		    	value="${content}"/>
		    </div>`);
		// 元投稿を削除
		$(content_edit).remove();

	})
	.fail(function(jqXHR, textStatus, errorThrown) {
		alert("error!");
		console.log("jqXHR          : " + jqXHR.status);
		console.log("textStatus     : " + textStatus);
		console.log("errorThrown    : " + errorThrown.message);
	})
};
// 編集機能 情報取得

//編集機能 更新機能
function UpdateFunk(id) {

	var updata_url = "/Updata/" + id;
	var update_value = "#update_content" + id;
	var update_content = $(update_value).val();

	$.ajax({
		url: updata_url,
		type: "PUT",
		data: {
			"id": id,
			"content": update_content
		},
		dataType: "json"
	})
	.done(function(data) {
		var data_stringify = JSON.stringify(data);
		var data_json = JSON.parse(data_stringify);

		var data_id = data_json["id"];
		var content = data_json["content"];

		// 追加、削除先を指定
		var update_btn = ".update" + data_id;

		// 編集ボタンを追加
		$(update_btn).before(`
		<div style="display:inline;" class="edit${data_id}">
			<a action="/Edit/${data_id}" method="get">
				<button type="button" onclick="getEditFunk('${data_id}')">編集</button>
			</a>
		</div>`);

		// 更新ボタンを削除
		$(update_btn).remove();

		var content_update = "#content" + data_id;
		// 投稿を表示
		$(content_update).after(`
		    <div id="content${data_id}" style="margin: 1rem 0;">
				<h4>${content}</h4>
		    </div>`);

		// 元投稿を削除
		$(content_update).remove();

	})
	.fail(function(jqXHR, textStatus, errorThrown) {
		alert("error!");
		console.log("jqXHR          : " + jqXHR.status);
		console.log("textStatus     : " + textStatus);
		console.log("errorThrown    : " + errorThrown.message);
	})

};
//編集機能 更新機能
// 追加２
```
＜補足＞
今回追加したコード追加１、追加２について説明します。
追加１に関しては単純に前回の投稿に編集ボタンを追加しているだけです。
追加２の// 編集機能 情報取得ではまず`var edit_url = "/Edit/" + id;`でURLを指定してControllerファイルの`@GetMapping("/Edit/{id}")`を呼び出します。
`var data_id = data["id"];`と`var content = data["content"];`で受け取ったJSON型のid、contentデータをそれぞれ変数data_id、contentに代入しています。
`$(update_btn).before('');`で要素追加beforeを使用して編集ボタンの前に更新ボタンを追加します（下記画像）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2645309/5807ee4d-e6e7-16bd-27ac-c1a4f1fc751b.png)
その後`$(update_btn).remove();`で編集ボタンを削除します。
更新ボタンの追加、編集ボタンの削除と同様に投稿も`$(content_edit).after();`で編集欄を表示して`$(content_edit).remove();`で投稿を削除します。（下記画像）
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2645309/62d5f175-5907-b537-bb59-ca038d3192dd.png)
次は追加2の//編集機能 更新機能について説明します。
`var updata_url = "/Updata/" + id;`で先程と同じ様にControllerファイルの`@PutMapping("/Updata/{id}")`を呼び出します。
`var update_value = "#update_content" + id;`で変数update_valueにHTMLファイルの`id=update_content + id`の値を代入します。(ex:idが1の場合 update_content1)
`var update_content`には編集欄に代入した値を代入します。
今回はidとupdate_conttentを引数としてController側に渡しています。
更新ボタン、編集欄の削除、投稿の更新、編集ボタンの表示は先程説明したように表示追加と削除を行っていきます。

[jQuery要素追加、削除　簡易まとめ](https://qiita.com/Sesoniso/items/5675594937aa05b93f33)



## 1.3 Controllerファイル
```java:/src/main/java/com/example/demo/Controller/TopController.java

//  編集する投稿を取得
	@GetMapping("/Edit/{id}")
	@ResponseBody
	public String editContent(@PathVariable Integer id) {
		Report report = topService.GetReport(id);
		return getEditJson(report);
	}

	private String getEditJson(Report editContent){
		String retVal = null;
		ObjectMapper objectMapper = new ObjectMapper();
		try{
			retVal = objectMapper.writeValueAsString(editContent);
		} catch (JsonProcessingException e) {
			System.err.println(e);
		}
		return retVal;
	}

//  編集した投稿を更新
	@PutMapping("/Updata/{id}")
	@ResponseBody
	public String updateContent (@PathVariable Integer id,@RequestParam  String content) {

		Report report = new Report();

		report.setContent(content);
		report.setId(id);

		// Update edited post
		topService.saveReport(report);

		// get info users with reports
		Report UsersPost = topService.GetReport(id);

		return UpdateJson(UsersPost);
	}

	private String UpdateJson(Report UsersPost){
		String retVal = null;
		ObjectMapper objectMapper = new ObjectMapper();
		try{
			retVal = objectMapper.writeValueAsString(UsersPost);
		} catch (JsonProcessingException e) {
			System.err.println(e);
		}
		return retVal;
	}
}
```

＜補足＞
今回追加するコードは`//  編集する投稿を取得`と`//  編集した投稿を更新`です。
//  編集する投稿を取得の`Report report = topService.GetReport(id);`では引数で渡されたidと一致するidをデータベースから持ってきてReport型のreportに代入します。
//  編集した投稿を更新では`Report report = new Report();`でReport型のreportを作成して`report.setContent(content);`、`report.setId(id);`でreportにcontentとidを代入します。その後`topService.saveReport(report);`でデータベースを更新します。
その後先程と同じ様に`Report UsersPost = topService.GetReport(id);`で一致するidのデータをデータベースから持ってきます。

## 1.4 Serviceファイル
```java:/src/main/java/com/example/demo/Service/TopService.java
	// レコードを取得
	public Report GetReport(Integer id) {
		return topRepository.findById(id).orElse(null);
	}
```

＜補足＞
Controllerファイルの`Report report = topService.GetReport(id);`で呼び出されるメソッドになり、先程も説明したように引数idを一致するデータをデータベースから持ってくるものになります。

# 2. 最後に
今回の記事で書いたAjaxを用いた編集機能を始めて実装する時は理解するのにかなり時間がかかりましたが理解するとかなり使い勝手が良いものだと思いました。
Webアプリケーションを作成する上で非同期通信を使用する事は多々あると思うので今後もAjaxなどの知識を深めていこうと思います。
また次の記事では「削除機能」について書いていこうと思います。