SpringBoot 프로젝트

Spring Boot - 댓글 CRUD기능 구현하기 (2)

orin602 2024. 11. 22. 15:35

이번 글에서는 댓글 CRUD기능 중 수정(U)과 삭제(D)에 관한 글을 써보려고 합니다.

부족해도 이해하고 봐주세요... :)

 

1. html에 수정 버튼 만들기

<div class="reply-content">
    <h5><span th:text="${reply.member.name}"></span> : 
    <span th:text="${reply.content}"></span><br>
    <span th:text="${#dates.format(reply.reply_date, 'yyyy-MM-dd HH:mm')}"></span></h5>
    <button type="button" th:data-reply-seq="${reply.replySeq}" th:data-reply-member-id="${reply.member.id}" 
            th:data-login-user-id="${loginUser.id}" class="detail-replyedit-btn"
            onclick="replyEdit(this)">댓글수정</button><br>
    <button type="button" th:attr="data-reply-seq=${reply.replySeq}"
            class="detail-replylike-btn" onclick="replyLike(this)">좋아요</button>&nbsp;
    <span>좋아요 수 : <span th:text="${reply.likes}"></span></span>&nbsp;
    <button type="button" th:data-reply-seq="${reply.replySeq}" th:data-reply-member-id="${reply.member.id}" 
            th:data-login-user-id="${loginUser.id}" class="detail-replydelete-btn"
            onclick="replyDelete(this)">댓글삭제</button>
    <!-- th:attr은 속성 이름과 값을 동적으로 설정할 수 있게 한다. (JavaScript와 상호작용할 때 유용) -->
</div>

 

댓글 수정 버튼

<button type="button" th:data-reply-seq="${reply.replySeq}" th:data-reply-member-id="${reply.member.id}" 
    th:data-login-user-id="${loginUser.id}" class="detail-replyedit-btn"
    onclick="replyEdit(this)">댓글수정</button><br>

 

  • data-reply-seq 속성은 각 댓글의 고유 식별자인 replySeq 값을 담습니다.
  • data-reply-member-id 속성은 댓글 작성자의 ID를 담습니다.
  • data-login-user-id 속성은 현재 로그인한 사용자 ID를 담습니다.
  • onclick 속성은 버튼이 클릭되었을 때 실행할 JavaScript 함수(replyEdit)를 지정합니다.
  • replyEdit(this)에서 this는 현재 클릭된 버튼 요소를 가리키며, replyEdit 함수에서 data-reply-seq, data-reply-member-id, data-login-user-id를 이용할 수 있게 해줍니다.

 

2. 버튼 클릭 시 호출할 함수 작성 (JavaScript)

