progress bar 기능 구현하기
웹 프로그램의 경우 요청에 대한 응답이 제대로 오지 않거나 너무 많은 시간이 걸린다면 사용자는 불평을 하면서 다른 싸이트로 가버리고 다시는 그 싸이트를 이용하지 않을 것이다. 혹은 금전적인 문제가 걸려있다면 서비스 콜센터로 항의 전화를 할 것이다.
2년전 국내 모 은행 인터넷 뱅킹을 개발하면서 로그인 기능을 구현해 놓을 것을 살펴보고 놀라지 않을 수 없었다. 로그인을 하는데 자그마치 30초가 걸렸다. 웹 프로그램에서 30초라...어떻게 생각하는가? 당연히 설계가 잘못됬다. 고객에게 이런 불편을 초래하는 싸이트라면 경쟁 인터넷뱅킹 은행에게 모든 고객을 빼앗길 것이다.
몇년전의 통계수치라 지금은 기억이 잘 나지 않지만, 인터넷 이용자가 응답정보를 기다리다 인내심을 더이상 참지 못하고 다른 싸이트로 가버리는 시간은 7~8초 였던 것으로 기억한다. 하지만 지금은 좀더 짧아지지 않았을까 생각한다.
30초는 정말 말도 안되는 시간이지만 5~6초정도의 시간이면 사용자에게 현재 서버의 작업 진행상태를 표시해주면 사용자는 안도감을 느끼면서 좀 더 기다려줄 확률은 높아질 수 있다. 이것은 일종의 서비스 차원의 아이디어일뿐이지, 사실 서버의 프로그램을 수정해서 최대한 프로세스를 단축하는 것이 가장 좋은 해결책이라 하겠다.
로그인 하는데 30초 걸렸던 그 프로젝트에서는 할 수 없이 서버의 상태바를 이미지로 붙여 놓았다. 이런 이미지는 사실 의미가 없는것이 현재 서버의 상태를 실시간으로 보여주는 것이 아니라 반복적인 이미지로 하여금 고객을 짜증나게 할 수도 있다. 실제 서버의 작업 진척도와 현재 브라우저에서 보여주는 정보가 일치해야 진정한 상태바 프로그램이라 할 수 있겠다.
상태바 프로그램을 위해서는 자원의 소모라는 손해를 감수해야만 한다. 서버의 비지니스 로직이 현재 얼마나 진행됬는지 별도로 체크해야 하는 코딩이 추가되어야 한다. 가뜩이나 시간이 오래걸리는 작업인데 그 작업이 얼마나 진행됬는지 확인하는 로직이 추가된다면 자원의 소모가 그만큼 더 많아지게 되고 시간도 더 지연되는 것이다. 장점이 있다면 단점이 있기 마련이다. 장점을 더욱 부각시키고 단점을 줄이는 방향으로 생각을 전환하자.
이런 복잡한 문제에서 벗어나 지금은 상태바에 대한 구현 자체가 목적이므로 단순한 예제를 통해서 살펴보기로 하자.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Ajax Progress Bar</title>
<script type="text/javascript">
var xmlHttp;
var key;
var bar_color = 'gray';
var span_id = "block";
var clear = " "
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
function go() {
createXMLHttpRequest();
checkDiv();
var url = "ProgressBarServlet?task=create";
var button = document.getElementById("go");
button.disabled = true;
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = goCallback;
xmlHttp.send(null);
}
function goCallback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
setTimeout("pollServer()", 1000);
}
}
}
function pollServer() {
createXMLHttpRequest();
var url = "ProgressBarServlet?task=poll";
xmlHttp.open("GET", url, true);
xmlHttp.onreadystatechange = pollCallback;
xmlHttp.send(null);
}
function pollCallback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var percent_complete = xmlHttp.responseXML.getElementsByTagName("percent")[0].firstChild.data;
var index = processResult(percent_complete);
for (var i = 1; i <= index; i++) {
var elem = document.getElementById("block" + i);
elem.innerHTML = clear;
elem.style.backgroundColor = bar_color;
var next_cell = i + 1;
if (next_cell > index && next_cell <= 9) {
document.getElementById("block" + next_cell).innerHTML = percent_complete + "%";
}
}
if (index < 9) {
setTimeout("pollServer()", 1000);
} else {
document.getElementById("complete").innerHTML = "Complete!";
document.getElementById("go").disabled = false;
}
}
}
}
function processResult(percent_complete) {
var ind;
if (percent_complete.length == 1) {
ind = 1;
} else if (percent_complete.length == 2) {
ind = percent_complete.substring(0, 1);
} else {
ind = 9;
}
return ind;
}
function checkDiv() {
var progress_bar = document.getElementById("progressBar");
if (progress_bar.style.visibility == "visible") {
clearBar();
document.getElementById("complete").innerHTML = "";
} else {
progress_bar.style.visibility = "visible"
}
}
function clearBar() {
for (var i = 1; i < 10; i++) {
var elem = document.getElementById("block" + i);
elem.innerHTML = clear;
elem.style.backgroundColor = "white";
}
}
</script>
</head>
<body>
<h1>Ajax Progress Bar Example</h1>
Launch long-running process: <input type="button" value="Launch" id="go" onclick="go();"/>
<p>
<table align="center">
<tbody>
<tr><td>
<div id="progressBar" style="padding:2px;border:solid black 2px;visibility:hidden">
<span id="block1"> </span>
<span id="block2"> </span>
<span id="block3"> </span>
<span id="block4"> </span>
<span id="block5"> </span>
<span id="block6"> </span>
<span id="block7"> </span>
<span id="block8"> </span>
<span id="block9"> </span>
</div>
</td></tr>
<tr><td align="center" id="complete"></td></tr>
</tbody>
</table>
</body>
</html>
<progressBar.html 의 전체 소스 코드>
package ajaxbook.chap4;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
*
* @author nate
* @version
*/
public class ProgressBarServlet extends HttpServlet {
private int counter = 1;
/** 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 {
String task = request.getParameter("task");
String res = "";
if (task.equals("create")) {
res = "<key>1</key>";
counter = 1;
}
else {
String percent = "";
switch (counter) {
case 1: percent = "10"; break;
case 2: percent = "23"; break;
case 3: percent = "35"; break;
case 4: percent = "51"; break;
case 5: percent = "64"; break;
case 6: percent = "73"; break;
case 7: percent = "89"; break;
case 8: percent = "100"; break;
}
counter++;
res = "<percent>" + percent + "</percent>";
}
PrintWriter out = response.getWriter();
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
out.println("<response>");
out.println(res);
out.println("</response>");
out.close();
}
/** Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Short description";
}
}
<ProgressBarServlet.java 의 전체 소스 코드>
우선 실행 결과 화면을 먼저 살펴보자.
위 그림에서 Launch 버튼을 클릭하면 아래와 같은 상태바 결과를 확인 할 수 있다.
이런 상태바 프로그램을 작성하는데에는 ajax 가 정말 적합하다고 생각한다. 물론 자바스크립트 코드가 많아져서 이해하는데 어려움이 있을 수도 있지만 ajax 을 사용하지 않고 다른 방식으로 구현한다고 했을때 가능은 하겠지만 이때에도 역시 스크립팅 코드가 없을 수 만은 없다.
소스 코드는 이전예제와 별로 크게 다르지 않으므로 설명은 생략한다.
'WEB2.0 > ajax' 카테고리의 다른 글
웹서비스 접근하기 (0) | 2006.04.12 |
---|---|
툴팁 구현하기 (0) | 2006.04.12 |
Auto Refresh 기능 구현하기 (0) | 2006.04.11 |
동적으로 리스트박스 구성하기 (0) | 2006.04.11 |
응답 헤더정보 다루기 (0) | 2006.04.11 |