728x90

게시판 댓글을 구현하는 도중 비동기 호출에 대해 알게 됐고, 이를 이용하려면 Ajax를 활용해야 한다는 정보를 얻었다.

비동기란?

  • 비동기의 반대인 동기적 통신의 경우 절차적으로 일을 차례로 하나씩 해 내려가는 것이다.
  • 비동기는 어떤 하나의 일을 하는 도중 기다리는 시간이 필요하다면 그 시간 동안 다른 일을 먼저 처리할 수 있도록 하는 것이다.
  • 즉, 절차적인 동기적 통신.   비절차적인 비동기 통신이라고 생각하면 된다!

Jquery 사용법과 Ajax를 통한 비동기 통신의 내용을 간단하게 정리. (1, 2번은 사용법)

만약 ajax를 사용할 때 동기적으로 실행하고 싶은 경우 코드에 async: false 를 붙여주면된다!

1. Jquery 시작

Jquery를 시작하기 위해 다음과 같은 코드를 html 내부에 작성한다.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  • 어디에 적어도 상관없다고 한다.
  • 대부분 </body> 바로 윗 부분 즉, 마지막 부분에 작성하는 것을 많이 볼 수 있었다.

2. (Jquery) javascript 코드 작성

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script>
        $(document).ready(function() {
            getAlert();
        })

        function getAlert() {
            alert('gd')
        }
    </script>
  • $(document).ready(function() {} : 문서가 준비되면 매개변수를 넣은 콜백함수를 실행하라는 의미
    • 여기서는 html파일이 로드되면 alert로 팝업을 띄우게 했다.

3. Ajax(비동기 통신) 및 자바스크립트(Jquery)

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script th:inline="javascript">
        $(document).ready(function () {
            getComments();
        })

        function getComments() {
            var loginUsername = [[${ loginUser }]]
            var boardId = $('input[name=boardId]').val()

            $.ajax({
                type: 'GET',
                url: '/board/comment/getCommentList',
                data: { boardId },
                success: function (response) {
                    var a = '';
                    var size = 0;
                    $.each(response, function (key, value) {
                        size = size + 1;
                        a += '<hr /><div>'
                        a += '<input type="hidden" id="commentId" name="commentId" value="' + value.id + '">'
                        a += '<span id="writer" style="font-weight: bold;">' + value.writer + '</span>'
                        if (value.writer == loginUsername) {
                            a += '<ul name="commentChange" class="justify-content-end" style="display: inline;">'
                            a += '<li name="commentUpdate" type="button" style="display: inline; opacity: 0.7; font-size: small; margin-right: 5px" onclick="updateCommentForm(' + value.id + ')">수정</li>'
                            a += '<li name="commentDelete" type="button" style="display: inline; opacity: 0.7; font-size: small;" onclick="deleteComment(' + value.id + ')">삭제</li></ul>'
                        }
                        a += '<pre id="' + value.id + '" name="comment' + value.id + '" style="margin-bottom: 5px; font-size: large;">' + value.content + '</pre>'
                        a += '<p name="createDate' + value.id + '" style="margin-bottom: 5px; opacity: 0.5; font-size: small;">' + value.createDate.substring(0, 10) + ' ' + value.createDate.substring(11, 19) + '</p></div>'
                    });
                    $("#count").html(size)
                    $("#comment").html(a)
                },
                error: function (response) {
                    console.log("error : " + response)
                },
                complete: function () { }
            })
        }

        function updateCommentForm(id) {
            var commentId = id;
            var content = document.getElementById(id).innerText;

            $('ul[name=commentChange]').hide()
            $('pre[name=comment' + commentId + ']').contents().unwrap().wrap('<textarea id="newComment" class="form-control mt-2" name="updateContent" rows="4"></textarea>');
            $('p[name=createDate' + commentId + ']').contents().unwrap().wrap('<input name="update" type="button" class="me-2 mt-2 btn btn-primary" value="수정하기" onclick="updateComment(' + commentId + ')">');
            $('input[name=update]').after("<button class=\"me-2 mt-2 btn btn-primary\" onclick=\"getComments()\">취소</button>")
        }

        function updateComment(id) {
            var commentId = id;
            var content = document.getElementById("newComment").value;

            $.ajax({
                type: 'POST',
                url: '/board/comment/update',
                data: { 
                    commentId:commentId,
                    content:content 
                },
                success: function (response) {
                    getComments()
                },
                error: function (response) {
                    console.log("update error : " + response)
                },
                complete: function () { }
            })
        }

        function deleteComment(id) {
            var commentId = id;

            if (confirm("정말 삭제하시겠습니까?")) {
                $.ajax({
                    type: 'POST',
                    url: '/board/comment/delete',
                    data: { commentId },
                    success: function (response) {
                        getComments()
                    },
                    error: function (response) {
                        console.log("delete error : " + response)
                    },
                    complete: function () { }
                })
            } else {
                return;
            }
        }
    </script>

댓글 [작성, 수정, 삭제]하는 동시에 페이지를 리로드하지 않고 비동기 통신으로 작성한 댓글을 바로 화면에 보여주는 코드이다. 즉, ajax 통신으로 수정이나 삭제 후 success: 에 getComments()를 호출하면 해당 페이지를 리로드 하지 않고 댓글이 최신화 된다. 

  • <script th:inline="javascript"> : 자바스크립에서 타임리프 변수를 쓰기위해 추가
  • [[${loginUser}]] : 컨트롤러에서 가져온 로그인해있는 사용자 아이디이다.
  • $('input[name=id]').val() : input 태그의 name이 id인 값을 가져와서 설정
    • 만약 $('input#idx').val() 이면 input태그의 id값이 idx인것을 가져와서 설정
    •  .val() : form 양식의 값을 설정하거나 가져옴
      • 만약 $('input#idx').val('abc') id가 idx인 input요소의 값을 abc로 설정
  • url : 서버의 컨트롤러에 호출할 url
  • data : 넘겨줄 데이터 (여기선 var id)
    • 여기서 들어가는 data 변수 이름은 컨트롤러의 인자명과 같아야 한다.
  • success : ajax 통신을 성공하고 서버로부터의 결과값을 response에 담아서 함수 실행
  • $.each(response, function(key, value) {}); : 서버에서 응답받은 데이터의 개수만큼 반복 (for or while)
    • 컨트롤러에서 List<Comment> comments 형태의 객체를 리턴했다.
    • key는 0, 1, 2, 3 ..
    • value.content 식으로 데이터 사용 가능. (comments.get(i).getContent와 동일)
    • size : 댓글 개수
    • $().html : 해당 태그의 요소를 수정
    • https://www.codingfactory.net/10324
  • if문을 이용해서 로그인한 사용자와 댓글 작성자가 동일하면 수정과 삭제를 가능하도록 버튼 표시한다.
  • error : ajax 통신을 실패하면 실행 (에러 정보 확인)
  • complete : success나 error가 끝나고 실행 (try catch의 finally와 동일)
  • 이외
    • datatype : 서버에서 받아올 데이터를 해석하는 형태 (xml, json 등)
    • cache : 요청 페이지의 캐시 여부 (true or false)
$('ul[name=commentChange]').hide()
  • name이 commentChange인 ul 태그를 숨김(한 댓글을 수정 중 다른 댓글을 수정, 삭제 못하게 함)
$('pre[name=comment' + commentId + ']').contents().unwrap().wrap('<p></p>')
  • 위 코드는 해당하는 name의 값을 가진 pre 태그를 p태그로 대체
$('input[name=a]').after("<button class=\"me-2 mt-2 btn btn-primary\" onclick=\"getComments()\">취소</button>")
  • 3번(ajax) 자바스크립트(jquery) 코드의 updateCommentForm 함수에 다음 코드를 추가해서 수정 버튼 옆에 취소버튼을 추가
  • 취소버튼 클릭 시 수정사항을 반영하지 않고 다시 댓글 목록을 보여줌
  • 이 외 자바스크립트 코드 https://black-mint.tistory.com/41
 

[JavaScript] 다른 태그 값, 양식 작성값(input, textarea ..)가져오기

1, 다른 태그 값 가져오기 var content = document.getElementById(id).innerText; 2. 사용자가 input 또는 textarea에 작성한 값 가져오기 (버튼 클릭시 실행) var content = document.getElementById("newCommen..

black-mint.tistory.com

4. 화면

                <!-- Comment -->
                <h4>댓글</h4>
                <div class="mb-5">
                    <div id="comment">
                    </div>

                    <form action="#" th:action="@{/board/comment/write}" method="post">
                        <input type="hidden" name="boardId" th:value="${board.id}">
                        <div class="mb-3">
                            <label for="content" class="form-label"></label>
                            <textarea class="form-control" id="content" name="content" rows="4"
                                placeholder="댓글을 작성해주세요."></textarea>
                        </div>
                        <button type="submit" class="me-2 btn btn-primary">write</button>
                    </form>
                </div>
  • div > id=comment : 작성된 댓글을 표시한 div 태그
  • 동적으로 댓글을 추가해주는 비동기 통신을 쓰기 때문에 3번 코드(자바스크립트)에 html이 닮겨 있다.

5. 컨트롤러

@Controller
@RequestMapping("/board/comment")
public class CommentController {

    @Autowired
    private CommentService commentService;

    // 댓글 작성
    @PostMapping("/write")
    @ResponseBody
    public void commentWrite(@RequestParam(name = "boardId", required = false) Long boardId,
                               @RequestParam(name = "content") String content,
                               Principal principal) throws Exception {
        String username = principal.getName();
        commentService.write(boardId, content, username);
    }

    // 댓글 조회
    @GetMapping("/getCommentList")
    @ResponseBody
    public List<Comment> getCommentList(@RequestParam(name = "boardId") Long boardId) throws Exception {
        List<Comment> comments = commentService.getCommentList(boardId);
        return comments;
    }

    // 댓글 수정
    @PostMapping("/update")
    @ResponseBody
    public void updateComment(@RequestParam(name = "commentId") Long commentId,
                              @RequestParam(name = "content") String content) throws Exception {
        commentService.update(commentId, content);
    }

    // 댓글 삭제
    @PostMapping("/delete")
    @ResponseBody
    public void deleteComment(@RequestParam(name = "commentId") Long commentId) throws Exception {
        commentService.delete(commentId);
    }
}
  • 댓글 작성
    • boardId : @RequestParam으로 url을 이용해 받는다. (현재 조회하고 있는 게시글)
    • content : 작성한 댓글 내용
  • 댓글 조회, 수정, 삭제
    • @ResponsBody : http요청의 body에 데이터를 넣어서 반환
    • @RequestParam(name = " ") : name은 ajax에서 보내주는 파라미터의 변수명과 같게 해야한다.

6. 서비스

    // 댓글 작성
    public void write(Long boardId, String content, String username) throws Exception {
        Comment comment = new Comment();
        Member member = memberService.getMember(username);

        comment.setBoardId(boardId);
        comment.setContent(content);
        comment.setWriter(member.getUsername());
        comment.setWriterId(member.getId());
        comment.setCreateDate(Timestamp.valueOf(LocalDateTime.now()));

        commentRepository.insertComment(comment);
    }

    // 댓글 조회
    public List<Comment> getCommentList(Long boardId) throws Exception {
        return commentRepository.selectCommentList(boardId);
    }

    // 댓글 수정
    public void update(Long commentId, String content) throws Exception {
        Comment comment = new Comment();

        comment.setId(commentId);
        comment.setContent(content);

        commentRepository.updateComment(comment);
    }

    // 댓글 삭제
    public void delete(Long commentId) throws Exception {
        commentRepository.deleteComment(commentId);
    }

7. 결과

시연 영상

 

+ Recent posts