자식창 제어하기

Web/JSP 2007. 10. 26. 10:46
우선 자식창을 띄우는 객체와 메소드를 설명하겠습니다.

window 객체와 open()메서드를 사용해서 새 창을 엽니다.
var newWindow = window.open(http://naver.com, "Naver", "toolbar=no,location=no,status=no,scrollbars=no,resizable=no,menubar=no, titlebar=no, width=400, height=425");

open 메서드는 대략 위와 같은 파라미터를 가집니다.

첫번째 파라미터는 새창의 주소를 두번째 파라미터는 그 창의 이름 띄어쓰기 사용하면안됩니다.

마지막으로 세번째 파라미터는 새 창의 속성을 정합니다.

리턴값은 새창으로 띄운 것을 지칭하므로 이 객체를 가지고 새 창을 제어가 가능합니다.

새 창에서는 opener 라는 객체를 통해 부모창을 제어할 수 있습니다.

closed 란 속성을 사용해서 창이 닫혀있는지 여부를 알 수있습니다.

이를 통해 새창을 새로 띄울 것인지 focus() 메서드를 써서 창을 가리킬 것인지 정할 수 있습니다.
Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

자바스크립트의 브라우저 객체


Navagator 객체

Navigator 객체는 브라우저 객체의 하나로 사용자의 웹 브라우저의 종류와 자바사용이 가능한 브라우저 인지의 여부 등을 판별 해 줍니다

속성

appCodeName

브라우저 코드 이름을 알려줍니다 ★

appName

브라우저의 이름을 알려줍니다 ★

appVersion

브라우저의 버전정보를 알려줍니다 ★

userAgent

브라우저의 User Agent를 알려줍니다 ★

platform

사용중인 시스템 정보를 알려줍니다 ★

메소드

JavaEnabled()

자바 사용이 가능한지 여부를 true, false 형태로 알려줍니다

예문에서 간단한 사용사례를 살펴봅니다

  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. document.write("navigator.appCodeName ==> " , navigator.appCodeName , "<br>");
  4. document.write("navigator.appName ==> " , navigator.appName , "<br>");
  5. document.write("navigator.appVersion ==> " , navigator.appVersion , "<br>");
  6. document.write("navigator.userAgent ==> " , navigator.userAgent , "<br>");
  7. document.write("navigator.platform ==> " , navigator.platform , "<br>");
  8. document.write("사용중인 언어는 ==> " , navigator.language , "<br>");
  9. document.write("Mime Type 의 갯수는 ==> " , navigator.mimeTypes.length , "<br>");
  10. document.write("설치된 플러그인의 갯수는 ==> " , navigator.plugins.length , "<br>");


  11. if(navigator.JavaEnabled == true) {
  12.         document.write("자바사용이 가능한 브라우저 입니다<br>");
  13. }
  14. else {
  15.         document.write("자바사용이 불가능한 상태입니다<br>");
  16. }
  17. //-->
  18. </SCRIPT>


8~10번행에서 사용된 속성들은 네츠케이프에서는 아래와 같은 결과를 반환합니다

  • navigator.appCodeName ==> Mozilla
  • navigator.appName ==> Netscape
  • navigator.appVersion ==> 5.0 (Windows; en-US)
  • navigator.userAgent ==> Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.4) Gecko/20011019 Netscape6/6.2
  • navigator.platform ==> Win32
  • 사용중인 언어는 ==> en-US
  • Mime Type 의 갯수는 ==> 5
  • 설치된 플러그인의 갯수는 ==> 4
  • 자바사용이 불가능한 상태입니다

경우에 따라 브라우저의 버전정보를 정확히 파악하여 특정 페이지로 이동시켜 준다든지 하는 스크립트가 필요할 때가 많습니다. 다음의 예문은 네츠케이프와 익스플로러의 2.x에서 6.x 까지의 버전정보를 정확하게 판별하는 방법을 보여주고 있습니다. 소스가 좀 길어서 이해가 힘들 것 같지만 브라우저객체의 속성을 이해한 후 자세히 보면 의외로 간단합니다

  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. if (navigator.appName.charAt(0) == "N") {
  4.         if (navigator.appVersion.charAt(0) == 2) {
  5.         document.write("당신의 브라우저는 네츠케이프 2.x 버전입니다");
  6.         }
  7.         if (navigator.appVersion.charAt(0) == 3 ){
  8.         document.write("당신의 브라우저는 네츠케이프 3.x 버전입니다");
  9.         }
  10.         if (navigator.appVersion.charAt(0) == 4) {
  11.         document.write("당신의 브라우저는 네츠케이프 4.x 버전입니다");
  12.         }
  13.         if (navigator.appVersion.charAt(0) == 5) {
  14.         document.write("당신의 브라우저는 네츠케이프 6.x 이상의 버전입니다");
  15.         }
  16. }

  17. if (navigator.appName.charAt(0) == "M") {
  18.         if (navigator.appVersion.charAt(0) == "2") {
  19.         document.write("당신의 브라우저는 익스플로러 2.x 입니다");
  20.         }
  21.         if (navigator.appVersion.charAt(0) == "3") {
  22.         document.write("당신의 브라우저는 익스플로러 3.x 입니다");
  23.         }
  24.         if (navigator.appVersion.charAt(0) == "4") {
  25.                 if(navigator.appVersion.indexOf("MSIE 5") != -1) {
  26.                 document.write("당신의 브라우저는 익스플로러 5.x 입니다");
  27.                 }
  28.                 if(navigator.appVersion.indexOf("MSIE 6") != -1) {
  29.                 document.write("당신의 브라우저는 익스플로러 6.x 입니다");
  30.                 }
  31.                 else {
  32.                 document.write("당신의 브라우저는 익스플로러 4.x 입니다");
  33.                 }
  34.         if (navigator.appVersion.charAt(0) == "5") {
  35.                 document.write("당신의 브라우저는 익스플로러 5.x 입니다");
  36.                 }
  37.         }
  38. }
  39. //-->
  40. </SCRIPT>


파란색으로 표시된 함수들은 String 객체의 메소드 들이라고 배웠습니다.

charAt(0) 은 앞에서 지정한 문자열의 맨처음에 오는 문자를 반환합니다. 따라서 navigator.appName.charAt(0) == "N" 이라고 하면 브라우저의 이름을 반환하는 문자열중에서 첫 번째 나오는 문자가 N 이면, 이라는 뜻이됩니다. navigator.appName 속성은 네츠케이프 인 경우에 "Netscape", 익스플로러 인 경우에 "Microsoft Internet Explorer"를 반환합니다.

navigator.appVersion 속성은 네츠케이프의 경우에 2.x, 3.x, 4.x, 그리고 6.0 인 경우 5.0 (Windows; en-US) 의 형식으로 값을 반환하며, 익스플로러에서는 4.0 (compatible; MSIE 6.0; Windows 98) 의 형태로 반환받게 됩니다.즉, 4.0 이상의 경우 모두 4.0 으로 보여주며, 괄호안에 "MSIE 버전" 형태로 값을 출력하므로 코드가 좀 더 복잡하게 만들어 졌습니다.

indexOf("MSIE 5") != -1 는, appVersion 속성으로 얻어진 값(문자열)에서 "MSIE 5" 라는 글자가 있으면.. 이라는 뜻입니다. indexOf() 속성은 괄호안의 문자열의 위치값을 반환해 주고, 없을 경우 -1을 반환한다고 하였습니다.

위의 예문을 이용하면 브라우저별로 각각 다른 페이지나 메시지를 출력할 수 있는 환경이 만들어 집니다.


Window 객체

window 객체는 계층적 구조로 되어 있는 자바스크립트 계층구조 중에서 최상위에 있는 어른(?) 객체입니다. 이 객체는 그 자체적으로도 여러 가지 작업을 수행하지만 대부분 이 객체의 자식들인 하위객체를 이용해서 많은 일들을 수행하게 됩니다.

예를들어 우리는 경고창을 띄우는데 alert() 라는 메소드를 아무런 생각없이 사용하고, 문장을 출력하는데 document.write() 메소드를 사용하지만 실제로 이들 메소드는 window.alert(), window.document.write() 가 올바른 사용법입니다. 하지만, 대부분의 경우 최상위 객체인 window 는 자연스럽게 생략하여 사용해도 이 어른(?)은 이해를 다 해 줍니다. 자식사랑은 끝이 없군요.

window 객체의 속성과 메소드는 다음과 같습니다

속성

메소드

closed

창의 닫힘여부(true/false)

alert()

경고창을 보여줍니다 ★

defaultStatus

상태표시줄의 초기문자열

blur()

focus를 제거합니다

document

document 객체

clearInterval()

setInterval()메소드에의해 수행되고 있는 함수를 중지합니다

frames

프레임 객체

clearTimeout()

setTimeout()메소드에의해 수행되고 있는 함수를 중지합니다

history

history 객체

close()

창을 닫습니다

length

프레임의 수

comfirm()

확인버튼이 있는 창을 엽니다 ★

location

location 객체

focus()

focus를 줍니다

name

창의 이름

moveBy()

상대적 좌표로 창을 이동합니다

opener

현재창을 열어준 윈도우

moveTo()

절대위치로 창을 이동합니다

parent

부모 프레임

open()

새로운 창을 열어줍니다

self

현재창 자신

print()

화면의 내용을 프린트로 출력합니다 ★

status

상태표시줄의 문자열

prompt()

입력란이 있는 대화상자를 엽니다 ★

top

가장 앞쪽 창

resizeBy()

상대적 크기를 이용해서 창의 크기를 변경합니다 ★

window

현재창(=self)

resizeTo()

절대크기로 창크기를 변경합니다 ★

 

scroll()

창을 스크롤 시킵니다 ★



scrollBy()

상대적 좌표로 창을 스크롤 시킵니다 ★



scrollTo()

절대적 좌표로 창을 스크롤 시킵니다 ★



setInterval()

일정시간 간격으로 지정함수를 반복 호출 합니다



setTimeout()

일정시간 후 지정함수를 호출 합니다

먼저, 팝업창을 만들어 주는 window.open() 메소드를 보겠습니다. window.open() 메소드의 사용법은 다음과 같습니다.

window.open("팝업창으로 보여줄 문서","팝업창의 이름","옵션")

  • <SCRIPT LANGUAGE="JavaScript">
  • <!--
  • window.open("http://cafe.naver.com/ss2education.cafe", "삼성컴퓨터인터넷강좌", "width=500,height=300,left=0,top=0,resizable=no");
  • //-->
  • </SCRIPT>


이 예문은 http://cafe.naver.com/ss2education.cafe 페이지를 가로 500픽셀, 높이 300 픽셀의 크기로 왼족위 모서리에 붙게 팝업창으로 열어줍니다. 두 번째 인자인 "dreamwiz" 는 뭐냐구요? 이 부분은 팝업창의 이름을 말하는 것으로 프레임 문서에서 타겟(target) 처럼 사용할 수 있습니다.. 즉, <a href="xxx.html" target="삼성컴퓨터인터넷강좌"> 열기</a> 처럼 사용하게 되면, 현재 드림위즈 홈페이지가 열려있는 팝업창에 xxx.html 문서가 열리게 되는 것이랍니다. 이 두 번째 인자에 아무것도 입력하지 않으려면 그냥 "" 만 표시 해 줍니다. (예) : window.open("http://cafe.naver.com/ss2education.cafe", "", "옵션들")

세 번째 인자에는 옵션들을 설정 합니다. 이곳에서 사용할 수 있는 옵션에는 아래와 같은 것들이 있습니다

menubar

yes/no, 1/0

메뉴바를 보여주거나 숨깁니다

toolbar

yes/no, 1/0

도구막대를 보여주거나 숨깁니다

directories

yes/no, 1/0

디렉토리바를 보여주거나 숨깁니다

scrollbars

yes/no, 1/0

스크롤바를 보여주거나 숨깁니다

status

yes/no, 1/0

상태표시줄을 보여주거나 숨깁니다

location

yes/no, 1/0

주소표시줄을 보여주거나 숨깁니다

width

픽셀

팝업 윈도우의 가로크기를 지정합니다

height

픽셀

팝업 윈도우의 높이를 지정합니다

left

픽셀

팝업 윈도우의 x축 위치를 지정합니다

top

픽셀

팝업 윈도우의 y축 위치를 지정합니다

resizable

yes/no 1/0

팝업윈도우의 크기를 사용자가 임의로 수정할 수 있는지 여부를 지정합니다

fullscreen


전체화면 모드로 열어줍니다

channelmode


채널모드 창으로 열어줍니다


옵션인자를 지정하지 않으면 현재 창의 모양과 같은 형태로 팝업윈도우가 열리게 되고, 어느 한가지 옵션만 지정하면 나머지는 모두 디폴트 값으로 no 가 설정 됩니다.

