AJAX

6 minute read



AJAX

1. 동기와 비동기방식

  • 동기방식
    • 요청 후, 응답이 올 때까지 client는 대기만 하는 것.
  • 비동기방식
    • 요청 후, 응답이 올 때까지 client가 다른 Background 작업을 할 수 있는 것.
    • client는 멈추지 않고 동작




2. AJAX 구성 및 특징

  • JavaScript
  • css
  • DOM
  • XMLHttpRequest
    • 자바스크립트 객체
    • 대부분의 브라우저에서 지원
    • 표준 HTTP방식(GET/POST)으로 서버와 통신
    • 서버와 통신시 비동기적으로 작업
    • 기존 서버 작업 방식 사용 (Servlet, JSP, …)
    • 응답문서 타입 : html외에 xml, json, 단순 텍스트 사용
  • client의 요청을 AJAX Engine이 가로채서 대신 요청과 응답을 Http프로토콜로 처리하는 기술




3. AJAX프로그래밍 순서

  1. 클라이언트 이벤트 발생 (ex. 버튼클릭, 텍스트 입력…)
  2. XMLHttpRequest 객체 생성
  3. XMLHttpRequest 객체 콜백함수 설정 ( 서버의 상태가 바뀔때마다 호출되는 함수 )
  4. XMLHttpRequest 객체를 통한 비동기화 요청
  5. 서버 응답결과를 생성하여 클라이언트로 전송
  6. XMLHttpRequest 객체는 서버 결과를 처리할 콜백함수 호출
  7. 결과를 클라이언트 화면에




4. 예제

4-1. ajaxTest.jsp에서 버튼을 누르면 hello.jsp의 값이 날아오게 하기

  • hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<h1>Hello AJAX!</h1>
  
  • ajaxTest.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style>
	#msgView{
		border:1px solid red;
		height:200px;
		width: 500px;
		margin-bottom:20px;
		text-align:center;
	}
</style>

<script>

	let httpRequest = null
	
	function requestMsg(){
		// 1단계 : XMLHttpRequest객체 생성
		if(window.XMLHttpRequest)
			httpRequest = new XMLHttpRequest()
		else if(window.ActiveXObject)
			// explore버전때문에 해주는거임. 최소한의 안전장치
			httpRequest = new ActiveXObject("Microsoft.XMLHTTP")
		else
			httpRequest = null
	
		// 2단계 : Callback함수 설정( 서버요청이 바뀔때마다 호출되는 함수 )
		/*
			httpRequest.onreadystatechage = function(){
			
			}아래와 같은 뜻
		*/
		httpRequest.onreadystatechange = responseMsg
		
		// 3단계 : 서버에 비동기 요청
		httpRequest.open('GET', 'hello.jsp' ,true) // 비동기방식 true
		httpRequest.send(null)

	}
	
	
	function responseMsg(){
		if(httpRequest.readyState == 4){
			// 모든 데이터 전송완료(응답완료 4) 했고 결과가 올바르다면(200) responseText한다.
			if(httpRequest.status == 200){
				
				let msgView = document.getElementById("msgView");
				msgView.innerHTML = httpRequest.responseText // +=는 계속 추가됨
				
				
			}
			
		}
		
	}
	
</script>

</head>
<body>
	<h2>서버에서 받은 메시지</h2>
	<div id="msgView">
		
	</div>
	<input type="button" value="서버에서 자료 요청" onclick="requestMsg()">

</body>
</html>
  


4-1. 가상의 url로 넘어가게 하기.

  • ajaxText2.jsp
    • 위의 ajaxText.jsp복사
    • httpRequest.open(‘GET’, ‘hello.jsp’ ,true)부분 httpRequest.open(‘GET’, ‘/Lecture-Web/ajax/hello’,true)로 수정
  • HelloServlet.java
package kr.ac.kopo.ajax;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */
@WebServlet("/ajax/hello")
public class HelloServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		
		PrintWriter out = response.getWriter();
		out.write("<h1>Hello AJAX!!!</h1>");
		out.close();
	}
}




