이전글



커스텀태그란
JSP에서 커스텀태그개발자가 특정 기능을 수행하는 액션태그를 직접 만든것 입니다. JSP에는 액션태그 라는것이 있는데, 액션태그는 JSP의 스크립트릿 안에서 자주 반복되는 Java 코드를 심플한 태그로 정의하여 둔 것을 말합니다.

대표적인 액션태그에는 <jsp:useBean>, <jsp:include>, <jsp:forward>가 있습니다. JSP에서는 기본적으로 제공되는 액션태그의 기능에는 한계가 있기에 개발자가 필요에 따라 직접 구현할 수 있도록 여러가지 API를 제공하고 있습니다.






JSP 1.2 이상의 Tag 구현 방식
servlet/jsp 환경에서 커스텀태그와 관련된 API들은 javax.servlet.jsp.tagext 패키지 하위에서 제공됩니다. JSP 1.2 버전의 방식으로 커스텀태그를 개발하려면 Tag 인터페이스를 구현한 태그 핸들러(TagSupport, BodyTagSupport)를 상속받아 구현하면 됩니다.

JSP 2.0의 SimpleTagSupport가 나온 시점에서 잘 사용되는 방법은 아니지만 아직도 오래된 레거시 시스템에서 사용될 수 있는 방법이므로 기록 차원에서 포스팅 해보도록 하겠습니다.

커스텀태그 개발시 사용되는 javax.servlet.jsp.tagext 패키지 다음과 같은 상속 관계도를 가지고 있습니다.





JSP 1.2 태그 개발 절차 요약
JSP 1.2 버전에서 커스텀태그를 개발하여 사용하는 과정을 요약하자면 다음과 같습니다. 특별히 어떤 라이브러리를 추가하거나 할 필요는 없으며 다음의 절차대로 개발이 가능합니다.

  1. TagSupport 또는 BodyTagSupport 태그 핸들러 클래스를 상속받아 원하는 기능을 구현합니다.
  2. TLD 파일을 작성합니다. TLD는 Tag Library Descriptor로 작성한 태그의 태그명이나 사용하는 속성 동작방식 등을 정하는 설정파일이며 *.tld파일을 작성하여 서블릿컨테이너가 인식하는 webapp/WEB-INF/ 하위 경로에 넣습니다.
  3. web.xml에 작성한 TLD 파일의 경로를 설정해줍니다. JSP 2.0방식은 이 과정 없이 인식이 되지만 JSP1.2 방식을 사용하는 경우 이과정이 필요합니다.
  4. JSP에서 커스텀 태그를 사용하기 위해 taglib 디렉티브(<%@ taglib %>) 를 상단에 선언하고 사용합니다.








실습 예제
실습 예제를 통해 어떤식으로 커스텀태그가 개발되는지 알아보도록 하겠습니다. 개발한 커스텀태그를 호출하면 로그를 출력하도록 할것입니다.



예제 프로젝트
프로젝트 구성은 아래와 같습니다. 모든 코드는 다음 주소에 있습니다. -> 예제 GIT 주소


이번 예제에서 필요한 파일은 사실상 아래 네개의 파일뿐입니다.
  • CustomTag.java - 실질적인 처리를 하는 태그 핸들러 클래스로 태그의 기능을 개발합니다.
  • WEB-INF/tld/custTag.tld - 개발한 CustomTag.java에 대한 태그 설정 정의파일
  • WEB-INF/web.xmltld파일의 경로를 설정해주어 서블릿컨테이너가 개발한 커스텀태그를 인식하도록 합니다.
  • customTagTest.jsp - 테스트를 실행해볼 JSP




태그 핸들러 CustomTag.java 작성
앞서 설명했지만 JSP 1.2방식으로 커스텀태그를 개발하려면 javax.servlet.jsp.tagext.Tag인터페이스를 구현하면 됩니다. 그러나 모든 기능을 직접 구현하기보다는 어느정도 기능을 이미 구현해 놓은 TagSupport 또는 BodyTagSupport 태그 핸들러를 상속받아 개발하는것이 훨씬 편한 방법입니다.

다음과 같이 BodyTagSupport 태그 핸들러를 상속받고 doStartTag()doAfterBody(), doEndTag() 메서드를 오버라이딩합니다.
package tag;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
public class CustomTag extends BodyTagSupport{
    
    @Override
    public int doStartTag() throws JspException {
        System.out.println("시작 태그 처리");
        return EVAL_BODY_INCLUDE;
    }
 
    @Override
    public int doAfterBody() throws JspException {
        System.out.println("태그 몸체 처리 완료");
        return super.doAfterBody();
    }
    
