1.  비동기 처리와 Axios

대부분 프로그래밍의 시작은 항상 동기화된 방식을 이용.

result1 = doA();
result2 = doB(result1);
result3 = doC(result2);


  ⚡️  흔하게 볼 수 있는 동기화된 코드인데 doA()를 실행해서 나온 결과로 result1을 이용해서 doB()를 호출하는 방식
  ⚡️  코드는 doA() -> doB() -> doC()의 순서대로 호출됨

  📍  동기화된 방식의 단점은 doA()의 실행이 완료되어야만 doB()의 실행이 가능함. 즉 doA()의 결과를 반환할 때까지 다른 작업은 실행되지 않기 때문에 동시에 여러 작업을 처리할 수없음

  📍  비동기 방식은 커피 가게에 여러 명의 점원이 있는 상황과 유사. 점원이 여러 명이면 한 명은 주문을 계속 받고, 다른 점원은 계속해서 커피를 제조할 수 있음. 
    ➡️  비동기 방식의 핵심은 '통보'. 비동기는 여러 작업을 처리하기 때문에 나중에 결과가 나오면 이를 '통보'해 주는 방식을 이용.
         이러한 방식을 전문용어로는 콜백 callback이라고 함.

  📍  비동기 방식은 'doA()'를 호출할 때 doB()를 해 줄 것을 같이 파라미터로 전달

function doA(callback) {
...
result1 = ....
callback(result1)
}


  ⚡️  파라미터로 전달되는 콜백을 내부에서 호출하는 코드

 

  📍 자바 스크립트에서 함수는 '일급 객체 first-class object'로 일반 객체와 동일한 위상을 가지고 있으므로 파라미터가 되거나 리턴타입이 될 수 있음
  📍  비동기 방식에서 콜백을 이용하는 것이 해결책이 되기는 하지만 동기화된 코드에 익숙한 개발자들에게는 조금만 단계가 많아져도 복잡한 코드를 만들어야 하는 불편함이 있음
    ➡️  자바 스크립트에서는 Promise하는 개념을 도입해서 '비동기 호출을 동기화된 방식'으로 작성할 수 있는 문법적인 장치가 있는데 Axios는 이를 활용하는 라이브러리
    ➡️  Axios를 이용하면 Ajax를 호출하는 코드를 작성할 때 마치 동기화된 방식으로 작성할 수 있어서 자바 스크립트를 기반으로 하는 프레임워크 (Angula)나 라이브러리 (React, Vue)에서 많이 사용

 

시작하기 | Axios Docs

시작하기 브라우저와 node.js에서 사용할 수 있는 Promise 기반 HTTP 클라이언트 라이브러리 Axios란? Axios는 node.js와 브라우저를 위한 Promise 기반 HTTP 클라이언트 입니다. 그것은 동형 입니다(동일한 코

axios-http.com

 


2.  Axios를 위한 준비

Axios를 활용해 Ajax를 이용하기 위해서는 댓글 처리가 필요한 화면에 Axios 라이브러리를 추가해주어야 함
자바 스크립트 코드의 경우 read.html에서는 주로 이벤트 관련된 부분을 처리하도록 하고 별도의 JS 파일을 작성해서 Axios를 이용하는 통신을 처리하도록 구성

static 폴더에 있는 js 폴더에 reply.js 파일을 추가
  • read.html의 <div layout:fragment="content">가 끝나기 전에 Axios 라이브러리를 추가 하고 reply.js 파일도 같이 추가
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">
</script>
<script src="/js/reply.js"></script>

 

read.html에 댓글과 관련된 화면 구성을 위한 코드 추가
  • 댓글 작성 버튼
  • 댓글 목록
  • 댓글 목록 페이징
<div class="row mt-3">
    <div class="col-md-12">
        <div class="my-4">
        <!-- 댓글 작성 버튼 -->
            <button class="btn btn-info addReplyBtn">ADD REPLY</button>
        </div>
        <!-- 댓글 목록 -->
            <ul class="list-group replyList">

            </ul>
        </div>
        <div class="row mt-3">
            <div class="col">
            <!-- 댓글 목록 페이징 -->
                <ul class="pagination replyPaging">

                </ul>
            </div>
    </div>
</div>

 


1)  Axios 호출해 보기

  👾  reply.js에 간단하게 Axios를 이용하는 코드를 추가. Axios를 이용할 때 async / await를 같이 이용하면 비동기 처리를 동기화된 코드처럼 작성할 수 있음
      ⚡️  async는 함수 선언 시에 사용하는 데 해당 함수가 비동기 처리를 위한 함수라는 것을 명시하기 위해서 사용하고,
            await는 async 함수 내에서 비동기 호츨하는 부분에 사용

async function get1(bno) {
    const result = await axios.get(`/api/replies/list/${bno}`);
    console.log(result);
}

 

read.html에 get1()을 호출하는 코드를 작성
<script layout:fragment="script" th:inline="javascript">
    const bno = [[${dto.bno}]];
    get1(bno);
</script>

 

브라우저에서 댓글이 많이 달린 조회 페이지로 이동

 

 

A.  비동기 함수의 반환

 

  ✓  화면에서 결과가 필요하다면 Axios의 호출 결과를 반환받아야 하기 때문에 reply.js에서 코드 수정

async function get1(bno) {
    const result = await axios.get(`/api/replies/list/${bno}`);
    //console.log(result);
    return result.data;
}
<script layout:fragment="script" th:inline="javascript">
    const bno = [[${dto.bno}]];
    console.log(get1(bno));
</script>

 


3.  댓글 처리와 자바스크립트