버튼을 클릭하면 아무런 옵션이 없는 팝업 윈도우가 열리게 하는 코드는 아래와 같습니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winOpen() {
  9. window.open("http://cafe.naver.com/ss2education.cafe","삼성컴인터넷강좌");
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <input type=button onclick="winOpen();" value="옵션없이 팝업윈도우 열기">

  16. </BODY>

  17. </HTML>


위에서 보듯이 옵션을 사용하지 않으면 <a href="xxx.html" target="_blank">열기</a> 처럼 태그를 사용한 것과 같은 효과를 줍니다. 이 옵션 인자는 지정하지 않아도 되지만, 두 번재 인자인 name 은 사용하지 않더라도 반드시 "" 으로 표시해 주어야 한다는 것은 명심하기 바랍니다.

그럼, 이번에는 몇가지 옵션만 선별적으로 주는 예를 보겠습니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winOpen() {
  9. window.open("http://cafe.naver.com/ss2education.cafe","삼성컴퓨터인터넷강좌","location=yes,width=400,height=300");
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <input type=button onclick="winOpen();" value="location=yes,width=400,height=300">

  16. </BODY>

  17. </HTML>


위의 예에서 보듯이 특정 옵션을 지정하면 나머지 옵션값은 자동으로 no를 준 것과 같은 효과를 나타냅니다. 옵션을 줄때 주의할점은 절대 공백을 주어서는 안됩니다. 공백을 주게되면 네츠케이프 등에서는 에러를 발생시킬 수 있습니다

이번에는 잘 이용하면 아주 요긴하게 사용될 수 있는 fullscreen 모드와 channelmode 옵션으로 팝업윈도우를 열어보도록 하겠습니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function fullOpen() { // fullscreen 모드로 열기 함수
  9. window.open("http://cafe.naver.com/ss2education.cafe","삼성컴퓨터인터넷강좌","fullscreen");
  10. }

  11. function channelOpen() { // 채널모드로 열기 함수
  12. window.open("http://cafe.naver.com/ss2education.cafe","삼성컴퓨터인터넷강좌","channelmode");
  13. }
  14. //-->
  15. </SCRIPT>

  16. </HEAD>

  17. <BODY>

  18. <input type=button onclick="fullOpen();" value="fullscreen">
  19. <p>fullscreen 윈도우를 닫으려면 Alt+F4 키를 누르세요
  20. <p>
  21. <input type=button onclick="channelOpen();" value="channelmode">

  22. </BODY>

  23. </HTML>


상태표시줄에 메시지를 보여주는 예제를 만들어 보겠습니다. window 객체에는 status 라는 속성이 있다고 하였습니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winStatus() {
  9. window.status = "안녕하세요? 자바스크립트는 재미있습니다";
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <a href="http://cafe.naver.com/ss2education.cafe" onmouseOver = "winStatus(); return true;">마우스를 대어 보세요</a>

  16. </BODY>

  17. </HTML>


링크에 마우스를 대면 상태표시줄에 메시지를 보여주는 함수를 9~11번행에서 미리 정의한 후 이 함수를 19번행에서 mouseOver 이벤트가 발생하면 호출되도록 코딩 되었습니다.

19번행에서 함수호출 다음에 return true를 사용하였는데, 이는 함수를 호출하고 마우스를 다른 곳으로 옮겨도 상태표시줄에 그 메시지가 그대로 남아 있게 하기위함입니다. return false 로 설정하면 마우스를 떼었을 때는 해당 링크 주소가 보여지게 됩니다.


window.close()

window.open() 메소드는 새로운 팝업윈도우를 열어주는 역할을 하고, window.close()0 메소드는 윈도우를 닫아주는 역할을 합니다.

이 window.close() 메소드를 사용하면 팝업창인 경우에는 그냥 닫아 버리지만, 팝업창이 아닌 경우에는 윈도우를 닫을지를 물어보는 경고 메시지가 뜨게 됩니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winOpen() {
  9. window.open("http://cafe.naver.com/ss2education.cafe","sample","width=400,height=300");
  10. }
  11. function winClose() {
  12. window.close();
  13. }
  14. //-->
  15. </SCRIPT>

  16. </HEAD>

  17. <BODY>

  18. <a href="#" onclick="winOpen()">팝업 윈도우 열기</a><br>
  19. <a href="#" onclick="winClose()">현재 윈도우 닫기</a><br>

  20. </BODY>

  21. </HTML>


물론 위와 같은 간단한 코드 사용시에는 특별히 함수를 사용하지 않고 인라인 자바스크립트를 사용해도 무방합니다. 아래처럼 HTML 태그내에서 사용되는 자바스크립트를 인라인 자바스크립트라고 합니다

  •  <a href="#" onclick="window.open('http://cafe.naver.com/ss2education.cafe','sample','width=400,height=300')">팝업 윈도우 열기</a><br>
  • <a href="#" onclick="window.close()">현재 윈도우 닫기</a><br>


window.moveTo(x,y)

window.moveTo(x,y) 메소드는 괄호안에서 지정된 위치로 윈도우의 위치를 이동시켜주는 메소드입니다.샘플 스크립트를 볼까요?

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winMoveTo() {
  9. window.moveTo(300,250);
  10. }
  11. function winMoveTo_00() {
  12. window.moveTo(0,0);
  13. }
  14. //-->
  15. </SCRIPT>

  16. </HEAD>

  17. <BODY>

  18. <p><input type=button onclick="winMoveTo()" value="이동하기">
  19. <p><input type=button onclick="winMoveTo_00()" value="원래대로 이동하기">
  20. <p><input type=button onclick="window.moveTo(300,250)" value="이동하기">

  21. </BODY>

  22. </HTML>


9~11번행에서 선언한 함수는 윈도우의 위치를 x축-300픽셀, y축-250 픽셀의 위치로 이동시켜주며, 12~14번행에서 선언한 함수는 x,y 축 의 위치를 왼쪽위(0,0) 로 이동시켜줍니다.

물론 14번행에서 처럼 인라인 자바스크립트를 사용해도 무방합니다.


window.moveBy(x,y)

window.moveBy(x,y) 메소드는 괄호안에서 지정된 픽셀수만큼 윈도우의 위치를 이동시켜주는 메소드입니다.window.moveTo() 메소드와 어떻게 다른지 샘플 스크립트를 볼까요?

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winMoveBy() {
  9. window.moveBy(10,10);
  10. }
  11. function winMoveBy2() {
  12. window.moveBy(-10,-10);
  13. }
  14. //-->
  15. </SCRIPT>

  16. </HEAD>

  17. <BODY>

  18. <p><input type=button onclick="winMoveBy()" value="이동하기(↘)">
  19. <p><input type=button onclick="winMoveBy2()" value="이동하기(↖)">
  20. <p><input type=button onclick="window.moveBy(10,10)" value="이동하기(↘)">

  21. </BODY>

  22. </HTML>


9~11번행에서 선언한 함수는 윈도우의 위치를 오른쪽으로 10픽셀, 아래쪽으로 10 픽셀의 위치로 이동시켜주며, 12~14번행에서 선언한 함수는 왼쪽으로10 픽셀, 위쪽으로 10 픽셀씩 이동시켜줍니다.

물론 24번행에서 처럼 인라인 자바스크립트를 사용해도 무방합니다.


window.resizeTo(x,y)

window.resizeTo(x,y) 메소드는 괄호안에서 지정된 크기로 윈도우 자체의 크기를 변경시켜주는 메소드입니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winResizeTo() {
  9. window.resizeTo(150,150);
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <p><input type=button onclick="winResizeTo()" value="윈도우 크기 변경하기">

  16. </BODY>

  17. </HTML>


9~11번행에서 선언한 함수는 윈도우의 크기를 150*150 픽셀 크기로 변경시켜주며, 19번행에서 호출하여 사용합니다.


window.resizeBy()

window.resizeBy() 메소드는 괄호안에서 지정된 크기만큼씩 윈도우 자체의 크기를 변경시켜주는 메소드입니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winResizeBy() {
  9. window.resizeBy(50,50);
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <p><input type=button onclick="winResizeBy()" value="윈도우 크기 변경하기">

  16. </BODY>

  17. </HTML>


9~11번행에서 선언한 함수는 윈도우의 크기를 50*50 픽셀씩 증가시켜주며, 19번행에서 호출하여 사용합니다. 물론, 숫자를 음수로 지정하면 그 크기만큼 작아집니다

예 : window.resizeBy(-50,-50)


window.scrollBy()

window.scrollBy() 메소드는 괄호안에서 지정된 크기만큼 문서의 내용을 스크롤 시켜주는 메소드입니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winScrollBy_1() {
  9. window.scrollBy(0,50);
  10. }
  11. function winScrollBy_2() {
  12. window.scrollBy(0,-50);
  13. }
  14. //-->
  15. </SCRIPT>

  16. </HEAD>

  17. <BODY>
  18. <p><img src="http://www.jasko.co.kr/java_data/img1.jpg">
  19. <p><input type=button onclick="winScrollBy_1()" value="아래로 스크롤">
  20. <p><input type=button onclick="winScrollBy_2()" value="위로 스크롤">
  21. <p><img src="http://www.jasko.co.kr/java_data/img2.jpg">

  22. </BODY>
  23. </HTML>


window.scrollTo()

window.scrollTo() 메소드는 괄호안에서 지정된 위치로 창을 스크롤 시켜주는 메소드입니다.scrollBy() 메소드와 다른점은 scrollBy() 가 상대적 위치만큼 이동하는데 비해, scrollTo() 메소드는 절대좌표로 이동시켜 줍니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winScroll() {
  9. window.scrollTo(0,200);
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <p><input type=button onclick="winScroll()" value="아래로 스크롤">
  16. <p><img src="http://www.jasko.co.kr/java_data/img1.jpg">
  17. <p><img src="http://www.jasko.co.kr/java_data/img2.jpg">

  18. </BODY>

  19. </HTML>


10번행에서는 창의 위치를 위쪽(y-좌표)에서 200픽셀 떨어진으로 스크롤 시켜주는 함수를 정의합니다.


window.alert()

이번에는 경고창(alert box)를 나타내 주는 스크립트에 대해 알아보도록 하겠습니다

경고창을 나타낼 때는 alert() 라는 메소드를 사용합니다. 먼저 아래 예문을 살펴보도록 하죠


  1. <HTML>
  2. <HEAD>
  3. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  4. <TITLE> Jasko Sample Script </TITLE>

  5. </HEAD>

  6. <BODY>

  7. <script>
  8. <!--
  9. alert("안녕하세요?\n자바스크립트를 공부하는 중입니다");
  10. //-->
  11. </script>

  12. </BODY>
  13. </HTML>
 


어때요? document.write() 메소드랑 다른게 있나요?

그렇습니다. 문자열을 따옴표 안에 넣어 표현하는 것은 같지만 줄바꿈태그 대신 이상한 부호들이 들어가 있죠?

파란색으로 표시된 \n 은 한줄바꿈 표시입니다. 두줄을 바꾸려면 연속해서 \n\n을 넣어주면 됩니다.

alert() 메소드를 사용할 때는 HTML 태그는 사용할 수 없답니다.


window.confirm()

이번시간에는 메시지를 방문자들에게 보여주고 확인/취소를 선택하면 특별한 행동을 할 수 있게 해 주는 확인상자에 대해 알아보도록 합니다.

확인상자는 confirm() 이라는 함수를 사용합니다

아래의 예문을 보도록 합니다

  1. <HTML>
  2. <HEAD>
  3. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  4. <TITLE> Jasko Sample Script </TITLE>

  5. </HEAD>

  6. <BODY>

  1. <script>
  2. <!--
  3. yesorno = confirm("당신은 남자분 이시군요. 그렇죠?")
  4. if(yesorno == true)
  5.    document.write("당신은 <font color=red>남성</font>입니다")
  6. else
  7.   document.write("당신은 <font color=blue>여성</font>입니다")
  8. //-->
  9. </script>

  1. </BODY>
  2. </HTML>


위의 예문에서는 갑자기 처음 보는 듯한 용어들이 많이 나왔습니다. 하지만 너무 걱정하지 마세요. 뒷부분에서 자세히 다루게 될테니까요.

우선 간단하게 설명 드리도록 하겠습니다.

3번째 줄에 있는 yesorno = confirm("당신은 남자분 이시군요. 그렇죠?")

에서 confirm() 이라는 함수를 사용하였습니다. 따옴표 안에는 사용자들에게 하는 질문이 들어 있는데 그 결과값을 yesorno 라는 변수에 담아두고, 확인 버튼을 클릭하면 5번째 구문이, 그렇지 않으면 7번째 구문이 실행 됩니다.

자바스크립트에서 A = 변수값 이라는 형태가 자주 사용되는데 이는 변수값을 A 라는 변수에 저장한다는 뜻으로 이해하면 됩니다

즉, 위의 예에서는 confirm() 함수의 결과값을 yesorno 라는 변수에 담아둔다는 말이 됩니다.

그리고, if ~ else 구문도 나왔는데, 이 구문은 앞으로 여러분들이 공부하면서 상당히 자주 접하게 되는 자바스크립트의 제어문의 하나입니다. 내용은 만약~이라면~, 그렇지 않으면~ 라는 영문법 식으로 해석을 해도 됩니다.


window.prompt()

어떤 사이트에 가면 이름을 물어보고 입력하면 문서에 내 이름을 출력 해주는 스크립트를 본적이 있나요?

이번시간에는 방문자들로부터 원하는 데이터를 입력받게 해주는 prompt() 함수에 대해 알아보도록 하겠습니다

  1. <HTML>
  2. <HEAD>
  3. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  4. <TITLE> Jasko Sample Script </TITLE>
  5. </HEAD>

  6. <BODY>

  7. <script>
  8. <!--
  9. name = prompt("손님의 이름을 적어주세요","나그네")
  10. document.write("<font color=blue>" + name + "</font>님 감사합니다")
  11. //-->
  12. </script>

  13. </BODY>
  14. </HTML>


자, 이번 예제는 name 이라는 변수를 사용한 것과 함수의 따옴표 안에 무자열을 넣어주는 법은 앞전의 confirm() 함수를 사용할 때와 비슷한 것 같아 보입니다.

우선, 설명부터 드리자면 prompt() 함수에서 '손님의 이름을 적어주세요' 라는 부분은 입력상자에 나타낼 메시지입니다. 그리고 오른쪽에 '나그네' 라고 되어 있는 부분에는 디폴트값을 넣어 주었습니다.

형식은 prompt("메세지","디폴트값") 의 모양으로 사용합니다

그리고, 사용자가 입력한 값을 name 이라는 변수에 담아 두었다가 12번째 라인에서 써먹게 됩니다.

12번째 라인을 자세히 보면 document.write() 함수의 괄호안에 따옴표가 좀 복잡하게 사용된 듯 합니다.

보시는대로 HTML 태그나 일반 문자열은 따옴표 안에 들어 있고, 11번째 라인에서 사용한 name 이라는 변수는 따옴표를 사용하지 않았죠? 그렇습니다. 자바스크립트 내에서 선언된 변수는 따옴표를 붙이지 않습니다.


window.print()

window.print() 메소드는 현재의 문서를 인쇄 할 수 있게 해 줍니다. 이 print() 메소드를 호출하면 브라우저의 프린트 버튼을 클릭한 것과 동일한 효과를 줍니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function winPrint() {
  9. window.print();
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <p><input type=button onclick="winPrint()" value="화면인쇄">
  16. <p><input type=button onclick="window.print()" value="화면인쇄">

  17. </BODY>

  18. </HTML>


19번행에서는 문서의 HEAD 부분에서 미리 선언해둔 함수를 통해 프린트를 하는 버튼을 보여주고 있고, 20번 행에서는 인라인 스크립트를 사용하여 화면을 프린트 하는 샘플을 보여주고 있습니다.


window.blur(), window.focus()

blur() 와 focus() 메소드는 현재창에 포커스를 주거나 해제하는 기능을 합니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. myWin = window.open("sample54-11.html","sample","width=300,height=300");
  9. function winFocus() {
  10. myWin.focus();
  11. }
  12. function winBlur() {
  13. myWin.blur();
  14. }

  15. //-->
  16. </SCRIPT>

  17. </HEAD>

  18. <BODY>

  19. <p><input type=button onclick="winFocus()" value="앞으로 보내기">
  20. <p><input type=button onclick="winBlur()" value="뒤로 보내기">

  21. </BODY>

  22. </HTML>


9번행에서 새로운 팝업윈도우를 열고 myWin 이라는 변수에 저장해 두었습니다

10~12번행에서 팝업윈도우에 포커스를 주는 함수를 정의하고, 13~15번행에서는 포커스를 해제하는 함수를 정의하였습니다.


setTimeout() 메소드

setTimeout() 은 지정된 시간후 특정 코드를 실행시켜주는 메소드입니다. 뒤에서 다룰 setInterval() 과는 달리 setTimeout() 메소드를 사용하면 지정된 코드는 한번만 실행 됩니다. 사용형식은 아래와 같습니다

 setTimeout(code,delay)

code : 일정시간 후 실행시킬 자바스크립트 코드를 포함한 문자열

delay : 문자열 code 내에 있는 자바스크립트 코드가 실행되기까지 걸리는 시간 (1/1000초 단위)

아래의 예는 3초 후에 alert()를 실행시키는 setTimeout()을 이용한 간단한 예문입니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function Timer() {
  9. setTimeout("alert('3초후에, 안녕하세요')",3000);
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <p><input type=button onclick="Timer()" value="3초후에 인사하기">

  16. </BODY>

  17. </HTML>

이번에는 setTimeout()을 이용하여 입력상자에 실시간으로 작동하는 디지털시계를 만들어 보겠습니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function Timer() {
  9. var now = new Date();
  10. var H = now.getHours();
  11. var M = now.getMinutes();
  12. var S = now.getSeconds();
  13. myForm.myText.value = "지금은 " + H + "시" + M + "분" + S + "초";
  14. setTimeout("Timer()", 1000);
  15. }
  16. document.onLoad = setTimeout("Timer()",1000);
  17. //-->
  18. </SCRIPT>

  19. </HEAD>

  20. <BODY>

  21. <form name=myForm>
  22. <input type=text name=myText style="text-align:center">
  23. </form>

  24. </BODY>
  25. </HTML>


9~14번행에서는 26번행의 텍스트 입력상자에 현재시간을 보여주는 Timer() 함수를 정의한 코드입니다. 그냥 단순히 보여주기만 해서는 실시간으로 변화하는 시간을 알려줄 수가 없기 때문에 15번행에서 1초(1000)후에 다시 Timer() 함수를 호출하여 현재시간을 표시하고 있습니다.

17번행에서 이렇게 재귀적으로 반복 호출되는 Timer() 함수를 페이지가 로딩되면 실행토록 하였습니다.


setInterval() 메소드

setInterval()은 지정된 시간후 특정 자바스크립트 코드가 포함된 문자열을 반복하여 호출하는 메소드입니다. setTimeout() 이 지정 시간 후 한번만 호출하는데 비해, 이 메소드는 반복하여 호출 됩니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function myFunc() {
  9. setInterval("alert('안녕하세요')",1000);
  10. }
  11. document.onLoad = myFunc();
  12. //-->
  13. </SCRIPT>

  14. </HEAD>

  15. <BODY>

  16. <b>1초 간격으로 반복해서 경고창이 뜹니다

  17. </BODY>
  18. </HTML>

9~11번행에서 1초(1000)마다 경고창을 띄우는 함수 myFunc()를 정의하고, 12번행에서는 이 함수를 문서가 로딩되면 실행되도록 호출하였습니다

window 의 setInterval() 메소드를 이용하여, 우리가 자바스크립트에 관심을 갖게되는 가장 기본적인 자바스크립트 효과인 브라우저의 상태표시줄에 메시지 보여주기를 할 수 있습니다.
아래의 자세한 설명이 첨부된 예문을 보면서 배워 보기로 할까요?

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. // 메세지의 시작부분을 결정하는 변수를 설정 합니다
  9. var $count = 0  

  10. // 공백 메세지를 설정 합니다
  11. var $message = " "      

  12. // 메세지 앞에 보여줄 공백칸을 50개 입력 합니다
  13. // 이 공백은 메세지를 흐르게 하는 효과를 주기위한 메세지 시작 앞 부분에
  14. // 보여줄 공백 문자열 입니다.
  15. for(i=0; i<50; i++) {
  16.         $message += " "
  17. }

  18. // 실제 메세지들을 공백 메세지 뒤에 붙입니다
  19. $message += "자바스크립트는 재미있습니다...."
  20. $message += "즐거운 시간 되세요...."

  21. // 이제, 메세지들을 스크롤 시키는 함수를 정의 합니다
  22. function myScroll()            
  23. {      
  24. // 메세지 문자열에서 $count 이후 부터, $count + 150 개의 문자열을 추출하여 보여줍니다
  25. // substring(start,length) 메소드는 start 번째 이후부터 length 개의 문자열을 추출합니다
  26. window.status = $message.substring($count, $count + 150)

  27. // 이제 $count 변수값을 1 씩 증가시켜 줍니다.
  28. // 그러면 substring($count, $count + 150) 메소드에 의해
  29. // 초기에는 substring(0,150) 이므로, 첫번째 문자부터 150 번째 까지 보여주고,
  30. // 그 다음에는 substring(1,151)이 되므로, 두번째 문자부터 151번째 까지 보여주고,
  31. // 그 다음에는 substring(2,152)이 되므로, 세번째 문자부터 152번째 까지 보여주는 식으로 되겠죠
  32. $count++;                               

  33. // 그렇게 해서 $count가 문자열의 길이($message.length) 보다 커지면 메시지가 모두 출력된 것이므로
  34. // 메시지가 처음부터 다시 흐르도록 $count 에 0을 다시 지정해 줍니다.
  35. if($count>$message.length)      {
  36.         $count = 0;
  37. }
  38. }
  39. // 이제 이렇게 설정 된 myScroll( ) 함수를 setInterval() 메소드를 이용해 0.05 초 마다 호출합니다
  40. setInterval(함수,시간간격) 메소드는 지정된 시간간격 마다 함수가 반복해서 호출해 주는 역할을 합니다
  41. document.onload=setInterval("myScroll()",50);
  42. //-->
  43. </SCRIPT>
  44. </HEAD>

  45. <BODY>

  46. <H3 align=center> 아래 상태표시줄을 보세요 </H3>

  47. </BODY>
  48. </HTML>


window.closed

이 속성은 특정 윈도우가 닫여있는지 여부를 체크하여 true 나 false 값으로 반환합니다.

아래 예문은 현재의 윈도우가 열려있는 상태인지 아닌지를 체크하여 메시지를 출력하도록 한 간단한 예문이지만, 팝업 윈도우를 열고 그 팝업 윈도우에서 opener 페이지(팝업윈도우를 열어준 페이지)를 참조하고자 할 때 이 closed 프로퍼티를 주로 사용합니다

  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. if (window.closed) {
  4. document.write("윈도우가 닫힌 상태입니다");
  5. }
  6. else {
  7. document.write("윈도우가 열려 있는 상태입니다");
  8. }
  9. //-->
  10. </SCRIPT>

3번행에서는 현재의 윈도우가 닫힌 상태이면 true 를, 열려있는 상태이면 false를 반환합니다. 당연히 여러분들이 보고 있는 이 윈도우는 열려있는 상태이므로 false를 반환받아 7번행을 리턴합니다

다음에서 오프너 윈도우가 열려있는지 여부를 알려주는 간단한 예문을 살펴보고 넘어가겠습니다. 이 예문은 현재윈도우(opener)에서 버튼을 클릭하면 열려지는 팝업 윈도우에 사용된 코드 입니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function myFunc() {
  9.         if (opener.closed) {
  10.         alert("오프너 윈도우가 사라졌어요");
  11.         }
  12.         else {
  13.         alert("오프너 윈도우가 아직 열려 있습니다");
  14.         }
  15. }
  16. //-->
  17. </SCRIPT>

  18. </HEAD>

  19. <BODY>

  20. <input type=button onClick="myFunc();" value="확인하기">

  21. </BODY>
  22. </HTML>

현재의 창을 닫고 팝업윈도우에 있는 버튼을 클릭하면 11번째행의 구문이, 현재의 창이 있는 상태에서 버튼을 클릭하면 14번째행의 구문이 출력 됩니다.


window.defaultStatus 속성

defaultStatus 프로퍼티는 윈도우의 상태표시줄에 메시지를 보여줍니다.일반적으로 문서내의 하이퍼링크에 마우스를 대면 상태표시줄에서는 해당 URL을 출력 해 주지만 마우스를 떼었을 때는 공백을 보여줍니다. 이 경우 defaultStatus를 설정 해 두면 마우스를 떼었을 때에도 상태표시줄에 기본값으로 설정한 defaultStatus 값을 출력 해 줍니다.

이 defaultStatus 속성은 읽기/쓰기가 가능하며 반영구적입니다. 일시적인 메시지를 출력 하려면 status 프로퍼티를 사용합니다

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. defaultStatus = "안녕하세요"
  9. //-->
  10. </SCRIPT>

  11. </HEAD>

  12. <BODY>

  13. <input type=button onClick="javascript:defaultStatus='반갑습니다';" value="바꾸기">
  14. <p>
  15. <a href="http://www.jasko.co.kr">JASKO</a>

  16. </BODY>
  17. </HTML>


opener 프로퍼티, name 프로퍼티

opener 프로퍼티는 팝업창에서 팝업창을 열어준 윈도우를 참조할 때 사용되는 프로퍼티입니다. 반대로 opener에서 팝업윈도우를 참조할 때는 팝업윈도우의 name 이 아닌, 팝업윈도우의 변수값을 참조한다는 점 기억해 두세요

아래 예문에서는 팝업윈도우를 열 때 myWin = window.open('sample61-2.html','popwindow','옵션') 의 코드로 열어주었으므로 오프너에서 팝업윈도우를 참조하려면 myWin 이라는 변수값을 사용해야 합니다

여기에서 사용된 팝업윈도우의 이름인 popwindow 는 HTML 코드에서 타겟을 지정할 때처럼 타겟으로 사용됩니다.

오프너 페이지

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> 삼성컴퓨터학원 인터넷강좌</TITLE>

  6. <SCRIPT LANGUAGE="JavaScript">
  7. <!--
  8. function openWin() {
  9. myWin = window.open('sample61-2.html','popwindow','width=600,height=300');
  10. }
  11. //-->
  12. </SCRIPT>

  13. </HEAD>

  14. <BODY>

  15. <input type=button onclick="openWin();" value="팝업창 열기">
  16. <input type=button onclick="myWin.close();" value="팝업창 닫기">

  17. </BODY>
  18. </HTML>

9~11번행에서 정의된 openWin() 함수에서는 새로운 팝업윈도우를 myWin 이라는 변수에 담아 열어주는 함수입니다. 21번행에서 사용된 팝업윈도우 닫기 코드에서 사용된 myWin을 주의깊게 살펴 보세요

오프너 페이지에서 <a href="http://cafe.naver.com/ss2education.cafe" target="popwindow"> 처럼 태그를 사용하면 팝업윈도우에 자스코 홈페이지가 열리게 됩니다

팝업 윈도우

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <META http-equiv="content-type" content="text/html; charset=euc-kr">
  5. <TITLE> Jasko Sample Script </TITLE>

  6. </HEAD>

  7. <BODY>

  8. <input type=button onclick="alert('현재창의 이름은 : ' + window.name)" value="현재창의 이름">
  9. <input type=button onclick="opener.location='http://cafe.naver.com/ss2education.cafe'" value="삼성컴퓨터인터넷강좌 열기">

  10. </BODY>
  11. </HTML>


window.name 프로퍼티는 현재윈도우의 이름값을 반환해 줍니다. 11번 행의 코드를 실행시키면 팝업윈도우의 이름인 popwindow를 반환해 줍니다

팝업윈도우에서 오프너 페이지에 다른 페이지를 불러오려면 참조값으로 opener 프로퍼티를 사용해야 합니다.



 
출처: http://cafe.naver.com/ss2education.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=78
Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

JavaScript 배열

Web/JSP 2007. 10. 26. 10:44
Java 의 Vector 클래스는 내부적으로 배열을 사용하고 있다. 따라서 Vector 의 자바스크립트 버전을 만들기 위해서는 Array 객체에 대한 빵빵한 지식이 필요하다 (없어도 된다. 그러나 있으면 매우 좋다). 자! 배열의 기초와 유용한 메쏘드들을 살펴보자.

배열의 생성
1. 생성자를 이용한 생성
- new Array(arrayLength)
ex) friends = new Array(3); // 크기가 3 인 배열 생성
- new Array(element0, element1, ... , elementN)
ex) friends = new Array("개똥이", "소똥이", "말똥이"); // 크기 3인 배열 생성(값이 채워짐)
2. 직접 생성
friends = ["개똥이", "소똥이", "말똥이"];

간접적인 배열 길이의 증가
배열의 길이는 현재 배열의 길이보다 큰 인덱스를 사용하면 자동으로 증가한다. 아래는 배열의 길이가 0 인 객체 생성 후 99번째 요소에 값을 할당하여 배열의 길이가 100 으로 증가한 예이다.
friends = new Array();
friends[99] = "새똥이";

메쏘드 종류
concat : 두개의 배열을 합쳐 새로운 배열을 리턴한다. 원본 배열은 변하지 않는다.
문법
arrayName.concat(arrayName2, arrayName3, ... , arrayNameN)
인자
arrayName2, ... , arrayNameN - 합쳐질 인자들
예제
두 배열을 합치는 예
alpha = new Array("a", "b", "c");
numeric = new Array(1, 2, 3);
alphaNumeric = alpha.concat(numeric); // ["a", "b", "c", 1, 2, 3] 배열 생성

join : 모든 요소가 구분자로 이어진 문자열을 리턴한다. 디폴트 구분자는 comma(,) 이다.
문법
arrayName.join(separator)
인자
separator 요소와 요소 사이에 사용될 구분자 문자열
예제
friends = new Array("소똥이", "개똥이", "말똥이");
strFriends1 = friends.join(); // 소똥이,개똥이,말똥이
strFriends2 = friends.join(", "); // 소똥이, 개똥이, 말똥이
strFriends3 = friends.join(" + "); // 소똥이 + 개똥이 + 말똥이

pop : 배열의 마지막 요소를 삭제한 후 그 값을 리턴하고 배열의 크기를 줄인다.
문법
arrayName.pop()
인자
없음
예제
// 말똥이가 pop 되고 배열에는 "개똥이", "소똥이"만 남는다.
// 배열크기도 2로 줄어든다.
friends = ["개똥이", "소똥이", "말똥이"];
popped = friends.pop(); // popped 에 말똥이가 할당된다.

push : 배열에 하나 또는 여러개의 값을 넣고 새로운 배열의 길이를 리턴한다.(배열길이 증가)
문법
arrayName.push(element1, element2, ... , elementN)
인자
element1, element2, ... , elementN - 추가될 요소들
예제
friends = ["개똥이", "소똥이"];
pushed = friends.push("말똥이", "새똥이"); // ["개똥이", "소똥이", "말똥이", "새똥이"]
alert(pushed); // 4

reverse : 배열 요소를 역순으로 재배치한다(첫번째 요소는 마지막으로, 마지막 요소는 처음으로).
문법
arrayName.reverse()
인자
없음
예제
myArray = new Array("1", "2", "3");
myArray.reverse(); // ["3", "2", "1"]

shift : 첫번째 요소를 삭제하고 배열의 길이를 하나 줄인 후, 삭제된 요소를 리턴한다.
문법
arrayName.shift()
인자
없음
예제
friends = ["개똥이", "소똥이", "말똥이"];
shifted = friends.shift(); // ["소똥이", "말똥이"]
alert("삭제된 요소는 " + shifted + " 입니다."); // 개똥이

slice : 얇게 썬 슬라이스 치즈가 생각난다(^^). 배열의 일부를 잘라내어 새로운 배열을 리턴한다.
문법
arrayName.slice(begin[,end]) : [] 은 선택사항임
인자
begin - 0보다 큰 시작 인덱스 (필수)
end - 0보다 큰 끝 인덱스 (선택). 지정되지 않으면 배열의 끝까지 복사된다.
예제
numbers = ["0", "1", "2", "3", "4"];
sliced1 = numbers.slice(2, 3); // ["2"]
sliced2 = numbers.slice(2); // ["2", "3", "4"]

sort : 배열의 요소를 정렬한다.
문법
arrayName.sort([compareFunction])
인자
compareFunction - 정렬방법을 지정한 함수.
생략시에는 요소들의 toString() 값을 사전순서(Dictionary order) 대로 정렬한다.
compareFunction(a, b) 에서
1) a > b : 0 보다 큰 값 리턴
2) a = b : 0 리턴
3) a < b : 0 보다 작은 값 리턴
예제
// 역행 정렬
function descComparator(a, b) {
return b - a;
}

// 순행 정렬
function ascComparator(a, b) {
return a - b;
}

numbers = ["0", "1", "2", "3", "4"];
numbers.sort(); // ["1", "2", "3", "4", "5"]
numbers.sort(ascComparator); // ["1", "2", "3", "4", "5"]
numbers.sort(descComparator); // ["4", "3", "2", "1", "0"]

splice : 이전 배열요소를 삭제하고 새로운 내용물을 추가하는 형태로 배열 내용을 변경한다. 삭제된 요소들은 리턴된다. Vector 와 유사한 기능을 하므로 숙지하자.
문법
arrayName.splice(index, howMany, [element1][, ..., elementN])
인자
index - 변경하고자 하는 요소의 시작 인덱스
howMany - 삭제하고자 하는 이전 배열요소 갯수.
element,...,elementN - 추가하고자 하는 배열 요소들
예제
// numbers[2]부터 2개("2", "3")를 삭제하고 그 자리에 "5"와 "6" 을 삽입한다.
numbers = ["0", "1", "2", "3", "4"];
spliced = numbers.splice(2, 2, "5", "6"); // ["0", "1", "5", "6", "4"]
alert(spliced); // "2", "3"

unshift : 하나 또는 여러개의 요소를 배열의 왼쪽에 추가한다. 배열길이는 증가한다.
문법
arrayName.unshift(element1,..., elementN)
인자
element1,...,elementN - 배열의 앞쪽에 들어갈 요소들
예제
numbers = ["0", "1", "2"];
numbers.unshift("-2", "-1"); // ["-2", "-1", "0", "1", "2"]

출처 : http://blog.empas.com/jjh7266/6264266
Posted by 행복한 프로그래머 궁금쟁이박

댓글을 달아 주세요

Commons-dbcp



I. DBCP (DataBase Connection Pool)

이제는 데이터베이스 풀을 이용한 커넥션 풀을 사용하지 않는다는것은 상상조차 할 수 없게 되었다. 각 WAS의 벤더들은 오래전부터 자사제품에 대해 최적화된 커넥션 풀을 기본적으로 제공을 하기까지 이르렀다. 또한 한스버그의 커넥션 풀링이나 풀맨의 풀등 여러 오픈된 커넥션 풀 소스들이 돌아다기기도 하였다.

여기서는 Jakarta Commons에서 진행하고있는 Commons-dbcp project에 대해 알아보고 간단한 예제를 소개하기로 하겠다


II. 다운로드 및 설치

dbcp는 commons의 pool과 collection을 사용하기때문에 다음3가지를 모두 설치해야 정상적으로 dbcp를 사용할 수 있다.

Commons-dbcp http://jakarta.apache.org/site/downloads/downloads_commons-dbcp.cgi

Commons-pool http://jakarta.apache.org/site/downloads/downloads_commons-pool.cgi

Commons-collections http://jakarta.apache.org/site/downloads/downloads_commons-collections.cgi

DBCP API http://jakarta.apache.org/commons/dbcp/apidocs/index.html


/WEB-INF/lib/ 에 다운받은 3가지 *.jar를 복사하도록 한다


III. DBCP 웹에서 사용하기!

이번 dbcp 강의는 웹에서 사용하는것을 전제로 설명하겠습니다 ^^

톰캣을 사용한다면 server.xml에 dbcp를 설정해도 되지만 web.xml에 설정하는것이 좀더 유연성을 지닙니다


1) JDBC 정보 정의

web.xml에 dbcp를 사용하기위한 jdbc 정보를 정의합니다.

   <servlet>
      <servlet-name>connectioninitialize</servlet-name>
      <servlet-class>db.ConnectionInitialize</servlet-class>
      <init-param>
         <param-name>driverClassName</param-name>
         <param-value>org.gjt.mm.mysql.Driver</param-value>
      </init-param>
      <init-param>
      <param-name>url</param-name>
      <param-value>jdbc:mysql://localhost/unicorn</param-value>
      </init-param>
      <init-param>
         <param-name>username</param-name>
         <param-value>unicorn</param-value>
      </init-param>
      <init-param>
         <param-name>password</param-name>
         <param-value>iloveyou</param-value>
      </init-param>
      <init-param>
         <param-name>defaultAutoCommit</param-name>
         <param-value>true</param-value>
      </init-param>
      <init-param>
         <param-name>defaultReadOnly</param-name>
         <param-value>false</param-value>
      </init-param>
      <init-param>
         <param-name>maxActive</param-name>
         <param-value>30</param-value>
      </init-param>
      <init-param>
         <param-name>maxIdle</param-name>
         <param-value>10</param-value>
      </init-param>
      <init-param>
         <param-name>maxWait</param-name>
         <param-value>10000</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>   
   </servlet>


driverClassName : 사용할 jdbc driver의 class name

url : jdbc driver의해 연결할 connection에 대한 url

username : connection을 연결할 사용자 이름

password : connection을 연결할 사용자 비밀번호

defaultAutoCommit : 풀에의해 생성된 커넥션의 auto-commit 상태

defaultReadOnly : 풀에의해 생성된 커넥션의 read-only 상태

                             jdbc에 따라 지원하지 않을수도 있다 (예 : informix)

maxActive : 커넥션풀의 Active한 커넥션의 최대 갯수

maxIdle : 커넥션풀의 idle한 커넥션의 최대 갯수

maxWait : 커넥션이 풀에 반납되기까지 기다리는 최대 시간 (millisecond)


2) JDBC 정보 로딩 및 초기화

이 클래스는 web.xml에 의해 서블릿 컨테이너가 구동될 때 딱 한번 실행됩니다.

db.ConnectionInitialize.java

package db;


import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;


public class ConnectionInitialize extends HttpServlet {
 
 public void init() throws ServletException {
 
    String driverClassName = null;
    String url = null;
    String username = null;
    String password = null;
    boolean defaultAutoCommit = true;
    boolean defaultReadOnly = false;
    int maxActive = 0;
    int maxIdle = 0;
    long maxWait = 0;


    // web.xml에서 정의한 파라미터 이름을 enumeration에 담습니다.

    Enumeration names = getServletConfig().getInitParameterNames();
       do {
          if(!names.hasMoreElements())
             break;


          // web.xml에 정의한 파라미터값을 가져옵니다.

          String name = (String)names.nextElement();
          String value = getServletConfig().getInitParameter(name).trim();

          System.out.println(name+" : "+value);


          if (name.startsWith("driverClassName"))
             driverClassName = value;
          else if (name.startsWith("url"))
             url = value;
          else if (name.startsWith("username"))
             username = value;
          else if (name.startsWith("password"))
             password = value;
          else if (name.startsWith("defaultAutoCommit"))
             defaultAutoCommit = "true".equals(value);
          else if (name.startsWith("defaultReadOnly"))
             defaultReadOnly = "true".equals(value);
          else if (name.startsWith("maxActive"))
             maxActive = Integer.parseInt(value);
          else if (name.startsWith("maxIdle"))
             maxIdle = Integer.parseInt(value);
          else if (name.startsWith("maxWait"))
             maxWait = Long.parseLong(value);

        } while(true);
       
        try {

           // jdbc driver 및 기타 정의를 설정합니다.
           setupDriver(driverClassName,

                           url,

                           username,

                           password,

                           defaultAutoCommit,

                           defaultReadOnly,

                           maxActive,

                           maxIdle,

                           maxWait);


           System.out.println("Connection initialize success");
        } catch (Exception exception) {
           System.out.println("Connection initialize fail!");
           exception.printStackTrace();
      }
 }
 
 public void setupDriver(String driverClassName,
       String url,
       String username,
       String password,
       boolean defaultAutoCommit,
       boolean defaultReadOnly,
       int maxActive,
       int maxIdle,
       long maxWait) throws Exception {


       try {

            // jdbc class를 로딩합니다.
            Class.forName(driverClassName);
        } catch (ClassNotFoundException classnotfoundexception) {
            System.out.println(driverClassName+" is not found");
            classnotfoundexception.printStackTrace();
            throw classnotfoundexception;
        }
       

        // 커넥션 풀로 사용할 commons-collections의 genericOjbectPool을 생성합니다.
        GenericObjectPool connectionPool = new GenericObjectPool(null);
        connectionPool.setMaxActive(maxActive);
        connectionPool.setMaxIdle(maxIdle);
        connectionPool.setMaxWait(maxWait);
       

        // 풀이 커넥션을 생성하는데 사용하는 DriverManagerConnectionFactory를 생성합니다.
        ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url, username, password);
       

        // ConnectionFactory의 래퍼 클래스인 PoolableConnectionFactory를 생성한다
        PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, connectionPool, null, null, defaultReadOnly, defaultAutoCommit);
       

        // 마지막으로 PoolingDriver 자신을 로딩한다
        Class.forName("org.apache.commons.dbcp.PoolingDriver");

        PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");

        // 그리고 풀에 등록한다. 풀이름을 "unicorn"이라고 지정하였다        
        driver.registerPool("unicorn",connectionPool);       
    }
}



