IBM Korea Skip to main content
       IBM 홈    |  제품 & 서비스  |  고객지원 & 다운로드  |  회원가입  

커스텀 태그로 JSP 페이지 제어하기
커스텀 태그 라이브러리 통신의 모든 것

Jeff K. Wilson
E-비즈니스 설계자, IBM
2002년 1월

JavaServer Pages 기술은 웹 개발자들에게 중요한 기능을 제공하지만, 많은 개발자들이 이 기술의 전 능력을 활용하지 못하고 있다. e-비즈니스 설계자인 Jeff Wilson (IBM의 존경받는 DragonSlayers 팀의 멤버이기도 함)은 이 기술에서 더 많은 것을 얻어 내기 위하여 JSP 태그를 커스터마이즈하는 방법을 보여준다. 이 글에서 그가 상세히 설명한 기법을 이용해서 여러분은 JSP에 보다 복잡한 로직을 추가하고 데이터 화면 출력을 더 엄격하게 제어하고 태그 간에 데이터를 공유시킬 수 있는데, 일선 웹 개발자들에게 자바 코드 작성법을 가르치지 않고도 이 모든 것을 할 수 있다.

여러분이 웹 개발에 관여하고 있다면 여러분은 오늘날의 웹 기반 애플리케이션이 보다 동적으로 생성되는 컨텐츠와 개인화된 데이터를 그 어느 때보다 더 많이 요구한다는 사실을 잘 알고 있을 것이다. 사용자에게 친근한 인터페이스를 설계한다는 것은 일선 개발자들이 숙련된 시각적 설계 스킬을 가지고 있어야 할 뿐 아니라 컨텐츠의 흐름을 관리하고 활용하는데도 능숙해야 함을 의미한다.

사용자 정의 (커스텀) JSP 태그는 이러한 일선 개발자들에게 JSP 페이지에 아무런 자바 코드를 작성하지 않고도 백엔드 자바 컴포넌트에서 데이터가 처리되는 방식을 제어할 수 있는 수단을 제공한다.

이 글에서 우리는 커스텀 태그가 서로 어떻게 통신하고 이들을 결합시키면 재사용성과 유연성이 어떻게 높아지는지에 포커스를 맞출 것이다. 또한 몇 가지 예도 살펴 보겠다.

커스텀 태그 개요

커스텀 태그는 <jsp:useBean .../><jsp:getProperty .../> 같은 일반적인 JSP 태그보다 더 진보되고 유연하다. 커스텀 태그가 일반 JSP 태그에 비해 가지는 주요 장점 중 하나는 커스텀 태그를 사용하면 JSP 개발자가 데이터를 태그 속성이나 시작과 끝 태그 태그 사이에 위치시킴으로써 입력 사항을 전달할 수 있다는 점이다.

커스텀 JSP 태그는 다음 세 부분으로 구성되어 있다.:

  • 태그가 사용되는 JSP 페이지
  • 태그를 처리하는 자바 클래스인 태그 핸들러 (tag handler)
  • 태그들을 하나의 "라이브러리"로 묶고, 속성, 태그 처리명, 단축명 등 각 태그의 세목을 기술하는 XML 파일인 태그 라이브러리 디스크립터 (tag library descriptor) .

커스텀 태그는 태그의 속성으로 입력된 사항에 기반하여 프로세스를 실행시키도록 구성될 수 있고, JSP 페이지 내에 임베디드된 자바 코드를 둘 필요가 없다.

예제를 살펴 보자. Listing 1은 사용자가 선택한 모든 제품에 대해 테이블의 한 행을 만드는 쇼핑 카트 태그이다.:

Listing 1. 쇼핑 카트 태그

<table width="100%" border="0">
  <user:getUserShoppingList userId="13">
  <tr>
    <td>
    <a href="/servlet/productDataServlet?prodID=$_productId">$_productName</a>
    </td>
    <td>$_productDescription</td>
  </tr>
  </user:getUserShoppingList>
</table>

이 경우, 태그 처리자 클래스는 HTML과 사용자 ID가 결과로 나오는 출력 (이 경우에는 테이블의 한 행)에 대한 템플릿으로 전달되기를 기대한다. 다양한 $_product...참조는 태그 핸들러에서 반복 수행되는 제품들의 실제 값으로 교체될 것이며, 이것이 태그를 구현하는 자바 클래스이다.

