Spring Boot To do List 비동기_01 전체 할 일 개수 조회, 완료된 할 일 개수 조회

송지윤·2024년 4월 15일
0

Spring Framework

목록 보기
24/65

동기 요청 a가 끝나면 b 시작 b 끝나면 c 시작
-> 동기 요청을 보내면 페이지 바뀔 때마다 새로고침 됨

비동기 요청 요청이 들어오면 바로 시작함 다른 요청이 끝날 때까지 기다ㅣ지 않음
-> 페이지 새로고침 되지 않음

main.html 에서 ajax/main.html 로 이동하게 만들기

common/main.html
a 태그 추가

<h3><a href="/ajax/main">TodoList - Ajax 버전</a></h3>

요청 받아줄 controller 생성
AjaxController

@Controller // 요청/응답을 제어 역할 명시 + Bean 등록
@Slf4j
@RequestMapping("ajax")
public class AjaxController {
	
	@GetMapping("main") // /ajax/main GET 요청 매핑
	public String ajaxMain() {
		
		// 접두사 : classpath:templates/
		// 접미사 : .html
		return "ajax/main";
	}
}

Ajax (Asynchronous JavaScript and XML)

Asynchronous == 비동기 (에이젝스, 아작스)
synchronous == 동기

동기식은 요청을 보냈을 때 응답이 돌아오기 전까지는 아무것도 못함

비동기적으로 서버와 브라우저 간에 데이터를 교환하는 기술로 웹 페이지를 새로고침 하지 않고도 서버로부터 데이터를 받아와서 웹 페이지의 일부분을 업데이트할 수 있도록 해주는 기술
-> 기존에는 웹 페이지를 다시 로드할 때 전체 페이지를 다시 받아와야했기 때문에 사용자 경험이 좋지 않았음
-> Ajax를 사용하면 웹 페이지를 로드한 후에도 웹 페이지와 서버 간에 데이터를 주고 받을 수 있으므로 사용자 경험을 향상시킬 수 있다.

비동기 요청 (ajax) html

resources/templates/ajax/main.html
css, js 연결

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TodoList - Ajax</title>

    <link rel="stylesheet" href="/css/ajax-main.css">
</head>
<body>
    <script src="/js/ajax-main.js"></script>
</body>
</html>

static/css/ajax-main.css

#popupLayer{
    width: 400px;
    height: 400px;
    border: 3px solid black;
    border-radius: 15px;
    background-color: white;
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); /* 그림자 효과 추가 */

    position: fixed; /* 브라우저에서 위치 고정 */

    /* 브라우저 정가운데 배치 */
    margin: auto;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;

    display: flex;
    flex-direction: column;
}
  
  
/* popup layer 행 */
.popup-row{
  padding: 10px;
  margin: 10px;
  border-bottom: 3px solid grey;

  /* 위치의 상대적 기준점 */
  position : relative;

  width: 90%;
}
  
  
/* popup layer 숨기기/보이기 */
.popup-hidden{ display: none !important; }
  
  
/* x 버튼 */
#popupClose{

  /* 절대적인 위치 지정(기준 내에서 아무곳에나 배치 가능) */
  position: absolute; 

  top: 0px;   /* 위쪽으로    부터 0px 떨어진 위치 */
  right: 10px; /* 오른쪽으로 부터 10px 떨어진 위치 */

  font-size: 30px;
  font-weight: bold;

  user-select: none; /* 드래그 방지 */

  cursor: pointer; /* 커서 손가락 모양 */
}
  
#popupClose:hover{ color :grey; }

#popupClose:active{ color : red; }


/* 버튼 영역 */
.btn-container{
  flex-grow: 1; /* 중심축 방향으로 팽창 */

  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
  margin: 15px;
}

.btn-container > button{ margin: 5px;}



/* ----------------------------------------------------- */

/* 수정 팝업 레이어 */
#updateLayer{
  width: 400px;
  height: 250px;
  border: 3px solid black;
  border-radius: 15px;
  background-color: white;

  position: fixed; /* 브라우저에서 위치 고정 */

  /* 브라우저 정가운데 배치 */
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;

  display: flex;
  flex-direction: column;
  align-items: center;
}


#updateTitle{ width: 300px; }

전체 Todo 개수/완료된 Todo 개수 보여주기

1. html id 값 넣어서 태그 작성