3) 커넥션 래퍼 클래스

데이터베이스 커넥션을 관리하는 Interface로 다음 4가지 함수를 정의하였습니다.

db.ConnectionContext.java

package db;


public interface ConnectionContext {
   public java.sql.Connection getConnection();
   public void rollback();
   public void commit();
   public void release();
}


ConectionContext를 구현한 커넥션 클래스

db.ConnectionResource.java

package db;

import java.sql.Connection;
import java.sql.DriverManager;

public class ConnectionResource implements ConnectionContext {
   private Connection connection = null;
   private boolean transaction = false;


   public ConnectionResource() throws Exception {
      init(false);
   }
   
    public ConnectionResource(boolean transaction) throws Exception {
       init(transaction);
    }
   
    public void init(boolean transaction) throws Exception {
       this.transaction = transaction;
       connection = DriverManager.getConnection("jdbc:apache:commons:dbcp:unicorn");

       if (connection == null) throw new Exception("fail to get connection");

      if (transaction) connection.setAutoCommit(false);

    }
     
    public Connection getConnection() {  
       return connection;
    }


    public void rollback() {
       if (transaction) {
          if (connection != null) try { connection.rollback(); } catch (Exception e) {}
      }
   }


   public void commit() {
      if (transaction) {
         if (connection != null) try { connection.commit(); } catch (Exception e) {}
      }
   }


   public void release() {
      if (connection != null) {
         if (transaction) {
            try { connection.setAutoCommit(true); } catch (Exception e) {}
         }
         try { connection.close(); } catch (Exception e) {}
      }
   }
}


4) 테스트 JSP

jsp에서 다음과 같이 사용하면 됩니다.

<%@ page contentType="text/html;charset=EUC_KR" %>
<%@ page import="java.sql.*,db.*" %>


<%

   ConnectionContext connectionContext = new ConnectionResource();
   Connection connection = null;

   try {
      connection = connectionContext.getConnection();

   } catch (Exception exception) {
       exception.printStackTrace();
   } finally {
       if (connection != null) try { connectionContext.release(); } catch (Exception exception) {}
   }

%>

관련 파일들을 첨부합니다 ^^&


IV. Struts와 DBCP

만약 Struts와 함께 사용한다면 다음과 같이 사용하세요. 현재 Unicorn이 다음과 같은 형식으로 되어있습니다.

1) struts-config.xml 에 DBCP 정보를 정의합니다.

 <data-sources>
  <data-source key="mysql" type="org.apache.commons.dbcp.BasicDataSource">
   <set-property property="defaultAutoCommit" value="true"/>
   <set-property property="defaultReadOnly" value="false"/>
   <set-property property="description" value="Tomcat Data Source"/>
   <set-property property="driverClassName" value="org.gjt.mm.mysql.Driver"/>
   <set-property property="maxActive" value="30"/>
   <set-property property="maxIdle" value="10"/>
   <set-property property="maxWait" value="10000"/>
   <set-property property="username" value="unicorn"/>
   <set-property property="password" value="iloveyou"/>
   <set-property property="url" value="jdbc:mysql://localhost/unicorn"/>
  </data-source>
 </data-sources>


2) Action classs에서 다음과 같이 커넥션을 얻어올 수 있습니다.

Connection connection = getDataSource(request, "mysql").getConnection();

이 getDataSource() 함수는 org.apache.struts.action.Action 클래스에 다음과 같이 정의되어 있습니다.

protected DataSource getDataSource(HttpServletRequest request) {
    return getDataSource(request, "org.apache.struts.action.DATA_SOURCE");
}

protected DataSource getDataSource(HttpServletRequest request, String key) {
    ServletContext context = getServlet().getServletContext();
    ModuleConfig moduleConfig = ModuleUtils.getInstance().getModuleConfig(request, context);
    return (DataSource)context.getAttribute(key + moduleConfig.getPrefix());
}


3) Struts에서 트랜잭션 관리를 위한 코딩으로는 unicorn의 소스에 충실히 구현되어 있습니다.

마찬가지로 Interface인 ConnectionContext와 이를 구현한 ConnectionResource를 사용하여 트랜잭션 관리를 하였습니다. 이 예제는 unicorn 소스를 참조하세요 ^^