이것은 커스텀 태그의 또 다른 주요 장점을 보여 준다. 자바 프로그래머들은 데이터를 클라이언트에게 재전송하기 전까지 데이터 포맷을 어떻게 할지 알 필요가 없다. 또한 내용은 유사한데 포맷이 다른 데이터를 요구하는 새로운 페이지가 개발되거나 현재 페이지의 모습이 바뀔 때 자바 컴포넌트를 업데이트할 필요가 없을 것이다.

유형 뿐 아니라 화면 로직도 제어하기

커스텀 태그의 또 다른 아주 중요한 장점은 같은 페이지 상의 다른 태그와 통신할 수 있다는 점이다. 기존의 JSP 태그에서는 개발자들이 JavaBean 컴포넌트의 행동을 제어하기 위해 특성을 설정할 수 있었지만, 빈은 그 자신이 할 수 있는 것만 할 뿐이다.

프로세스를 보다 작은 컴포넌트들로 나눔으로써 JSP 개발자들은 커스텀 태그들을 섞고 맞출 수 있으며, 이를 통해 동적인 컨텐츠에 대한 제어력을 높일 수 있도록 보다 복잡한 프로세스를 구축할 수 있다.

한 커스텀 태그의 출력을 다른 태그에 대한 입력으로 사용하면 태그의 재사용성이 높아진다. 예를 들어, 위의 예에서 사용자 쇼핑 카트 태그는 구매한 제품에 대한 모든 정보를 보유하고 있다. 사용자 태그는 제품 ID만을 가지고 다른 태그 (제품 태그)가 제품 데이터를 필요에 따라 관리하도록 하면 더 휼륭한 설계가 될 것이다. 일단 제품 상세 사항을 모으는 프로세스를 분리시키면 여러분은 이런 목적으로 다른 태그와 함께 사용될 수 있는 제품 태그를 가지게 된다.

이는 검색된 동적인 데이터를 제어하기 위한 객체지향적 방식을 만들어내고, 일선 개발자들은 프로그래밍에 대해 알지 못해도 이 방식을 따라갈 수 있다.

Listing 2의 코드는 실행 중인 이 방식을 보여준다. 또한 사용자의 쇼핑 목록 태그는 error:setErrorTemplate이라는 다른 태그를 구현한다는 점에 주의한다. 이 예에서 어떤 제품도 발견되지 않을 경우 우리는 에러 메시지가 나타나기를 원한다. 우리의 제품 목록에 필요한 2열로 된 테이블이 에러 메시지에 그리 적절하지 않을 것임을 쉽게 알 수 있다.

Listing 2. 객체 지향적 방식


<table width="100%" border="0">
  <tr class="headerRow">
    <td>Product Name</td>
    <td>Product Description</td><tr>
  </tr>
  <user:getUserShoppingList userId="13">
    <products:getProductData productId="$_productId"/>
    <tr>
      <td>
        <a href="/servlet/productDataServlet?$_productId">$_productName</a>
      </td>
      <td>$_productDescription</td>
    </tr>
    <error:setErrorTemplate>
    <tr class="errorRow">
        <td colspan="2">You have nothing in your shopping cart...</td>
    </tr>
    </error:setErrorTemplate>
  </user:getUserShoppingList>
</table>

태그 핸들러 클래스는 사전 정의된 특정 환경 하에서 변경된 포맷을 처리하도록 설계될 수 있다. 이것은 JSP 개발자가 JSP 페이지 내에 if 절이나 다른 자바 코드를 사용하지 않고도 어떻게 데이터의 논리적 흐름을 제어할 수 있는지를 보여주는 좋은 예이다. 커스텀 태그를 사용해 JSP 개발자들은 어떻게 표시되는지 뿐 아니라 무엇이 표시되는지를 판별하는 방법도 정할 수 있다.

다른 상황에서, 동일한 제품 데이터 태그가 제품 목록을 가진 다른 태그에 재사용될 수 있다. Listing 3에서 다른 HTML이 태그로 전달

Listing 3. 제품 목록과 사용되는 제품 데이터 태그

