728x90

저번에 작성한 댓글 기능 구현 코드를 REST API 규칙에 맞게 수정하도록한다.

 

* 이전 댓글 구현 글

https://black-mint.tistory.com/35

 

[Spring Boot] Ajax(비동기) 통신으로 댓글 구현 (+ Jquery 사용법)

게시판 댓글을 구현하는 도중 비동기 호출에 대해 알게 됐고, 이를 이용하려면 Ajax를 활용해야 한다는 정보를 얻었다. 비동기란? 비동기의 반대인 동기적 통신의 경우 절차적으로 일을 차례로

black-mint.tistory.com


1. REST(Representational State Transfer) API 란?

  • 네트워크 아키텍처 원리의 모음
  • 네트워크 아키텍처 : 자원을 정의하고 자원에 대한 주소를 지정하는 방법 전반을 의미
  • 예를 들어 학생

2. REST API 설계

  • URI는 정보의 자원을 표현
  • 자원에 대한 행위로 HTTP Method(GET, POST, PUT, PATCH, DELETE)로 표현
GET 데이터를 조회 (게시글 조회) GET /boards/1
게시글 중 1번 게시글을 조회
POST 데이터를 등록 (게시글 작성) POST /boards
게시글 등록
PATCH 데이터를 일부 수정 (게시글 수정) PATCH / boards/1
게시글 중 1번 게시글을 수정
PUT 데이터를 전체적으로 수정 PUT /boards/1
게시글 중 1번 게시글을 수정
DELETE 데이터를 삭제 DELETE /boards/1
게시글 중 1번 게시글을 삭제

3. REST API 규칙

  • 소문자로 작성하고 밑줄(_) 대신 하이픈(-)을 사용
  • 동사가 아닌 명사로 작성
  • 슬래시 구분자(/)는 계층 관계를 나타낼 때 사용하고 URI 마지막에 쓰지 않는다.
  • URI에 파일 확장자는 작성하지 않는다.

이 외 규칙이 많지만 이러한 2~3번 규칙을 잘 지켜서 만든 API를 RESTful API라고 한다.


4. 컨트롤러

@RequestMapping("/comments")
@RestController
public class CommentController {

    @Autowired
    private CommentService commentService;

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

    // 댓글 작성
    @PostMapping("/{boardId}")
    public void commentWrite(@PathVariable(value = "boardId") Long boardId,
                             @RequestBody Comment comment,
                               Principal principal) throws Exception {
        String username = principal.getName();
        commentService.write(boardId, comment.getContent(), username);
    }

    // 댓글 수정
    @PatchMapping("/{commentId}")
    public void updateComment(@PathVariable(value = "commentId") Long commentId,
                              @RequestBody Comment comment) throws Exception {
        commentService.update(commentId, comment.getContent());
    }

    // 댓글 삭제
    @DeleteMapping("/{commentId}")
    public void deleteComment(@PathVariable(value = "commentId") Long commentId) throws Exception {
        commentService.delete(commentId);
    }
  • @RestController : 클래스 레벨에 선언하면 이전에 각 매핑마다 @ResponseBody 선언 했던 것을 하지 않아도 된다.
  • @ResponseBody : 해당 어노테이션이 선언된 매핑은 HTTP의 BODY에 자바 객체를 직접 반환한다.
  • @RequestBody : View에서 받아오는 JSON데이터를 파싱해준다. (변환할 데이터를 매핑 가능하도록 필드명 맞춰줘야함) 단, Content-Type이 multipart/form-data로 전달받을 때는 오류를 일으킨다. (주로 파일, 이미지를 전달받을 때)
  • @PathVariable : REST방식에서 주로 사용하며, @RequestParam과 유사. URI에 전달받을 변수를 지정

5. Ajax 통신 스크립트 코드

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

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

            $.ajax({
                type: 'GET',
                url: url,
                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;">' + moment(value.createDate).format("YYYY-MM-DD HH:mm") + '</p></div>'
                    });
                    $("#count").html(size)
                    $("#comment").html(a)
                },
                error: function (response) {
                    console.log("getComments error : " + response)
                },
                complete: function () { }
            })
        }

        function insertComment() {
            var boardId = $('input[name=boardId]').val()
            var content = document.getElementById("content").value
            var param = {"content": content}
            var url = '/comments/' + boardId

            if (isEmpty(content) == true) {
                alert('댓글을 입력해주세요.')
                return false;
            } else {
                $.ajax({
                    contentType: 'application/json',
                    type: 'POST',
                    url: url,
                    data: JSON.stringify(param),
                    success: function (response) {
                        getComments()
                    },
                    error: function (response) {
                        console.log("insertComment error : " + response)
                    },
                })
            }
        }

        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
            var param = {"content": content}
            var url = '/comments/' + commentId

            if (isEmpty(content) == true) {
                alert('댓글을 입력해주세요.')
                return false;
            } else {
                $.ajax({
                    contentType: 'application/json',
                    type: 'PATCH',
                    url: url,
                    data: JSON.stringify(param),
                    success: function (response) {
                        getComments()
                    },
                    error: function (response) {
                        console.log("updateComment error : " + response)
                    },
                    complete: function () { }
                })
            }
        }

        function deleteComment(id) {
            var commentId = id
            var url = '/comments/' + commentId

            if (confirm("정말 삭제하시겠습니까?")) {
                $.ajax({
                    type: 'DELETE',
                    url: url,
                    success: function (response) {
                        getComments()
                    },
                    error: function (response) {
                        console.log("deleteComment error : " + response)
                    },
                    complete: function () { }
                })
            } else {
                return;
            }
        }
        function isEmpty(strIn) {
            if (strIn === undefined) {
                return true;
            }
            else if (strIn == null) {
                return true;
            }
            else if (strIn == "") {
                return true;
            }
            else {
                return false;
            }
        }
    </script>
  • 이전 글과 바뀐 부분
    • Json으로 서버에 데이터를 보내주기 위해 contentType을 json으로 설정
    • url을 REST API 규칙에 맞춰 작성
    • data: json.stringify( ) : ajax 통신의 데이터 전달부분을 미리 만들어둔 json형식의 자바스크립트 변수를 서버로 전달
    • type을 REST API 규칙에 맞춰 작성
    • 날짜 포맷을 변경하기 위해 moment라이브러리 사용
    • https://black-mint.tistory.com/51
 

[JavaScript] 날짜 포맷 변경 라이브러리

서버에서 Json 형태로 프론트로 넘어오면 날짜 형식이 다음과 같이 변경돼서 날아온다. "createDate": "Jan 5, 2022, 4:25:48 PM" 원하는 날짜 형식으로 바꿔 보여주고 싶을 때 사용할 라이브러리 https://m

black-mint.tistory.com

 

* REST 관련 참고 

https://congsong.tistory.com/30?category=749196 

+ Recent posts