Last Modified : 2009.09.19

Ajax - First Steps

간단한 예로서 Ajax 가 기존의 웹 프로그램 기법과 어떤 차이가 있는지 살펴보겠습니다. 예제는 회원등록 화면에서 아이디 중복 체크를 하는 것입니다. 먼저 팝업창을 이용하는 방법입니다.

1. 팝업창을 이용한 ID 중복 체크

write_form.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>회원가입양식</title>
<script type="text/javascript">

	function checkID() {
		var form = document.getElementById("signform");
		var id = form.id.value;
		
		if (id != '' ) {
		  var winFeatures = "toolbar=no," + 
				  "location=no," + 
				  "directories=no," + 
				  "status=no," +
				  "menubar=no," +
				  "scrollbars=no,"+
				  "resizable=no,"+
				  "copyhistory=no,"+
				  "width=400, height=400";
		  window.open("popIDCheck.jsp?id="+id, "IDCheckWin", winFeatures);
		} else {
		  alert('ID를 입력하세요!');
		}
	  }
		
</script>
</head>
<body>
<form id="signform" action="write.jsp" method="post">
<p>
	ID <input type="text" name="id" />
	<input type="button" value="ID중복체크" onclick="checkID()" />
</p>
<p>
	<span id="idChkMsg"></span>
</p>
</form>
</body>
</html>

popIDCheck.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ page import="java.sql.*" %>
<%
	String id = request.getParameter("id");
	
	Class.forName("oracle.jdbc.driver.OracleDriver");
	
	Connection con = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	
	String sql = "select count(*) from member where id = ?";
	boolean isExist = false;
	
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	
	try {
		con = DriverManager.getConnection(url,"scott","tiger");
		
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1, id);
		rs = pstmt.executeQuery();
		
		if ( rs.next() ) {
			int i = rs.getInt(1);
			if ( i > 0 ) isExist = true;
		}
		
	} catch ( SQLException e ) {
		System.out.println( "Error Source:popIDCheck.jsp : SQLException" );
		System.out.println( "SQLState : " + e.getSQLState() );
		System.out.println( "Message : " + e.getMessage() );
		System.out.println( "Oracle Error Code : " + e.getErrorCode() );
		System.out.println( "Query : " + sql );
	} finally {
		rs.close();
		pstmt.close();
		con.close();
	}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>ID 중복 체크</title>
<script type="text/javascript">

	function idCheck() {
		var form = document.getElementById("frmID");
		if ( form.id.value == '' ) {
			alert('ID를 입력하세요!');
			return;
		}
		form.submit();
	}

	function idConfirm(id) {
		var form = opener.document.getElementById("signform");
		form.id.value = id;
		self.close();
	}
		
</script>
</head>
<body>
<%
	if ( isExist == true ) {
%>
	<p>
	<%=id %>는 이미 사용중입니다.<br />
	다른 ID를 사용하세요!
	</p> 
	<form id="frmID" action="popIDCheck.jsp" method="post">
		<p>
			ID <input type="text" name="id" />
			<input type="button" value="ID중복체크" onclick="idCheck()" />
		</p>
	</form>	
<%
	} else {
%>
	<%=id %>는 사용할 있습니다.<br />
	<input type="button" value="확인" onclick="idConfirm('<%=id %>')" />
<%
	}
%>
</body>
</html>

브라우저 설정에 따라 팝업창을 띄우지 않도록 할 수 있기 때문에 이제는 좋은 방법이 되지 못합니다. 다음은 iframe 을 이용하여 ID 중복 체크입니다.

2. iframe 을 이용한 ID 중복 체크

write_form.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>회원가입양식</title>
<script type="text/javascript">

	function checkID() {
		var checkform = document.getElementById("checkform");
		var signform = document.getElementById("signform");
		var id = signform.id.value;
		
		if ( id != '' ) {
			checkform.id.value = id;
			checkform.submit();
		} else {
			alert('ID를 입력하고 중복확인하세요!')
			signform.id.value = '';
			signform.id.focus();
		}
	}

	var textNode;
	
	function idNotOKMsg ( id ) {
		var msg = document.getElementById('idChkMsg');
		if ( textNode ) msg.removeChild(textNode);
		var str = id + " 는 이미 사용자가 있습니다. 다른 ID를 사용하세요.";
		textNode = document.createTextNode(str);
		msg.appendChild(textNode);
		msg.style.background = "#FCBFC0";
	}
	
	function idOKMsg ( id ) {
		var msg = document.getElementById('idChkMsg');
		if ( textNode ) msg.removeChild(textNode);
		var str = id + " 는 사용이 가능한 ID입니다.";
		textNode = document.createTextNode(str);
		msg.appendChild(textNode);
		msg.style.background = "#BFCDFC";
	}
	
</script>
</head>
<body>
<form id="signform" action="write.jsp" method="post">
<p>
	ID <input type="text" name="id" />
	<input type="button" value="ID중복체크" onclick="checkID()" />
</p>
<p>
	<span id="idChkMsg"></span>
</p>
</form>
<form id="checkform" action="iframeIDCheck.jsp" method="post" target="iIDCHKframe">
	<input type="hidden" name="id" />
</form>
<iframe id="iIDCHKframe" name="iIDCHKframe" 
  style="width: 0px;height: 0px;border: 0px;"></iframe>
</body>
</html>