<table width="100%" border="0">
  <products:getProductList category="fitness">
    <products:getProductData productId="$_productId"/>
    <tr>
      <td rowspan="2">
        <a href="/servlet/productDataServlet?$_productId"><img 
        src="$_productImage" border="0"></a></td>
      <td>
      <a href="/servlet/productDataServlet?$_productId">$_productName</a>
      </td>
    </tr>
    <tr>
      <td>$_productDescription: $_productPrice</td>
    </tr>
    <error:setErrorTemplate>
    <tr>
      <td colspan="2" class="errorRow">Sorry, no products in this category...</td>
    </tr>
    </error:setErrorTemplate>
  </user:getUserShoppingList>
</table>

태그 통신 메소드 : 장점 및 예제

커스텀 태그가 서로를 참조하고 데이터를 공유하는 몇 가지 방법이 있다. 적절한 메소드가 무엇이냐는 물론 상황에 달려 있을 것이다.

중첩 태그
한 태그가 다른 태그에 의해 완전히 둘러싸여져 있을 때 태그가 중첩되어 있다고 말한다. :

<outer:tag><inner:tag/></outer:tag>

한 태그를 다른 태그 내에 두기 위해 특별한 설정이나 코딩이 필요하지는 않다. 한 태그가 한 곳에 중첩될 수 있고 그 자체로 다른 곳에 중첩될 수 있다. 물론 일부 태그는 다른 태그들 내에 중첩되도록 설계되겠지만, 태그가 중첩 가능하다고 선언하기 위해 특별히 필요한 것은 없다.

여러분은 HTML 테이블, 테이블의 행과 테이블의 셀 태그를 중첩 태그로 생각할 수 있다. 테이블 태그에 공유된 데이터의 예로 테이블의 배경 색 (bgcolor 속성)을 들 수 있다. 배경이 테이블 태그 내에 <table bgcolor="blue">...</table>이라고 설정되면, bgcolor 속성이 개별적인 태그 (예 : <table bgcolor="blue">...<td bgcolor="red">...</td>...</table>)에 의해 오버라이드되지 않는 이상 모든 행과 셀이 파란색으로 설정될 것이다.

가장 기본적인 구현에서, 평가된 내부 태그는 간단히 외부 태그의 body 입력이 될 수 있다. 그러나 중첩된 태그는 또한 자신을 둘러싸고 있는 태그를 참조할 수 있고 (부모 태그 혹은 조부모 태그 등) 연결된 클래스가 서로의 메소드와 특성을 호출할 수 있도록 한다. 이런 방법으로 자식 태그와 부모 태그가 데이터를 공유할 수 있다.

중첩 태그는 다음 두 메소드 중 하나를 사용하여 조상 태그를 참조할 수 있다.:

  • TagSupport.getParent(): 부모 태그 (즉 태그를 바로 둘러싸고 있는 태그)를 반환한다.

  • TagSupport.findAncestorWithClass(from,class): 태그의 특정 계층이 알려지지 않거나 반드시 사전 설정된 것은 아닐 때 사용된다. findAncestorWithClass(from,class)의 인자는 어떤 클래스로부터 시작해야 하는지와 어떤 클래스를 찾아야 하는지를 각각 알려준다. 예를 들어, HTML 테이블 태그 계층에서 테이블 태그에 접근하는 한 테이블 셀 태그는 다음과 같은 모습일 수 있다.:

    TableTag table = (TableTag)findAncestorWithClass(this, TableTag.class);

현재의 태그가 지정된 클래스(TableTag.class, in this case)를 태그 핸들러로 가진 태그에 중첩되지 않았거나 getParent()가 호출되었는데 부모 태그가 없는 경우, 두 메소드 모두 null 값을 반환할 것이다.

태그를 ID로 참조하기

데이터를 공유하는 또 다른 방법은 클래스를 ID로 등록하여 다른 태그의 핸들러 클래스에 의해 검색될 수 있도록 하는 것이다. 이 방법을 사용하면 JSP 개발자는 태그가 이를 받아들이도록 특수하게 프로그래밍되지 않은 경우 ID를 어떤 커스텀 태그에도 설정할 수 없다.