1)  댓글 목록 처리

  👾  가장 먼저 개발하려는 기능은 댓글 목록 기능
  👾  댓글도 페이징 처리가 가능하도록 구성

reply.js에서 개발하려는 함수의 이름은 getList()라 하고, 파라미터는 다음과 같이 결정
  • bno : 현재 게시물 번호
  • page : 페이지 번호
  • size : 페이지당 사이즈
  • goLast : 마지막 페이지 호출 여부

    ⚡️  이 중에서 goLast는 조금 특별한 용도로 사용. 댓글의 경우 한 페이지에서 모든 동작이 이루어지므로 새로운 댓글이 등록되어도 화면에는 아무런 변화가 없다는 문제가 생김
    ⚡️  또한 페이징 처리가 되면 새로 등록된 댓글이 마지막 페이지에 있기 때문에 댓글의 결과를 볼 수 있다는 문제가 생김

    📍  goLast변수를 이용해서 강제적으로 마지막 댓글 페이지를 호출하도록 함

reply.js에 getList() 함수를 작성
async function getList({bno, page, size, goLast}) {
    const result = await axios.get(`/api/replies/list/${bno}?page=${page}`, {params: {page, size}})
    return result.data
}

 

read.html에는 getList()를 호출하는 함수와 현재 페이지가 로딩되면 해당 함수를 호출하도록 작성
function printReplies(page, size, goLast) {
    getList({bno, page, size, goLast}).then(
        data => {console.log(data);}
    ).catch(e => {
        console.error();
    });
}
printReplies(1, 10); // 무조건 호출

 

  👾  결과 데이터는 dtoList로 화면에 목록(replyList)을 처리하고, 나머지 정보들로 페이지 번호를 출력

 

read.html에는 댓글 목록을 출력하는 printList()와 페이지 번호를 출력하는 printPages() 함수를 작성하고 Axios의 결과를 출력하도록 수정
const bno = [[${dto.bno}]];
// console.log(get1(bno));

function printReplies(page, size, goLast) {
    getList({bno, page, size, goLast}).then(
    data => { 
        console.log(data);
        printList(data.list); // 목록 처리
        printPages(data); // 페이지 처리
    }
    ).catch(e => {
        console.error();
    });
}
printReplies(1, 10); // 무조건 호출

const replyList = document.querySelector('.replyList'); // 댓글 목록 DOM
const replyPaging = document.querySelector('.replyPaging'); // 페이지 목록 DOM

function printList(dtoList) { // 댓글 목록 출력
    let str = '';
    if(dtoList && dtoList.length > 0) {
        for (const dto of dtoList) {
            str += ` <li class="list-group-item d-flex replyItem">
                <span class="col-2">${dto.rno}</span>
                <span class="col-6" data-rno="${dto.rno}">${dto.replyText}</span>
                <span class="col-2">${dto.replyWriter}</span>
                <span class="col-2">${dto.regDate}</span>
            </li>`;
        }
    }
    replyList.innerHTML = str;
}

function printPages(data) { // 페이지 목록 출력
    // pagination
    page = data.page;
    let pageStr = '';
    
    if(data.prev) {
        pageStr += `<li class="page-item">
            <a class="page-link" data-page="${data.start - 1}">PREV</a></li>`;
    }
    for(let i = data.start; i <= data.end; i++) {
        pageStr += `<li class="page-item ${i === data.page ? "active" : ""}">
            <a class="page-link" data-page="${i}">${i}</a></li>`;
    }
    if(data.next) {
        pageStr += `<li class="page-item">
            <a class="page-link" data-page="${data.end + 1}">NEXT</a></li>`;
    }
    // console.log(pageStr);
    replyPaging.innerHTML = pageStr;
}

 


A. @JsonFormat, @JsonIgnore


  📍 출력된 댓글의 모양을 보면 등록 시간 regDate 부분이 배열로 처리되어서 지저분해 보임. 

         ➡️  RelyDTO에 @JsonFormat을 이용해서 JSON 처리 시에 포맷팅을 지정
  📍 댓글 수정 시간 modDate의 경우 화면에서 전혀 출력할 일이 없으므로 JSON 으로 변환될 때 제외하도록 @JsonIgnore를 적용

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime regDate;

@JsonIgnore
private LocalDateTime modDate;

 


B. 마지막 페이지로 이동


  📍 댓글 페이징은 새로 글이 추가되는 상황이 발생하면 마지막으로 등록되기 때문에 확인이 어려운 문제가 있음
        ➡️  이를 처리하려면 댓글 목록 데이터의 total을 이용해서 다시 마지막 페이지를 호출해야 함

    ⚡️  현재 게시물의 댓글에 마지막 페이지를 알아낸 후, 마지막 페이지를 다시 호출하는 방식으로 동작
          ✓  마지막 페이지의 호출은 total 값과 size 값을 이용해서 마지막 페이지를 계산하고 다시 Axios로 호출하는방식

 

reply.js의 getList()는 마지막 페이지로 호출할 수 있는 goLast 변수를 추가해서 수정
async function getList({bno, page, size, goLast}){

    const result = await axios.get(`/api/replies/list/${bno}?page=${page}`, {params: {page, size}})
    if(goLast) {
        const total = result.data.total
        const lastPage = parseInt(Math.ceil(total/size))

        return getList({bno:bno, page:lastPage, size:size})
    }

    return result.data
}

 

  📍  read.html에서 처음부터 댓글의 마지막 페이지를 보고 싶다면 printReplies()를 호출할 때 true 값을 추가

    //printReplies(1, 10); // 무조건 호출
    printReplies(1, 10, true);

 

 

 

 

[ 내용 참고 : IT 학원 강의 ]

+ Recent posts