iframeIDCheck.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ page import="java.sql.*" %>
<%
	String id = request.getParameter("id");
	
	Class.forName("oracle.jdbc.driver.OracleDriver");
	
	Connection con = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	
	String sql = "select count(*) from member where id = ?";
	
	boolean isExist = false;
	
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	
	try {
		con = DriverManager.getConnection(url,"scott","tiger");
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1, id);
		rs = pstmt.executeQuery();
		if ( rs.next() ) {
			int i = rs.getInt(1);
			if ( i > 0 ) isExist = true;
		}
	} catch ( SQLException e ) {
		System.out.println( "Error Source:iframeIDCheck.jsp : SQLException" );
		System.out.println( "SQLState : " + e.getSQLState() );
		System.out.println( "Message : " + e.getMessage() );
		System.out.println( "Oracle Error Code : " + e.getErrorCode() );
		System.out.println( "Query : " + sql );
	} finally {
		rs.close();
		pstmt.close();
		con.close();
	}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>ID 중복 체크</title>
</head>
<body>
<%
	if ( isExist == true ) {
%>
	<script type="text/javascript">
		parent.idNotOKMsg( '<%=id %>' );
	</script>
<%
	} else {
%>
	<script type="text/javascript">
		parent.idOKMsg( '<%=id %>' );
	</script>
<%
	}
%>
</body>
</html>

앞으로의 웹은 아마도 팝업창을 이용하거나 ifrmae 을 이용하는 이와 같은 방식은 점점 좋은 방법이 되지 못할 것입니다. xhtml 1.0 strict 에서는 팝업창과 iframe 을 아예 사용할 수 없기 때문입니다.

3. Ajax 를 이용한 ID 중복 체크

write_form.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
	"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>회원가입양식</title>
<script type="text/javascript">

	var xmlHttp = false;

	try {
		xmlHttp = new XMLHttpRequest();
	} catch ( trymicrosoft ) {
		try {
			xmlHttp = new ActiveXObject( "Msxml2.XMLHTTP" );
		} catch ( othermicrosoft ) {
			try {
				xmlHttp = new ActiveXObject( "Microsoft.XMLHTTP" );
			} catch ( failed ) {
				xmlHttp = false;
			}  
		}
	}

	if ( !xmlHttp ) {
		alert( "Error initializing XMLHttpRequest!" );
	}	
		
	function checkID() {
	    var form = document.getElementById("signform");
	    var id = form.id.value;
	    
	    // TODO 아이디 유효성 체크
	    
	    var queryString = "id=" + id;
	    
	    var url = "ajaxIdCheck.jsp";
	    
	    xmlHttp.open("POST", url, true);
	    xmlHttp.onreadystatechange = updatePage;
	    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");    
	    xmlHttp.send(queryString);
	}

	function updatePage() {
	    if ( xmlHttp.readyState == 4 ) {
	        showIDCheckMsg();
	    }
	}

	function showIDCheckMsg() {
	    
	    var response = xmlHttp.responseText;
	    var str = response.split("|");
	    var msg = document.getElementById( "idChkMsg" );

	    if ( str[0] == 0 ) {
		    idOKMsg ( str[1] );
		} else {
		    idNotOKMsg ( str[1] );
		}
	}

	var textNode;

	function idNotOKMsg ( id ) {
		var msg = document.getElementById('idChkMsg');
		if ( textNode ) msg.removeChild(textNode);
		var str = id + " 는 이미 사용자가 있습니다. 다른 ID를 사용하세요.";
		textNode = document.createTextNode(str);
		msg.appendChild(textNode);
		msg.style.background = "#FCBFC0";
	}
	
	function idOKMsg ( id ) {
		var msg = document.getElementById('idChkMsg');
		if ( textNode ) msg.removeChild(textNode);
		var str = id + " 는 사용이 가능한 ID입니다.";
		textNode = document.createTextNode(str);
		msg.appendChild(textNode);
		msg.style.background = "#BFCDFC";
	}
	
</script>
</head>
<body>
<form id="signform" action="write.jsp" method="post">
<p>
	ID <input type="text" name="id" />
	<input type="button" value="ID중복체크" onclick="checkID()" />
</p>
<p>
	<span id="idChkMsg"></span>
</p>
</form>
</body>
</html>

ajaxIdCheck.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ page import="java.sql.*" %>    
<%
	String id = request.getParameter("id");

	Class.forName("oracle.jdbc.driver.OracleDriver");

	Connection con = null;
	String sql = null;
	PreparedStatement  pstmt = null;
	ResultSet rs = null;

	int result = 0; 
	
	String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
	
	try {
		con = DriverManager.getConnection(url,"scott","tiger");
		sql = "select count(*) from member where id = ?";
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1, id);
	
		rs = pstmt.executeQuery();
		rs.next();
		result = rs.getInt(1);

	} catch ( SQLException e ) {
		System.out.println( "Error Source:ajaxIdCheck.jsp : SQLException" );
		System.out.println( "SQLState : " + e.getSQLState() );
		System.out.println( "Message : " + e.getMessage() );
		System.out.println( "Oracle Error Code : " + e.getErrorCode() );
		System.out.println( "Query : " + sql );
	} finally {
		rs.close();
		pstmt.close();
		con.close();
	}
	
	out.println ( result + "|" + id);
%>

기존 기술과 차이점은 자바스크립트를 이용하여 서버 컴포넌트와 직접 통신한다는 것입니다.

참고 문서

http://www.w3schools.com/HTMLDOM/met_win_open.asp
http://www.ibm.com/developerworks/kr/series/web/index.html