프론트엔드/Ajax

타임리프와 JS을 활용한 AJAX 구현

두개의 문 2023. 8. 21. 12:24

◉ 타임리프와 바닐라(순수) 자바스크립트를 활용한 Ajax 구현 

 

 

▪︎ AjaxExamController.java

 - 세 번째 'member 목록 요청' 클릭 시, 요청 처리 메서드 작성 

    // * /index.html에서 member 목록 요청 누를 경우 
    @GetMapping("ajax/member/all")
    public String getMemberList() {
        log.info("{}", "ajax/member/all 요청 중");	
        return "ajax/member/list";
    }

 

 


▪︎ templates/member 에 list.html 생성 

 

① 타임리프 네임스페이스 선언 

<html xmlns:th="http://www.thymeleaf.org">

 

 

② body 태그 안에 Ajax 호출 버튼 및 호출 후 받아온 데이터를 이용해 테이블을 그려 줄 memberTable 작성 

   - <table> 태그 안에 th:fragment 속성 추가 ( 아래 개념 설명 참고 )

<body>
    <h1>Member List</h1>
    <button id="btnMemberList">멤버 리스트 요청</button>
    
    <table id="memberTable" th:fragment="memberTable">
        <tr>
            <th>아이디</th>
            <th>이름</th>
        </tr>
        <!--  tr 태그 사이 루프 반복  -->
        <tr th:each="member : ${ memberList }">
            <td th:text="${ member.key }">여기에 아이디</td>
            <td th:text="${ member.value }">여기에 이름</td>
        </tr>
    </table>
</body>

 

 

③ script 태그 코드 → <header> 태그 안에 위치시키고, window.onload 이용 

▪︎ DOM(Document Object Model)은 반드시 body 태그를 모두 읽어오고 나서 작동해야 함 
  - 다음 두 방식은 같은 원리로 작동함 ( 태그와 스크립트를 분리하는 2번째 방식 권장 )
      1. </body> 위에 <script> 태그 위치시키기 
      2. window.onload 이용 - body 태그 안의 내용을 모두 읽어오면 'load' 이벤트 작동함 

<script type="text/javascript">
    window.onload = function(){
    // * 로그 확인 - alert 이용해서 실행 여부 확인하기 
        //alert('window.onload 이벤트 등록')
        	
        // 바닐라 자바스크립트 순수 ajax 라이브러리인 XMLHttpRequest 이용 
       
        // ① ajax 객체 선언 
        let xhr;
        // ② id = btnMemberList 찾아 변수 button에 저장 
        let button = document.getElementById("btnMemberList")
        // ③ 버튼 객체 클릭 시, ajax 요청 : button의 'click' 이벤트리스너 등록 
        button.addEventListener('click', () => {
        	// ❶ xhr(ajax 객체 생성)
        	xhr = new XMLHttpRequest();
        	// ❷ ajax 객체에 상태변화이벤트(readystatechange) 등록 
        	xhr.onreadystatechange = () => {
        		// xhr 객체의 준비가 모두 마쳤는지 
        		if( xhr.readyState === xhr.DONE ){
        			// 서버로부터 응답이 오면 
        			if( xhr.status === 200 ){
        				let table = document.getElementById('memberTable')
        				table.innerHTML = xhr.response;
        			} else {
        				alert('Ajax Request 에러!')
        			}
        		}
        		
        	} // ❷ 상태변화 이벤트 핸들러 등록 끝 - 
        	
        	// ④ xhr 객체 상태변화를 위해 서버에 연결 (xhr 객체의 연결 이벤트)
                xhr.open('GET', '/ajax/member/list')
        	// ⑤ xhr 객체 상태변화 (xhr 객체가 서버에 응답을 요청하는 이벤트)을 위해
        	//   서버가 응답에 필요한 요청데이터 전송 
        	xhr.send()
        	
        }) // ③ 버튼 객체 클릭 시, ajax 요청 끝 - 
    }
</script>

 

 