    @Override
    public int doEndTag() throws JspException {
        System.out.println("끝태그 처리");
        return EVAL_PAGE;
    }
}
cs


doStartTag()doAfterBody(), doEndTag() 메서드는 각각 태그가 호출되었을때 태그가 처리되는 과정에 따라 호출되는 메서드입니다.
<dololak:toSpan>hello</dololak:toSpan>
cs

예를 들어 위와 같이 개발한 태그를 호출했다고 했을때 각각 다음과 같이 호출됩니다. 리턴값에 대해서는 이후에 다시 설명합니다.
  • doStartTag() - <dololak:toSpan>처리시 호출됨
  • doAfterBody() - 태그의 몸체로 입력된 "hello"가 처리된 후 호출됨
  • doEndTag() - </dololak:toSpan>처리시 호출됨






태그 설정 정의를 위한 custTag.tld 작성
이번에는 WEB-INF/tld 디렉터리에 tld 파일을 작성합니다. tld 파일은 *.tld라는 확장자를 가진 파일로 Tag Library Descriptor의 약자입니다. 개발한 태그라이브러리에 쓰이는 속성이나 태그명, 처리방식 등 개발한 태그핸들러 클래스에 대한 설정을 정의합니다.

파일명을 custTag.tld로 하여 다음과 같이 작성하도록 합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag  Library 1.2//EN"  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd" >
 
<taglib>
    <tlib-version>1.0</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>myTags</short-name>
    <tag>
        <name>toSpan</name>
        <tag-class>tag.CustomTag</tag-class>
        <body-content>JSP</body-content>
    </tag>
</taglib>
cs


eclipse에서는 tld 파일을 생성해주는 기능이 있습니다. 위의 내용을 그대로 복사하여 사용해도 되지만 다음 링크를 참고해보시기 바랍니다.






TLD 태그 설명
tld파일에서 사용된 태그들에 대한 설명입니다.
태그
설명
<taglib>
tld 파일의 최상단 태그로 스키마 url을 지정합니다.
<tlib-version>
현재 태그라이브러리 정보를 나타냅니다.
<short-name>
현재 태그라이브러리의 이름을 나타냅니다.
<tag>
태그 라이브러리 안에 포함된 태그에 대한 정보입니다. 태그라이브러리에는 여러가지 태그가 있을 수 있으므로 <tag>또한 여러개를 정의할 수 있습니다.
<name>
태그의 이름을 지정합니다. JSP에서 여기서 정의한 태그이름으로 태그를 사용합니다.
<tag-class>
현재 정의하는 태그에 대한 태그핸들러 클래스를 패키지명까지 정의합니다. 예제 프로젝트에서 구현한 태그핸들러 클래스인 tag.CustomTag를 입력해주었습니다.
<body-content>
태그 사용시 시작태그와 끝태그 사이의 몸체(body)를 어떻게 처리할지 지정합니다. 다음의 세가지 중 하나를 지정합니다.

JSP : JSP코드로서 처리합니다.
tagdependent : 단순한 텍스트로 처리하며 태그 구현에 처리를 맡깁니다.
empty : 태그 몸체를 가질 수 없습니다. 태그 호출시 몸체에 값을 입력해도 처리되지 않습니다.
<attribute>
태그에서 사용할 속성에 대해 정의하는 태그입니다. 사용할 속성이 여러개라면 여러개를 정의할 수 있습니다.
<name>
속성명을 지정합니다. 개발한 태그 핸들러 클래스의 멤버변수로 선언하고 자바빈 규약에 맞게 getter setter메서드를 작성해 주어야 동작합니다.
<required>
태그 사용시 속성 필수입력 여부를 결정합니다.
<rtexprvalue>
속성에 스크립트릿 표현식을 사용할 수 있는지 여부를 지정합니다.
<type>
속성의 타입을 지정합니다.





web.xml에 tld 파일 경로 설정
tld 파일을 통해 태그에 대한 내용을 정의했습니다. 이제 작성한 tld 파일의 위치를 서블릿컨테이너에 인식시켜주어야 합니다. 이 설정은 web.xml 파일에 등록합니다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
     
    <jsp-config>
        <taglib>
            <taglib-uri>http://customTag.com</taglib-uri>
             <taglib-location>/WEB-INF/tld/custTag.tld</taglib-location>
        </taglib>
    </jsp-config>
</web-app>
cs


