강좌
클라우드/리눅스에 관한 강좌입니다.
프로그램 분류

JSP에서 Beans 사용하기

작성자 정보

  • 웹관리자 작성
  • 작성일

컨텐츠 정보

본문

icon01.gif title14.gif

김세곤 <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 좌표는 입력을 받지만 원점으로부터의 거리는 입력받는 값이 아니고 계산되는 값이다.

다음은 x, y 좌표 값을 form으로 입력받는 html 문서이다. 
이 form의 submit 버튼을 누르면 calc.jsp가 호출된다. 이제 calc.jsp를 작성하자. 
calc.jsp의 6번 행은 Point 클래스 타입으로 myPoint라는 인스턴스 이름을 갖는 bean을 생성하라는 뜻이다. 7번 행은 이 myPoint bean의 field인 parallelValue를 form의 parallelValue 값으로 설정하라는 것이고, 8번 행은 verticalValue를 form의 verticalValue 값으로 설정하라는 말이다. 이 6번 행부터 8번 행 까지는 다음의 자바 코드의 의미를 함축한다. 
물론 완전히 동등한 것은 아니다. 특히, calc.jsp의 6번 행은 위의 1번 행의 의미보다 더 포괄적이다. 이것은 다음 절에서 설명하기로 하고, 7번 행과 8번 행만을 주목하면 각각 위의 2번 행, 3번 행과 동등하다. 9번 행은 myPoint bean의 속성인 distance 값을 얻는다. 9번 행은 
과 동등하며, 따라서, calc.jsp는 다음처럼 고쳐써도 똑같다. 
JSP 태그를 사용한 것과 위의 자바 코드를 사용한 코드를 살펴보자. 어떤 것이 더 명료한가? JSP는 HTML 문서 안에 자바 코드를 사용할 수 있는 장점이 있지만, HTML 코드와 자바 코드가 복잡하게 섞이면 이해하기 어려워진다. 따라서, 좋은 코딩 습관은 되도록 JSP 파일 내에서는 자바 코드를 줄이고 복잡한 자바 코드는 beans나 Servlet을 통해 사용하는 것이다. JSP 태그는 이처럼 자바 코드 대신 XML 스타일의 태그를 사용하여 beans와 교통할 수 있도록 하여, 코드를 보다 더 명료하게 해 준다. 

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

Bean 사용 방법

  Bean 생성/선언

Bean의 생성/선언은 <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() 메쏘드는 값을 넘겨받는 인자가 하나 존재해야 한다. 코드를 통해 본다면, 만일,

라 하면, 다음처럼 bean에는 대응되는 메쏘드가 존재해야 한다. 
getXXX 메쏘드의 리턴 값과, setXXX 메쏘드의 인자는 어떤 타입이 되어도 좋으나, setXXX 메쏘드에 인자로 넘겨주는 값의 형이 정의와 다르면 에러가 나므로 주의한다. 

  Bean 속성 설정하기

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


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


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


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

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

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

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

후자처럼 직접 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 문서를 보자.

두 문서 내에 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의 소스는 다음과 같다.

위의 session1.jsp를 브라우저를 통해 보면, 다음과 같은 결과를 얻게 된다. 
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 버튼을 눌러보자. 다음과 같은 결과가 얻어진다. 
초기 값이 바뀌었다. RELOAD 버튼을 누르기 전에 이미 session이 시작되었으므로 RELOAD 버튼을 통해 새로 접속했을 때는 두 개의 bean이 생성된 것이 아니라 선언된 것에 불과하다. 따라서, 생성자가 불리지 않고 이미 생성된 beans을 참조하게 되는 것이고, 이에 따라 이미 설정한 값인 3과 5가 얻어진다. 

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

이 session2.jsp는 아무런 기능없이 단지 session3.jsp로의 링크만 담고 있다. 역시 아래의 next를 눌러 session3.jsp를 호출해 보자. session3.jsp는 아래와 같다. 
아직 inc.jsp 소스의 내용을 모르므로 11번 행의 결과를 빼고 8번과 9번 행의 결과를 눈치빠른 독자들은 이미 결과를 알고 있을 것이다. 결과는 다음과 같다. 
session1.jsp에서 session3.jsp로 직접 가지 않고 beans에 대해서는 아무런 언급이 없는 session2.jsp를 거쳤는데도 여전히 myBean1의 값이 3으로 유지가 되고 있음을 알 수 있다. 더불어 9번 행을 보면 <jsp:getPropery> 태그를 사용하는 것이 직접 getData() 메쏘드를 실행하는 것과 동등하다는 것도 알 수 있다. 이제, 위 결과의 5번 행을 이해하기 위해서 inc.jsp의 소스를 살펴보자. 
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의 사용 방법

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

첫번째는 닫는 태그 없이 하나의 태그로 표현되었고, 두번째는 </jsp:useBean> 태그를 사용하여 닫았다. 두번째 방법에서 <jsp:useBean> 과 </jsp:useBea> 사이에는 어떤 것이든 제한없이 들어갈 수 있다. 다만, 사이에 들어가는 내용은 session이 새로 생성될 때만 실행된다. 다음의 예제를 보자. 
최초로 이 문서를 실행하면 다음처럼 결과가 얻어진다. 
그러나, RELOAD를 통하여 재차 실행하면, 
와 같은 결과를 얻는다. <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 사용하기를 참고하도록 한다.

관련자료

댓글 0
등록된 댓글이 없습니다.

공지사항


뉴스광장


  • 현재 회원수 :  60,039 명
  • 현재 강좌수 :  35,845 개
  • 현재 접속자 :  101 명