ํ์๊ด๋ฆฌ ์์ & ์ญ์ Rest API ๋ฐฉ์์ผ๋ก ๋ง๋ค๊ธฐ!
- ์ฌ์ฉ IDE : IntelliJ IDEA Ultimate
- ์ฌ์ฉ DB : MySQL
- ์ฌ์ฉ ์ธ์ด & SDK : Java & Amazon correto 11
- thymeleaf ์ฌ์ฉ์ ๊ฐ๊ธ์ ์ค์ธ ์์ ์ ๋๋ค.
- ajax๋ก ์กฐํ๋ ํ๋ ์์ํฌ์ ๋์ผํ๋ฏ๋ก ๋นผ๊ฒ ์ต๋๋ค.
- ์ ๋ฆฌ๋ณธ์ ๋๋ค ์ฐธ๊ณ ์ฉ์ผ๋ก๋ง ๋ด์ฃผ์ธ์!
์ด์ ๊ธ
ฮธ Spring Boot ์์ 1 (ํ์๊ด๋ฆฌ)
๐ Spring Boot ์์ 2 (ํ์๊ด๋ฆฌ)
๐ Spring Boot ์์ 3 (ํ์๊ด๋ฆฌ)
์์
findAll.html์์ Controller๋ก memberId(pk๋ก ์ฐ๋ ํ์๋ฒํธ) ์ ๋ฌ
Controller์์ Service๋ก ์ ๋ฌ
Service์์ jpa ํธ์ถ ๋ฐ ์ญ์ ์งํ
์ฌ์ฉ์๊ฐ ์ง์ ํ ์์ ์ํ
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script>
function deleteById(memberId) {
console.log(memberId)
const reqUrl = "/member/"+memberId
$.ajax({
type: "delete",
url: reqUrl,
// dataType: "json", ๋ฐ์์ฌ ํ์๊ฐ ์์ผ๋ฉด ์๋ต๊ฐ๋ฅ
success: function () {
console.log("ajax ์ฑ๊ณต")
// ์ญ์ ์ฑ๊ณต ์ ํ์๋ชฉ๋ก ํ์ด์ง๋ฅผ ๋ค์ ์์ฒญ
location.href = "/member/"
},
error: function () {
alert("ajax ์คํจ")
}
})
}
// ์๋๋ ํจ์์ ์ธ ๋ฐฉ๋ฒ ์ค ํ๋์.
// ํจ์์ด๋ฆ : deleteFn, ๋งค๊ฐ๋ณ์ : memberId
const deleteFn = (memberId) => {
console.log(memberId)
}
// ํจ์์ด๋ฆ : deleteFn2, ๋งค๊ฐ๋ณ์ : X
const deleteFn2 = () => {
}
</script>
<body>
<h2>findAll.html</h2>
<table>
<thead>
<tr>
<th>๋ฒํธ</th>
<th>์ด๋ฉ์ผ</th>
<th>๋น๋ฐ๋ฒํธ</th>
<th>์ด๋ฆ</th>
<th>์กฐํ</th>
<th>์ญ์ (get)</th>
<!-- ์ด๋ฒ ์๊ฐ์๋ ์๋ delete ๋ฐฉ์์ผ๋ก ๋ณด๋ด๋๊ฑธ ์ฌ์ฉํ๋๊ฒ๋๋ค. -->
<th>์ญ์ (delete)</th>
</tr>
</thead>
<tbody>
<tr th:each="member: ${memberList}">
<td th:text="${member.memberId}">๋ฒํธ</td>
<td th:text="${member.memberEmail}">์ด๋ฉ์ผ</td>
<td th:text="${member.memberPassword}">๋น๋ฐ๋ฒํธ</td>
<td th:text="${member.memberName}">์ด๋ฆ</td>
<!-- detail ์ฃผ์ ์ฒ๋ฆฌ๋ฐฉ์ @{|/์ฃผ์/${๊ฐ์ด ๋ณด๋ผ ๋ฐ์ดํฐ}|} -->
<td><a th:href="@{|/member/${member.memberId}|}">์กฐํ</a></td>
<td><a th:href="@{|/member/delete/${member.memberId}|}">์ญ์ </a></td>
<!-- ์ญ์ ๋ฒํผ ํด๋ฆญ ์ delete ํจ์ ํธ์ถ -->
<!-- ํจ์ํธ์ถํ๋ฉด์ memeberId ๋๊ฒจ์ผํจ -->
<!-- delelte ํจ์() : /member/memberId ์ฃผ์๋ก ์์ฒญํ๋ฉฐ, ์์ฒญ ๋ฉ์๋๋ delete -->
<td><button th:onclick="deleteById([[${member.memberId}]])">์ญ์ </button></td>
</tr>
</tbody>
</table>
</body>
</html>
ajax๋ก ๊ฐ์ ๋ณด๋์ผ๋ ์ด์ Controller์์ ๋ฐ์ ์ค๋น๋ฅผ ํด๋ด ์๋ค.
// ํ์์ญ์ (/member/5)
@DeleteMapping("{memberId}")
public ResponseEntity deleteById2(@PathVariable Long memberId) {
ms.deleteById(memberId);
/*
๋จ์ ํ๋ฉด์ถ๋ ฅ์ด ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํดํ๊ณ ์ ํ ๋ ์ฌ์ฉํ๋ ๋ฆฌํด๋ฐฉ์
ResponseEntity : ๋ฐ์ดํฐ & ์ํ์ฝ๋(200, 400, 404, 405, 500 ๋ฑ ์ค๋ฅ์ฝ๋)๋ฅผ ํจ๊ป ๋ฆฌํดํ ์ ์์.
@ResponseBody : ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํดํ ์ ์์.
*/
// 200์ฝ๋๋ฅผ ๋ฆฌํด (200์ OK๋ผ๋ ๋ป์ผ๋ก ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๊ฐ ๋์๋ค ๋ผ๋ ๋ป)
// ์ํ์ฝ๋๊ฐ OK(200)๋ฉด ๋ฐ๋ก ajax์์ success๊ฐ ํธ์ถ
return new ResponseEntity(HttpStatus.OK);
}
์์์๋ถํฐ ์ญ ์ ๋ฐ๋ผ์ค์ จ๋ค๋ฉด ๋ฌธ์ ๋ ์ ํ ์์๊ฒ๋๋ค.
์๋ก์ด๊ฑธ ๊ณ์ ๋ฐฐ์ฐ๊ธฐ ๋๋ฌธ์ ์ด๋ ค์ด๊ฒ ์์ ์ ์์ผ๋ ๊ธ๋ฐฉ ์ ์ํ๋ฉด์ ์ํ์ค ์ ์์๊ฒ๋๋ค!!
๊ทธ๋ผ ์ด์ ์ ๋ฐ์ดํธ(์์ )์ผ๋ก ๋์ด๊ฐ๋ณด๊ฒ ์ต๋๋ค!
์ด๋ฒ์๋ ์์ ์ ๋๋ค :D
์ผ๋ฐ์ ์ธ ์์ ํ๋ ๋ฐฉ๋ฒ๊ณผ, Rest API๋ฐฉ์์ผ๋ก ์์ ํ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํด๋ณผ๋ ค๊ณ ํฉ๋๋ค.
๋ก๊ทธ์ธ ํ findAll๋ก ๊ฐ๋๊ฑฐ์์ mypage๋ก ๊ฐ๊ฒ๋ ๋ณ๊ฒฝ ํ ์์ ์ update.html์์ ์งํํ๊ฒ ํ์ต๋๋ค.
Service์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ๊ฐ์ผ๋ ์ฃผ์ ์ฒ๋ฆฌ๋ฐฉ์๋ง ๋ค๋ฅด๋ฏ๋ก ๊ฐ์ด ์ค๋ช ํด๋ณด๊ฒ ์ต๋๋ค!
Controller์ html์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ณ ์ค๋ช ํ๋๊ฑธ๋ก ํ๊ฒ ์ต๋๋ค :D
// ๋ก๊ทธ์ธ
@PostMapping("login")
public String login(@ModelAttribute MemberLoginDTO memberLoginDTO, HttpSession session) {
if (ms.login(memberLoginDTO)) {
session.setAttribute(LOGIN_EMAIL,memberLoginDTO.getMemberEmail());
// return์ mypage๋ก ๊ฐ๊ฒ๋ ๋ณ๊ฒฝ. ๊ทธ ์ธ ๋๋จธ์ง๋ ๋ณ๊ฒฝํ๊ฑฐ ์์
return "member/mypage";
} else {
return "member/login";
}
}
// ์์ ํ๋ฉด ์์ฒญ
@GetMapping("update")
public String updateForm(Model model, HttpSession session) {
// jsp, html์ด ์๋ ๊ณณ์์๋ session์ ๋ด๊ธด ๊ฐ์ ๊บผ๋ด์ฌ ์ ์์.
// ์์๋ก ์ ์ธํ ๋ณ์๋ก session์ ์ค์ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ์ฌ์ฉ.
String memberEmail = (String) session.getAttribute(LOGIN_EMAIL);
// Object ํ์
์ผ๋ก ๋์ด์ค๊ธฐ ๋๋ฌธ์ ๊ฐ์ ํ ๋ณํ์ ํด์ค์ผํจ.
// thymeleaf๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด Update์ฉ DTO๋ฅผ ํ๋ ๋ ๋ง๋ค์ด์ผํจ.
// ํ์ง๋ง, ๊ฐ๊ธ์ ์ฌ์ฉํ์ง ์๊ธฐ๋ก ํ๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ Detail์ฉ DTO ์ฌ์ฉ
MemberDetailDTO memberDetailDTO = ms.findByEmail(memberEmail);
model.addAttribute("member", memberDetailDTO);
return "member/update";
}
// ์ผ๋ฐ ์์
@PostMapping("update")
public String update(@ModelAttribute MemberDetailDTO memberDetailDTO) {
Long memberId = ms.update(memberDetailDTO);
// ์์ ์๋ฃ ํ ํด๋นํ์์ ์์ธ ํ์ด์ง ์ถ๋ ฅ
return "redirect:/member/"+memberDetailDTO.getMemberId();
}
// ์์ ์ฒ๋ฆฌ (put)
@PutMapping("{memberId}")
// json์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ ๋ฌ๋๋ฉด @RequestBody๋ก ๋ฐ์์ค์ผํจ
public ResponseEntity update2(@RequestBody MemberDetailDTO memberDetailDTO) {
Long memberId = ms.update(memberDetailDTO);
return new ResponseEntity(HttpStatus.OK);
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>mypage.html</h2>
<!-- common ์ ๋ด๊ฒจ์๋ ๊ฐ์ ์ฐ๋๊ฒ, ์์๋ก ์ ์ธํ ๋ณ์ ์ด๋ฆ์ ์ฐ๋๊ฒ์ด ์๋! -->
์ธ์
: <p th:text="${session['loginEmail']}"></p>
<!-- ์ ๋ณด์์ ๋งํฌ๋ฅผ ํด๋ํ๋ฉด update.html์ DB์ ์ ์ฅ๋ ์ ๋ณด๋ฅผ form, inputํ๊ทธ๋ฅผ ์ด์ฉํ์ฌ ์ถ๋ ฅ, ์ด๋ฆ๋ง ์์ ๊ฐ๋ฅํ๋๋ก -->
<a href="/member/update/">์ ๋ณด์์ </a>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>
// ํจ์ ์ด๋ฆ์ด memberUpdate, ๋งค๊ฐ๋ณ์๊ฐ ์๋ ํํ -> function memberUpdate() ์ ๊ฐ์ ๋ป
const memberUpdate = () => {
console.log('์์ ํจ์ ํธ์ถ')
// DOM API๋ฅผ ์ด์ฉํ์ฌ memberId, ์ด๋ฉ์ผ, ๋น๋ฐ๋ฒํธ, ์ด๋ฆ์ ๊ฐ์ ธ์์ ๊ฐ๊ฐ javascript ํจ์์ ๋ด์ผ์์ค.
const id = document.getElementById("memberID").value
const email = document.querySelector("#memberEmail").value
// jQuary ๋ฌธ๋ฒ์ผ๋ก id๊ฐ ๊ฐ์ ธ์ค๊ธฐ.
const password = $("#memberPassword").val()
const name = $("#memberName").val()
// ์ ์ฝ๋ ์ ๋ถ ๋๊ฐ์ ์ญํ ์ ์ํํ๋ ์ฝ๋์. (value๊ฐ ๊ฐ์ ธ์ค๊ธฐ)
// const name = "[[${member.memberName}]]"
// ์ ์ฝ๋๋ DB์์ ๊ฐ์ ธ์จ ๋ด์ฉ์ ๋ค์ ๋ฃ๋๊ฒ์ด๋ฏ๋ก ์
๋ฐ์ดํธ์์๋ ์ฌ์ฉ ๋ถ๊ฐ.
// javascript object์ ๋ด์์ ajax ์ปจํธ๋กค๋ฌ์ ๋ณด๋.
// stringigfy : ๋ฐ์ดํฐ๋ฅผ JSONํ์
์ผ๋ก ๋ง๋ค๊ฒ ๋ค๋ ์ฝ๋
const updateData = JSON.stringify({
memberId: id,
memberEmail: email,
memberPassword: password,
memberName: name
})
console.log(updateData) // ์ฝ์์ ์ฐ์ด๋ณด๋ฉด jsonํ์
์ผ๋ก ๋ด๊ธด๊ฒ์ ๋ณผ ์ ์๋ค.
const reqUrl = "/member/"+id
$.ajax({
// put(์ ์ฒด ๋ฎ์ด์ฐ๊ธฐ), patch(์์ ์ด ํ์ํ ๊ฒ๋ง ๋ฐ๊ฟ)
type: "put",
data: updateData,
url: reqUrl,
// jsonํ์
์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ๋๋ ์๋ ์ฝ๋๋ฅผ ๊ผญ ์จ์ผํจ.
contentType: "application/json",
success: function () {
location.href = "/member/"+id;
// ์์ ์ฑ๊ณต ์ /member/{memberId} ๋ก ๊ฐ๊ฒ ๋ค.(ํ์ ์์ธ์กฐํ)
},
error: function () {
alert("ajax ์คํจ")
}
})
}
</script>
</head>
<body>
<h2>save.html</h2>
<form action="/member/update" method="post">
<input type="hidden" name="memberId" id="memberID" th:value="${member.memberId}" placeholder="ํ์๋ฒํธ" readonly>
<input type="text" name="memberEmail" id="memberEmail" th:value="${member.memberEmail}" placeholder="์ด๋ฉ์ผ" readonly>
<input type="text" name="memberPassword" id="memberPassword" th:value="${member.memberPassword}" placeholder="๋น๋ฐ๋ฒํธ">
<input type="text" name="memberName" id="memberName" th:value="${member.memberName}" placeholder="์ด๋ฆ">
<input type="submit" value="์์ ">
<input type="button" value="์์ (put๋ฐฉ์)" th:onclick="memberUpdate()">
<!-- ๋๋ฅผ ์ ๋ฐ๋ก ๊ฐ์ง๋๊ฒ ์๋ ๋ฌด์ธ๊ฐ ๋์ ํ ๊ฐ๊ฒํ๊ณ ์ถ์ ๋ ํ์
์ ๋ฒํผ์ผ๋ก ์ฌ์ฉ -->
</form>
</body>
</html>
JPA์์ ์ง์ํ๋ ๊ธฐ๋ฅ ์ค ํ๋์ธ๋ฐ, save ๋ฉ์๋, ์ฆ ํ์๊ฐ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉ ์
์๋์ผ๋ก DB์์ ๊ธฐ์กด์ ๋ฐ์ดํฐ๊ฐ ์๋์ง ๋น๊ต ํ ์์ ์ ์ ๋ฐ์ดํธ ์ฟผ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค
๊ทธ๋์ ์ ๋ฐ์ดํธ ์ฟผ๋ฆฌ๋ฅผ ์ผ์ผํ ์ธ ํ์ ์์ด save ๋ฉ์๋๋ฅผ ๋ถ๋ฅด๋ ๊ฒ๋ง์ผ๋ก๋ ์ ๋ฐ์ดํธ๊น์ง ๊ฐ๋ฅํฉ๋๋ค!!
์ผ๋ฐ ๋ฐฉ์๊ณผ Put๋ฐฉ์ (Rest API) ๋ฐฉ์์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํ๋๋ง ์์ต๋๋ค :D
๊ทธ๋ผ ํจ๊ป ๋ณด์์ฃ !
// Interface์ ์๋ ์ฝ๋ ์ถ๊ฐ.
Long update(MemberDetailDTO memberDetailDTO);
@Override
public Long update(MemberDetailDTO memberDetailDTO) {
// update ์ฒ๋ฆฌ ์ save ๋ฉ์๋ ํธ์ถ
// ๊ธฐ์กด์ ์๋ ์ ๋ณด๋ฉด ์์์ ์
๋ฐ์ดํธ ์ฟผ๋ฆฌ ์ํ
// MemberDetailDTO -> MemberEntity๋ก ๋ณํํด์ค์ผํจ.
// ๋ฐ๊พธ๊ณ ์ ํ๋ ๋์ ํด๋์ค์ ํด๋น ๋ฉ์๋๊ฐ ์์ฑ๋์ด์ผํจ.
MemberEntity memberEntity = MemberEntity.toUpdateMember(memberDetailDTO);
Long memberId = mr.save(memberEntity).getId();
return memberId;
}
์ฌ๊ธฐ๊น์ง ์ ์ค์ จ๋ค๋ฉด ์์ ๊น์ง๋ ๋ฌธ์ ์์ด ์ ๋์ํ ๊ฒ๋๋ค.
ํ์๊ด๋ฆฌ ์์ ๋ฅผ ์ ๋ฐ๋ผ์ค์๋๋ผ ์๊ณ ๋ง์ผ์ จ์ต๋๋ค.
ํ์๊ด๋ฆฌ ์์ 1 ๋ถํฐ ์ด๋ ๊ฒ ๊ธธ์ด์ง์ง๋ ๋ชฐ๋์๋๋ฐ ์ด ๊ธ์ ๋ณด๊ณ ์๋ค๋ฉด ์ ๋ฐ๋ผ์ค์ ๊ฑฐ๋ผ ๋ฏฟ์ต๋๋ค :D
๋ค์ ์๊ฐ์๋ ํ์๊ด๋ฆฌ ์์ ์ ์ด Test ์ฝ๋์ ๋ํด ์์๋ณผ๋ ค๊ณ ํฉ๋๋ค!
๋ง์ฝ ๋ ์ถ๊ฐ๋๋ ๋ด์ฉ์ด ์๋ค๋ฉด ์๋ก์ด ์ ๋ฆฌ๊ธ์์ ๋ง๋๋๋ก ํด์!!
๋ค์ ์๊ฐ์ ๊ฑด๊ฐํ ๋ชจ์ต์ผ๋ก ๋ง๋์ :D