5. GET방식과 POST방식의 파라미터 전달방법

5-1. GET방식

  • open(‘GET’, ‘hello.jsp?id=duke’, true)
  • send(null)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>

	let httpRequest = null

	function getXMLHttpRequest(){
		
		let httpRequest=null
		
		if(window.XMLHttpRequest)
			httpRequest = new XMLHttpRequest()
		else if(window.ActiveXObject)
			// explore버전때문에 해주는거임. 최소한의 안전장치
			httpRequest = new ActiveXObject("Microsoft.XMLHTTP")
		return httpRequest
	}
	
	
	function sendProcess(param){
		
		httpRequest = getXMLHttpRequest()
		httpRequest.onreadystatechange = callbackFunction
		
		let msg="==================================================\n";
		msg += "/Lecture-Web/eaxm02/param.jsp?name=" + param + "\n";
		debugTrace(msg)
		
		let url = "param.jsp?name=" + param
		httpRequest.open('GET', url, true)
		httpRequest.send(null)
		
	}
	
	function callbackFunction(){
		
		let msg =''
		
		switch(httpRequest.readyState){
		case 1:
			msg += 'Loading...\n'
			break
		case 2:
			msg += 'Loaded...\n'
			break
		case 3:
			msg += 'Interaction...\n'
			break
		case 4:
			msg += 'Completed...\n'
			
			if(httpRequest.status == 200){
				msg += '웹서버에서 정상적으로 수행...\n'
				msg += '실행결과 : ' + httpRequest.responseText + '\n'
			}else{
				msg += '웹서버에서 오류 발생...\n'
				msg += '오류코드 : ' + httpRequest.status + '\n'
				
				// Explorer에서 한글인자호출시 400에러가 난다?
			}
			msg += "===================================================\n"
			break
		}
		
		debugTrace(msg)
		
	}
	
	function debugTrace(msg){
		//debug메시지 출력하는 메소드
		let degug = document.getElementById("debug")
		debug.value += msg
	}

</script>


</head>
<body>
	<textarea rows="10" cols="80" id="debug"></textarea><br>
	<button onclick="sendProcess('hong gill-dong')">영문인자호출</button>
	<button onclick="sendProcess('홍길동')">한글인자호출</button>

</body>
</html>
  
  • Explorer에서 한글인자호출시 400에러가 난다?
    • 400Error : Explorer에서 한글을 인식 못해서 나오는것.
    • Chrome은 알아서 인코딩이 되지만, Explorer는 인코딩이 안되기 때문.

  param = encodeURIComponent(param) 
  // 모든 브라우저에서 동작하기 위해서는 encode해줘야함
  let url = "param.jsp?name=" + param