V. 톰캣에서의 DBCP 사용

1) DBCP에 대한 정보를 server.xml에 정의할 수 있습니다.

<Context path="/unicorn" docBase="unicorn" debug="0"
                 reloadable="true" crossContext="true">
          <Logger className="org.apache.catalina.logger.FileLogger"
                     prefix="localhost_ktng_log." suffix=".txt"
              timestamp="true"/>


    <Resource name="jdbc/unicorn" auth="Container"

                    type="javax.sql.DataSource"/>
    <ResourceParams name="jdbc/unicorn">
       <parameter>
         <name>factory</name>
         <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
       </parameter>
       <parameter>
         <name>username</name>
         <value>unicorn</value>
       </parameter>
       <parameter>
         <name>password</name>
         <value>iloveyou</value>
       </parameter>
       <parameter>
         <name>driverClassName</name>
         <value>org.gjt.mm.mysql.Driver</value>
       </parameter>
       <parameter>
         <name>url</name>
         <value>jdbc:mysql://localhost/unicorn</value>
       </parameter>
       <parameter>
         <name>maxActive</name>
         <value>30</value>
       </parameter>
       <parameter>
         <name>maxIdle</name>
         <value>10</value>
       </parameter>
       <parameter>
         <name>maxWait</name>
         <value>10000</value>
       </parameter>
     </ResourceParams>


2) web.xml에 JNDI 리소스를 사용할 수 있도록 다음을 추가합니다.

<resource-ref>
   <description>unicorn db</description>
   <res-ref-name>jdbc/unicorn</res-ref-name>
   <res-type>javax.sql.DataSource</res-type>
   <res-auth>Container</res-auth>
</resource-ref>

3) 실제 소스에서는 다음과 같이 DataSource를 사용합니다.

InitialContext context = new InitialContext();

DataSource dataSource = (DataSource) context.lookup("java:/comp/env/jdbc/unicorn");

Connection connection = dataSource.getConnection();

간단하죵?


=========================================================

본문서는 자유롭게 배포/복사 할수 있지만 이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=========================================================

Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

1. 모든 페이지 상단
   <%@ page contentType="text/html; charset=euc-kr" pageEncoding="euc-kr"%>
   추가

2. Request값이 있을 경우
   <% request.setCharacterEncoding("euc-kr"); %>
   추가

3. String 변수
   ST_Str = new String(ST_Str.getBytes("Cp1252"),"euc-kr");
   로 한글처리

4. Class를 이용
package common;
import java.lang.*;
import java.io.*;
public class CharacterSet {
   public static String toKorean(String str) {
      try {
         return new String(str.getBytes("Cp1252"), "euc-kr");
      } catch (UnsupportedEncodingException e) {
         return null;
      } catch (NullPointerException e) {
         return null;
      }
   }
}
   <%@ page import ="common.*"%>
   ST_Str = CharacterSet.toKorean(ST_Str);

출처 : http://savour.tistory.com/200

Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

JSP에서 Beans 사용하기

김세곤 <sehkone@bawi.org>

2000년 4월 23일, 2001년 1월 4일 일부 수정

개요

  Beans란?

Beans는 일종의 특정한 일을 독립적으로 수행하는 콤포넌트이다. Beans는 크게 JavaBeans와 EJB(Enterprise JavaBeans)가 있는데, 두 가지는 콤포넌트라는 개념 외에는 많이 다르다. JSP 문서에서는 JavaBeans와 EJB 모두 사용할 수 있는데, 이번 글에서는 JavaBeans에 대해서만 다루겠다. 이후 Beans는 JavaBeans를 가리키는 말이다.

JSP에서 JavaBeans를 사용하기 위해서 JavaBeans에 대한 모든 내용을 다 알 필요는 없다. 이번 글에서는 JSP 문서에서 Beans를 사용하기 위한 필요한 내용들만 설명할 것이므로, 특별히 JavaBeans 자체에 대해서 더 알고 싶은 분은 썬의 JavaBeans 스펙을 참고하기 바란다.

하나의 bean은 속성을 갖는 개체이다. 또한, bean은 그 속성의 값을 설정하고 얻는 방법도 갖고 있다. 뿐만 아니라, 속성을 제어하고 지정한 여러가지 일을 수행하는 방법들도 갖추고 있다. Bean은 한 프로그램에 전속하지 않는 독립적인 객체로서 다른 프로그램에서도 사용할 수 있다. Bean의 정의는 클래스로서 표현되며 개별 bean은 정의된 클래스의 인스턴스로서 구별된다. 어떤 것도 bean으로 추상화될 수 있다. 예를 들면 복소평면 위의 한 점으로 표현되는 복소수도 bean이 될 수 있다. 이 bean은 실수 축 위의 좌표와 허수 축 위의 좌표를 그 속성으로 갖게 될 것이며, 복소수의 연산을 가능토록 하는 방법들을 갖을 수 있다. Bean의 속성은 클래스의 내부 필드 값으로, 속성을 제어하는 방법들은 메쏘드로서 표현된다. 이어지는 절들에서 보다 구체적인 예를 살펴보기로 하자.

  왜 Beans를 사용하는가?

크게 세 가지 이유가 있다.

먼저, form을 통한 데이터 프로세싱이 매우 용이하다는 장점을 들 수 있다. 동적인 웹 페이지 생산의 중요한 요소는 클라이언트로부터 데이터를 입력받아 이를 처리하는 것인데, http 프로토콜을 사용하는 HTML은 GET 또는 POST 방법을 통해 이를 처리한다. JSP 문서에서는 간단하게 request.getParameter()를 통해 GET 또는 POST로 넘어오는 데이타를 전달받을 수 있지만(이 방법에 대해서는 WebDox의 JSP 맛보기를 참고하도록 하자) 프로그래밍 코드가 지저분해지기 쉽다. 또한, request라는 JSP Engine(JSP 문서를 Servlet 코드로 변환시키는 일을 한다)이 내부적으로 사용하는 인스턴스를 참조하는 것도 어딘지 석연치 않다. 이후에 살펴보겠지만 beans를 사용하면 번잡한 form 제어를 우아하게 할 수 있다.

다음으로, 클라이언트의 데이터를 여러가지 범위에서 지속적으로 유지할 수 있다는 이유가 있다. 간단한 예를 들어보자. 쇼핑몰을 운영하는 사이트는 장바구니 개념이 구현되어야 한다. 소비자가 물건을 사이트에서 살피고 이를 장바구니에 담으면 이 정보는 소비자가 구입을 모두 끝마칠 때까지 유효해야 한다. 이런 장바구니를 구현하기 위해서는 다음의 세 가지 요건이 모두 잘 해결되어야 한다.

  • 클라이언트 요청이 누구의 것인지 구별하기(session tracking)

  • 사용자에 따라 물품 구매 정보를 저장하고 지속적으로 유지하기

  • 장바구니 정보는 오랜 기간 지속하는 것이 아니므로 수행 성능을 고려하여 디스크 등의 기억장치를 쓰지 않기

위의 세 가지를 만족하는 방법으로 흔히 쿠키를 사용하는데, 쿠키는 여러가지로 불편한 점이 많다. 저장할 수 있는 아이템의 개수도 한정적일 뿐만 아니라, 보안 측면에서도 허점이 많다. 결정적으로 쿠키는 개발 언어 차원의 방법이 아닌 웹 서버와 브라우저 간의 기능이라 인터페이스가 개발 언어와 밀접하지 못하다. Java는 위와 같은 기능을 수행하는데 있어서 보다 Java의 개념에 맞도록 진보된 방법을 제공하고 있는데 이것이 beans이다.

마지막으로, Beans를 사용하는 가장 중요한 이유는 컴포넌트 기반 개발을 하기 위한 것이다. Beans를 잘 사용하면 보여주기와 구현하기를 분리하여 비즈니스 로직을 보다 잘 설계할 수 있다. 이에 대한 자세한 이야기는 다음 기회로 미루고, 우선 이번 글에서는 JSP에서 beans를 사용하는 방법에 대한 개념적인 이야기와 앞의 두 가지 장점에 대해서 중점적으로 알아보도록 하겠다.

간단한 예제

2차원 평면에서 점의 좌표를 입력받아 원점으로부터의 거리를 계산하는 웹 프로그램을 짜보자. 편리를 위해 좌표는 정수로만 입력 받기로 한다. 좌표와 원점으로부터의 거리를 속성으로 갖는 bean을 먼저 만든다. x, y 좌표는 입력을 받지만 원점으로부터의 거리는 입력받는 값이 아니고 계산되는 값이다.

Bean의 정의 (Point.java)

1   import java.io.*;
2
3   public class Point {
4       private int parallelValue;
5       private int verticalValue;
6       private double distance;
7
8       public void setParallelValue(int x) {
9           parallelValue = x;
10      }
11   
12      public void setVerticalValue(int y) {
13          verticalValue = y
14      }
15
16      public int getParallelValue() {
17          return parallelValue;
18      }
19
20      public int getVerticalValue() {
21          return verticalValue;
22      }
23
24      public double getDistance() {
25          calculateDistance();
26          return distance;
27      }                
28
29      private void calculateDistace() {
30          distance = Math.sqrt((double) parallelValue * parallelValue
31                       + verticalValue * verticalValue);
32      }
33  }

다음은 x, y 좌표 값을 form으로 입력받는 html 문서이다.
form.html

1   <html>
2   <head><title>좌표값 입력</title>
3   </head>
4   <body>
5
6   <form action="calc.jsp" method="post">
7   x 좌표 : <input type="text" name="parallelValue"><br>
8   y 좌표 : <input type="text" name="verticalValue"><br>
9   <input type="submit">
10  </form>
11
12  </body>
13  </html>

이 form의 submit 버튼을 누르면 calc.jsp가 호출된다. 이제 calc.jsp를 작성하자.
calc.jsp

1   <html>
2   <head><title>원점으로부터의 거리</title>
3   </head>
4
5   <body>
6   <jsp:useBean id="myPoint" class="Point"/>
7   <jsp:setProperty name="myPoint" property="parallelValue"/>
8   <jsp:setProperty name="myPoint" property="verticalValue"/>
9   거리는 <jsp:getProperty name="myPoint" property="distance"/>이다.
10  </body>
11  </html>

calc.jsp의 6번 행은 Point 클래스 타입으로 myPoint라는 인스턴스 이름을 갖는 bean을 생성하라는 뜻이다. 7번 행은 이 myPoint bean의 field인 parallelValue를 form의 parallelValue 값으로 설정하라는 것이고, 8번 행은 verticalValue를 form의 verticalValue 값으로 설정하라는 말이다. 이 6번 행부터 8번 행 까지는 다음의 자바 코드의 의미를 함축한다.
1   Point myPoint;
2   myPoint.setParallelValue(request.getParameter("parallelValue"));
3   myPoint.setVerticalValue(request.getParameter("verticalValue"));

물론 완전히 동등한 것은 아니다. 특히, calc.jsp의 6번 행은 위의 1번 행의 의미보다 더 포괄적이다. 이것은 다음 절에서 설명하기로 하고, 7번 행과 8번 행만을 주목하면 각각 위의 2번 행, 3번 행과 동등하다. 9번 행은 myPoint bean의 속성인 distance 값을 얻는다. 9번 행은
  거리는 <%= myPoint.getDistance() %>이다.

과 동등하며, 따라서, calc.jsp는 다음처럼 고쳐써도 똑같다.
1   <html>
2   <head><title>원점으로부터의 거리</title>
3   </head>
4
5   <body>
6   <jsp:useBean id="myPoint" class="Point"/>
7   <% myPoint.setParallelValue(request.getParameter("parallelValue"));
8      myPoint.setVerticalValue(request.getParameter("verticalValue")); %>
9   거리는 <%= myPoint.getDistance() %>이다.
10  </body>
11  </html>

JSP 태그를 사용한 것과 위의 자바 코드를 사용한 코드를 살펴보자. 어떤 것이 더 명료한가? JSP는 HTML 문서 안에 자바 코드를 사용할 수 있는 장점이 있지만, HTML 코드와 자바 코드가 복잡하게 섞이면 이해하기 어려워진다. 따라서, 좋은 코딩 습관은 되도록 JSP 파일 내에서는 자바 코드를 줄이고 복잡한 자바 코드는 beans나 Servlet을 통해 사용하는 것이다. JSP 태그는 이처럼 자바 코드 대신 XML 스타일의 태그를 사용하여 beans와 교통할 수 있도록 하여, 코드를 보다 더 명료하게 해 준다.

이제, Point 클래스의 인스턴스이자 bean의 역할을 하는 myPoint는 form으로부터 좌표값을 입력받아 거리를 계산해 주는 일을 수행하게 된다.

Bean 사용 방법

  Bean 생성/선언

Bean의 생성/선언은 <jsp:useBean ... /> 태그를 이용한다. 일반적인 용법은 다음과 같다.

<jsp:useBean id="beanInstanceName" class="package.class"
             scope="page|request|session|application"/>

또는

<jsp:useBean id="beanInstanceName" class="package.class"
              scope="page|request|session|application">

.....

</jsp:useBean>

각각의 파라미터들이 어떤 의미를 갖는지 살펴보자. 먼저, class 파라미터는 사용하는 bean의 클래스 타입을 명시한다. Bean은 하나의 클래스로 표현되므로 bean을 사용하기 위해서는 용도에 맞는 클래스가 정의되어 있어야 한다. id는 생성되는 bean 인스턴스의 이름이다. 쉽게 생각해서 변수라고 보면 된다. 예를 들어 위의 예에서 Point 타입의 bean은 여러 개 생성될 수 있는데 id를 myPoint이라고 했다면 생성된 여러 개의 bean들 중에서 이 bean을 구별하는 이름이 myPoint이 되는 것이다. scope에 대해서는 다음 절에서 설명하겠다.

Bean의 생성/선언 방법은 위의 것 외에 serialization을 위한 또 하나의 방법이 있는데, serialization을 이해하는 일이 선행되어야 하므로 이 글의 범주를 벗어나서 생략한다. Bean의 serialization은 웹의 데이터베이스 연동이 일반화된 마당에 파일 처리를 통해 데이터를 관리할 것이 아니라면 특별히 사용할 일이 없을 것으로 생각된다.

  Bean 클래스의 정의 요건

JSP에서는 어떤 클래스라도 bean이 될 수 있다. 다만, <jsp:setProperty> 태그와 <jsp:getProperty>를 위해 setXXX() 메쏘드와 getXXX() 메쏘드가 준비되어야 한다. 예를 들어 <jsp:getProperty> 태그에 property의 값으로 abcDefGhi를 사용했다면, getAbcDefGhi() 메쏘드가 존재하여야 한다. 소문자인 a가 메쏘드에서는 대문자로 사용된 것에 유의하자. 마찬가지로, <jsp:setProperty> 태그에 property의 값으로 jklMno를 사용했다면, setJklMno() 메쏘드가 정의되어 있어야 한다. setXXX() 메쏘드와 getXXX() 메쏘드는 public 이어야 하고. setXXX() 메쏘드는 값을 넘겨받는 인자가 하나 존재해야 한다. 코드를 통해 본다면, 만일,

<jsp:useBean id="myBean" class="MyBean"/>
<jsp:getProperty name="myBean" property="abcDefGhi"/>
<jsp:setProperty name="myBean" property="jklMno"/>

라 하면, 다음처럼 bean에는 대응되는 메쏘드가 존재해야 한다.
public class MyBean {
    .....
    public String getAbcDefGhi() {...}
    public void setJklMno(String arg) {...}
    .....
}

getXXX 메쏘드의 리턴 값과, setXXX 메쏘드의 인자는 어떤 타입이 되어도 좋으나, setXXX 메쏘드에 인자로 넘겨주는 값의 형이 정의와 다르면 에러가 나므로 주의한다.

  Bean 속성 설정하기

Bean의 속성을 설정하는 것은 bean 클래스의 setXXX() 메쏘드를 사용하여 field의 값을 정해주는 일이다. 이는 <jsp:setProperty> 태그를 이용하여 수행한다. <jsp:setProperty> 태그의 용법은 다음의 네 가지가 있다.

1 <jsp:setProperty name="beanInstanceName" property="*"/>
2 <jsp:setProperty name="beanInstanceName" property="propertyName"/>
3 <jsp:setProperty name="beanInstanceName" 
                   property="propertyName" param="parameterName"/>
4 <jsp:setProperty name="beanInstanceName" 
                   property="propertyName value="propertyValue" />

첫 번째 방법은 form에서 값을 넘겨받아 bean에 설정하는 방법으로서 매우 효과적이다. 이 방법을 사용하면 form의 모든 파라미터를 조사하여 대응되는 setXXX() 메쏘드가 있는지 살피고 있다면 대응되는 메쏘드를 통해 bean 속성을 설정한다. Form의 파라미터에 대응되는 bean의 메쏘드가 없다고 해도 아무런 에러를 내지 않고 대응되는 것만 수행한다. 간단한 예를 살펴보자. 다음은 아이디와 패스워드를 입력받는 예이고, bean은 다음처럼 정의한다.

Bean의 정의 (Login.java)

public class Login {
    private String userId;
    private String userPassword;

    public void setUserId(String id) {
        userId = id;
    }

    public void setUserPassword(String pw) {
        userPassword = pw;
    }

    public String getUserId() {
        return userId;
    }

    public String getUserPassword() {
        return userPassword;
    }
}

다음은 아이디와 비밀번호를 입력받는 HTML 문서이다.

<html>
<head><title>jsp:setProperty예제</title>
</head>
<body>
<form action="example.jsp" method="post">
ID : <input type="text" name="userId"><br>
Password : <input type="password" name="userPassword"><br>
<input type="submit">
</form>

Form의 submit을 통해 호출되는 example.jsp를 다음처럼 만든다면,

<jsp:useBean id="login" class="Login"/>
<jsp:setProperty name="login" property="*"/>

<html>
....
</html>

login 인스턴스에는 form으로부터 넘겨지는 사용자의 아이디와 비밀번호가 자동적으로 설정된다.

두 번째 방법을 사용할 때는 위의 거리 계산 예제에서도 사용한 것처럼 property의 값이 form의 파라미터 이름과 같아야 하고, 이에 대응되는 setXXX() 메쏘드가 존재해야 한다. Form의 파라미터 이름과 bean의 setXXX() 메쏘드의 이름이 대응되지 않을 때는 세 번째 방법을 사용한다. Property에는 bean의 setXXX() 메쏘드의 XXX 부분과 호응하는 이름을 설정해야 하며, param에는 form의 파라미터 이름을 써 넣으면 된다.

마지막 방법은 직접 bean의 setXXX() 메쏘드에 값을 넘겨주어 속성을 설정할 때 사용한다. 여기서 주의할 것은 value의 값이 setXXX() 메쏘드의 인자와 그 타입이 같아야 한다는 점이다. 아래처럼 사용하면 된다.

<jsp:setProperty name="login" property="userId" value="sehkone"/>

or

<jsp:setProperty name="login" property="userId" value="<%= yourId %>"/>

후자처럼 직접 expression을 사용해도 된다.

Beans의 Scope

지금까지 beans의 생성/선언 및 사용 방법에 대해서 살펴보았다. 눈치가 빠른 독자는 필자의 "beans의 생성/선언"이란 표현에서 "선언"이란 말에 의문을 품었을 것이다. 전통적인 프로그래밍 개념에서 생성은 없는 객체를 새로 만들 때 사용하는 용어이고, 선언은 이미 생성된 객체를 참조할 때 사용하는 말이다. 따라서 어떤 bean을 "선언"한다는 말은 이미 객체가 생성되어 있음을 함축한다. 그렇다면, beans은 언제 생성되고 언제 선언되며 언제 소멸되는가? 과연, beans는 얼마 동안 메모리에 적재되어 사용될 수 있는가?