<jsp-config> - JSP 관련 설정을 하기 위한 태그입니다.
<taglib> - 커스텀태그를 등록하기 위한 태그입니다.
<taglib-uri> - 현재 등록하는 태그라이브러리의 uri를 나타냅니다. JSP에서 태그를 사용할때 이 uri를 통해 어떤 태그라이브러리를 사용할지 지정할 수 있습니다. 인터넷상에 실제 존재하는 uri를 적을 필요는 없으며 태그라이브러리를 구분할 수 있는 id같은것이므로 유일해야 합니다.
<taglib-location> - 작성한 tld 파일의 경로를 웹어플리케이션의 루트경로부터 지정합니다.









테스트 JSP 파일 작성
개발한 태그를 테스트하기 위한 customTagTest.jsp페이지를 작성합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="dololak" uri="http://customTag.com" %>
 
<html>
<head>
<title>커스텀 태그 테스트</title>
</head>
<body>
<dololak:toSpan>hello</dololak:toSpan>
 
<br>태그 테스트 완료!!!
</body>
</html>
cs


taglib 디렉티브를 통해 개발한 태그 라이브러리를 선언합니다. Java 클래스에서 필요한 클래스파일을 import 하는것과 비슷합니다.
<%@ taglib prefix="dololak" uri="http://customTag.com" %>
cs

uri속성에는 web.xml에서 <taglib-uri>태그에 지정했던 uri를 입력합니다. prefix는 태그라이브러리의 접두사를 결정합니다. 만약 하나의 웹어플리케이션에서 여러가지 태그라이브러리를 사용하는 경우 태그이름이 겹칠 수 있는데, 접두사를 지정해주어 겹치지 않게 하는 네임스페이스 역할을 합니다. 마치 Java의 클래스명이 겹치더라도 패키지 경로가 다르면 다른 클래스인것으로 인식하는것과 같습니다.


드디어 개발한 태그를 사용하는 부분입니다. 태그라이브러리를 사용할때는 <prefix:태그명>형식으로 사용합니다. 따라서 여러 태그라이브러리를 사용하여 toSpan이라는 태그가 여러개 중복되어 존재하더라도 prefix로 구분되어 실행됩니다.
<dololak:toSpan>hello</dololak:toSpan>
cs





테스트
customTagTest.jsp를 실행하면 다음과 같이 결과가 출력됩니다.



콘솔창을 보게되면 태그핸들러에서 사용했던 출력문이 실행된것을 볼 수 있습니다.






doStartTag(), doAfterBody(), doEndTag() 실행 순서 및 반환값
태그가 실행되었을때 기본적으로 doStartTag(), doAfterBody(), doEndTag() 순서대로 실행되지만 리턴되는 반환값에 따라 실행 흐름을 변경할 수 있습니다. 앞서 구현한 태그 핸들러에서 다음과 같이 세가지 메서드를 오버라이딩 하였습니다.
@Override
public int doStartTag() throws JspException {
    System.out.println("시작 태그 처리");
    return EVAL_BODY_INCLUDE;
}
 
@Override
public int doAfterBody() throws JspException {
    System.out.println("태그 몸체 처리 완료");
    return super.doAfterBody();
}
 
@Override
public int doEndTag() throws JspException {
    System.out.println("끝태그 처리");
    return EVAL_PAGE;
}
cs


리턴 타입은 int형 정수이며, 상위 클래스에서 상수로 이미 정의되어 있기때문에 사용가능합니다. doAfterBody() 메서드에서처럼 super.doAfterBody()와 같이 사용할수도 있지만 이또한 실질적으로 리턴되는 값은 정의된 상수입니다. 따라서 직접 상수를 지정하여 리턴하는것이 더욱 명확합니다.

  • EVAL_BODY_INCLUDE - 메소드 종료후 태그의 몸체를 처리합니다.
  • SKIP_BODY - 태그의 몸체 처리를 스킵(무시하고 넘어감)합니다.
  • EVAL_BODY_AGAIN - 태그의 몸체를 한번 더 처리합니다.
  • EVAL_PAGE - 태그 실행후 JSP의 나머지 부분을 처리합니다.
  • SKIP_PAGE - 태그 실행후 JSP의 나머지 부분 처리를 무시합니다.


예를 들어 doStartTag() 메서드에서 반환값을 SKIP_BODY으로 지정하면 doAfterBody() 메서드가 실행되지 않습니다. 또한 doEndTag() 메서드에서 반환값을 SKIP_PAGE로 지정하면 JSP상에서 태그 호출 이후 부분이 처리되지 않아 태그 테스트 완료!!가 출력되지 않습니다.




다음글에서는 JSP 1.2 방식의 커스텀태그에서 속성과 태그 몸체를 처리하는 방법을 알아보도록 하겠습니다.



다음글


블로그 이미지

도로락

IT, 프로그래밍, 컴퓨터 활용 정보 등을 위한 블로그

댓글을 달아 주세요! 질문 환영합니다!