이번에는 댓글관련부분을 작성해보려고 합니다.  댓글에 대한 댓글은 구현하지않았고 자유게시판에만 댓글이 가능하도록 구성하였습니다.

 

1.  엔티티및 레포지로티 설정

1-1 commentEntity.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "comment")
public class CommentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String content;
    private String writer;
    private LocalDateTime timestamp;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "frboardid")
    private FreeBoardEntity freeBoard;
}

@GeneratedValue(strategy = GenerationType.IDENTITY)

엔티티의 Primary Key값이 db에 의해 자동으로 생성되도록 지정해줍니다.

 

@ManyToOne(fetch = FetchType.LAZY)

다대일관계를 나타내는 어노테이션으로 LAZY로딩 전략은 연관된 객체를 필요로 할때만 로드하여 성능을 최적화시킵니다. 즉, 객체를 사용할때까지 실제 데이터베이스 조회를 연기합니다.

 

@JoinColumn(name = "frboardid")

어노테이션은 현재 엔티티가 참조하는 다른 엔티티의 기본 키를 가리키는 외래 키(Foreign Key) 열을 매핑합니다. 여기서 frboardidCommentEntity가 참조하는 FreeBoardEntity의 기본 키를 나타냅니다.

 

댓글에 대한 id값, 내용, 작성자, 작성시간 그리고 어느게시글에 작성했는지 알기위한 연관관계가 필요합니다.

Freeboard : Reply : User -> 1: N : 1

한게시글에 여러 개의 댓글과 한 유저가 여러개의 댓글을 달 수 있습니다.

 

1-2 CommentRepository.java

public interface CommentRepository extends JpaRepository<CommentEntity, Long> {
	
	// 특정 게시글 ID에 해당하는 모든 댓글을 조회하는 메서드 (MYPAGE 댓글작성목록을 확인할때 사용됩니다.)
	List<CommentEntity> findByFreeBoard_Frboardid(Integer frboardid);
	
	// 특정 게시글 ID에 해당하는 댓글 수를 카운트하는 메서드(MYPAGE 작성한댓글수를 확인할때 사용됩니다)
	int countByFreeBoard_Frboardid(Integer frboardid);
	
	// 특정 게시글과 연관된 모든 댓글을 삭제하는 메서드 (게시글을 삭제했을떄 댓글도 삭제되어야하므로)
	@Transactional
	@Modifying
	@Query("DELETE FROM CommentEntity c WHERE c.freeBoard.frboardid = :frboardid")
	void deleteByFreeBoardId(Integer frboardid);
}

@Transactional은 일련의 데이터베이스 작업들이 모두 성공하거나 실패하는 것을 보장합니다.
이 경우, deleteByFreeBoardId 메서드가 데이터베이스 작업을 수행할 때, 작업들이 모두 성공하거나, 오류 발생 시 롤백(원 상태로 되돌림)이 일어나도록 합니다.

 

@Modifying은 메서드가 데이터를 변경하는 쿼리(예: DELETE, UPDATE)를 실행함을 명시합니다.
@Query와 함께 사용되며, 데이터 조회가 아닌 수정, 삭제 등의 작업을 수행합니다.

 

1-3. 프론트엔드부분 HTML

Freeboard.html

<!-- 댓글 목록 -->
<section>
    <ul class="list-unstyled">
        <li th:each="comment : ${comments}">
            <div class="comment-content" id="comment-${comment.id}">
                <strong th:text="${comment.writer}"></strong>
                <p th:text="${comment.content}"></p>
                <small th:text="${#dates.format(comment.timestamp, 'yyyy-MM-dd HH:mm')}"></small>
                <!-- 댓글 수정 및 삭제 버튼 -->
                <button class="edit-comment" th:data-comment-id="${comment.id}">수정</button>
                <button class="delete-comment" th:data-comment-id="${comment.id}">삭제</button>
            </div>
        </li>
    </ul>
</section>

 

 

 

2. 댓글 작성 부분

2-1.  프론트엔드 html     Freeboard.html

<!-- 댓글 작성 폼 -->
<form th:action="@{/community/freeboard/{frboardid}/addComment(frboardid=${freeboard.frboardid})}" method="post">
    <textarea name="content" required placeholder="댓글을 입력하세요"></textarea>
    <button type="submit">댓글 등록</button>
</form>

 

댓글작성폼을 작성합니다.  이폼은 로그인한 사용자만 사용할수 있도록 해야합니다.

 

2-2.  FreeBoardController.java  comment구문 추가 

            // 댓글 추가 (로그인 필요)
		@PostMapping("/{frboardid}/addComment")
		public String addComment(@PathVariable Integer frboardid, CommentEntity comment, Principal principal) {
		    FreeBoardEntity board = frbService.freeBoardView(frboardid);
		    if (board == null) {
		     
		        return "redirect:/community/freeboard/list";
		    }
		    comment.setFreeBoard(board);// 댓글객체에 조회된 게시글 객체를 연결
		    comment.setWriter(principal.getName());  // 댓글작성자를 현재로그인된 사용자로 연결
		    comment.setTimestamp(LocalDateTime.now());  // 댓글작성시간을 현재시간으로
		    frbService.saveComment(comment); // 댓글객체를 db에 저장
		    return "redirect:/community/freeboard/view?id=" + frboardid;  //댓글추가완료후 상세페이지로 리다이렉트
		}

 