Beans가 지속하는 범위는 <jsp:useBean> 태그의 scope 파라미터로 설정한다. 앞서, <jsp:useBean> 태그의 사용법을 언급할 때 scope에 대한 설명은 뒤로 미루었는데, 이제 자세히 살펴보도록 하자. Scope는 beans가 살아있을 수 있는 기간을 말하고 그 기간은 page, session, request, application 등의 네 가지가 있다. 디폴트 값은 page이다. Scope가 page라면 page가 끝날 때까지 bean이 존재한다는 의미고, scope가 session이라면 session이 끝날 때까지 bean이 존재한다는 의미이다. Request나 application도 같은 식으로 적용된다. 이 네 가지를 차례로 살피자.

  Page Scope

Page는 JSP 문서 하나를 일컫는다. 따라서, scope가 page라면 <jsp:useBean>으로 설정되는 bean은 모두 새로이 생성되고, 그 문서의 실행이 모두 종료되면 bean은 소멸된다. 앞서의 모든 예제들은 scope를 따로이 명기하지 않았고 이는 scope가 page임을 나타내며, 따라서, 앞의 예제들의 모든 beans는 그것들을 포함하고 있는 문서의 실행이 종료될 때 소멸된다.

  Session Scope

Scope를 session으로 명시했다면 그 bean는 session이 끝날 때까지 존재한다. 다음의 두 JSP 문서를 보자.

dox1.jsp

<html>
<jsp:useBean id="myBean" class="MyClass" scope="session">
.....
</html>


dox2.jsp

<html>
<jsp:useBean id="myBean" class="MyClass" scope="session">
.....
</html>


두 문서 내에 scope가 session이고 id가 같은 bean인 myBean이 정의되어 있다. Session이 같다면, 두 문서의 myBean은 같은 객체를 나타내게 된다.

그렇다면, 과연 session이란 무엇인가? 한 클라이언트가 자신의 브라우저에서 어떤 사이트에 웹 문서를 요청을 하면 해당 웹 서버는 클라이언트의 브라우저와 접속하여 결과물을 보내고 다시 이 접속을 끊는다. 다시 이 클라이언트가 같은 문서(RELOAD 버튼 등을 통하여) 혹은 다른 문서를 요청하면, 웹 서버는 이 추가적인 요청이 이전의 요청과 같은 클라언트로부터 접수되는 것인지를 알 수 있는가? 기본적인 http 프로토콜은 이와 같은 일이 불가능하다. 즉, 연속적인 문서 요청을 모두 별개로 본다는 뜻이다. 매 문서 요청마다 브라우저와 접속했다가 그 요청이 끝나면 다시 접속을 끊기 때문에 생기는 당연한 결과이다. 이런 http 프로토콜의 특성상 장 바구니와 같이 지속적으로 클라이언트 접속을 관리하기 위해서는 추가적인 방법을 사용해야 한다. Session이란 말은 클라이언트의 지속적인 접속을 의미하며, 이어지는 접속이 이전 클라이언트의 것으로부터 온 것인지를 확인하기 위해서, 즉 session을 유지하기 위해서 Java는 쿠키를 통해 session id를 확인하고 session에 기반한 객체는 beans으로 표현한다.

메커니즘은 간단하다. 최초로 session을 설정하기 위해 웹 서버는 브라우저에 고유 번호를 쿠키 값으로 건네 준다. 그리고, 접속 시마다 이 쿠키 값을 살펴서 어떤 클라이언트로부터의 접속인지를 확인하는 것이다. 만일 쿠키 값이 없다면 아직 session을 설정하지 않았으므로 고유 번호를 생성해서 쿠키 값으로 브라우저에 건네 줄 것이고, 쿠키 값이 이미 있다면, 생성한 쿠키 값 리스트를 살펴서 그 출처를 확인하는 것이다. 만일, 브라우저가 갖고 있는 고유 번호가 현재 리스트에 없는 것이라면 그 session은 유효하지 않은 것으로 간주한다(타임 아웃 등에 해당한다).

위와 같은 session 관리를 다른 도움이 없이 쿠키만으로 구현하려면 번잡스러운 작업을 처리해야 한다. 만드는 모든 문서마다 이 쿠키 값을 주고 받고 유효한지 확인하고 새로운 고유 번호를 생성하고 이 번호들의 리스트를 관리하는 일 등은 만만한 것만은 아니다. Java는 이런 작업을 매우 간단하게 처리한다. 특히, JSP의 beans를 사용하면 매우 효율적으로 session을 관리할 수 있다.

    예제 1

간단한 예제를 통해서 session beans를 이해하자. 예제에 사용되는 문서는 session1.jsp, session2.jsp, session3.jsp, inc.jsp 등 네 개의 JSP 문서이다. session1.jsp는 session2.jsp로의 링크를 포함한다. 사용되는 bean과 session1.jsp의 소스는 다음과 같다.

Beans의 정의(Test.java)

public class Test {
    private int data;

    public void setData(int i) {
        data = i;
    }
    public int getData() {
        return data;
    }
    public Test() {
        data = 7;
    }
}

session1.jsp

1   <%@ page import="Test" %>
2   <jsp:useBean id="myBean1" class="Test" scope="session"/>
3   <jsp:useBean id="myBean2" class="Test" scope="session"/>
4
5   <html>
6   <head><title>Session Test</title>
7   </head>
8
9   <body>
10  Initial Values of two beans : <br>
11  myBean1 : <jsp:getProperty name="myBean1" property="data"/><br>
12  myBean2 : <jsp:getProperty name="myBean2" property="data"/><br><br>
13  Now setting...<br><br>
14  <jsp:setProperty name="myBean1" property="data" value="3"/>
15  <jsp:setProperty name="myBean2" property="data" value="5"/>
16  Values after setting :<br>
17  myBean1 : <jsp:getProperty name="myBean1" property="data"/><br>
18  myBean2 : <jsp:getProperty name="myBean2" property="data"/><br><br>
19  <a href="session2.jsp">next</a>
20  </body>
21  </html>

위의 session1.jsp를 브라우저를 통해 보면, 다음과 같은 결과를 얻게 된다.
session1.jsp의 최초 실행 결과

1    Initial Values of two beans : 
2    myBean1 : 7
3    myBean2 : 7
4
5    Now setting...
6  
7    Values after setting :
8    myBean1 : 3
9    myBean2 : 5
10
11   next

session1.jsp 문서에서는 Test 클래스 타입의 myBean1, myBean2 라는 이름의 두 개 bean을 정의하였다. 아직 bean이 생성된 것이 아니므로 이번 실행에서는 두 개의 bean이 모두 생성된다. 생성될 때는 Java 언어의 문법에 따라 Test 클래스의 생성자인 test() 가 실행되고 여기서 속성 data를 7로 설정하므로 위 결과의 2번, 3번 행처럼 초기값은 7로 얻어진다. session1.jsp의 14번 행과 15번 행은 myBean1과 myBean2의 속성 data를 각각 3과 5로 설정하였고, 이에 따라 이후 <jsp:getProperty> 태그를 통해 3과 5의 값이 얻어지는 것을 확인할 수 있다. 이제, 브라우저의 RELOAD 버튼을 눌러보자. 다음과 같은 결과가 얻어진다.
session1.jsp의 재실행(RELOAD) 결과

1    Initial Values of two beans : 
2    myBean1 : 3
3    myBean2 : 5
4
5    Now setting...
6  
7    Values after setting :
8    myBean1 : 3
9    myBean2 : 5
10  
11   next

초기 값이 바뀌었다. RELOAD 버튼을 누르기 전에 이미 session이 시작되었으므로 RELOAD 버튼을 통해 새로 접속했을 때는 두 개의 bean이 생성된 것이 아니라 선언된 것에 불과하다. 따라서, 생성자가 불리지 않고 이미 생성된 beans을 참조하게 되는 것이고, 이에 따라 이미 설정한 값인 3과 5가 얻어진다.

이제, 아래 쪽에 보이는 next 링크를 눌러보자. 이 링크는 session2.jsp를 호출하게 된다. session2.jsp의 소스는 다음과 같다.

session2.jsp

<html>
<head>
<title>
Next Page
</title>
</head>
<body>

<a href="session3.jsp">next</a>

</body>
</html>

이 session2.jsp는 아무런 기능없이 단지 session3.jsp로의 링크만 담고 있다. 역시 아래의 next를 눌러 session3.jsp를 호출해 보자. session3.jsp는 아래와 같다.
session3.jsp

1   <%@ page import="Test" %>
2   <jsp:useBean id="myBean1" class="Test" scope="session"/>
3
4   <html>
5   <head><title>Session Test</title>
6   </head>
7   <body>
8   myBean1's data : <jsp:getProperty name="myBean1" property="data"/><br>
9   myBean1의 getData 메쏘드를 직접 실행한 결과값 : <%= myBean1.getData() %><br><br>
10  아래는 include로 포함하는 문서의 결과이다.<br>
11  <jsp:include page="inc.jsp" flush="true"/><br>
12
13  </body>
14  </html>

아직 inc.jsp 소스의 내용을 모르므로 11번 행의 결과를 빼고 8번과 9번 행의 결과를 눈치빠른 독자들은 이미 결과를 알고 있을 것이다. 결과는 다음과 같다.
session3.jsp의 실행 결과

1   myBean1's data : 3
2   myBean1의 getData 메쏘드를 직접 실행한 결과값 : 3
3
4   아래는 include로 포함하는 문서의 결과이다.
5   myBean2's data : 6

session1.jsp에서 session3.jsp로 직접 가지 않고 beans에 대해서는 아무런 언급이 없는 session2.jsp를 거쳤는데도 여전히 myBean1의 값이 3으로 유지가 되고 있음을 알 수 있다. 더불어 9번 행을 보면 <jsp:getPropery> 태그를 사용하는 것이 직접 getData() 메쏘드를 실행하는 것과 동등하다는 것도 알 수 있다. 이제, 위 결과의 5번 행을 이해하기 위해서 inc.jsp의 소스를 살펴보자.
inc.jsp

<%@ page import="Test" %>
<jsp:useBean id="myBean2" class="Test" scope="session"/>

<html>
<head><title>Session Test</title>
</head>
<body>
<jsp:setProperty name="myBean2" property="data" value="6"/>
myBean2's data : <jsp:getProperty name="myBean2" property="data"/>
</body>
</html>

inc.jsp가 하는 일은 myBean2의 속성을 바꾸고 나서 이를 출력하는 일이다. <jsp:include>는 include되는 파일을 동적으로 포함한다. 즉, session3.jsp가 실행될 때, inc.jsp도 실행되고 그 결과가 session3.jsp의 결과 내 <jsp:include>태그의 위치에 보여지게 된다. <jsp:include> 태그와는 달리 <%@ include file=..> 태그는 정적으로 소스 코드를 포함한다. 즉 한 문서에 <%@ inlcude file..> 태그를 사용하면 그 부분에 태그에서 지정한 파일의 내용이 그대로 포함되어 실행되는 것이다. <jsp:include> 태그는 동적으로 페이지를 포함하기 때문에 포함되는 페이지가 변경된다면 변경된 내용이 제대로 보여지게 된다. 그러나, <%@ include file..> 태그를 사용하면 포함되는 페이지가 변경되면 포함하는 페이지를 다시 rebuild해야지만 변경사항이 반영된다. 두 태그의 차이에 대해서는 독자들이 실제 테스트를 통해 파악하도록 하자.

    Session Bean의 사용 방법

다음의 두 가지 문법이 있다.

1  <jsp:useBean id="beanInstanceName" scope="session" ..... />

2  <jsp:useBean id="beanInstanceName" scope="session" ..... >
   ......
   </jsp:useBean>

첫번째는 닫는 태그 없이 하나의 태그로 표현되었고, 두번째는 </jsp:useBean> 태그를 사용하여 닫았다. 두번째 방법에서 <jsp:useBean> 과 </jsp:useBea> 사이에는 어떤 것이든 제한없이 들어갈 수 있다. 다만, 사이에 들어가는 내용은 session이 새로 생성될 때만 실행된다. 다음의 예제를 보자.
1   <%@ page import="Test" %>
2   <html>
3   <head><title>Session Test</title>
4   </head>
5
6   <body>
7   <jsp:useBean id="myBean1" class="Test" scope="session">
8   생성<br>
9   myBean1's Initial : <jsp:getProperty name="myBean1" property="data"/><br>
10  <jsp:setProperty name="myBean1" property="data" value="3"/>
11  After setting : <jsp:getProperty name="myBean1" property="data"/><br><br>
12  </jsp:useBean>
13  선언<br>
14  <jsp:setProperty name="myBean1" property="data" value="9"/>
15  myBean1 : <jsp:getProperty name="myBean1" property="data"/><br>
16  </body>
17  </html>

최초로 이 문서를 실행하면 다음처럼 결과가 얻어진다.
생성
myBean1's Initial : 7
After setting : 3

선언
myBean1 : 9

그러나, RELOAD를 통하여 재차 실행하면,
선언
myBean1 : 9

와 같은 결과를 얻는다. <jsp:useBean>과 </jsp:useBean> 사이는 session이 최초 시작될 때, 즉 bean이 생성될 때 실행되는 것을 확인할 수 있다.

    Session Beans의 소멸

Session beans는 메모리 상에 존재하며 소멸될까지 일을 수행한다. 따라서, 메모리가 충분하지 않은 웹 서버를 운영할 때는 session beans 사용 시 주의를 기울여야 한다. Session beans은 보통 일정한 시간 동안 접속이 없다면 timeout되어 JVM의 garbage collection 대상이 된다.

  Request Scope와 Application Scope

Scope를 request로 설정하면 웹 서버에 한 번 요청하는 동안만 bean이 존재한다는 뜻이다. Page scope와 대개의 경우 차이가 없으나, <jsp:forward> 태그와 <jsp:include> 태그를 사용하여 넘겨지거나 포함되는 문서에서도 bean이 소멸되지 않고 존재한다는 점만 다르다.

Application scope는 웹 서버 혹은 JSP를 구동시키는 모듈이 셧다운 되기 전까지 beans를 살아있도록 할 때 사용된다. Scope가 application으로 설정된 beans는 살아있는 동안 어떤 문서에서도 사용이 가능하다.

Request와 application 두 가지 모두 session scope 처럼 사용방법은 두 가지가 있다. <jsp:useBean .... />과 <jsp:useBean ..> ... </jsp:useBean>의 두 가지인데, 용법은 앞의 session scope과 동일하여 후자의 경우 열고 닫는 태그 사이의 내용은 bean이 최초 생성될 때에만 수행된다.

Request와 application scope에 대해서는 독자들이 실제 테스트해 보기 바란다.

마치며

다른 웹 개발 솔루션(PHP, ASP, Perl)등과 Java 솔루션이 확연이 구분되는 점이 이 글에서 설명한 beans이다. Beans를 잘 사용한다면 깔끔하고 멋진 코딩을 실현할 수 있을 뿐만 아니라, 개념적으로 훌륭한 설계를 바탕으로 개발을 진행할 수 있다. 특히, 웹 개발은 화면 디자인과 소스의 로직이 마구 뒤섞이기 쉬운데, beans를 활용하면 디자인과 코딩을 효과적으로 분리할 수 있으며, 따라서, 진정한 의미의 코딩을 실현할 수 있다.

Beans를 제대로 사용하려면 환경을 먼저 잘 구축해야 한다. Freeware로는 Tomcat을 추천한다. Tomcat의 설치 방법에 대해서는 WebDox의 Apache에서 Tomcat 사용하기를 참고하도록 한다.

Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

자바 기반의 웹 개발 소개

김세곤 <sehkone@bawi.org>

1999년 12월 19일

개발자의 고민

프로그래밍을 공부하고 싶은 사람이나 프로젝트를 목전에 두고 있는 개발자 모두가 고민하고 있는 것은 과연 어떤 개발 방법이 가장 적합할 것인가 하는 문제이다. 큰 범주로는 어떤 OS를 택할 것인가하는 것에서부터 작게는 어떤 에디터를 사용할 것인가에 이르기까지 고민거리는 널려있다. 문제는 개발 방향 선정 과정에서의 고민으로 그치는 것이 아니다. 우여곡절끝에 한번 개발 방향이 잡혀서 상당 기간 동안 관련 자료를 수집, 학습하고 개발을 진행시키게 되면 다른 가능성을 고려해 보기란 쉽지 않다. 리눅스에 대한 이해가 없는 직장 상사때문에 윈도우즈에서 개발을 착수해 놓고나서 중간에 리눅스로 전환한다는 것은 상상하기 어려운 일이다. 오랫동안 C/C++을 공부하여 CGI 기법을 득도했다고 해도 보다 진보된 방법들로 여겨지는 Server-side Script 방식을 새로이 공부하여 사용하기란 만만치 않은 일이다. 따라서, 개발 과정에서의 후회를 최소화하기 위해서라도, 더 나아가서는 향후 프로젝트에도 유용하게 써먹을 수 있도록 하기 위해서, 초기 개발 방향 선정에 보다 혜안을 갖고 신중을 기해야 한다.

그러나, 어떤 개발 방향이 현재의 요건과 향후의 비전을 동시에 만족시켜줄 수 있는지를 찾아내는 것도 쉽지 않다. 진보적인 방법으로 보이는 것들은 진행 상태가 베타 정도인 경우가 많고 심지어는 스펙만 있고 관련 툴을 찾기 어려울 때도 있다. 그렇다고, 막상 손에 익은 개발 방법은 뭔가 향후 비전이 없어 보이고, 벤치마크 테스트에서 새로운 개념에 비해 못 미치기도 한다. 여기저기 관련 사이트를 뒤져가면서 비교적 그럴싸한 개발 방법 몇 가지를 압축해 놓고 나서도, 조언을 해 주는 개발자마다 딱히 어떤 개발 방법이 최선이라는 답을 내 주지 못 한다. 그도 그럴 것이, 이런 저런 방법을 모두 학습하고 실제에서 다 적용시켜 본 개발자는 거의 없기 때문이다. 인터넷에 널려 있는 벤치마크 테스트 자료도 내가 알고 싶은 것만 꼭 빠져있기 일쑤고, 어쩌다 나와 있는 정말 궁금한 정보는 테스트 자료마다 다르다. 설상가상으로 좀 좋은 툴이다 싶은 것은 열심히 다운로드 받으려고 보면 트라이얼 버전이고, 상업적으로는 절대 이용하지 말란다.

