회원가입/ 로그인 기능을 끝마친 후 나는 게시글 상세화면에 대한 js작업과 thymeleaf작업을 진행하였다.
게시글 쓰는 페이지는 다른 팀원이 하기로 하고 나는 메인페이지에서 게시글을 클릭했을 때 나오는 게시글 상세화면을 만들었다.
해당 게시글이 자신이 쓴 게시글이라면 게시글 수정 및 삭제 버튼 활성화
해당 게시글 thymeleaf 작업
해당 게시글의 댓글 thymeleaf 작업
이 부분이 사실 게시글 상세화면 부분에서 가장 어려운 부분이라고 생각한다.
우선 게시글 상세화면은 로그인세션이 있는 상태, 로그인이 되어있지 않은 상태 둘다 해당 페이지를 들어올 수 있기 때문에 게시글 수정 및 삭제 버튼은 게시글의 주인이 로그인하지 않는이상 활성화 되면 안된다.
이 부분을 어떻게 하면 좋을까 곰곰히 생각해보았다.
해당 게시글의 index와 로그인된 유저의 index가 같으면 해당 버튼들이 활성화 되어야 한다.
그래서 게시글을 가져올때의 메서드에 thymeleaf값 하나를 가져와서 만들기로 생각했다.(나중에 좋은 방법이 생각났다.)
@GetMapping("/post/{postId}")
public String read(HttpSession session, @PathVariable(name = "postId") Long postId, Model model) {
Long userIndex = (Long) session.getAttribute("userIndex");
model.addAttribute("userIndex", userIndex);
// 게시글 model
Optional<PostEntity> post = postService.read(postId);
post.ifPresent(o -> model.addAttribute("post", o));
// 세션을 가져와서 만약 게시글, 댓글 userIndex와 같다면
// 1을 출력해 수정 및 삭제 버튼 활성화
// 로그인 했지만, 다르면 0
// 로그인하지 않았다면, 2 출력
// 수정 필요
Integer checkedUserIndexForPost = 0;
if(userIndex != null){
if(userIndex == post.get().getUserIndex()){
// 게시글, 댓글, 세션이 같으면
checkedUserIndexForPost = 1;
model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
} else if(userIndex != post.get().getUserIndex()){
checkedUserIndexForPost = 2;
model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
}
}
else if(userIndex == null){
model.addAttribute("checkIndexForPost", checkedUserIndexForPost);
}
return "post_detail";
}
가장 먼저 해당 게시글을 가져와 model화 해준다.
그 후 userIndex가 있을 때 없을 때를 비교하고 없다면 2,
로그인하여 userIndex가 있지만, 게시글 index와 다르다면 0,
해당 게시글이 로그인한 사용자의 게시글이면 1을 반환하여 model에 넣어주었다.
이 값을 js에서 받아서 확인하는 방식으로 진행하였다.
$(document).ready(() => {
var index_button = $("input[name=index_button]").val();
if (index_button == 1) {
console.log(index_button);
$(".deleteEdit").css("display", "flex");
}
});
$("input[name=index_button]").val();
이 부분은 해당 타임리프 값을 input hidden 값으로 html에 집어넣어 해당 value를 가져오게 만든 것이다.
<input type="hidden" name="index_button" th:value="${checkIndexForPost}"/>
사실 어짜피 로그인세션의 userIndex를 model화 한다면, 위의 방법보다, userIndex의 value값을 가져오고, thymeleaf로 가져온 게시글 model에서 userIndex를 뽑아와 그 둘을 비교시켜도 되었을 것이다.
그것이 유지보수에 좀 더 도움이 되었을 것이다.
나중에 해당 프로젝트를 리펙토링하게 된다면 이 부분을 고쳐주고 싶다.
해당 thymeleaf 작업은 너무 쉬워서 넘어가겠다.
댓글 작성은 form 태그를 이용하여 구현하였다.
여기서 댓글을 작성한 후 해당 댓글을 보게 되면 만약 로그인한 유저가 해당 댓글을 썼다면, 수정 및 삭제 버튼이 생긴다.
이 부분을 위에 게시글 수정 삭제 버튼의 개선사항으로 만들어 보았다.
thymeleaf의 th:style을 이용하여 만약 같다면 해당 display를 활성화 시키는 방법으로 만들었다.
<div
class="deleteEditC"
th:style="${reply.replyUserIndex == userIndex ? 'display:flex' : 'display:none'}"
>
<button class="editC">수정</button>
<form
th:action="@{/reply/delete/{replyIndex}(replyIndex=${reply.replyIndex})}"
method="post"
>
<input type="hidden" name="_method" value="delete" />
<button class="deleteC">삭제</button>
</form>
</div>
각각의 댓글의 userIndex를 가져와 만약 로그인세션의 userIndex와 같다면 해당 버튼들을 활성화 하고 다르면 비활성화 하게 만들었다.
댓글 수정은 ajax를 이용하여 비동기 방식으로 구현하였다.
document.addEventListener("DOMContentLoaded", function () {
// Addeventlisteners "수정" 버튼
function handleEditClick(event) {
const commentBox = event.target.closest(".commentBox");
const commentText = commentBox.querySelector(".comment");
const commentContent = commentText.innerText;
const textarea = document.createElement("textarea");
textarea.classList.add("editTextarea");
textarea.name = "editedComment";
textarea.value = commentContent;
const saveButton = document.createElement("button");
saveButton.classList.add("saveC");
saveButton.innerText = "저장";
const editDeleteContainer = commentBox.querySelector(".deleteEditC");
editDeleteContainer.innerHTML = "";
commentText.innerHTML = "";
commentText.appendChild(textarea);
editDeleteContainer.appendChild(saveButton);
//기능 삭제
event.target.removeEventListener("click", handleEditClick);
saveButton.addEventListener("click", function () {
const editedComment = textarea.value;
var reply_index = $("input[name=reply_index]").val();
$.ajax({
url: "/reply/edit/" + reply_index,
type: "POST",
data: {
replyDescription: editedComment,
},
success: function (response) {
console.log("업데이트에 성공했습니다.");
commentText.innerText = editedComment;
editDeleteContainer.innerHTML = "";
const editButton = document.createElement("button");
editButton.classList.add("editC");
editButton.innerText = "수정";
const deleteButton = document.createElement("button");
deleteButton.classList.add("deleteC");
deleteButton.innerText = "삭제";
editDeleteContainer.appendChild(editButton);
editDeleteContainer.appendChild(deleteButton);
//다시 적용
editButton.addEventListener("click", handleEditClick);
},
});
});
}
const editButtons = document.querySelectorAll(".editC");
editButtons.forEach((button) => {
button.addEventListener("click", handleEditClick);
});
});
수정 버튼을 눌렀을 때, handleEditClick함수가 실행되어 textarea와 저장 버튼을 추가 시킨뒤 저장 버튼을 눌렀을 때 ajax로 수정이 가능하게 만들었다.
삭제 버튼은 form 태그를 이용하여 바로 삭제 가능하게 구현하였다.