main.html

    <h3 id="todoHeader">
        전체 Todo 개수 : <span id="totalCount">0</span>개
        /
        완료된 Todo 개수 : <span id="completeCount">0</span><button id="reloadBtn">새로고침</button>
    </h3>

js 에서 id 값으로 요소 얻어와서 변수 저장

const totalCount = document.querySelector("#totalCount");
const completeCount = document.querySelector("#completeCount");
const reloadBtn = document.querySelector("reloadBtn");

전체 todo개수 조회 및 출력하는 함수 정의

fetch("요청주소")

비동기로 서버(DB)에서 전체 Todo 개수 조회하는 fetch() API 코드 작성
(fetch : 가지고 오다)
기본 GET 요청

fetch("요청주소") 비동기 요청 수행 -> Promise 객체 반환
응답을 가지고 돌아올 때 객체 하나를 반환해줌
=> Promise 객체 반환 (비동기요청 보냈을 때 받는 응답 형태)

첫번째 .then
.then 은 응답이 됐을 때 돌아온 객체명을 response 라고 하겠다
(매개변수형태) 이름은 어떻게 쓰든 상관 없음

response : 비동기 요청에 대한 응답이 담긴 객체

두번째 .then
매개변수 (result) == 첫번째 then 에서 반환된 Promise 객체의 PromiseResult 값
result 매개변수 == Controller 메서드에서 반환된 진짜 값

ajax-main.js

function getTotalCount() {

    fetch("/ajax/totalCount")
    .then(response => {

		return response.text();

    })
PromiseResult 값
    .then(result => {

        totalCount.innerText = result;
  
    });
};

함수 호출

getTotalCount(); // 함수 호출

return response.text();
응답이 담긴 객체.text() : 응답 데이터를 문자열/숫자 형태로 변환한 결과를 가지는 Promise 객체 반환
단일 값으로 넘어오는 값은 .text() 로 두번째 .then한테 넘겨줄 수 있음

totalCount.innerText = result;
첫번째 then에서 text()로 변환해서 보내준 값을 result 로 받아서 #totalCount 요소의 내용을 result로 변경

Controller 에서 비동기 요청 받은 method 에서 값 그대로 돌려주기

AjaxController

	@GetMapping("totalCount")
	@ResponseBody
	public int getTotalCount() {
		
		// 전체 할 일 개수 조회 서비스 호출 및 응답
		return service.getTotalCount();

	}

동기요청할 때는 return 자리에 forward/redirect 주소 적음

비동기 요청은 return 자리에 돌려 받은 값 그대로 돌려주겠다고 @ResponseBody 적어서 그대로 돌려보냄

@ResponseBody

  • 컨트롤러 메서드의 반환값을 HTTP 응답 본문에 직접 바인딩하는 역할임을 명시
    -> 컨트롤러 메서드의 반환값을 비동기 요청했던 HTML/JS 파일 부분에 값을 돌려보내 것이다 명시

  • @ResponseBody 어노테이션 붙어있으면 forward/redirect 로 인식하지 않음

완료된 할 일 개수 조회

1. js 에서 id 값 얻어와서 함수 작성 및 controller로 요청 보내기

main.html

완료된 Todo 개수 : <span id="completeCount">0</span>

ajax-main.js

function getCompleteCount() {

    // fetch() : 비동기로 요청해서 결과 데이터 가져오기
    fetch("/ajax/completeCount")

};

2. Controller 에서 service 호출하고 값 그대로 돌려줌

AjaxController

	@ResponseBody
	@GetMapping("completeCount")
	public int getCompleteCount() {
		return service.getCompleteCount();
	}

service, xml sql 문 실행하고 다시 controller로 돌아온 후

3. js에서 비동기 요청 받은 객체를 text로 변환해서 html innerText 로 값 넣어줌

    .then(resp => resp.text())
    .then(result => {
        completeCount.innerText = result;
    });

4. 함수 호출

getCompleteCount(); // 함수 호출

새로고침 버튼 클릭 됐을 때

1. main.html 요소 얻어오기

main.html

<button id="reloadBtn">새로고침</button>

ajax-main.js

const reloadBtn = document.querySelector("reloadBtn");

2. 함수 정의

ajax-main.js

reloadBtn.addEventListener("click", () => {
    getTotalCount(); // 비동기로 전체 할 일 개수 조회
    getCompleteCount(); // 비동기로 완료된 할 일 개수 조회
});

-> 새로고침 버튼 누르면 함수가 호출되면서 비동기로 서버 갔다옴

0개의 댓글