현재까지의 경험들과 산더미같은 관련 자료를 바탕으로하여 기도하는 심정으로 개발 방향을 잡았다고 하자. 그것으로 해결되는가? 문제는 이제부터 시작이라고 보면 된다. 돈 싸 들고 문제를 해결하려고 하면 간단하겠지만, 오픈 소스 진영의 개발자들의 자존심으로 상업용을 쓸 수 있겠는가. 자존심은 둘째로 쳐도 돈이 없는데 어쩌겠는가. 다행히도 절망에서 건져주는 것은 어딘가에 숨어있는 자유로이 배포가능한 소프트웨어! 중요 기능을 비교적 다 갖추고 있는 그래도 쓸만한 툴이 숨어 있기 마련이다. 그러나, 반가움도 잠깐, 설치해서 운영해 보려고 하면 어딘지 찜찜하다. 개발자야 열심히 노력해서 만들었겠지만, 그 양반이 언제까지 업그레이드 해 줄지 의문이 생기기도 하고, 어딘가에 심각한 버그 있을지 알 길 없음이다. 다시 여기 저기 뒤져보다 보면 내가 찾아낸 소프트웨어가 비교적 안정적으로 여러 사람의 지지를 받고 있는 것이 확인된다. 그렇다면 역시 이것을 찾아낸 나의 혜안에 놀라게 되며 설치를 시도해 보게 된다. 이제 본격적인 문제가 발생한다. 전세계의 많은 사람들이 좋다고 지지를 보낸 소프트웨어가 왜 나의 컴퓨터에서는 설치가 안 되는 문제가 발생한단 말인가. 싼 맛에 조립한 나의 펜티엄은 역시 비지떡이었단 말인가. 나랑 설치를 같이 시작한 다른 개발자가 7000만원짜리 컴팩 서버에서 잘 돌리고 있는 모양을 보면 열이 받기까지 한다. 이틀을 고민하고 머리를 쥐어 뜯고 나니 어느 순간 꿈쩍도 않던 소프트웨어가 돌아가고 문제는 디렉토리에 쓰기 퍼미션을 안 열어 놓았기 때문이라는 사실을 깨닫게 된다. 겨우 퍼미션 따위로 이틀을! 그러나, 기쁨도 잠시, 설치만 하면 무엇하겠는가. 개발하려고 모니터 앞에 앉으면 손에 쥐게 되는 자료라고는 README나 API를 줄줄이 설명해 놓은 정도이다. 튜토리얼을 열심히 읽어도 겨우 입문 정도지 본격적인 개발에 도움이 크게 되기 어렵다. 결정적으로 그 놈의 문서들은 죄다 영어로 씌여 있는 통에 해독하는데만 해도 한숨 나온다.

이 모든 어려운 과정을 헤치고 개발에 착수해서 프로젝트가 완수될 무렵, 개발자의 가슴을 찧는 것은 더욱 진보적인 방법이 수없이 생겨나고 내가 열심히 쌓은 기술이 오래가지 못 할지도 모른다는 불안감이다.

웹 개발의 역사와 추세

정적인 HTML에서 동적인 CGI로

초기에는 HTML만으로도 놀라운 인터넷의 세계라고 여길 수 있었다. 그러나, 곧 정적인 문서에 식상하게 되고 뭔가 방문자와 호흡할 수 있는 동적인 사이트를 만들 필요성이 생겨나기 시작했다. 사실 지금은 전세계의 모든 사이트가 정적인 HTML문서만으로 움직이지 않는다. 끊임없이 데이터베이스와 연동하여 방문자에게 맞는 맞춤 정보를 제공하고 있다.

초기 HTML의 정적인 자료를 동적으로 움직이게 하기 위해서 등장한 방법이 CGI(Common Gateway Interface)이다. 초기 한동안은 많은 개발자에게 쉽게 전달되지 않아서 특별하고 대단한 기법쯤으로 여겨지기도 했는데, 그 메카니즘은 매우 간단하다. 별도로 만들어 놓은 프로그램에 HTML의 GET이나 POST의 방법을 통해 클라이언트의 데이터를 환경 변수로 전달하고 프로그램의 표준 출력 결과를 그대로 클라이언트에 되돌려 주는 형식이다. CGI는 특별한 라이브러리나 개발 툴을 지칭하는 것이 아니고 웹 서버와 별도로 만들어 놓은 프로그램 간의 데이터 교환 방식을 일컫는 것으로서 어떤 프로그래밍 언어로도 구현이 가능하다. 초기에는 C, C++, Perl, Visual Basic(물론 윈도그에서만) 등이 주류를 이루었다.

데이터베이스와 연동하기 위해서는 개별 데이터베이스가 제공하는 해당 언어의 라이브러리를 이용하는 방식을 취하였다. 예를 들어 postgreSQL을 웹과 연동시키기 위해서는 postgreSQL이 제공하는 C라이브러리를 이용한다든지 하는 식이었다.

CGI의 문제점

작성과 유지의 한계

구동 메카니즘의 취약성을 차치하고서라도 CGI 방법에서 표준 출력으로 HTML문서 양식을 만들어야 한다는 것이 개발자에게 가장 번잡스러운 문제로 등장하였다. 예를 들어, C로 CGI 프로그램을 만들었다고 하자. 간단한 HTML문서를 출력하기 위해서도 다음과 같은 C코드를 써야 했다.

...
printf("<HTML><HEAD><TITLE>CGI결과물</TITLE></HEAD>");
printf("\n<BODY>");
printf("\n난 \"멋진 넘\"이야");
...

HTML 문서 양식이 한눈에 들어오는가? 절대 그럴 수 없다. 겨우 한 줄의 HTML 코드를 쓰려고 해도 표준 출력 함수를 불러야 하고, 줄 넘김을 위해서 \n을 남발해야 하며, 큰 따옴표를 쓰려고 하면 앞에 \(backslash)를 붙여주어야만 한다. 매번 printf 함수가 호출되는 것도 달갑지 않다. HTML 문서의 한계상 문서 체계를 코드만으로 이해하는 것이 쉬운 일은 아니지만, C 코드와 섞여 있으니 어디가 어딘지 도통 감이 서지 않는다.

천신만고 끝에, 절대 직관적으로 눈에 들어오지 않는 HTML 코드에서 헤매다가 간신히 프로그램을 작성하고, 작성한 CGI 프로그램을 웹에서 동작하게 하려면 컴파일러로 컴파일을 우선 해야 한다. 그리고, 브라우저를 띄운다. 테스트를 했더니, "멋진 놈"이라고 나와야 할 것이 "멋진 넘"으로 오타가 나고 있다. 단 한 글자를 수정하기 위해 해야 할 일은 작성한 C 프로그램 코드의 "멋진 넘" 부분을 열심히 찾아서 한 글자 고치고 다시 컴파일을 하고 브라우저의 다시 읽기 버튼을 누르는 것이다. 상상해보자. 조금 긴 문서, 테이블이 복잡하게 들어간 문서를 고치려고 하면 과연 쉬울까? 그래도 디자인과 CGI를 함께 한다면 작성자 스스로 디자인을 고쳐갈 수 있으니 꺼이꺼이 수정할 수 있다고 치자. 그러나, 디자이너가 별도로 있고 개발자가 이를 CGI로 변환하는 작업만을 한다면? 디자이너가 C 코드를 봐가면서 고칠리 만무다. 예를 들어, 홈페이지의 대대적인 개선 작업의 일환으로 게시판의 디자인이 확 바뀌었다고 하자. 디자이너는 바뀐 게시판의 샘플 디자인을 CGI 작업자에게 던져 준다. 프로그래머는 이를 COPY-PASTE로 C 에디터로 가져 와서 열심히 표준 출력 함수로 우겨 넣어야 한다. 예전에 작업했던 것은 다 필요 없이 새 부대에 담아야 한다. 이제, 웹 개발자는 노가다 인력으로 전락하고 만다.

메카니즘의 한계

CGI의 결정적인 한계는 성능에 있다. 간략한 페이지를 CGI를 통해 보여 주려고 해도 웹 서버는 별도의 프로그램을 실행시켜야 한다. 프로그램 실행이 뭐 대수냐고? OS가 프로그램을 실행하는 단계를 잠깐 생각해 보자. 각각의 프로그램은 실행되면서 하나의 프로세스가 되는데, 개별 프로세스를 제어하기 위해 OS는 PCB(Process Control Block)를 사용한다. PCB에는 각 프로세스의 상태, 프로그램 카운터, CPU 레지스터, 스케줄링 정보, 메모리 정보, I/O 정보 등등등이 저장되고 이 PCB는 메모리에 저장된다. 더불어, 코드 내용이 메모리에 적재되는데, 프로그램 코드를 모두 메모리에 저장하는 것은 무리이므로 필요한 부분만을 찾아서 메모리에 싣는다. 프로세스가 하나만 도는 것이 아니므로 CPU는 현재 진행 중인 프로세스를 적절하게 스케줄링하여 동시에 수행되고 있는 효과를 내도록 한다. 위에서 언급한 프로그램이 실행되면서 OS가 처리해야 하는 일련의 일과 동시에 여러 작업을 수행하기 위해 프로세스를 전환하는 과정 등은 OS의 관점에서 보면 매우 Heavy한 일이다. 뿐만아니라, CGI는 클라이언트의 요청이 같은 URL, 즉 같은 CGI 프로그램을 실행시키는 것이라고 해도, 각각의 요청을 모두 개별 프로세스로 처리한다. 1000명이 카운터 CGI를 요청했다고 하면 1000개의 프로세스가 생긴다는 말이다. 몇 줄의 HTML 문서 결과를 보여 주기 위해 위에서 언급한 일들을 매번 수행한다는 것은 어딘지 효율적이지 못하다.

Server-side Script 방식의 도래

프로그램 코드 속에 HTML 문서를 우겨 넣는 방식은 디자인과 개발을 별도의 작업으로 분리시키지 못 하고 유지, 보수에 많은 시간을 들게 하는 등의 단점이 있었다. 이를 개선하는 방법들이 등장하기 시작했는데, 뭔고하니, HTML 문서 안에 우아하게 프로그램 코드를 넣는 방식이다. 대표적인 것이 ASP(물론 윈도그에서만), PHP 등이다. 이 중 근래에 사용의 편리성으로 인해 주목받고 있는 방법이 PHP이다.

PHP를 생각해 보자. PHP는 C 코드와 비슷해 보이지만 절대 C가 아닌 새로운 언어 스펙을 사용하고 있다. 기존 언어처럼 복잡하지 않고, 사용하기 간편하다. 뿐만아니라, 온갖 종류의 데이터베이스를 제어할 수 있는 함수도 제공되고 있으며, 기타 웹 개발에 필요하다 싶은 함수들은 잔뜩 들어가 있다. 그러나 PHP 한계는 여기에 있다. 모든 필요한 것은 PHP가 해결을 해 주어야 한다. PHP가 제공하지 않는 방법으로는 해결책을 찾을 수 없다는 말이다. PHP는 기존 언어를 사용하는 것이 아닌 새로운 언어이므로, 기존의 수많은 라이브러리, 소프트웨어와 연동시킬 수 없는 한계가 있다. 더욱이, PHP는 웹 서버에 모듈로 포함되어 있어서, 이런 온갖 기능이 웹 서버에 상당한 부하를 주게 된다. 구동 방식을 생각해 보자. 웹 서버에 PHP 문서가 요구되면 웹 서버는 PHP 모듈로 그 제어권을 넘긴다. PHP 모듈은 PHP 문서를 문법적으로 해독하면서 관련 함수들을 구동하여 결과물을 브라우저에 보내게 된다. 언어를 문법적으로 해독하는 과정은 아무리 간단한 문법의 언어라고 해도 일정 수준의 시간이 필요하다. 함수가 많아지고 기능이 복잡해질 수록 요구되는 시간은 늘어난다. 뿐만아니라, 한번 실행한 문서의 해독 정보를 저장하는 것이 아니라 매번 그 문서가 요구될 때마다, 같은 작업을 수행해야 한다. PHP 모듈은 웹 서버에 들어가는 다른 모듈에 비해 매우 큰 규모로 웹 서버 수행에 부담을 가중시킨다. 이런 이유로 성능 향상을 위해 구문을 최소화하느라 객체지향 등의 최신 언어 기법을 구사할 수 없다. 때문에, C++이나 Java처럼 한번 사용한 소스 코드를 재사용하기 어렵다.

웹 개발 최후의 솔루션 - 자바

자바란?

자바는 Sun이 개발한 객체지향 언어로서 플랫폼에 구애 받지 않는 장점때문에 급속히 확산되고 있다. 최신 프로그램 언어 개념인 객체지향, 멀티쓰레드, Garbage Collection, Exception Handling 등을 복합시킨 언어로서 기반이 매우 훌륭하다. 그동안 등장했던 Lisp, C, C++ 등 모든 언어의 장점을 절묘하게 복합시켰으며 C에서 사용해온 포인터와 동적 메모리 관리 등을 아예 없애 개발자의 부담을 덜어주었다. 자바 코드는 어느 OS에서도 JVM(Java Virtual Machine)만 있다면 단 한 줄의 코드 수정 없이 똑같이 가동시킬 수 있다. 자바 소스를 자바 컴파일러로 컴파일 하면 Bytescode가 생성이 되고, 이 Bytescode는 어떤 OS의 JVM에서도 동등하게 실행된다. 그러나, 초기엔 자바의 개념적 우월성에도 불구하고 JVM의 수행 속도가 매우 느려 실제 개발 현장에서 채택하기에는 무리였다. 그러나, 하드웨어 사양의 발전과 JVM의 성능 향상으로 초기의 느리다는 지적은 점차 사라지고 있다.

웹과 자바

Applet : 클라이언트

초기에 자바는 애플릿 작성에 많이 이용되었다. 애플릿은 HTML 코드안에 포함되는 독립적 프로그램으로 브라우저가 이를 받아서 수행한다. 넷스케이프와 익스플로러 모두 브라우저 안에 자바를 수행할 수 있는 JVM을 내장하고 있으므로 OS와 독립적으로 동등하게 실행시킬 수 있다. 애플릿은 서버측에서 동적으로 생성되는 것이 아니라 클라이언트(브라우저)에게 보내져 클라이언트 환경에서 수행된다. 자바 Bytescode는 소스를 자바 컴파일러로 컴파일한 결과물로서 HTML 문서에 비해 크기가 매우 크며 웹 서버에서 브라우저로 전송되기까지가 많은 시간이 걸린다. 일단 전송된 애플릿은 브라우저가 수행시키므로 그 속도는 클라이언트의 시스템 환경과 브라우저가 내장하고 있는 JVM의 성능에 따라 좌우된다. 28.8K 정도의 모뎀 환경이라면 그럴듯한 애플릿을 다운 받아서 수행하는데는 많은 인내심이 필요하게 된다. 그러나, 점차 인터넷 통신 환경이 좋아지고 있으며 가정집을 제외한 대부분의 사무실과 학교 등에서는 전용 회선이 깔려 있고, 넉넉한 환경의 전용선이라면 애플릿을 구동하는데 무리가 없다. 근래에는 가정에서도 초고속 통신 환경을 싼 값에 구축할 수 있으므로 점차적으로 인터넷 환경에서 애플릿의 전송은 부담이 되지 않을 것이다. JVM도 기술적으로 많이 향상되었고, Sun뿐 아니라, IBM과 같은 매머드급 회사들이 뛰어들어 개발하고 있어 초기 지적받았던 JVM의 구동 속도는 점차 문제가 되지 않는 상황이다.

Servlet과 JSP : 서버

오늘날의 많은 개발은 웹과의 연동을 염두에 두고 있다. 자바 진영도 예외는 아니어서, 근래의 발전 방향은 인터넷에 초점이 맞추어져 있다. 지금까지 등장한 웹 개발 방법들은 페이지 생산에 비해 보수가 매우 어렵다는 점과, 동시 접속자가 많아지면 성능이 저하된다는 점, 기존에 산재해 있는 많은 개발 방법들과 연계가 번거롭다는 점 등이라고 말하였다. 이를 개선하려는 노력이 반영되어 자바 진영에서는 이러한 단점을 극복해 줄 수 있는 방법을 제시하고 있다. 뿐만 아니라, 대규모 프로젝트에서 적합한 훌륭한 아키텍쳐를 제공하고 있다.

보통 웹 개발이라면 단순히 방문자에게 효과적인 화면을 제공하는 것 쯤으로 생각하기 쉬운데, 내부적으로는 끊임없이 데이터베이스와 연동하기도 하고 각종 미들웨어를 사용하여 효율을 증대하기도 한다. 이 중에서 웹은 클라이언트와의 접점이며 인터페이스이다. 자바에서는 웹 인터페이스로서 서블릿과 자바 서버 페이지의 두 가지 방법을 제공한다.

서블릿과 JSP 엿보기

서블릿

우선 서블릿에 대해서 간략히 소개하겠다. 서블릿은 일종의 CGI이다. 그러나, 그 구동 방식은 여러가지 점에서 다른데 가장 큰 장점은 클라이언트가 요청하는 서블릿이 개별적인 프로세스로 실행되는 것이 아니고 서블릿을 제어하는 모듈 내에서 실행된다는 것이다. 아파치와 JServ를 사용했다고 하면 쉽게 ps를 통해 java 프로세스가 하나만 돌고 있는 것을 확인할 수 있다. 이것은 클라이언트들이 같은 서블릿을 요청하면 이 서블릿이 메모리에 개별적으로 올라오는 것이 아니라 하나만 메모리에 적재된다는 뜻이고 이는 엄청난 퍼포먼스 향상을 가져온다. 뿐만 아니라, 모든 실행되는 서블릿은 이를 제어하는 모듈의 통제하에 놓이게 되므로 서블릿끼리의 자유로운 통신이 가능하고 쓰레드를 사용한다면 멀티쓰레드 프로그래밍이 가능해진다. 일반적인 CGI의 큰 단점 중에 하나인 보안 문제도 서블릿을 사용하면 걱정할 필요가 없다.

또 하나의 장점은 서블릿이 자바를 사용하기 때문에 자바가 제공하는 수많은 기능을 제한없이 사용할 수 있다는 것이다. 예를 들면 자바가 제공하는 2D, 3D 그래픽 툴을 이용해서 동적인 이미지를 생산할 수 있고, 자바가 제공하는 메일 클래스들을 이용하면 효과적으로 메일 전송 및 관리를 할 수 있다.

또, 자바를 기반 언어로 사용하기 때문에 자연스럽게 얻어지는 장점이 있는데 이것은 코드의 손쉬운 재사용, 플랫폼 독립성, JDBC 사용 등이다. 코드의 재사용은 객체지향언어의 중요한 개념으로 잘 만들어 놓은 구조의 클래스라면 어느 코드에서도 쉽게 사용할 수 있고 계승 등을 이용하여 기능을 추가할 수 있다. 플랫폼 독립성도 역시 자바의 중요한 장점인데 만일 서블릿으로 웹을 구축하였다면 어떤 OS, 어떤 기계라도 그 플랫폼이 자바를 지원하기만 하면 한 줄의 코드 바꿈없이 개발해 놓은 코드를 그대로 이식할 수 있다. 자바는 리눅스, 유닉스를 비롯하여 심지어 윈도그에서도 무리없이 돌아가며, 서블릿 환경도 어떤 플랫폼이라도 쉽게 구축할 수 있다. JDBC를 사용하면 어떤 데이터베이스와도 똑같은 인터페이스로 연동할 수 있으므로, 데이터베이스를 다른 기종으로 교체한다고 해도 서블릿 소스 코드를 거의 수정할 필요가 없다.

서블릿 코드를 잠깐 소개하겠다.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CMemberTest extends HttpServlet {
    
    public void doGet(HttpServletRequest request,
		       HttpServletResponse response)
	throws ServletException, IOException {
	
	response.setContentType("text/html; charset=EUC_KR");
	PrintWriter out = response.getWriter();

	out.println("<HTML><HEAD><TITLE>세션 테스트</TITLE></HEAD></HTML>");
	out.println("<BODY>");

	Cookie[] cookies = request.getCookies();
	boolean pass = false;
	String email = "";

	for (int i = 0; i < cookies.length; i++) {
	    Cookie thisCookie = cookies[i];
	    out.println(thisCookie.getName() + ":" + thisCookie.getValue());
	    if (thisCookie.getName().equals("pass") &&
		thisCookie.getValue().equals("yes")) pass = true;
	    if (thisCookie.getName().equals("email")) 
		email = new String(thisCookie.getValue().getBytes(), "EUC_KR");
	}

	try {
	    if (pass) {
		out.println("인증 통과된 아이디임" + " : " + email);
	    } else {
		out.println("인증 통과되지 않았음");
	    } 
	} catch (NullPointerException e) {
		out.println("인증 과정을 거치지 않았음");
	}
	out.println("</BODY></HTML>");
    }
}

