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)에서 많이 사용
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 학원 강의 ]
'Spring & Spring Boot' 카테고리의 다른 글
@Lombok 및 Entity 관련 어노테이션 (0) | 2024.07.25 |
---|---|
[Spring Boot] 댓글 등록 · 수정 · 삭제 (0) | 2024.06.07 |
[Spring Boot] 댓글 컨트롤러 계층 구현 (0) | 2024.06.01 |
[Spring Boot] 댓글 서비스 계층의 구현 (0) | 2024.06.01 |
[Spring Boot] 다대일ManyToOne 연관관계, 댓글 수 반영 화면 구현 (0) | 2024.05.31 |