
Ajax(Asynchronous JavaScript and XML)는 비동기적으로 서버와 브라우저 간에
데이터를 교환하는 기술로 웹 페이지를 새로고침하지 않고도
서버로부터 데이터를 받아와서 웹 페이지의 일부분을 업데이트 할 수 있도록 해줌
-> 기존에는 웹 페이지를 다시 로드할 때 전체 페이지를
다시 받아와야 했기 때문에 사용자 경험이 좋지 않았음
-> Ajax를 사용하면 웹 페이지를 로드한 후에도
웹 페이지와 서버 간에 데이터를 주고받을 수 있으므로 사용자 경험을 향상시킬 수 있다.
* fetch() API
* - 비동기 요청을 수행하는 최신 Javascript API 중 하나.
*
* - Promise는 비동기 작업의 결과를 처리하는 방법으로
* - 어떤 결과가 올지는 모르지만 반드시 결과를 응답을 해주겠다는 약속임
* -> 비동기 작업이 맞이할 완료 또는 실패와 그 결과값을 나타냄.
* -> 비동기 작업이 완료되었을 때 실행할 콜백함수를 지정하고,
* 해당 작업의 성공 또는 실패 여부를 처리할 수 있도록 함.
*
*
* Promise 객체는 세가지 상태를 가짐
* - Pending(대기 중) : 비동기 작업이 완료되지 않은 상태
* - Fulfiled(이행됨) : 비동기 작업이 성공적으로 완료된 상태
* - Rejected(거부됨) : 비동기 작업이 실패한 상태
* @ResponseBody
* - 컨트롤러 메서드의 반환값을
* Http 응답 본문에 직접 바인딩하는 역할임을 명시
*
* -> 컨트롤러 메서드의 반환값을
* 비동기 요청했던 HTML/JS 파일 부분에 값을 그대로 돌려 보낼 것이다 를 명시.
*
* -> 해당 어노테이션이 붙은 컨트롤러의 메서드는 return 에 작성된 값이 forward/redirect 로 인식 X
*
*
* @RequestBody
* - 비동기 요청시 전달되는 데이터 중 body 부분에 포함된 요청 데이터를
* 알맞은 Java 객체 타입으로 바인딩하는 어노테이션
*
* - 기본적으로 JSON 형식을 기대함.
*
*
* [HttpMessageConvertor]
* Spring에서 비동기 통신 시
* - 전달받은 데이터의 자료형
* - 응답하는 데이터의 자료형
* 위 두가지를 알맞은 형태로 가공(변환)해주는 객체
*
* Java JS
* 문자열,숫자 <--------------> TEXT
* Map <-> JSON <-> JS Object
* DTO <-> JSON <-> JS Object
*
* (참고)
* Spring에서 HttpMessageConvertor 작동하기 위해서는
* jackson-data-bind 라이브러리가 필요한데
* Spring boot에는 모듈에 내장되어 있음
*
AjaxController.java
@ResponseBody
@GetMapping("totalCount") // /ajax/totalCount로 요청을 Get 매핑
// 전체 Todo 개수 비동기 조회
// -> forward / redirect를 원하는게 아님
// -> ex) 전체 Todo 개수라는 데이터를 비동기 요청을 보낸 클라이언트(브라우저)에게
// 반환되는 것을 원하는 것!!
// -> 반환되어야하는 결과값의 자료형을 반환형에 써줘야 한다.
public int getTotalCount() {
// @ResponseBody일 때는
// 내가 반환하고자 하는 타입으로 타입이 바뀜
// 전체 할 일 갯수 조회 서비스 호출 결과 반환받기
int totalCount = service.getTotalCount();
// 결과 리턴하기 (JS쪽으로)
return totalCount;
}
ajax-main.js
function getTotalCount() {
// 비동기로 서버에 전체 Todo 개수를 조회하는 요청
// fetch() API 로 코드 작성
// /ajax/totalCount
fetch("/ajax/totalCount") // 서버로 "/ajax/totalCount" 로 GET 요청
// 첫번 째 then (응답을 처리하는 역할)
.then((response) => {
// 서버에서 응답을 받으면,
// 이 응답(response)을 텍스트 형식으로 변환하는 콜백함수로 바꾸기
// => 상태값, 결과값이 들어가있음
// 매개변수 response : 비동기 요청에 대한 응답이 담긴 객체
// response.text() : 응답 데이터를 문자열/숫자 형태로 변환한 결과를 가지는 Promise 객체 반환
return response.text();
}) // 두번째 then (첫번째에서 return된 데이터를 활용하는 역할)
.then((result) => {
// 첫번쨰 콜백함수가 완료된 후 호출되는 콜백함수
// result는 response.text() return된 결과를 의미
// 매개변수로 전달되어진 데이터(result)를 받아서
// 어떤식으로 처리할지 정의
// -> #totalCount인 span 태그의 내용으로 result 값 대입
totalCount.innerText = result;
});
}

ajax-main.js
fetch("/ajax/add", {
// key:value
method: "POST", // post 방식 요청
headers: {
// 요청 데이터의 형식을 JSON으로 지정
"Content-Type": "application/json",
},
// 요청 본문, 즉 요청할 때 보낼 데이터를 가지고 있음
// js 객체로 보내는 것이 아닌, JSON의 String으로 바꾸겠다는 것
// param이라는 JS 객체를 JSON(string)으로 변환
body: JSON.stringify(param),
})
.then((response) => response.text())
.then((result) => {
if (result > 0) {
alert("추가 성공!");
todoTitle.value = "";
todoContent.value = "";
getTotalCount();
// -> 전체 Todo 목록 조회하는 함수 재호출 예정
} else {
alert("추가 실패..");
}
});
⇒ 이렇게 body에 값을 실어서 보내준다면 백단에서는
@RequestBody
* - 비동기 요청시 전달되는 데이터 중 body 부분에 포함된 요청 데이터를
* 알맞은 Java 객체 타입으로 바인딩하는 어노테이션
*
* - 기본적으로 JSON 형식을 기대함.
AjaxController.java
public int getTotalCount() {
// @ResponseBody일 때는
// 내가 반환하고자 하는 타입으로 타입이 바뀜
// 전체 할 일 갯수 조회 서비스 호출 결과 반환받기
int totalCount = service.getTotalCount();
// 결과 리턴하기 (JS쪽으로)
return totalCount;
}
@ResponseBody
@GetMapping("completeCount")
public int getCompleteCount() {
return service.getCompleteCount();
}
@ResponseBody
@PostMapping("add")
public int addTodo(@RequestBody Todo todo) {
// 요청 body(본문)에 담긴 값을 Todo라는 DTO에 저장해서
// 반환을 해준다
// 할 일 추가 서비스 호출 후 결과값 리턴하기
return service.addTodo(todo.getTodoTitle(), todo.getTodoContent());
}
@ResponseBody
@GetMapping("selectList")
public List<Todo> selectList() {
return service.selectList();
// List (Java 전용 타입)를 반환
// -> JS에는 List 타입이 없기 때문에
// 인식할 수 없기 때문에 JSON으로 변환을 해줘야 함
// HTTPMessageConveter가 알맞은 형태로 변환해줌
}

fetch("/ajax/selectList")
.then((response) => response.json()) // 응답 결과를 json으로 받음
.then((result) => {
.
.
}
⇒ 개발자모드에서 보면 JSON 형식으로 출력됌