위의 예에서는 쿠키를 이용하여 인증 여부를 확인시켜 주는 간단한 방법을 보여준다. 쿠키를 이용하는 인증은 보안 측면에서는 빈약하여 WebDox가 제공하는 아파치에 추가 되는 postgreSQL 인증 모듈을 쓰는 방법이 훌륭하지만, 우선 위의 방식은 쿠키 사용예를 보여주며 보안이 크게 필요하지 않는 수준이라면 사용할 수 있다.

JSP

서블릿은 CGI와는 비교할 수 없는 수준의 좋은 아키텍처를 갖고 있고 다양한 장점들이 있다. 그러나 역시 자바 코드 속에 HTML 코드를 넣어야 한다는 단점이 있는데, 이를 극복한 것이 JSP(Java Server Page)이다. JSP는 HTML문서 안에 자바 코드를 넣는 형식으로 PHP, ASP와 같이 Server-side script 방식이다. 그러나, JSP는 소스 수정 시 자동적으로 서블릿으로 전환되어 구동되며 이점에서 완전히 서블릿과 동등하다. JSP의 코드를 잠시 살펴보자.

<%@ page import="java.sql.*" contentType="text/html; charset=EUC_KR" %>

<%
String userId = request.getParameter("userid");

Connection db;
ResultSet rs;
Statement stmt;

try {
   Class.forName("postgresql.Driver");
} catch (java.lang.ClassNotFoundException e) {
   System.err.println(e.getMessage());
}
%>

<HTML>
<HEAD><TITLE>JSP Sample page</TITLE></HEAD>
<BODY>
<TABLE>
<TR>

<%
try {
    db = DriverManager.getConnection("jdbc:postgresql:dbname", "dbowner", "password");
    stmt = db.createStatement("SELECT name FROM member WHERE userid = " + userId);
    rs = stmt.executeQuery();

    while (rs.next()) {
%>

<tr>
<td><%= rs.getString("name") %><td>
</tr>

<%
    }
%>

</TABLE>
</BODY>
</HTML>

<%
} catch (SQLException e) {
%>
    <%= e.getMessage() %>
<%
}
%>

HTML 문서 안에 자바 코드가 들어가는 모습과 JDBC를 이용하여 postgreSQL과 연동되는 모습을 볼 수 있다. <% %> 태그 안에는 자바 코드를 아무런 제한 없이 써 넣으면 되고, <%= %> 태그 안의 자바 코드 결과는 화면에 그 결과가 보여지게 된다. Post나 Get으로 전달받는 값들은 request.getParameter() 함수를 이용하면 쉽게 제어할 수 있다.

다른 개발 방법과의 비교

많은 개발자들이 가장 궁금해 하는 것이 역시 여러 개발 방법들 중 어떤 것이 더 나은가 하는 점일 것이다. 지금까지 여러가지 방법들의 장단점을 언급했는데 정리해 보기로 하자. 비교 대상은 일반 CGI, Server-side scripts(PHP, ASP), Servlet+JSP 등이다.

성능면

ASP는 스크립트로 씌여 졌지만 일단 컴파일 되면 CGI로 바뀌므로 CGI가 갖고 있는 여러가지 문제점을 그대로 지니게 된다. 따라서, ASP와 CGI가 성능면에서 가장 취약하다. PHP의 경우는 대체적으로 매우 뛰어난 속도를 보여 준다. Servlet과 JSP는 JVM에 그 성능이 의존적이다. 현재는 ASP나 CGI보다는 빠르지만 PHP보다는 약간 느리다는 평을 얻고 있다. 그러나, 여러 미들웨어를 사용하거나 DB와의 많은 트랜잭션이 있는 경우는 PHP에 앞선다고 보고되고 있으며, JVM의 성능 향상에 따라 꾸준한 성능 향상을 기대할 수 있다.

확장성면

단연, Servlet+JSP 방식이 우월하다. 자바가 제공하는 모든 기능을 자유롭게 사용할 수 있으며 코드의 재사용 등에서 탁월하다. JDBC를 사용하여 모든 데이터베이스와 똑같은 인터페이스로 데이터 교환이 가능한 점에서도 Servlet+JSP 방식이 뛰어난 확장성을 갖고 있다.

난이도

ASP나 PHP는 간단한 문법이므로 초보자도 쉽게 사용할 수 있다. 그러나 Servlet과 JSP는 자바를 알아야 한다는 전제 때문에 쉽게 다가서기 어려운 면이 있다. 하지만, 개발자는 간단한 웹 인터페이스만을 작업하는 것이 아니기 때문에 제대로 한 언어를 알아두면 어느 때고 약이 된다. 간단한 작업을 위해서라면 자바를 전부 익혀야 하는 부담없이 손쉽게 작업할 수 있기도 하다.

결론

향후 웹 개발에서 자바를 이용한 솔루션은 큰 몫을 차지할 것이며, 큰 프로젝트일수록 그 사용 비중은 높아질 것이다. webdox는 웹 개발에 있어서의 자바의 비전을 인식하여 지속적으로 자바를 이용한 웹 개발 방법에 대한 자세한 글을 게재할 예정이다.

Posted
Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

  1. BlogIcon Nike Air Max Shoes 2012.05.04 16:37  댓글주소  수정/삭제  댓글쓰기

    http://www.nikejordanairmaxshoes.com/ Nike Air Max Shoes http://www.nikejordanairmaxshoes.com/ Air Max Shoes http://www.nikejordanairmaxshoes.com/ Nike Air Max http://www.nikejordanairmaxshoes.com/ nike jordan air max http://www.nikejordanairmaxshoes.com/ nike air jordon http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-Run-sale-id-187.html Barefoot Nike Free Run http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-Run--2-sale-id-321.html Barefoot Nike Free Run+ 2 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-Run--3-sale-id-322.html Barefoot Nike Free Run+ 3 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-Run-sale-id-323.html Barefoot Nike Free Run http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Free-Run-3-0-V2-sale-id-324.html Barefoot Free Run 3.0 V2 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Free-Run-3-0-V3-sale-id-325.html Barefoot Free Run 3.0 V3 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-5-0-V4-sale-id-326.html Barefoot Nike Free 5.0 V4 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-7-0-sale-id-327.html Barefoot Nike Free 7.0 http://www.nikejordanairmaxshoes.com/cheap-Barefoot-Nike-Free-Tr-Fit-sale-id-328.html Barefoot Nike Free Tr Fit http://www.nikejordanairmaxshoes.com/cheap-Dual-Fusion-St-2-sale-id-329.html Dual Fusion St 2 http://www.nikejordanairmaxshoes.com/cheap-Air-Max-sale-id-330.html Air Max http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-2009-sale-id-331.html Nike Air Max 2009 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-2011-sale-id-332.html Nike Air Max 2011 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-2012-sale-id-333.html Nike Air Max 2012 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-24-7-sale-id-334.html Nike Air Max 24-7 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-87-sale-id-335.html Nike Air Max 87 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-89-sale-id-336.html Nike Air Max 89 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-90-sale-id-337.html Nike Air Max 90 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-91-sale-id-338.html Nike Air Max 91 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-93-sale-id-339.html Nike Air Max 93 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-95-sale-id-340.html Nike Air Max 95 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-180-sale-id-341.html Nike Air Max 180 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-360-sale-id-342.html Nike Air Max 360 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-2010-sale-id-343.html Nike Air Max 2010 http://www.nikejordanairmaxshoes.com/cheap-Nike-Max-Alpha-2012-sale-id-344.html Nike Max Alpha 2012 http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-ACG-sale-id-345.html Nike Air Max ACG http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Tailwind--4-sale-id-346.html Air Max Tailwind +4 http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Classic-BW-sale-id-347.html Air Max Classic BW http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Griffey-sale-id-348.html Air Max Griffey http://www.nikejordanairmaxshoes.com/cheap-Air-Max-LTD-sale-id-349.html Air Max LTD http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Skyline-sale-id-350.html Air Max Skyline http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Terra-Ninety-sale-id-351.html Air Max Terra Ninety http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-Tn-sale-id-352.html Nike Air Max Tn http://www.nikejordanairmaxshoes.com/cheap-Air-Max-Zenyth-sale-id-353.html Air Max Zenyth http://www.nikejordanairmaxshoes.com/cheap-Air-Max-2009-Heels-sale-id-354.html Air Max 2009 Heels http://www.nikejordanairmaxshoes.com/cheap-Nike-Air-Max-Barkley-sale-id-355.html Nike Air Max Barkley http://www.nikejordanairmaxshoes.com/cheap-Nike-Lunar-sale-id-356.html Nike Lunar http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarGlide--3-sale-id-367.html Nike LunarGlide+ 3 http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarGlide--2-sale-id-368.html Nike LunarGlide +2 http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarGlide---sale-id-369.html Nike LunarGlide + http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarElite--sale-id-370.html Nike LunarElite+ http://www.nikejordanairmaxshoes.com/cheap-LunarEclipse--2-sale-id-371.html LunarEclipse+ 2 http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarEclipse--sale-id-372.html Nike LunarEclipse+ http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarMX--sale-id-373.html Nike LunarMX+ http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarSwift-sale-id-374.html Nike LunarSwift http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarHaze-sale-id-375.html Nike LunarHaze http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarFly--2-sale-id-376.html Nike LunarFly+ 2 http://www.nikejordanairmaxshoes.com/cheap-Nike-Lunaracer--2-sale-id-377.html Nike Lunaracer+ 2 http://www.nikejordanairmaxshoes.com/cheap-Lunar-Orbit-Nd-sale-id-378.html Lunar Orbit Nd http://www.nikejordanairmaxshoes.com/cheap-Lunar-Rejven8-Mid-sale-id-379.html Lunar Rejven8 Mid http://www.nikejordanairmaxshoes.com/cheap-Nike-LunarElite--2-sale-id-380.html Nike LunarElite+ 2 http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-sale-id-357.html Air Jordan http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-2012-sale-id-381.html Air Jordan 2012 http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-2011-sale-id-382.html Air Jordan 2011 http://www.nikejordanairmaxshoes.com/cheap-Jordan-Melo-M7-sale-id-383.html Jordan Melo M7 http://www.nikejordanairmaxshoes.com/cheap-Jordan-Fly-Wade-II-sale-id-384.html Jordan Fly Wade II http://www.nikejordanairmaxshoes.com/cheap-Jordan-Alpha-Trunmer-sale-id-385.html Jordan Alpha Trunmer http://www.nikejordanairmaxshoes.com/cheap-Jordan-Heels-sale-id-386.html Jordan Heels http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-III-3--sale-id-387.html Air Jordan III(3) http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-V-5--sale-id-388.html Air Jordan V(5) http://www.nikejordanairmaxshoes.com/cheap-Air-Jordan-IV-4--sale-id-389.html Air Jordan IV(4) http://www.nikejordanairmaxshoes.com/cheap-Jordan-Retro-XI-11--sale-id-390.html Jordan Retro XI(11) http://www.nikejordanairmaxshoes.com/cheap-Jordan-3-5-Spiziker-sale-id-391.html Jordan 3.5 Spiziker http://www.nikejordanairmaxshoes.com/cheap-Nike-Shox-sale-id-358.html Nike Shox http://www.nikejordanairmaxshoes.com/cheap-Nike-Shox-R4-sale-id-392.html Nike Shox R4 http://www.nikejordanairmaxshoes.com/cheap-Nike-Shox-NZ-sale-id-393.html Nike Shox NZ http://www.nikejordanairmaxshoes.com/cheap-Nike-Shox-Turbo-sale-id-394.html Nike Shox Turbo http://www.nikejordanairmaxshoes.com/cheap-Air-Force-1-sale-id-359.html Air Force 1 http://www.nikejordanairmaxshoes.com/cheap-Air-Force-1-Heels-Hi-Top-sale-id-395.html Air Force 1 Heels Hi-Top http://www.nikejordanairmaxshoes.com/cheap-Nike-Dunk-SB-sale-id-360.html Nike Dunk SB http://www.nikejordanairmaxshoes.com/cheap-Nike-Dunk-Heels-Lo-Top-sale-id-396.html Nike Dunk Heels Lo-Top http://www.nikejordanairmaxshoes.com/cheap-Nike-Dunk-Heels-Hi-Top-sale-id-397.html Nike Dunk Heels Hi-Top http://www.nikejordanairmaxshoes.com/cheap-Nike-Dunk-Block-Heels-sale-id-398.html Nike Dunk Block Heels http://www.nikejordanairmaxshoes.com/cheap-Nike-Dunk-Block-Heels-Hi-Top-sale-id-399.html Nike Dunk Block Heels Hi-Top http://www.nikejordanairmaxshoes.com/cheap-Nike-Zoom-sale-id-361.html Nike Zoom http://www.nikejordanairmaxshoes.com/cheap-Hyperdunk-2011-Low-sale-id-400.html Hyperdunk 2011 Low http://www.nikejordanairmaxshoes.com/cheap-Zoom-Kobe-VI-sale-id-401.html Zoom Kobe VI http://www.nikejordanairmaxshoes.com/cheap-Zoom-Rookie-sale-id-402.html Zoom Rookie http://www.nikejordanairmaxshoes.com/cheap-Lebron-VIIII-9-sale-id-403.html Lebron VIIII 9 http://www.nikejordanairmaxshoes.com/cheap-Zoom-Kobe-VII-sale-id-404.html Zoom Kobe VII http://www.nikejordanairmaxshoes.com/cheap-Air-GO-LWP-sale-id-405.html Air GO LWP http://www.nikejordanairmaxshoes.com/cheap-Zoom-Lebron-VII-sale-id-406.html Zoom Lebron VII http://www.nikejordanairmaxshoes.com/cheap-Football-Soccoer-sale-id-363.html Football Soccoer http://www.nikejordanairmaxshoes.com/cheap-Tiempo-Legend-IV-sale-id-365.html Tiempo Legend IV http://www.nikejordanairmaxshoes.com/cheap-Nike-MERCURIAL-sale-id-366.html Nike MERCURIAL http://www.nikejordanairmaxshoes.com/cheap-Nike-Trail-Blazer-sale-id-364.html Nike Trail Blazer

JSP 맛보기

Web/JSP 2007. 10. 26. 10:30

김세곤 <sehkone@bawi.org>

1999년 12월 19일

이번 글은 JSP를 어떻게 쉽게 사용해 볼 수 있는지, 그 사용 방법에 대한 일종의 간단한 튜토리얼이다. 메카니즘에 대한 이해와 높은 난이도의 JSP 사용에 대한 글을 계속적으로 연재할 예정이다.

JSP의 문서 구성

JSP는 HTML문서안에 자바 코드를 써 넣는 방법으로 동적 문서를 생산한다. HTML안에 써 놓은 자바 코드는 웹 서버가 가동한 JVM을 통해 알맞는 HTML 문서로 동적 생산되어 브라우저로 보내진다. 정확하게 말하면 웹 서버의 여러 모듈 중 JSP를 담당하는 모듈이 이 일을 하게 된다. 메카니즘에 대한 소개는 뒤로 미루고, 우선 JSP 문서가 어떻게 구성되는지 살펴 보자. JSP 문서 내에 JSP를 위한 태그는 <% %>, <%= %>, <%@ %>, <%! %>, <jsp: /> 등이 있다(태그는 기본적으로 XML 체계를 따르고 있다). 먼저, <%@ %>, <% %>, <%= %> 태그를 살펴보자. 이것만으로도 어지간한 웹 문서는 모두 만들 수 있으며, <jsp: />는 1.0 이상에서만 가능하므로 간혹 지원을 제대로 하지 못 하는 환경이 있을 수도 있다. JSP문서의 기본 구성을 보자.

<%@ page contentType="text/html; charset=EUC-KR" %>
<HTML>
<HEAD><TITLE>JSP 문서</TITLE></HEAD>
<BODY>
<% 
    String email = 
"sehkone@bawi.org";

%> 저에게 연락을 하시고 싶으시면 <ahref="mailto:<%= email %>">여기를</a> 클릭하세요.

</BODY>
</HTML>

JSP의 구성은 매우 간단하다. 우선 맨 위의 <%@ page contentType="text/html; charset=EUC-KR" %>는 브라우저가 전송받는 문서가 HTML이고 한글 문서라는 사실을 알도록 하기 위한 것이다. 쉽게 생각해서, 이 줄은 공통적으로 모든 JSP파일의 첫머리에 들어가는 것으로 보면 된다. <% %>안에는 자바 코드가 들어간다. 위의 예에서는 String 클래스로 email 인스턴스(변수)를 만든 것이 전부이지만, <% %>안에는 코드의 분량에 구애됨이 없이 자유롭게 자바 코드를 써 넣을 수 있다. <% 로 시작한 자바 코드는 %>로 끝나며 다시 HTML 문서가 등장한다. 위의 예에서 "저에게...클릭하세요" 가운데를 살펴보면 <%= %> 태그를 볼 수 있는데, <%= %> 태그 안의 자바 코드 결과는 그대로 HTML 문서내에 보여지게 된다. 따라서, 위의 예는 다음의 HTML 문서가 되어 브라우저로 보내지게 된다.
<HTML>
<HEAD><TITLE>JSP 문서</TITLE></HEAD>
<BODY>

저에게 연락을 하시고 싶으시면 <a href="mailto:sehkone@bawi.org">여기를</a> 클릭하세요.

</BODY>
</HTML>

간단하지 않은가? 이제 여러분은 JSP 문서의 대체적인 골격은 이해하였다.

다음으로 넘어가기 전에 한 가지만 더 알아둘 것이 있다. 첫번째 줄 <%@ page ... %> 안에는 import 변수가 들어가는 경우가 많은데, java.io.*와 java.lang.*, javax.servlet.*, javax.servlet.http.*, javax.servlet.jsp.* 클래스는 JSP 문서에 기본적으로 import 되므로 굳이 import 변수에 명시할 필요가 없으나, 그 외의 클래스를 쓰고 싶다면 import 변수에 써 주어야 한다. JDBC를 쓴다면 java.sql.* 클래스를 포함시켜야 하고 자바 메일 클래스를 이용하려면 javax.mail.*, javax.mail.internet.* 등을 포함시켜야 하는데 이 경우는 다음처럼 쓰면 된다.

<%@ page import="java.sql.*, javax.mail.*,javax.mail.internet.*" contentType="text/html; charset=EUC-KR" %>

import의 값으로 포함시키고자 하는 클래스를 콤마로 구분하여 나열하기만 하면 되는 것이다.

GET, POST도 간편하게 - getParameter() 이용하기

동적인 문서 생산하기 위해서는 사용자와 호흡해야 하고, 이를 위해서는 브라우저 내에 사용자가 정보를 입력하는 일이 많다. 이 정보를 처리하기 위해서 JSP는 getParameter() 메쏘드를 제공한다. getParameter 메쏘드는 ServletRequest 인터페이스의 메쏘드로서 GET이나 POST로 넘어온 값들을 얻을 수 있도록 해 준다. ServletRequest는 HttpServletRequest가 계승하는데 JSP 표준 스펙에서는 HttpServletRequest 클래스 타입으로 request 인스턴스(변수)를 만든다. 따라서, JSP 문서에서 getParameter 메쏘드를 사용하려면 다음처럼,

String name = request.getParameter("name");

