티스토리 뷰

JSTL 태그를 통해 JSP 페이지에서 반복, 상태제어, 국제화(i18n), SQL 등을 사용할 수 있습니다. 하지만 때로는 이것들이 충분하지 않기 때문에 JSP페이지에서 약간의 작업을 수행하기 위해 자바스크립트를 쓰려는 유혹에 빠질 수 있습니다. 다행히도 JSP는 확장 가능하며 특정 작업을 수행할 수 있도록 고유한 사용자 지정 태그를 생성할 수 있습니다.

JSP 커스텀 태그 (JSP Custom Tag)

예를들어, 우리는 숫자가 콤마와 소수점 2번째 자리까지만 보여지도록 하고싶다고 가정합시다. 이는 숫자가 매우 길때 유용할 수 있습니다. 그래서 다음과 같은 커스텀 태그를 만들면 편하게 사용할 수 있을 것입니다.

<mytags:formatNumber number="100050.574" format="#,###.00"/>

위의 커스텀 태크를 통해 number에 입력된 숫자가 format 형식에 맞게 100,050.57를 JSP 페이지에 출력하게끔 할 수 있습니다.

JSTL에서는 위와 같이 동작하는 태그를 지원하지 않으므로, 우리는 우리만의 커스텀 태그를 구현하여 JSP 페이지에 사용할 것입니다. 아래는 이 예시 프로젝트의 최종 구조입니다.


JSP 커스텀 태그 핸들러 (JSP Custom Tag Handler)

첫 번째 단계에서 JSP 커스텀 태그를 만들어볼 것입니다. javax.servlet.jsp.tagext.SimpleTagSupport 클래스를 상속받아 doTag() 메서드를 override를 하면됩니다.

중요한 점은 태그에 사용될 속성들의 setter 메서드를 만들어야 합니다. 그래서 setFormat(String format)setNumber(String number) 두 개의 setter 메서드를 정의할 것입니다.

SimpleTagSupport는 JspWriter 객체를 얻고 response에 값을 쓸 수 있는 방법을 제공합니다. DecimalFormat 클래스를 이용하여 형식화된 string을 생성하고 이를 response에 보낼 것입니다. 최종 구현은 다음과 같습니다.

NumberFormatterTag.java

package tk.itstory.jsp.customtags;

import java.io.IOException;
import java.text.DecimalFormat;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class NumberFormatterTag extends SimpleTagSupport {

    private String format;
    private String number;

    public NumberFormatterTag() {
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public void doTag() throws JspException, IOException {
        System.out.println("Number is:" + number);
        System.out.println("Format is:" + format);
        try {
            double amount = Double.parseDouble(number);
            DecimalFormat formatter = new DecimalFormat(format);
            String formattedNumber = formatter.format(amount);
            getJspContext().getOut().write(formattedNumber);
        } catch (Exception e) {
            e.printStackTrace();
            // stop page from loading further by throwing SkipPageException
            throw new SkipPageException("Exception in formatting " + number
                    + " with format " + format);
        }
    }

}

try catch 구문에서 format() 메서드에서 던져진 예외를 잡아 JSP 페이지가 더 로딩되지 않게 SkipPageException을 던지도록 처리한 점을 살펴보세요.

JSP Custom Tag Library Descriptor (TLD) 생성

태그 핸들러 클래스를 구현했다면, 어플리케이션이 배포될 때 컨테이너가 해당 핸들러를 로드할 수 있도록 WEB-INF 디렉터리 하위에 TLD 파일을 정의할 필요가 있습니다.

numberformatter.tld

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
<description>Number Formatter Custom Tag</description>
<tlib-version>2.1</tlib-version>
<short-name>mytags</short-name>
<uri>http://itstory.tk/jsp/tlds/mytags</uri>
<tag>
    <name>formatNumber</name>
    <tag-class>tk.itstory.jsp.customtags.NumberFormatterTag</tag-class>
    <body-content>empty</body-content>
    <attribute>
    <name>format</name>
    <required>true</required>
    </attribute>
    <attribute>
    <name>number</name>
    <required>true</required>
    </attribute>
</tag>
</taglib>

TLD 파일에 URI 요소를 정의해야합니다. 또한 format과 number 속성이 필수 속성임을 표시해야합니다(required: true). body-content의 empty는 태그가 body를 가지고 있지 않다는 것을 의미합니다.

JSP Custom Tag Deployment Descriptor 설정

우리는 아래의 예시처럼 jsp-config와 taglib 요소를 이용하여 jsp 커스텀 태그를 웹 어플리케이션에 포함시킬 것입니다.

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" version="3.0">
  <display-name>JSPCustomTags</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <jsp-config>
  <taglib>
    <taglib-uri>http://itstory.tk/jsp/tlds/mytags</taglib-uri>
    <taglib-location>/WEB-INF/numberformatter.tld</taglib-location>
  </taglib>
  </jsp-config>
</web-app>

taglib-uri 값은 TLD 파일에 정의된 것과 동일해야 합니다. 이로써 모든 설정이 완료되었고 이제 JSP 페이지에서 커스텀 태그를 사용할 수 있습니다.

JSP 페이지에서 JSP Custom Tag 사용하기

우리가 만든 number formatter 커스텀 태그를 JSP 페이지에 사용한 예제입니다.

index.jsp

<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Custom Tag Example</title>
<%@ taglib uri="http://itstory.tk/jsp/tlds/mytags" prefix="mytags"%>
</head>
<body>

<h2>Number Formatting Example</h2>

<mytags:formatNumber number="100050.574" format="#,###.00"/><br><br>

<mytags:formatNumber number="1234.567" format="$# ###.00"/><br><br>

<p><strong>Thanks You!!</strong></p>
</body>
</html>

웹 어플리케이션을 실행시키면 JSP 페이지는 다음과 같은 화면을 보여줄 것 입니다.


JSP 응답 페이지에는 포맷된 숫자가 표시됩니다. 이와 유사하게, 더 많은 jsp 사용자 지정 태그 핸들러 클래스를 생성할 수 있습니다. 태그 라이브러리에 여러개의 태그를 정의할 수도 있습니다.

만약 커스텀 태그 핸들러가 매우 많거나 다른 사용자들에게 JAR 파일로 제공하길 원한다면, JAR 파일의 META-INF 디렉터리에 TLD 파일들을 포함시키고, JAR 파일을 웹 어플리케이션의 lib 디렉터리에 포함시키면 됩니다. JSP 컨테이너가 이들을 자동으로 로드하기 때문에 web.xml에 추가적으로 설정할 필요는 없습니다.

이것이 우리가 JSP 표준 태그(JSTL)을 사용할 때 web.xml에 따로 설정할 필요 없이 JSP에서 사용할 수 있는 이유입니다. 만약 믿지 못하겠다면, JSTL Tomcat stardard.jar 파일을 압축 해제하면 META-INF 디렉터리에 수많은 TLD 파일들이 있는 것을 확인하실 수 있을 것입니다.

댓글