5-2. POST방식

  • open(‘POST’, ‘hello.jsp’, true)
  • send(‘id=duke’)
  • POST방식은 html에서 form태그를 써야만 넘길 수 있음
    • 함수안에 처리를 해주면 form없이도 가능
      • form enctype=”application/x-www-form-urlencoded”
    • 그래서 httpRequest.setRequestHeader(‘Content-type’, ‘application/x-www-form-urlencoded’)가 필요
  • 근데 한글이 깨지네?
    • param2.jsp에서 인코딩 수행

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>

	let httpRequest = null

	function getXMLHttpRequest(){
		
		let httpRequest=null
		
		if(window.XMLHttpRequest)
			httpRequest = new XMLHttpRequest()
		else if(window.ActiveXObject)
			// explore버전때문에 해주는거임. 최소한의 안전장치
			httpRequest = new ActiveXObject("Microsoft.XMLHTTP")
		
		return httpRequest
	}
	
	
	function sendProcess(method, param){
		
		httpRequest = getXMLHttpRequest()
		httpRequest.onreadystatechange = callbackFunction
		
		let msg="==================================================\n";
		
		msg += method + " /Lecture-Web/eaxm02/param2.jsp?name=" + param + "\n";
		// method인자가 안들어올 수도 있어서 위험한 방식이긴 함 (예제를 위한 예제)
				
		debugTrace(msg)
		
		let url = 'param2.jsp'
			param = encodeURIComponent(param)
			let args = 'name=' + param
			
		if(method == 'GET'){
			//GET일때
			httpRequest.open(method, url + '?' + args, true)
			httpRequest.send(null)
			
		}else if(method == 'POST'){
			//POST일때
			httpRequest.open(method, url, true)
			httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
			
			/* 1. POST방식인데 왜 올바르게 날아가지 않을까?
					html에서 POST방식으로 넘기기 위해서는 form태그를 쓸때만 POST방식으로 넘길 수 있다.
					form enctype="application/x-www-form-urlencoded"
					그래서 위의 httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')가 필요
				
				2. 근데 한글이 깨지네?
					param2.jsp에서 인코딩 수행	
			*/
			httpRequest.send(args)
			
		}

	}
	
	function callbackFunction(){
		
		let msg =''
		
		switch(httpRequest.readyState){
		case 1:
			msg += 'Loading...\n'
			break
		case 2:
			msg += 'Loaded...\n'
			break
		case 3:
			msg += 'Interaction...\n'
			break
		case 4:
			msg += 'Completed...\n'
			
			if(httpRequest.status == 200){
				msg += '웹서버에서 정상적으로 수행...\n'
				msg += '실행결과 : ' + httpRequest.responseText + '\n'
			}else{
				msg += '웹서버에서 오류 발생...\n'
				msg += '오류코드 : ' + httpRequest.status + '\n'
				
				// Explorer에서 한글인자호출시 400에러가 난다?
			}
			msg += "===================================================\n"
			break
		}
		
		debugTrace(msg)
		
	}
	
	function debugTrace(msg){
		//debug메시지 출력하는 메소드
		let degug = document.getElementById("debug")
		debug.value += msg
	}

</script>


</head>
<body>
	<textarea rows="10" cols="80" id="debug"></textarea><br>
	<button onclick="sendProcess('GET','hong gill-dong')">GET영문인자호출</button>
	<button onclick="sendProcess('GET','홍길동')">GET한글인자호출</button><br>
	<button onclick="sendProcess('POST','hong gill-dong')">POST영문인자호출</button>
	<button onclick="sendProcess('POST','홍길동')">POST한글인자호출</button>

</body>
</html>
  
  • param2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	// POST방식은 한글 출력시 인코딩이 필요함
	if(request.getMethod().equalsIgnoreCase("POST"))
		request.setCharacterEncoding("utf-8");
%>
name=${ param.name }
  




6. httpRequest라이브러리 만들기

6-1. httpRequest.js

/**
 *  AJAX 통신과 관련된 함수의 집합
 */

let hgttpRequest = null

function getXMLHttpRequest(){
		
	let httpRequest=null
	
	if(window.XMLHttpRequest)
		httpRequest = new XMLHttpRequest()
	else if(window.ActiveXObject)
		// explore버전때문에 해주는거임. 최소한의 안전장치
		httpRequest = new ActiveXObject("Microsoft.XMLHTTP")
	
	return httpRequest
}