사용해야 한다. 다시 말하면, JSP는 컴파일되면 정상적인 자바 코드로 만들어진 서블릿이 되는데, 이 서블릿 코드 내에서 request는 내부적으로 사용되는 변수라는 말이다. 즉, JSP 문서 내에서는 request라는 이름의 인스턴스(변수)를 어떤 형태로든 사용할 수 없고, 프로그래머는 이미 만들어지는 request 인스턴스를 이용하여 getParameter(나중에 설명하겠지만, 쿠키를 얻기 위한 getCookies() 등과 같은 메쏘드도 포함된다) 메쏘드를 사용하면 된다. JSP가 서블릿으로 변환되면서 내부적으로 정의되는 인스턴스는 몇 가지가 더 있는데, 이는 추후에 차차 알아나가기로 하자. GET이나 POST로 전달되는 값을 처리하는 방법을 좀 더 자세히 코드를 봐 가면서 알아보자. 사용자의 이름과 비밀번호를 입력받아서 이를 확인하는 JSP를 예로 들겠다. 우선, 사용자의 이름과 비밀번호를 입력받는 Form을 사용한 HTML 문서를 만들어야 한다.
....
<form method="post" action="member.jsp">
이름 : <input type="text" name="username"><br>
비밀번호 : <input type="password" name="userpasswd"><br>
<input type="submit">
</form>
....

이 HTML문서의 이름, 비밀번호 필드에 적당한 값을 입력하고 submit 버튼을 누르면 이 값들이 member.jsp로 전달될 것이다. 이제, POST로 전달되는 값을 member.jsp에서 어떻게 받는지를 살펴보자.
<%@ page contentType="text/html; charset=EUC-KR" %>
<%
String name = request.getParameter("username");
String password = request.getParameter("userpasswd");
%>
<HTML>
<HEAD>
<TITLE>회원인가?</TITLE>
</HEAD>
<BODY>
이름은 <%= name %>이고, 비밀번호는 <%= password %>라고 입력하였습니다.
</BODY>
</HTML>

GET으로 전달받는 값들도 POST와 같은 방법으로 request.getParameter()를 사용하면 된다.

쿠키를 사용하자

웹 개발을 하다보면 쿠키를 사용할 일이 종종 있다. 쿠키에 대한 자세한 이야기는 필자가 따로이 글을 준비 중이므로 많은 기대 부탁드리며, 여기서는 간략하게 JSP에서 쿠키를 다루는 법만 소개하겠다.

먼저, 쿠키를 세팅하는 코드를 보기로 하자.

<%@ page contentType="text/html; charset=EUC-KR" %>
<%
String myEmail = "sehkone@bawi.org";
Cookie cookieEmail = new Cookie("email", myEmail);
cookieEmail.setMaxAge(-1);
response.addCookie(cookieEmail);
%>
<HTML>
<HEAD>
<TITLE>쿠키 세팅</TITLE>
</HEAD>
<BODY>
별로 하는 일은 없는 JSP 문서지만 쿠키를 세팅하는 예를 보여줍니다.
</BODY>
</HTML>

여기서, 새로운 인스턴스(변수)인 response를 만나게 된다. response는 JSP문서가 서블릿으로 변환될 때 내부적으로 사용하는 HttpServletResponse 클래스의 인스턴스(변수)로서, JSP 문서 내에서 자유롭게 사용할 수 있다. 앞서 언급한 request가 사용자의 요청에 관한 것을 다룬다면, 이 response는 사용자의 요청에 대한 JSP 문서의 응답에 관한 것을 다룬다. 초보 단계에서는 역시 자세한 메카니즘에 대한 이해는 뒤로 미루어 두고, 쿠키를 사용하기 위해서는 response 변수를 사용하여 addCookie() 메쏘드를 호출해야 한다는 사실을 알아두자. 염두에 둘 것은 request, response가 인스터스들이므로 이와 같은 이름의 다른 인스턴스를 정의하면 안 된다는 사실이다.

한 줄 한 줄 살펴보자. 자바 코드 부분의 첫번째 줄에서는 이메일 주소를 스트링 인스턴스에 넣었다. 두번째 줄은 Cookie 클래스 타입으로 새로운 쿠키를 만드는데, 그 이름은 email이고 값은 myEmail 인스턴스 값으로 한다는 뜻이다. 세번째 줄에서는 이 쿠키의 유효 기간을 설정하는 것인데, -1처럼 음의 값은 브라우저 종료 시까지 이 쿠키가 유효하도록 하는 설정이다. 0은 이 쿠키를 없애라는 설정이며, 특별히 유효 기간을 명시하고 싶으면 setMaxAge 메쏘드의 인자로 초 단위 값을 써 주면 된다.

브라우저에 쿠키를 세팅하는 방법을 살폈고, 이제 브라우저로부터 쿠키를 얻는 방법을 알아보자. JSP나 서블릿에서 쿠키를 얻을 때는 쿠키 이름을 명시하여 얻을 수 있는 방법은 없고 모든 쿠키를 다 받아서 각각의 쿠키의 이름과 값을 검사하는 방법을 사용해야 한다. 다음의 예는 쿠키 중에서 그 이름의 "id"인 것을 찾아서 그 값을 출력하는 JSP이다.

<%@ page contentType="text/html; charset=EUC-KR" %>
<HTML>
<HEAD><TITLE>id 쿠키 값 검사</TITLE></HEAD>
<BODY>
<%
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
   Cookie thisCookie = cookies[i];
   if ("id".equals(thisCookie.getName())) {  // if문 시작
%>
아이디는 <%= thisCookie.getValue() %> 입니다.<BR>
이 부분에는 자유로운 HTML 코드가 들어갈 수 있습니다.
<%
   }  // if문의 끝
%>
</BODY>
</HTML>

for 문 두 줄 아래의 if문 내의 JSP 형태를 주의깊게 보도록 하자. <% } %>로 if 문을 닫아 주는 일을 종종 잊는 경우가 많은데 항상 신경을 쓰도록 하자.

이제, 특정한 쿠키를 찾아서 그 쿠키를 없애는 방법을 알아보자. 바로 위의 코드에 몇 줄만 추가하면 id 쿠키를 없앨 수 있다. 다음을 보자.

<%@ page contentType="text/html; charset=EUC-KR" %>
<HTML>
<HEAD><TITLE>id 쿠키 값 없애기</TITLE></HEAD>
<BODY>
<%
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {
   Cookie thisCookie = cookies[i];
   if ("id".equals(thisCookie.getName())) {  // if문 시작
%>
아이디는 <%= thisCookie.getValue() %> 입니다.<BR>
이 부분에는 자유로운 HTML 코드가 들어갈 수 있습니다.
<%
        thisCookie.setMaxAge(0);   // 쿠키를 없애라는 유효기간 설정
        response.addCookie(thisCookie);   // 다시 쿠키를 세팅
   }  // if문의 끝
%>
이제 id 쿠키는 없어졌습니다.
</BODY>
</HTML>

데이터베이스를 맘대로 - JDBC

웹 개발에서 역시 가장 중요한 부분은 데이터베이스와의 연동이다. JDBC는 필자가 별도의 쓰레드로 연재할 생각이며, 여기서는 역시 맛만 보도록 하자.

JDBC를 사용하기 위해서는 사용하는 데이터베이스의 JDBC 드라이버를 설치하여야 한다. postgreSQL의 경우는 http://www.retep.org.uk/postgres/에서 JDK 버전에 따른 드라이버를 구할 수 있다.

역시, 예제부터 보자.

<%@ page import="java.sql.*" contentType="text/html; charset=EUC-KR" %>
<%
    String userId = request.getParameter("userid");
    Connection db;
    ResultSet rs;
    PreparedStatement stmt;

    try {
        Class.forName("postgresql.Driver");
    } catch (java.lang.ClassNotFoundException e) {
        System.err.println(e.getMessage());
    }

    try {
        db = DriverManager.getConnection("jdbc:postgresql:dbname", "dbuser", "password");
        stmt = db.prepareStatement("SELECT id, name FROM member WHERE id = ?");
        stmt.setString(1, userId);
        rs = stmt.executeQuery();       
        rs.next();

        String resultId = rs.getString("id");
        String resultName = rs.getString("name");
        
        stmt.close();
        rs.close();
        db.close();
    } catch (SQLException e) {
    }
%>
<HTML>
<HEAD>
<TITLE>
JDBC 사용
</TITLE>
</HEAD>
<BODY>
<%= resultId %>의 이름은 <%= resultName %> 입니다.
</BODY>
</HTML>

JDBC를 사용하기 위해서는 JDBC 드라이버를 로드해야 하는데, 이를 위해서 다음처럼 한다.
try {
    Class.forName("postgresql.Driver");
} catch (java.lang.ClassNotFoundException e) {
    System.err.println(e.getMessage());
}

쉽게 생각하여 이 부분은 모든 JSP 문서에서 DB에 연결하기 전 공통적으로 들어간다고 보면 된다. 다음으로 DB와 연결해야 하는데, 이를 위해서 다음처럼 한다.
db = DriverManager.getConnection("jdbc:postgresql:dbname", "dbuser", "password");

첫번째 인자는 접속하고자 하는 DB 이름을 알려주는 것인데, 앞의 jdbc:postgresql은 사용되는 드라이버 이름이다. 이 부분은 개별 DBMS에 따라 다른데, 드라이버 설치 문서에 나와 있으므로 참고하여 명시하면 된다. jdbc:postgresql: 다음에는 접속하고자 하는 DB이름을 그대로 쓰면 된다. 두번째, 세번째 인자는 접속하고자 하는 DB의 사용자 아이디와 비밀번호를 써 넣으면 된다.

JDBC는 DB에 질의를 던지는 방법으로 두 가지를 제공하고 있다. Statement와 PreparedStatement 클래스가 그 두 가지 방법인데, 여기서는 PreparedStatement에 대해서 간단히 설명하겠다. 먼저, DB에 묻고자 하는 질의를 다음과 같은 방법으로 생성한다. stmt는 PreparedStatement 클래스의 인스턴스여야 하며, prepareStatement의 인자로는 SQL 구문이 들어간다.

stmt = db.prepareStatement("SELECT id, name FROM member WHERE id = ?");

여기서, ?는 정해지지 않은 값으로서 다음처럼 세팅한다.
stmt.setString(1, userId);

다음으로, 이 질의를 DB에 던지고 결과를 받는다.
rs = stmt.executeQuery();       
rs.next();

rs는 ResultSet 클래스의 인스턴스이며, next 메쏘드는 질의 결과로 얻어진 릴레이션에서 튜플 포인터를 하나씩 증가시키는 일을 한다. 쉽게 말해서, 얻어진 질의 결과를 한 줄씩 넘기는 것이라 보면 된다. 현재 가리키고 있는 튜플의 필드 값을 읽기 위해서는 getXXX 메쏘드를 사용하는데 필드의 타입이 문자열이라면 getString을 쓰면 된다.
String resultId = rs.getString("id");
String resultName = rs.getString("name");

위와 같이 하면 id, name 필드 값이 각각 resultId와 resultName 스트링에 저장되게 된다. 마지막으로 PreparesStatement, ResultSet, Connection 인스턴스들을 없애는 일을 해야 한다.
stmt.close();
rs.close();
db.close();

사실, Java는 Garbage Collection 기능이 있으므로 불필요한데, Sun에서는 외부 클래스를 사용할 경우 이 기능이 제대로 수행되지 못 할 가능성 때문에, close 메쏘드를 사용하기를 권장하고 있다.

마치며

이번 글에서는 JSP와 JDBC를 맛 보았다.

사실, 위에서 설명한 request.getParameter() 메쏘드는 beans를 사용하면 거의 사용할 일이 없다. 초기에는 beans를 지원하지 못하는 환경이 많았으나 요새는 대부분 지원이 가능하므로, 독자 여러분은 우아한 beans를 사용하여 JSP 문서를 개발하도록 하자. Beans에 대해서는 WebDox의 JSP에서 Beans 사용하기를 참고하면 자세한 사용법을 알 수 있다. Beans가 없는 JSP는 생각하기 어려우므로 꼭 살펴본다.

JDBC에 대해서는 좀 더 상세한 용법이 WebDox의 JDBC를 익히자에 있으므로 참고하면 좋겠다.

Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요

JSP에서의 include

Web/JSP 2007. 10. 26. 10:29
★ JSP에서의 include

Last Modified 2003/06/06
Written by hsboy
ReadCount 10276


JSP 에서는 두가지 방법으로 다른 문서를 현재의 문서에 포함 시킬수 있습니다. 이번 강좌에서는 이러한 두가지 include 문에 대해서 알아 봅니다.

* include 란?

다른 웹 언어(PHP or ASP등)를 프로그래밍 해본 경험이 있으신 분들은 include 가 무었인지 잘 알고 있을 것입니다.
include 란 현재의 문서에 다른 문서, 즉 다른 파일의 내용을 포함시켜 출력하는 것을 말합니다. 예를 들어 doc1.jsp 라는 문서의 내용이 아래와 같다고 합시다.

doc1.jsp
<%@ page contentType="text/html;charset=euc-kr"%>
<%
    out.print("<h2>이것은 doc1.jsp의 내용입니다.</h2>");
%>

그리고 doc2.jsp 의 내용이 아래와 같을때

doc2.jsp
<%
    out.print("<h2>이것은 doc2.jsp의 내용입니다.</h2>"); 
%>

위의 두개 문서의 출력을 한번에 보고자 할 때 include를 사용합니다.

doc3.jsp
<%@ page contentType="text/html;charset=euc-kr"%>

<jsp:include page="doc1.jsp" flush="true" />

<%@include file="doc2.jsp" %>

위의 doc3.jsp 를 출력하면 아래와 같은 화면이 출력됩니다.

doc3.jsp 실행화면


위의 소스에서 눈여겨 볼 부분이 doc2.jsp 의 상단 부분인데, doc2.jsp에는 page Directive가 생략 되어 있습니다. 이것은 두가지 include 방식의 차이 때문인데, 자세한 설명은 아래에서 하도록 하겠습니다.
또한 이러한 기능을 SSI(Server Side Include)를 이용해서 구현할수도 있는데 이것은 apache웹서버에서 지원하는 내용 이므로 여기에서는 다루지 않도록 하겠습니다. 자세한 내용이 궁금하신분은 여기를 참고 하시기 바랍니다.


* JSP Action - <jsp:include page="URI" flush="true" />

[syntax]
1). body 구문이 없는 경우
<jsp:include page="URI" flush="true" />

2). body 구문이 있는 경우
<jsp:include page="URI" flush="true">
<jsp:param name="파라메터이름" value="파라메터값" /> /* xxx.jsp?파라메터이름=파라메터값 */
</jsp:include>  

위와 같이 두가지 사용 용법이 있으며, 두번째 방법을 사용하면 해당 jsp파일에 파라메터값도 넘겨 줄수가 있습니다.
JSP Action 구문의 include 는 include되는 파일과 include 시키는 파일(doc1.jsp와 doc3.jsp)를 각각 컴파일 한후 두 파일의 실행 결과를 한곳에 합쳐서 출력을 하게 됩니다. 즉, 완전히 "별도로" 동작하게 됩니다.
여기에서 flush="true" 문장은 true나 false 가 들어 갈수 있는 부분으로써 include를 실행하기 전에 out.flush()를 실행할지 여부를 결정하는 것입니다. 물론 true일때 out.flush()를 실행하겠지요. JSP 스펙 1.1 까지는 반드시 true로 설정이 되어 있어야만 했으니, 1.2 부터는 true/false중 원하는것을 선택하면 됩니다.


* include 지시어 - <%@ include file="URI" %>

include 지시어 와 Action 구문과의 가장 큰 차이점은 include 지시어는 컴파일 되기전에 파일이 내용이 합쳐진다는 것입니다. 즉, doc3.jsp 는 doc2.jsp의 내용을 자신의 문서내에 포함하여 하나의 파일로 인식한다는 것입니다. doc2.jsp 에 보면 page Directive 가 생략이 되어 있는데, 그것이 바로 이러한 이유 때문입니다.

doc2.jsp에도 page Directive를 설정해 주었다면 에러가 발생할 것입니다. 하나의 페이지에 두번 선언을 하는 꼴이 되어 버릴테니까 말이죠.


* Action 구문과 include 지시어의 중요한 차이점

JSP프로그래밍을 조금이라도 접해 보신 분들이라면 누구나 아는 대로 JSP는 먼저 servlet 으로 변환되고, 그 다음 servlet 이 컴파일 되어 그결과를 화면에 출력해 주게 되어 있습니다.
그런데, Action 구문을 사용 하였을 때에는 두개의 파일 각각 다른 파일처리 되어 두개의 servlet 파일 생성하게 됩니다. 따라서 어느 한 파일이 수정되면 곧바로 적용되어 화면에 출력이 되게 됩니다.

하지만 include 지시어 문을 사용하게 되면 하나의 servlet 파일이 생성되게 됩니다. 이로 인해 엄청난 차이점이 발생하게 되는데, JSP의 특성상 JSP파일이 조금이라도 수정이 되어 있으면 servlet 으로 재 변경되어 다시 컴파일이 이루어 지게 됩니다. 그런데, doc2.jsp 파일을 내용을 수정하고, doc3.jsp 파일을 부르게 되면 수정되기 전의 doc2.jsp 파일의 내용이 출력됩니다.

또다시 doc3.jsp 파일을 살짝 고치고 doc3.jsp 을 부르게 되면 이제서야 수정된 doc2.jsp파일의 내용이 화면에 출력 되게 될 것입니다. 눈치 빠르신 분들은 알아 차리셨으리라 생각됩니다만..
이렇게 된 원인은 아무리 doc2.jsp의 내용이 수정된다 하더라도 JSP엔진에서는 doc3.jsp가 수정이 되지 않아 JSP 엔진에서는 수정되지 않은 같은 파일로 인식하여, servlet 파일을 다시 생성하지 않았기 때문입니다.

따라서, include 지시어 문을 사용하셨을 경우에는 두개의 파일 모두 수정해 주어야(doc3.jsp는 공백하나가 추가 되더라도 수정되어야 합니다) 원하는 결과를 얻을수가 있게 됩니다.
이경우 하나의 파일을 여러개의 파일에서 include 지시어 로 include 하였다면 이것은 치명적일수도 있습니다. 예를 들어 dbcon 같은 내용을 만들어 include 해서 사용하는 경우 상당히 많은데, 이럴때 큰 문제 거리가 될수도 있습니다.
이러한 문제점을 한번에 해결하는 방법이 있는데, ...tomcat/ 디렉토리에 보면 work 라는 디렉토리가 있습니다. 이곳이 바로 변환된 servlet 파일들이 저장되어 있는 곳인데, 이 디렉토리를 완전 삭제 한후에 tomcat을 재시작 시키면, 변경된 내용들이 한번에 적용이 될것입니다.(모든 servlet 파일이 재작성되니 당연한 결과 이겠지요)
그런데 이러한 특징은 tomcat 5 버젼대부터 달라지게 되었는데, include되는 파일을 수정하더라도 서블릿 컨테이너가 알아서 모두 재 컴파일 해준다는 것입니다. 필자가 확인한 바로는 OC4J 최신 버젼에서도 tomcat 5와 같이 자동으로 처리되었습니다.


저자 : 이선재(hsboy)
http://www.aboutjsp.com
다른곳에 올리실 때는 반드시 출처를 명시해 주시기 바라며 되도록 이면 링크를 걸어 주시기 바랍니다.
Posted by 행복한 프로그래머 궁금쟁이박
TAG JSP

댓글을 달아 주세요