ID 특성은 이런 목적으로 이미 TagSupport 내에 선언되었고, 어떤 태그 핸들러 클래스에서도 사용 가능하다. 그러나 다른 태그가 접근할 수 있도록 ID 특성을 사용하여 객체를 저장하려면 두 단계를 거쳐야 한다.:

  1. ID 특성이 태그 라이브러리 디스크립터에 지정되어야 한다. (필요한 노드는 참이나 거짓 중 하나로 설정될 수 있다.)

  2. 태그 핸들러는 pageContext의 속성으로 자신을 명확하게 설정해야 한다.

태그가 쉽게 중첩되지 않는 경우 태그 객체를 등록된 ID와 공유하는 것이 필요할 수 있다.

우리의 예제인 사용자 쇼핑 카트를 다시 언급해 보자. 아래 Listing 4의 <user:getUserShoppingList .../>getProductIds()라는 제품 ID 목록을 반환하는 메소드를 포함해 쇼핑 목록에 대한 다양한 정보를 포함하고 있다고 생각해보자. JSP 페이지의 다른 어딘가에서 <products:getProductData> ... </products:getProductData> 태그가 제품 ID 목록을 취해 각 제품에 대한 상세 사항을 검색한 후 이들의 포맷을 정하여 클라이언트에게 재전송 할 것이다.

user:getUserShoppingList 태그가 실행되어 userShoppingList라는 이름의 pageContext의 한 속성으로 자신을 저장할 것이다. product:getProductData 태그는 속성의 값을 검색하고 getUserShoppingList 객체로부터 getProductIds()메소드를 호출할 것이다.

Listing 4. getUserShoppingList

    <user:getUserShoppingList userId="13" id="userShoppingList"/>
    ...
    <products:getProductData productData="userShoppingList">
       <!-- Some formatting template -->
      ...
    </products:getProductData>

getUserShoppingList 태그에 대한 태그 라이브러리 디스크립터는 Listing 5와 같은 모습일 것이다.:

Listing 5. getUserShoppingList에 대한 라이브러리 디스크립터

  <tag>
       <name>getUserShoppingList</name>
       <tagclass>com.taglib.UserShoppingListTag</tagclass>
        <bodycontent>JSP</bodycontent>
        <attribute>
            <name>userId</name>
            <required>true</required>
            <rtexprvalue>false</rtexprvalue>
        </attribute>
        <attribute>
           <name>id</name>
           <required>false</required>
           <rtexprvalue>false</rtexprvalue>
        </attribute>
    </tag>

태그가 자신의 모든 처리를 완료하고 나면 (아마도 doEndTag()메소드로) getShoppingList 태그 핸들러는 다음 행을 포함할 것이다.:

pageContext.setAttribute(getId(),this);

getId()는 태그 (userShoppingList) 내의 ID 세트를 검색하고, this는 전체 클래스 자체를 참조한다.

일단 userShoppingList 태그가 pageContext에 저장되고 나면 getProductData 태그 핸들러 클래스가 productData 속성과 함께 자신에게 전달된 ID를 사용하여 여기에 접근할 수 있다. getProductData 태그의 핸들러 클래스는 그 ID (getProductData() 메소드로 검색된)를 사용하여 pageContext 에서 속성을 발견하고 이를 UserShoppingListTag 객체로 되돌려줄 것이다. Listing 6의 코드는 productList라는 List를 선언하고 제품 목록을 추출하기 위해 getProductIds()라는 사용자 클래스 메소드를 호출한다.

Listing 6. 제품 목록 추출하기

UserShoppingListTag userShoppingList = 
        (UserShoppingListTag)pageContext.getAttribute(getProductData());
    List productList = (List)userShoppingList.getProductIds();

페이지와 세션 context에서 태그 참조하기

전체 태그 객체를 저장하면 그 안의 특성과 메소드를 다른 태그가 자유롭게 사용할 수 있도록 하는데 유용하다. 그러나 여러분은 또한 객체의 일부만을 공개하기로 결정할 수도 있다. 사실 위 예제의 한계는 제품 태그가 제품 목록이UserShoppingListTag 객체에서 올 것으로 예상하고 있다는 것이다.