function sendProcess(method, url, params, callback){
	httpRequest = getXMLHttpRequest()
	httpRequest.onreadystatechange = callback
	
	let httpMethod = method
	if(httpMethod !='GET' && httpMethod != 'POST')
		httpMethod = 'GET'
		
	
	let httpParams=''
	if(params !=null && params != '' ){
		
		/*
		// name=홍길동&age=24
		paramArr = params.split('&')
		for(let param of paramArr){
			pdata = param.split('=')
			if(httpParams != '')
				// &로 다시 결합
				httpParams += '&'
			//name=value로만들기
			httpParams += pdata[0] + '=' + encodeURIComponent(pdata[1])
			
		=====  원리설명==============================
			
				name=홍길동&age=24
				paramArr[0] -> name = 홍
				paramArr[1] -> age = 24
				
				-----------------------------------
				
				pdata[0] -> name
				pdata[1] -> 홍 (인코딩필요) : encodeURIComponent(pdata[1]
				...
				
				-----------------------------------
				
				httpParams -> name=0xAAxVVBB0xCC...
				...
				
				-----------------------------------
		}
		*/
		
		
		if(params instanceof String){
			paramArr = params.split('&')
			for(let param of paramArr){
				pdata = param.split('=')
				if(httpParams != '')
					// &로 다시 결합
					httpParams += '&'
				//name=value로만들기
				httpParams += pdata[0] + '=' + encodeURIComponent(pdata[1])
			}
			
		}else{// object형일때
			// {name:name ,age:age, addr:addr}를  "name=홍길동&age=30&addr=서울시서초구"로
			for(let key in params){
				console.log(key, params[key])
				if(httpParams!=''){
					httpParams +='&'
				}
				httpParams += key + '=' + encodeURIComponent(params[key])
			}
			
			
		}
		
	}
	
	
	// Method, GET방식일때는 httpURL에 ?도 들어가게
	// GET방식에서는 파라미터가 ?뒤에 붙어오기 떄문에
	let httpURL = url
	if(httpMethod == 'GET' && httpParams!='')
		httpURL = url + '?' + httpParams
	
	console.log(httpMethod, httpURL, httpParams)
		
	httpRequest.open(httpMethod, httpURL, true)
	
	if(httpMethod=='GET'){
		httpRequest.send(null)
	}else if(httpMethod == 'POST'){
		httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
		httpRequest.send(httpParams)
	}
}

6-2. module.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="httpRequest.js"></script>
<script>
	function clickBtn(){
		// 비동기 통신을 위한 함수
		let name = document.inputForm.name.value
		let age = document.inputForm.age.value
		let addr = document.inputForm.addr.value
		
		// 비동기 통신
		
		// 1단계
//		sendProcess('POST', 'sample.jsp', "name=홍길동&age=30&addr=서울시서초구", callback)
		
		//2단계
//		let params = 'name=' + name + '&age=' + age + '&addr=' + addr
//		sendProcess('POST', 'sample.jsp', params, callback)

		//3단계
		let params = {name:name ,age:age, addr:addr}
		//json으로 들어온 값을 "name=홍길동&age=30&addr=서울시서초구"이렇게 만들어주어야함.
		sendProcess('POST', 'sample.jsp', params, callback)
		
	}
	
	function callback(){
		let msg =''
			
		switch(httpRequest.readyState){
		case 1:
			msg += 'Loading...\n'
			break
		case 2:
			msg += 'Loaded...\n'
			break
		case 3:
			msg += 'Interaction...\n'
			break
		case 4:
			msg += 'Completed...\n'
			
			if(httpRequest.status == 200){
				msg += '웹서버에서 정상적으로 수행...\n'
				msg += '실행결과 : ' + httpRequest.responseText + '\n'
			}else{
				msg += '웹서버에서 오류 발생...\n'
				msg += '오류코드 : ' + httpRequest.status + '\n'
				
				// Explorer에서 한글인자호출시 400에러가 난다?
			}
			msg += "===================================================\n"
			break
		}
		
		debugTrace(msg)
		
		
		
	}
		
	function debugTrace(msg){
		//debug메시지 출력하는 메소드
		let degug = document.getElementById("debug")
		debug.value += msg
	}
	
</script>
</head>
<body>
	<h2>XMLHTTPRequest 모듈을 이용한 예제</h2>
	<form name="inputForm">
		<textarea rows="10" cols="80" id="debug"></textarea><br>
		이름 : <input type="text" name="name"><br>
		나이 : <input type="text" name="age"><br>
		주소 : <input type="text" name="addr"><br>
		<button type="button" onclick="clickBtn()">서버에 자료 요청</button>
	</form>	 
</body>
</html>
  

6-3. sample.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	if(request.getMethod().equals("POST")){
		request.setCharacterEncoding("utf-8");
	}
%>

안녕하세요 ${ param.name } 회원님<br>
회원님의 나이는 ${param.age}<br>
회원님의 주소는 ${param.addr}