Spring Framework (5) - todo 완료 및 ajax todo 구현 Day 52

jaehoon ahn·2025년 12월 2일

Spring boot

목록 보기
5/20
post-thumbnail

오늘의 깨달음..!

  • 항상 구현 흐름에 대해서 파악하고 개발 시작하기
  • 개발하기 전 흐름 미리 작성해보기 → 주석

동기 & 비동기

  • 동기식
    • 줄 세우는 것
  • 비동기식
    • 줄 안세우고 그때그때

Ajax

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

fetch API 및 상태

 * fetch() API
 * - 비동기 요청을 수행하는 최신 Javascript API 중 하나.
 *
 * - Promise는 비동기 작업의 결과를 처리하는 방법으로
 * - 어떤 결과가 올지는 모르지만 반드시 결과를 응답을 해주겠다는 약속임
 * -> 비동기 작업이 맞이할 완료 또는 실패와 그 결과값을 나타냄.
 * -> 비동기 작업이 완료되었을 때 실행할 콜백함수를 지정하고,
 * 해당 작업의 성공 또는 실패 여부를 처리할 수 있도록 함.
 *
 *
 * Promise 객체는 세가지 상태를 가짐
 * - Pending(대기 중) : 비동기 작업이 완료되지 않은 상태
 * - Fulfiled(이행됨) : 비동기 작업이 성공적으로 완료된 상태
 * - Rejected(거부됨) : 비동기 작업이 실패한 상태

@ResponseBody

* @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에는 모듈에 내장되어 있음
*

ajax로 총 개수 가져오기

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;
    });
}

form & button의 유무의 따른 의미

  • form
    • form 존재
      • 동기식
    • form 존재 X
      • 비동기로 개발 O
  • button
    • form 존재
      • type = “submit”
    • form 존재 X
      • type = “button”

POST 비동기(@RequestBody)

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

@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());
		
	}

HTTPMessageConverter

@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 형식으로 출력됌

0개의 댓글