2-3.  FreeBoardService.java  comment구문 추가 

// 댓글저장
		 public CommentEntity saveComment(CommentEntity comment) {
		        return commentRepository.save(comment);
		    }

댓글을 저장할때는 게시글의id를 기반으로 해당게시물을 조회합니다.  saveComment는 설정된 댓글 객체를 데이터베이스에 저장합니다. 

 

 

3. 댓글 수정 및 삭제

3-1.  FreeBoardController.java 수정 및 삭제 구문 추가 

 

댓글수정

@PostMapping("/comment/{commentId}/update")
		public ResponseEntity<?> updateComment(@PathVariable Long commentId, @RequestBody Map<String, String> payload) {
		    CommentEntity existingComment = frbService.findCommentById(commentId).orElse(null); //해당id의 댓글내용을 찾습니다.
		    if (existingComment == null) {
		        return ResponseEntity.notFound().build(); // 댓글이 없는 경우 404 에러 반환
		    }
		    existingComment.setContent(payload.get("content")); // 찾은 댓글의 내용을 새로운 내용으로 업데이트 합니다.
		    frbService.updateComment(existingComment); // 업데이트된 댓글을 저장합니다.
		    return ResponseEntity.ok().build(); // 성공적으로 업데이트한 경우 OK 상태 코드 반환
		}

 

댓글삭제

		@PostMapping("/comment/{commentId}/delete")
		public String deleteComment(@PathVariable Long commentId) {
		    CommentEntity comment = frbService.findCommentById(commentId).orElse(null); 
		    if (comment == null) {
		        return "redirect:community/freeboard/list";   
		    }
		    Integer boardId = comment.getFreeBoard().getFrboardid();
		    frbService.deleteComment(commentId);   // 존재한다면 해당댓글을 삭제합니다.
		    return "redirect:/community/freeboard/view?id=" + boardId;
			}

@PostMapping("/comment/{commentId}/delete"): 특정 댓글 ID에 대한 삭제 요청을 처리합니다.
if (frbService.findCommentById(commentId).isPresent()): 해당 ID의 댓글이 존재하는지 확인합니다.
frbService.deleteComment(commentId): 존재한다면 해당 댓글을 삭제합니다.

 

 

3-2.  FreeBoardService.java 수정 및 삭제 구문 추가 

            // 댓글 업데이트
	    public void updateComment(CommentEntity comment) {
	        commentRepository.save(comment);
	    }
	    // 댓글 삭제
	    public void deleteComment(Long id) {
	        commentRepository.deleteById(id);
	    }

updateComment(CommentEntity comment)

 주어진 CommentEntity를 데이터베이스에 저장합니다. 이미 존재하는 ID의 경우 내용을 업데이트합니다.
deleteComment(Long id)

주어진 ID를 가진 CommentEntity를 데이터베이스에서 삭제합니다.

 

3-3.  프론트엔드 html     Freeboard.html 수정 삭제구문 추가

<div th:each="comment : ${comments}">
    <!-- 댓글 내용 -->
    <div th:text="${comment.content}"></div>
    <!-- 수정 버튼 -->
    <button th:attr="data-comment-id=${comment.id}" class="edit-comment-btn">수정</button>
    <!-- 삭제 버튼 -->
    <button th:attr="data-comment-id=${comment.id}" class="delete-comment-btn">삭제</button>
</div>

 

자바스크립트 Freeboard.js 생성

댓글수정 및 삭제 이벤트 처리

// 댓글 수정
document.querySelectorAll('.edit-comment-btn').forEach(btn => {
    btn.addEventListener('click', function() {
        let commentId = this.dataset.commentId;
        let newContent = prompt("댓글 내용을 수정하세요");
        if(newContent) {
            fetch(`/comment/${commentId}/update`, {
                method: 'POST',
                body: newContent
            }).then(response => {
                if(response.ok) {
                    alert("댓글이 수정되었습니다.");
                    location.reload();
                }
            });
        }
    });
});

// 댓글 삭제
document.querySelectorAll('.delete-comment-btn').forEach(btn => {
    btn.addEventListener('click', function() {
        let commentId = this.dataset.commentId;
        if(confirm("댓글을 삭제하시겠습니까?")) {
            fetch(`/comment/${commentId}/delete`, {
                method: 'POST'
            }).then(response => {
                if(response.ok) {
                    alert("댓글이 삭제되었습니다.");
                    location.reload();
                }
            });
        }
    });
});

자바스크립트를 사용하여 댓글의 수정 및 삭제 작업을 동적으로 처리합니다.
댓글 수정: 사용자가 '수정' 버튼을 클릭하면, 새로운 내용을 입력할 수 있는 프롬프트가 나타납니다. 새로운 내용이 입력되면 AJAX 요청을 통해 서버에 수정 요청을 보냅니다.
댓글 삭제: 사용자가 '삭제' 버튼을 클릭하면, 삭제 확인 메시지가 나타납니다. 사용자가 확인하면 AJAX 요청을 통해 서버에 삭제 요청을 보냅니다.