아마도 사용자 태그인 getShoppingList가 제품 목록을 다른 태그가 사용할 수 있도록 pageContext에 "반출"하는 것이 더 나은 방식일 것이다. 이 방식의 장점은 다른 태그가 제품 목록을 반환하는 메소드에 관해, 그리고 심지어는 목록을 처음 만든 객체에 대해서도 미리 알고 있지 않아도 된다는 것이다. pageContext에 저장된 데이터에 대한 라벨이 productData 속성에 의해 제공되면, 제품 태그의 태그 핸들러는 다음과 같은 모습일 것이다.:


List productList = (List)pageContext.getAttribute(getProductData());

이 기법은 쇼핑 목록 태그를 비롯한 다른 태그들에 대해 작동할 것인데, 세일 품목이나 주어진 카테고리 내의 제품을 호출하는 태그 같은 것을 예로 들 수 있다.

데이터가 세션에 저장되면 다음과 같은 모습일 것이다. :


HttpSession session = pageContext.getSession();
List productList = (List)session.getAttribute(getProductData());

예제 커스텀 태그 살펴보기

아래의 참고 자료 섹션에서 여러분은 예제 커스텀 태그 세트에 대한 링크를 볼 수 있다. 코드 패키지를 다운로드하여 살펴보자. 이 글의 마지막 부분에서 나는 이 예제들을 이용하여 여러분에게 커스텀 태그를 사용해 얻을 수 있는 장점 몇 가지를 보여 줄 것이다.

예제 태그 개요

샘플 태그 뒤의 아이디어는 매우 간단하고 직접적이다. 총 7개의 커스텀 태그와 하나의 JSP 파일 및 하나의 태그 라이브러리 디스크립터 (a.tld 파일)가 있다.

태그들은 함께 작동하여 환영 화면, 로그인 화면, 혹은 에러가 발생했을 경우 로그인 에러 메시지 중 하나를 표시한다. (실제 로그인 절차는 태그에 의해 처리되지 않는다. -- 간편함을 위해 우리는 servlet이나 JavaBean 컴포넌트가 설정해야 했을 세션과 요청 변수를 설정함으로써 프로세스를 모방해보자.)

Listing 7에 나와 있듯이, getUserDatanestedLogin이라는 두 개의 주 태그가 있다. 첫번째는 사용자 정보를 불러오고 두번째는 사용자인 John Q. Citizen이 로그인했는지, 아닌지에 따라 적절한 HTML을 표시한다.

이 두 태그는 nestedLogin이라는 태그가 pageContext에 저장되어 있는 getUserData 태그에 접근할 수 있는 방법을 표시한다.

nestedLogin 태그는 또한 한 태그 내에 다른 태그를 중첩시키는 프로세스를 보여주며, 다른 태그가 자신의 메소드에 접근하도록 해준다. isLoggedInHTML, notLoggedInHTML, 및 logInFailureHTML라는 세 개의 다른 태그에 의해 세 개의 화면이 표시될 수 있다. 이 세 태그는 nestedLogin 태그의 특성에 접근하도록 해준다.; nestedLogin에 의해 적절한 코드 블록이 결정되어 화면 출력될 것이다.

나머지 두 태그인 getUserNamegetLoginError는 중첩된 태그를 사용하는 두 가지 방식을 보여준다. : 간단한 body 컨텐츠로 사용하는 것과 조상 태그 내의 메소드에 접근하는 수단으로 사용하는 그것이다. 이 둘 모두 자신의 조상 태그를 오버라이드하지 않는다.; 조상 태그에서 간단히 데이터 (즉 사용자명과 로그인 에러, 둘 모두 설정되었을 경우)를 가져온다.

Listing 7. 예제 JSP 코드

<HTML>
<HEAD>
<TITLE>Custom Tag Communication</TITLE>
</HEAD>

<BODY bgcolor="#ffffff">

<!-- LOAD TAG LIBRARY -->
<%@ taglib uri="goforit.tld" prefix="goforit" %>

<!-- SET THE USER -->
<goforit:getUserData id="user"/>