// 댓글 수정
function replyEdit(buttonElement) {
	// 댓글 작성자 id와 현재 로그인한 사용자 id 가져오기
	var replySeq = $(buttonElement).attr("data-reply-seq"); // 댓글 seq
	var replyMemberId = $(buttonElement).attr("data-reply-member-id"); // 댓글 작성자 ID
	var loginUserId = $(buttonElement).attr("data-login-user-id"); // 로그인한 사용자 ID
	
	// 댓글 작성자와 로그인한 사용자가 일치하는지 확인
	if(replyMemberId === loginUserId) {
		swal.fire({
			title: '댓글 수정',
			input: 'text',
			inputLabel: '수정할 댓글을 입력하세요.',
			inputPlaceholder: '댓글 내용을 입력해 주세요.',
			showCancelButton: true,
			confirmButtonText: '수정하기',
			cancelButtonText: '취소',
			inputValidator: (value) => {
				if(!value) {
					return '수정할 댓글 내용을 입력해야 합니다.';
				}
			}
		}).then((result) => {
			if(result.isConfirmed) {
				var updatedReply = result.value;
				
				$.ajax({
					url: '/update-reply',	// controller 요청 url
					type: 'PUT',
					contentType: 'application/json',
					data: JSON.stringify({
						replySeq: replySeq,
						content: updatedReply
					}),
					success: function(response) {
						swal.fire({
							title: '수정 완료',
							text: '댓글을 성공적으로 수정하였습니다.',
							icon: 'success',
							confirmButtonText: '확인'
						}).then(() => {
							location.reload();
						});
					},
					error: function(xhr, status, error) {
						swal.fire({
							title: '수정 실패',
							text: '서버에서 오류가 발생했습니다. 다시 시도해 주세요.',
							icon: 'error',
							confirmButtonText: '확인'
						});
					}
				});
			}
		});
	} else { // 댓글 작성자와 수정버튼을 누른 사용자가 다를경우
		swal.fire({
			title: '수정 불가',
			text: '댓글 작성자만 수정이 가능합니다.',
			icon: 'warning',
			confirmButtonText: '확인'
		});
	}
}
  • buttonElement에서 댓글 시퀀스(replySeq), 댓글 작성자 ID(replyMemberId), 로그인한 사용자 ID(loginUserId)를 data 속성에서 가져옵니다.
  • if(replyMemberId === loginUserId) { : 댓글 작성자 ID와 로그인 사용자 ID가 일치하면 댓글 수정 기능을 제공하고, 일치하지 않으면 수정이 불가능하다는 알림을 표시합니다.
  • SweetAlert2를 사용하여 댓글을 수정할 수 있는 입력 창을 표시하고, inputValidator: (value) => { 로 입력값이 없을 경우 return '수정할 댓글 내용을 입력해야 합니다.'; 경고 메시지를 띄웁니다.
  • 수정된 댓글 내용을 서버로 전송하기 위해 PUT 요청을 사용하여 /update-reply URL에 AJAX로 데이터를 전송합니다.
  • 성공 시 SweetAlert2로 수정 완료 메시지를 띄우고, 페이지를 새로 고칩니다.
  • 실패 시 에러 메시지를 표시합니다.

3. Controller 구현

// 댓글 수정 처리
@PutMapping("/update-reply")
public ResponseEntity<String> updateReply(@RequestBody Map<String, Object> request) {
    try {
        // 요청받은 데이터 추출
        int replySeq = Integer.parseInt(request.get("replySeq").toString());
        String updatedReply = request.get("content").toString();

        replyService.updateReply(replySeq, updatedReply);

        return ResponseEntity.ok("댓글이 성공적으로 수정되었습니다."); 
    } catch(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).
                body("댓글 수정에 실패했습니다. 다시 시도해 주세요.");
    }
}
  • @PutMapping은 HTTP PUT 요청을 처리하는 메서드임을 나타냅니다. PUT 요청은 주로 리소스를 업데이트하는 데 사용됩니다.
  • @RequestBody Map<String, Object> request : Map<String, Object>로 받는 이유는, 클라이언트가 JSON 형식으로 데이터를 보내며, replySeq와 content를 포함한 다양한 데이터를 전송할 수 있기 때문입니다. 각 데이터 항목은 String 타입의 키와 Object 타입의 값으로 매핑됩니다.
  • Integer.parseInt(request.get("replySeq").toString()) : Map에서 replySeq 값을 가져오고, 이를 Integer.parseInt()로 정수로 변환합니다.
  • request.get("content").toString() : Map에서 content 값을 가져옵니다. 이 값은 수정할 댓글의 새 내용입니다.

+ Service 메서드

@Override
@Transactional
public void updateReply(int replySeq, String content) {
    Optional<Reply> beforeReply = replyRepo.findById(replySeq); 
    if (beforeReply.isPresent()) {
        Reply reply = beforeReply.get();
        reply.setContent(content); // 댓글 내용 수정
        replyRepo.save(reply); // 수정된 댓글 저장
    } else {
        throw new IllegalArgumentException("잘못된 댓글 번호: " + replySeq); // 댓글이 없으면 예외 발생
    }
}

+++ 날짜도 수정하려면 reply.setReply_date(new Date()) 를 추가 하시면 됩니다.

 

테스트

id가 일치하지 않을 경우와 일치할 경우
아무것도 입력하지 않은 경우
수정 성공