[v3] springboot 블로그 만들기-6
ajax 비동기 통신을 활용한 댓글 작성 기능 구현
form 도 데이터를 서버로 전송할 때 사용되는데 ajax 를 사용한 이유는 통신 방식의 차이 때문이다.
Sep 10, 2024
비동기 댓글 등록 구현
기존 코드는 댓글 작성을 폼 처리 형식으로 구현 했다.
이는 매번 댓글이 작성될 때 마다 페이지를 새로 그려 트래픽에 문제를 발생시킬 가능성이 크다.
따라서 AJAX를 이용한 비동기 통신을 사용하여 댓글 등록을 할 것이다.
댓글을 등록하기 위해서는 이 댓글이 어떤 게시글에 속해있는지 알아야한다.
게시글의 정보를 폼 데이터에 숨겨두는 방법은 다음과 같다.
<div class="card-body">
<form>
<input type="hidden" id="boardId" value="{{model.id}}">
<div id="boardId2" data-hello="{{model.id}}"></div>
<textarea class="form-control" rows="2" id="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<input type="hidden" id="boardId" value="{{model.id}}">
<div id="boardId2" data-hello="{{model.id}}"></div>
이런 형식으로 댓글 폼 내부에 board id 를 넣을 수 있으며
let boardId = $("#boardId2").data("hello");
let boardId2 = document.querySelector("#boardId2").dataset.hello;
이렇게 추출할 수 있다.
댓글 저장 DTO
public class ReplyRequest {
@Data
public static class SaveDTO {
private Integer boardId;
private String comment;
// insert into reply_tb(comment, board_id, user_id, created_at) values('댓글1', 5, 1, now());
// 바로 boardId 받아올 수 없음 빌더의 board 는 orm 이라서
public Reply toEntity(User sessionUser, Board board) {
return Reply.builder()
.comment(comment)
.user(sessionUser)
.board(board)
.build();
}
}
}

AJAX 통신은 jsonData 를 리턴받기 때문에 파라미터에 @RequestBody 가 붙는다.

작성이 완료된 댓글은 화면에 바로 추가 되어야 하기 때문에 저장 정보를 담은 DTO 를 리턴한다.
public ReplyResponse.DTO 댓글쓰기(ReplyRequest.SaveDTO saveDTO, User sessionUser) {
//1 게시글 존재유무 확인
System.out.println(saveDTO.toString());
Board boardPS = boardRepository.findById(saveDTO.getBoardId())
.orElseThrow(()-> new ExceptionApi404("게시글을 찾을 수 없습니다"));
//2. 비영속 댓글 객체 만들기
Reply reply = saveDTO.toEntity(sessionUser, boardPS);
//3. 댓글 저장 이 코드를 통해 영속 개체가 되었음
replyRepository.save(reply);
return new ReplyResponse.DTO(reply);
}
JAP에서는
save()
를 호출하면 데이터가 데이터베이스에 저장된다.
저장된 엔티티는 영속성 컨텍스트
에서 관리되어 해당 엔티티의 모든 필드 값이 사용 가능해진다.
즉, 리턴되는 reply
는 PK 값을 갖고 있게된다. (별도의 select 조회가 필요 없음)mustache 폼 수정
등록 폼
<div class="card-body">
<form >
<input type="hidden" id="boardId" value="{{model.id}}">
<textarea class="form-control" rows="2" id="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="button" onclick="saveReply()" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
ajax 요청 코드
<script>
async function saveReply(){
//1. reply 객체 만들기 (id 로 찾아)
let reply = {
comment : $("#comment").val(),
boardId : $("#boardId").val()
};
//2. fetch 요청
let response = await fetch(`/api/reply`,{
method : "post",
body: JSON.stringify(reply),
headers: {
"Content-type":"application/json; charset=utf-8"
}
});
let responseBody = await response.json(); // dto
console.log(responseBody);
//3. csr 하기
}
</script>

처리결과
이제 받아온 댓글 정보를 화면에 반영해야 한다.
어차피 isowner 은 true 일거라 굳이 보여줄 필요 없음 따라서 삭제

function replyItem(reply) {
return `<div id="reply-${reply.id}" class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">${reply.username}</div>
<div>${reply.comment}</div>
</div>
<button onclick="deleteReply('${reply.id}')" type="button" class="btn">🗑</button>
</div>`;
}
replyItem 라는 함수를 만들어 댓글 데이터를 바인딩 한다.
이후 ajax 요청코드의 3번. csr 하기 자리에 해당 코드를 추가한다.
//3. CSR 하기
$("#reply-box").prepend(replyItem(responseBody.body));
$("textarea").val(""); //댓글 입력이 완료되면 기존에 있던 text 제거
로그인 상태에 따른 댓글 등록 처리
로그인 안되어 있으면 세션에 저장된 정보가 없어 오류가 발생한다.
따라서 미리 세션을 확인하여 로그인된 유저만 댓글 작성창을 보여주도록 조정했다.

로그인할 때 저장한
sessionUser


마무리
ajax
를 사용한 댓글 등록 기능을 만들어 보았다.
form 도 데이터를 서버로 전송할 때 사용되는데 ajax 를 사용한 이유는 통신 방식의 차이 때문이다. form 요청시, 서버에서 응답을 받으면 전체 화면을 리로드 하게 되고 이는 많은 트래픽 발생을 유발한다. 또한, 사용자 경험도 비동기 통신에 비해 떨어진다.
ajax 를 사용하게 비동기 통신이 가능해져 부분 랜더링이 가능하다. 따라서 트래픽 감소로 이어진다. 화면의 깜빡임이 없기 때문에 사용자 경험도 개선된다. 이처럼 댓글 작성같은 빠른 응답과 간단한 데이터 처리가 필요할 때는
ajax
를 통한 비동기 통신을 추천한다.SpringBoot 블로그 만들기 - v3 시리즈 1. https://inblog.ai/hj/v3-시작-27809 (개발환경 설정 및 post 맨 이용한 api 테스트) 2. https://inblog.ai/hj/v3-springboot-블로그-만들기-2-28708 (댓글 엔티티 생성 및 양방향 매핑) 3. https://inblog.ai/hj/v3-springboot-블로그-만들기-3-28793 (댓글 조회하기 완료) 4. https://inblog.ai/hj/v3-rest-api-를-위한-exception-설정-28848 (REST API 위한 익셉션 핸들러 구현) 5. https://inblog.ai/hj/v3-springboot-블로그-만들기5-28859 (댓글 삭제 기능 구현) 6. https://inblog.ai/hj/v3-springboot-블로그-만들기6-29071 (ajax 를 사용한 댓글 작성) 7. https://inblog.ai/hj/v3-springboot-블로그-만들기7-29077 (게시물 검색 기능 구현) 8. https://inblog.ai/hj/v3-springboot-블로그-만들기8-29073 (유효성 검사)
Share article