<!-- SET THE LOGIN HTML BASED ON WHETHER OR NOT THE USER IS LOGGED IN -->
<!-- ONE OF THE NESTED NODES WILL BE DISPLAYED ACCORDINGLY -->
<goforit:nestedLogin userDataID="user">

    <goforit:isLoggedIn>
    <!-- THE HTML IN THIS NODE IS DISPLAYED IF THE USER IS LOGGED IN -->
    </goforit:isLoggedIn>

    <goforit:notLoggedIn>
    <!-- THE HTML IN THIS NODE IS DISPLAYED IF THE USER IS NOT LOGGED IN -->
    </goforit:notLoggedIn>

    <goforit:loginFailure>
    <!-- THE HTML IN THIS NODE IS DISPLAYED IF THERE WAS A LOGIN ERROR -->
    </goforit:loginFailure>

</goforit:nestedLogin>

</BODY>
</HTML>

태그 라이브러리 디스크립터

Listing 8은 두개의 주 태그에 대한 디스크립터이다. getUserDataid 속성이, nestedLoginuserDataID가 필요함에 주의한다. 이들은 사용자 객체를 pageContext에 등록하고 이를 다른 클래스에서 검색하는데 사용된다.

Listing 8. Tag 디스크립터
  
  <tag>
    <name>getUserData</name>
    <tagclass>com.taglibrarycommunication.taglib.GetUserDataTag</tagclass>   
    <info></info>
    <bodycontent>JSP</bodycontent>    
    <attribute>
      <name>id</name>
      <required>true</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>     
  </tag>

  <tag>
    <name>nestedLogin</name>
    <tagclass>com.taglibrarycommunication.taglib.NestedLoginTag</tagclass>   
    <info></info>
    <bodycontent>JSP</bodycontent>    
    <attribute>
      <name>userDataID</name>
      <required>true</required>
      <rtexprvalue>false</rtexprvalue>
    </attribute>     
  </tag>

태그 핸들러

다음 섹션에서는 클래스간 통신의 몇 가지 중요한 측면을 설명하겠다.

GetUserData

이 태그 핸들러 클래스는 다른 태그가 사용할 사용자 데이터를 검색한다.

주의 : 우리의 태그는 로그인 프로세스를 처리하지 않기 때문에, 태그들은 (로그인 절차 없이) 세션에 저장되어 있는 로그인한 사용자와 작업 수행 요청에 저장되어 있는 에러를 찾도록 만들어졌다. 우리는 실제로 사람들을 로그인시키지 않을 것이기 때문에, 이 태그의 시작 부분은 누군가를 세션에 설정하거나 혹은 하나의 에러를 요청에 설정함으로써 세 개의 가능한 시나리오를 흉내낸다. Listing 9에 나와 있는 코드는 세 시나리오를 제어한다. 아래의 두 라인 모두 주석 처리를 없애지 않은 채 남아 있다면 사용자가 로그인하지 않은 것으로 간주된다.:

Listing 9. 예제 시나리오를 제어하는 코드

// UNCOMMENT TO MIMIC A LOGGED IN USER STORED IN SESSION
//session.setAttribute("user","John Q. Citizen");

// UNCOMMENT TO MIMIC LOGIN ERROR STORED IN REQUEST
//pageContext.getRequest().setAttribute("loginError","Password incorrect");

사용자 데이터를 등록하기 위한 키는 doStartTag()메소드에 있다.:

Listing 10. doStartTag()

public int doStartTag() {

    session = pageContext.getSession();
    
    ... SET VARIOUS PROPERTIES BASED ON THE USER ...

    // THIS IS THE LINE THAT SAVES THIS CLASS TO pageContext
    pageContext.setAttribute(id,this);

    return SKIP_BODY;
}

NestedLoginTag

Listing 11에 나와 있는 이 클래스는 사용자가 로그인했는지의 여부와 에러가 있는지의 여부에 따라 세 특성 중 어떤 것이 클라이언트에게 반환될지를 결정한다. 이 세 특성의 값은 JSP 페이지에서 이 클래스 내에 중첩된 다른 태그에 의해 결정된다. NestedLoginTag는 이전 태그에서 pageContext에 등록된 사용자를 추선 가져옴으로써 어떤 태그가 화면 출력될지를 결정한다. 그 후 사용자 명과 발생한 에러가 있는지 검색한다. 둘 다 비어 있으면 사용자가 로그인하지 않았다고 가정한다. 에러 메시지가 비어 있지 않으면 분명히 에러가 발생한 것이다. 사용자 이름이 설정되어 있으면, 사용자가 성공적으로 로그인한 것이다.

