바로 이전의 3-14 샘플은 브라우저의 파라미터를 XML 형식으로 변환하여 서버로 보내는 방법을 제시했 었다. 데이타 포맷의 표준이 되서버린 XML을 이용한다는 전체적인 맥락은 그럴싸했지만 사실 XML을 만 드는 과정이 복잡한 쿼리 스트링 조합작업이라면 누가 하려하겠는가 말이다. 나 자신도 이런 작업은 정말 싫어한다.
XML 을 생성하기 위한 javascript 날코딩의 대안으로 JSON(Javascript Object Notation, www.json.org) 을 소개한다. JSON 은 텍스트 포맷기반의 경량 데이터 변환 포맷이다. 프로그래밍 언어에 독립적며, C 언 어계열에 익숙한 데이터 구조 형식을 취하고 있다. JSON은 두가지 텍스트 포맷을 가지고 있는데, 첫번째 는 name/value 쌍의 컬렉션 데이터 구조로 프로그래밍 언어로 따지면 object, record, struct 쯤 되겠다.
두번째는 정렬된 value 의 리스트형태로써 프로그래밍 언어로 비유하자면 배열이라고 보면 될 것이다.
JSON 의 데이터 구조는 많은 프로그램 언어에 의해서 지원되고 있기때문에 XML 보다는 이기종 시스템간 의 이상적인 선택이 될 것이다. 추가적으로 JSON 은 표준 자바스크립트의 부류이므로 모든 웹 브라우저간 에도 양립할 수 있는 것이다.
<3-17 JSON 오브젝트구조도(출처 : www.json.org)>
위 그림은 JSON의 데이터 구조를 나타내고 있다.
Object는 {} 으로 표시한다. 오브젝트에는 name/value 쌍이 콜론(:) 혹은 콤마(,) 로 구분되어져 있으며 순서는 없다.
Array 는 [] 으로 표시한다. 배열은 정렬된 value 가 콤마(,) 에 의해서 구분되어져 있으며, value 값은 스 트링("" 으로 둘러싸야 함), 숫자, true or false, null, object , array 가 올수 있으므로 배열의 구조는 계 층적이라고 할 수 있다.
스트링은 유니코드 조합 및 백래쉬 이스케이프(₩)를 사용할 수 있으며 '' 을 사용하여 character 를 표현 할 수 있다.
스트링과 숫자는 C언어 혹은 자바의 스트링과 거의 흡사하지만 8진수 및 16진수 포맷은 지원하지 않는다.
공백을 name/value 쌍 사이사이에 사용할 수 있다.
하나의 예를 들어보자. Employ 라는 클래스(멤버로 firstName, lastName, employeeNumber, title)의 인 스턴스를 JSON 을 이용해서 아래와 같이 표현해 볼 수 있다.
var employee = { "firstName" : John, "lastName" : Doe, "employNumber" : 123, "title" : "Manager"
}
그러면 위 표현을 오브젝트 속성을 이용해서 아래와 같이 다룰 수 있다.
var lastName = employee.lastName;//lastName 에 접근 var title = employee.title;//title 에 접근
employee.emplyeeNumber = 456;//employeeNumber 를 456 으로 수정
JSON 의 인코딩은 확실히 XML 인코딩보다 가볍다. 따라서 네트웍을 통해서 큰 데이터가 오고가는 상황에 서는 많은 퍼포먼스의 차이가 발생할 것이다. JSON 싸이트에 가보면 적어도 14개 이상의 서버쪽 어플리케 이션을 다루는 프로그래밍언어에서 JSON 을 사용할 수 있게끔 준비가 되어 있다.
이제 3장의 마지막 주제인 JSON 을 이용한 간단한 샘플을 살펴보자.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JSON Example</title>
<script type="text/javascript" src="json.js"></script>
<script type="text/javascript">
var xmlHttp;
function createXMLHttpRequest() { if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest();
} }
function doJSON() {
var car = getCarObject();
//Use the JSON JavaScript library to stringify the Car object var carAsJSON = JSON.stringify(car);
alert("Car object as JSON:₩n " + carAsJSON);
var url = "JSONExample?timeStamp=" + new Date().getTime();
createXMLHttpRequest();
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send(carAsJSON);
}
function handleStateChange() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { parseResults();
} } }
function parseResults() {
var responseDiv = document.getElementById("serverResponse");
if(responseDiv.hasChildNodes()) {
responseDiv.removeChild(responseDiv.childNodes[0]);
}
var responseText = document.createTextNode(xmlHttp.responseText);
responseDiv.appendChild(responseText);
}
function getCarObject() {
return new Car("Dodge", "Coronet R/T", 1968, "yellow");
}
function Car(make, model, year, color) { this.make = make;
this.model = model;
this.year = year;
this.color = color;
}
</script>
</head>
<body>
<br/><br/>
<form action="#">
<input type="button" value="Click here to send JSON data to the server"
onclick="doJSON();"/>
</form>
<h2>Server Response:</h2>
<div id="serverResponse"></div>
</body>
</html>
<3-18 jsonExample.htm 의 전체 소스 코드>
package ajaxbook.chap3;
import java.io.*;
import java.net.*;
import java.text.ParseException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.json.JSONObject;
public class JSONExample extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String json = readJSONStringFromRequestBody(request);
//Use the JSON-Java binding library to create a JSON object in Java JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(json);
}
catch(ParseException pe) {
System.out.println("ParseException: " + pe.toString());
}
String responseText = "You have a " + jsonObject.getInt("year") + " "
+ jsonObject.getString("make") + " " + jsonObject.getString("model") + " " + " that is " + jsonObject.getString("color") + " in color.";
response.setContentType("text/xml");
response.getWriter().print(responseText);
}
private String readJSONStringFromRequestBody(HttpServletRequest request){
StringBuffer json = new StringBuffer();
String line = null;
try {
BufferedReader reader = request.getReader();
while((line = reader.readLine()) != null) { json.append(line);
} }
catch(Exception e) {
System.out.println("Error reading JSON string: " + e.toString());
}
return json.toString();
} }
<3-19 JSONExample.java 의 전체 소스 코드>
마지막 예제에서 중요한 부분을 굵게 표시하였다. 이번 예제를 실행해 보기 위해서는 json.js 와 자바관련 json 라이브러리가 필요하다. 관련 파일들은 json 웹싸이트에서 다운받으면 된다. 우선 자바스크립트쪽 핵 심코드를 먼저 살펴보자.
function getCarObject() {
return new Car("Dodge", "Coronet R/T", 1968, "yellow");
}
function Car(make, model, year, color) { this.make = make;
this.model = model;
this.year = year;
this.color = color;
}
위 코드는 설명이 별로 필요치 않을 것 같다. Car 객체를 만들어 주는 메소드이다.
function doJSON() {
var car = getCarObject();
//Use the JSON JavaScript library to stringify the Car object var carAsJSON = JSON.stringify(car);
alert("Car object as JSON:₩n " + carAsJSON);
var url = "JSONExample?timeStamp=" + new Date().getTime();
createXMLHttpRequest();
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send(carAsJSON);
}
위 코드를 보면 자바스크립트 car 객체를 생성한 후 JSON 자바스크립트 라이브러이의 stringify 를 사용해 서 JSON 객체로 변환하고 있다. 나머지 로직은 POST 방식을 구현한 것이고 send(() 메소드에 JSON 객체 를 넣어준다.
이번엔 서버쪽 프로그램을 확인해 보자.
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(json);
}
catch(ParseException pe) {
System.out.println("ParseException: " + pe.toString());
}
String responseText = "You have a " + jsonObject.getInt("year") + " "
+ jsonObject.getString("make") + " " + jsonObject.getString("model") + " " + " that is " + jsonObject.getString("color") + " in color.";
우선 서버 프로그램은 Http request 객체에서 JSON 문자열을 추출한다. 이렇게 추출된 문자열을 JSON 자 바 라이브러리의 JSONObject 클래스를 생성할때 생성자의 파라미터로 입력된다. JSONObject 는 자동으로 JSON 문자열을 파싱하고 getXxx 메소드를 이용해서 여러 타입의 데이터를 추출할 수 있는 것이다. 정말 간단하지 않은가?
다음은 3-19 샘플을 실행한 결과 화면이다.
Click here to send JSON data to the server 버튼을 클릭하면 alert 창으로 JSON object 데이터 구조 를 확인할 수 있다. 그리고 서버에서 처리된 결과문자열인 You have a 1968 Dodge Coronet R/T that is yellow in color. 을 확인 할 수 있을 것이다.
AJAX 강의 4-1장 - 폼 입력값 검증 하기
Chapter04-jinoxst.zip
3장에서는 AJAX 의 여러가지 기본적인 특성에 대해서 공부하였다. 또한 아주 간단한 예제를 통해서 그 특 징들이 어떻게 적용되는지도 살펴보았다. 이번 4장에서는 좀더 발전하여 실제적으로 쓰임새 측면에서 AJAX 를 다루어 보기로 한다.
실용적인 측면에서 AJAX 를 어떻게 활용할 수 있을지 살펴보자. 첫번째로 사용자가 브라우저의 입력폼에 값을 입력했을때 그 값을 검증하는 기능을 구현해볼 것이다. 이번 예제에서는 간단하게 날짜를 입력했을때, 그 값을 맞게 입력했는지 검증하는 로직을 AJAX 로 적용해 볼것이다. 여러 프로젝트를 수행한 결과 이런 폼 입력값 검증작업의 경우 간단한 것은 자바스크립트를 사용하면 아주 쉽게 끝나버린다. 오히려 서버의 로직을 거치지 않으므로 서버에 부담도 없다. 하지만 서버의 DB 나 혹은 XML 에 담겨진 데이타와 비교 혹은 검증을해야만 하는 경우엔 어쩔 수 없이 서버의 비지니스 로직을 거쳐야 한다. 하지만 이럴경우 코아 비지니스 로직을 수행하기 전에 입력폼의 값을 검증하는 로직을 추가로 코딩해야만 한다. 또한 입력값이 잘못 되었다면 어떤입력값이 어떻게 잘 못되었다고 친절하게 알려주는 새로운 페이지로 이동해야 한다거 나, 쉽게는 팝업처리를 할 수도 있다. 이렇게 되면 사용자는 또다시 처음부터 다시 입력을 해야하는 고생을 해야 한다.
이럴경우 AJAX 를 이용한 폼 입력값 검증작업을 해주면 비지니스 로직을 개발할때는 코어 로직만 작성하 면 되고, 고객 입장에서는 입력한 값이 어디가 어떻게 잘못된건지 바로 알수 있기때문에 아주 유용한 방법 이 될 것이다.
그럼 소스를 살펴보자. 코드가 길어지는 것을 방지하기 위해 되도록 소스는 단순하게 짜여졌다.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Using Ajax for validation</title>
<script type="text/javascript">
var xmlHttp;
function createXMLHttpRequest() { if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
} }
function validate() {
createXMLHttpRequest();
var date = document.getElementById("birthDate");
var url = "ValidationServlet?birthDate=" + escape(date.value);
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = callback;
xmlHttp.send(null);
}
function callback() {
if (xmlHttp.readyState == 4) { if (xmlHttp.status == 200) {
//var mes = xmlHttp.responseXML.getElementsByTagName("message")[0].firstChild.data;
var mes = xmlHttp.responseXML.getElementsByTagName("message")[0].firstChild.data;
var val = xmlHttp.responseXML.getElementsByTagName("passed")[0].firstChild.data;
setMessage(mes, val);
} } }
function setMessage(message, isValid) {
var messageArea = document.getElementById("dateMessage");
var fontColor = "red";
if (isValid == "true") {
fontColor = "green";
}
messageArea.innerHTML = "<font color=" + fontColor + ">" + message + " </font>";
} </script>
</head>
<body>
<h1>Ajax Validation Example</h1>
Birth date: <input type="text" size="10" id="birthDate" onchange="validate();"/>
<div id="dateMessage"></div>
</body>
</html>
<validateion.html 전체 소스 코드>
package ajaxbook.chap4;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.servlet.*;
import javax.servlet.http.*;
public class ValidationServlet extends HttpServlet {
/** Handles the HTTP <code>GET</code> method.
* @param request servlet request * @param response servlet response */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
boolean passed = validateDate(request.getParameter("birthDate"));
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
String message = "You have entered an invalid date.";
if (passed) {
message = "You have entered a valid date.";
}
out.println("<response>");
out.println("<passed>" + Boolean.toString(passed) + "</passed>");
out.println("<message>" + message + "</message>");
out.println("</response>");
out.close();
} /**
* Checks to see whether the argument is a valid date.
* A null date is considered invalid. This method * used the default data formatter and lenient * parsing.
*
* @param date a String representing the date to check
* @return message a String represnting the outcome of the check */
private boolean validateDate(String date) {
boolean isValid = true;
if(date != null) {
SimpleDateFormat formatter= new SimpleDateFormat("MM/dd/yyyy");
try {
formatter.parse(date);
} catch (ParseException pe) { System.out.println(pe.toString());
isValid = false;
} } else {
isValid = false;
}
return isValid;
} }
<ValidationServlet.java 의 전체 소스 코드>
이번 예제는 사실 설명이 불필요할 정도로 매우 간단하다. 브라우저에서는 날짜를 입력받는 필드만 있다.
날짜를 입력하고 난후 포커스가 빠져나가면 입력했던 날짜는 서버 프로그램으로 전송되고 입력된 값이 날 짜 형식에 적절한지 판단해서 다시 브라우저로 보내주는 형식이다.
<날짜를 잘못 입력했을 경우>
<날짜 형식으로 입력했을 경우>
AJAX 강의 4-2장 - 응답 헤더정보 다루기
웹 프로그래밍에서는 브라우저의 요청에 응답을 해야 한다. 정상적인 응답이든 비정상이든 브라우저는 그 결과를 표시한다. 이번 주제는 AJAX 를 이용하여 서버의 상태만을 확인해 볼 수 있는 방법을 제시하고자 한다. 서버의 상태를 확인하기 위해서는 특정 리소스 url 로 요청을 보내면 된다. 하지만 서버는 응답정보 를 브라우저에 보내게 되는데, 이럴경우에 응답정보의 모든 부분이 필요하지는 않는다. 단지 헤더정보만 얻 을 수 있으면 서버의 상태를 파악할 수 있다.
지금까지 XMLHttpRequest 객체의 open(method, url, asynch) 메소드의 method 에는 GET 및 POST 만 을 사용했었다. 하지만 HEAD 을 사용하면, 즉 브라우저가 HEAD 요청을 보내면, HEAD 요청을 받은 서버 는 응답을 보낼때 body 의 내용은 빼버리고 헤더 정보만 채워서 보내게 된다. 따라서 오고가는 정보의 양 이 극히 줄기때문에 브라우저에서 시간간격으로 서버의 상태를 점검하는데 아주 유용하게 사용할 수 있다.
이번 주제의 예제를 살펴보자.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Reading Response Headers</title>
<script type="text/javascript">
var xmlHttp;
var requestType = "";
function createXMLHttpRequest() { if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest();
} }
function doHeadRequest(request, url) { requestType = request;
createXMLHttpRequest();
xmlHttp.onreadystatechange = handleStateChange;
xmlHttp.open("HEAD", url, true);
xmlHttp.send(null);
}