◎ list.html 전체 코드 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script type="text/javascript">
    // * DOM(Document Object Model)은 반드시 body 태그를 모두 읽어오고 나서 작동해야 함 
        // 다음 두 방식은 같은 원리로 작동함 ( 태그와 스크립트를 분리하는 2번째 방식 권장 )
        //  1. </body> 위에 <script> 태그 위치시키기 
        //  2. window.onload 이용 - body 태그 안의 내용을 모두 읽어오면 'load' 이벤트 작동함 
    window.onload = function(){
    // * 로그 확인 - alert 이용해서 실행 여부 확인하기 
        //alert('window.onload 이벤트 등록')
        	
        // 바닐라 자바스크립트 순수 ajax 라이브러리인 XMLHttpRequest 이용 
       
        // ① ajax 객체 선언 
        let xhr;
        // ② id = btnMemberList 찾아 변수 button에 저장 
        let button = document.getElementById("btnMemberList")
        // ③ 버튼 객체 클릭 시, ajax 요청 : button의 'click' 이벤트리스너 등록 
        button.addEventListener('click', () => {
        	// ❶ xhr(ajax 객체 생성)
        	xhr = new XMLHttpRequest();
        	// ❷ ajax 객체에 상태변화이벤트(readystatechange) 등록 
        	xhr.onreadystatechange = () => {
        		// xhr 객체의 준비가 모두 마쳤는지 
        		if( xhr.readyState === xhr.DONE ){
        			// 서버로부터 응답이 오면 
        			if( xhr.status === 200 ){
        				let table = document.getElementById('memberTable')
        				table.innerHTML = xhr.response;
        				//alert(xhr.response)
        			} else {
        				alert('Ajax Request 에러!')
        			}
        		}
        		
        	} // ❷ 상태변화 이벤트 핸들러 등록 끝 - 
        	
        	// ④ xhr 객체 상태변화를 위해 서버에 연결 (xhr 객체의 연결 이벤트)
            xhr.open('GET', '/ajax/member/list')
        	// ⑤ xhr 객체 상태변화 (xhr 객체가 서버에 응답을 요청하는 이벤트)을 위해
        	//   서버가 응답에 필요한 요청데이터 전송 
        	xhr.send()
        	
        }) // ③ 버튼 객체 클릭 시, ajax 요청 끝 - 
    }
</script>
</head>

<body>
    <h1>Member List</h1>
    <button id="btnMemberList">멤버 리스트 요청</button>
    
	    <table id="memberTable" th:fragment="memberTable">
	        <!-- th붙지 않았으므로, 정적인 영역  -->
	        <tr>
	            <th>아이디</th>
	            <th>이름</th>
	        </tr>
	        <!--  tr 태그 사이 루프 반복  -->
	        <tr th:each="member : ${ memberList }">
	            <td th:text="${ member.key }">여기에 아이디</td>
	            <td th:text="${ member.value }">여기에 이름</td>
	        </tr>
	    </table>
</body>
</html>

 


▪︎ AjaxExamController.java

  : XMLHttpRequest 객체가  '/ajax/member/list'로 GET 요청 시, 처리할 메서드 작성

// * xhr.open('GET', '/ajax/member/list')
//   xhr 객체가 위의 url 주소로 GET 요청했으므로, 이 요청을 처리할 메서드 작성 
@GetMapping("/ajax/member/list")
public String getMembers(Model model) {
    log.info("{}", "/ajax/member/list 요청 중");
    // * 가상의 멤버 테이블 생성 
    //   : Map<회원번호, 회원이름>으로 구성된 가상의 멤버리스트 생성 
    //     → 나중에 리포지토리를 이용해 대체 
    Map<Integer, String> memberList = new HashMap<>();
    // * 테스트용 가상의 회원 추가 
    memberList.put(1, "하늘");
    memberList.put(10, "구름");
    memberList.put(20, "바다");
    memberList.put(200, "태양");

    model.addAttribute("memberList", memberList);

    // * 템플릿 조각에 데이터 넘기기 
    //   뷰템플릿 타임리프에서 html파일의 일부 영역에 접근해 그 내용을 바꾸는 방법 
    //   → templates 파일 이름 + '::' + 데이터가 변경될 fragment id 
    return "ajax/member/list :: memberTable";
}

 

 


◎ 요청 흐름 및 결과 

 

1. 홈에서 세번째 'member 목록 요청' 클릭 → AjaxExamController에서 매핑된 "ajax/member/all"로 이동 

 

2. 이동 시, 아직 memberList 생성되지 않았기 때문에, 현재 테이블에 나올 데이터 없음 

 

3. '멤버 리스트 요청' 버튼 클릭 → list.html의 <script> 태그 : 버튼 클릭 시 등록된 함수 실행 → 서버로 요청 데이터 전송 

    AjaxExamController에 의해 템플릿 조각의 데이터가 바뀐 상태의 뷰를 반환 → 아래와 같이 데이터 출력됨  

 

 


◎ 타임리프 템플릿 조각 

 

▪︎ 웹 페이지 개발 시, 여러 페이지에서 공통으로 사용하는 영역들이 존재 

  → 이런 공통 영역 페이지마다 코드를 작성하게 될 경우, 코드 중복 뿐만 아니라 수정하게 될 경우, 모든 페이지를 각각 수정해주어야 한다는 불편함이 있음 

 ∴ 이러한 문제를 해결하기 위해 템플릿 조각과 레이아웃 기능 지원함 

 

▪︎ 타임리프 템플릿 조각 

  - HTML 파일에서 특정 태그의 속성에 th:fragment로 이름 지정해주면 끝 

  - 컨트롤러에 의해 뷰 파일 반환 시, 아래와 같이 경로만 지정해주면 됨 

" 템플릿_조각_경로 :: 조각명 "

'프론트엔드 > Ajax' 카테고리의 다른 글

AJAX 실습 - POST 방식 구현  (0) 2023.08.18
AJAX 실습 - GET 방식 구현  (0) 2023.08.18
AJAX  (0) 2023.08.18