Listing 11. NestedLoginTag

// PULL THE userData OUT OF THE pageContext 
// WITH THE userDataID SUPPLIED THROUGH THE CUSTOM TAG
GetUserDataTag userData = 
     (GetUserDataTag) pageContext.getAttribute(getUserDataID());

// SET userName AND loginError FROM VALUES IN userData OBJECT
setUserName(userData.getUserName());
SetLoginError(userData.getLoginError());

...

if (getUserName()!="" &&
    getLoginError()==""){
    // IF userName IS SET PERSON IS LOGGED IN
    pageContext.getOut().print(getIsLoggedInHTML());
} else {
    if (getLoginError()=="")
        // IF NO userName SET BUT NO loginError SHOW LOGIN
        pageContext.getOut().print(getNotLoggedInHTML());
    else
        // IF loginError SHOW LOGIN AND ERROR
        pageContext.getOut().print(getLogInFailureHTML());
}

IsLoggedInTag, NotLoggedInTag과 LogInFailureTag
Listing 12의 세 태그는 nestedLogin 내에 중첩된 태그들이다. 이들은 모두 비슷한 기능을 수행하지만, nestedLogin의 다른 특성들을 설정한다. 이들의 body 내용은 JSP 개발자가 nestedLogin의 isLoggedInHTML, notLoggedInHTMLlogInFailureHTML 특성에 접근하고 설정하도록 해준다.

Listing 12. 부모 태그에 접근하기

    // THIS LINE ACCESSES THE PARENT CLASS NestedLoginTag
    NestedLoginTag parent = (NestedLoginTag) getParent();

    if (parent != null){
        BodyContent bc = getBodyContent();
        String body = bc.getString();

        // SET THE isLoggedInHTML PROPERTY OF THE PARENT CLASS
        // WITH THE BODY SUPPLIED THROUGH THE CUSTOM TAG
        parent.setIsLoggedInHTML(body);
    }

GetUserNameTag과 GetLoginErrorTag
Listing 13의 태그들은 간단히 pageContext에서 userData 객체를 검색하여 이 객체의 특성을 가져온다.

Listing 13. pageContext에 저장된 객체에 접근하기

    GetUserDataTag userData = 
        (GetUserDataTag) pageContext.getAttribute(getUserDataID());

    ...

    if (userData.getUserName() !=null){
        pageContext.getOut().print(userData.getUserName());
    }

결론

JSP 페이지는 서버측 로직에서 클라이언트측 화면을 분리하고, 자바 프로그래머가 아닌 웹 개발자도 자바 기술의 힘을 자유롭게 이용할 수 있도록 해준다. 커스텀 태그를 사용하여 여러분은 웹 애플리케이션의 양 계층 모두에서 작업하는 개발자들에게 좀 더 많은 선택권을 줄 수 있고, 코드 모듈과 태그의 재사용을 장려할 웹 개발자에게 객체 지향적 접근 방식을 부과할 수 있다. 일단 여러분이 이 글에 포함된 샘플 태그 라이브러리를 검토했다면, 여러분의 애플리케이션에 커스텀 태그 사용을 시작할 준비가 된 것이다.

참고자료

목 차:
개요
유형 뿐 아니라 화면 로직도 제어하기
장점 및 예제
예제 커스텀 태그
결론
참고 자료
필자 소개
기사에 대한 평가
관련 dW 링크:
JSP taglibs: Better usability by design
Subscribe to the developerWorks newsletter
US 원문 읽기
Also in the Java zone:
Tutorials
Tools and products
Code and components
Articles
필자소개
Photo of Jeff WilsonJeff Wilson은 IBM의 개발자 관계 부문 내 컨설턴트들, 교육 담당자들 및 전도사들의 그룹인 DragonSlayers의 e-비즈니스 설계자이다.
이 기사에 대하여 어떻게 생각하십니까?

정말 좋다 (5) 좋다 (4) 그저그렇다 (3) 수정보완이 필요하다(2) 형편없다 (1)

  회사소개  |  개인정보 보호정책  |  법률  |  문의