참조
Easy Custom Tags with Tag Files, Part 1
Easy Custom Tags with Tag Files, Part 2

JSP 2.0 이전의 커스텀 태그 사용법
1. 핸들러를 작성하고 컴파일 한다.
2. 태그 핸들러와 관련된 태그를 정의한다.

그러나 태그 파일은 미리 컴파일 할 필요 없다. 호출 되는 순간 컴파일 된다.
핸들러 또한 오직 JSP 문법만을 사용하여 만들 수 있다.
태그 라이브러리 서술자 역시 만들 필요 없다. 태그 파일이름을 태그 이름으로 사용하기 때문에.

태그 파일에서 묵시적으로 사용 가능한 객체들
- request     javax.servlet.http.HttpServletRequest
- response     javax.servlet.http.HttpServletResponse
- out     javax.servlet.jsp.JspWriter
- session     javax.servlet.http.HttpSession
- application     javax.servlet.ServletContext
- config     javax.servlet.ServletConfig
- jspContext     javax.servlet.jsp.JspContext

태그 파일 지시자
- <%@ 로 열고 %> 로 닫는다.
- tag      JSP 페이지의 page와 비슷한 지시자
- include     태그 파일에 다른 자원을 포함시킬 때 사용하는 지시자
- taglib     태그 파일에서 커스텀 태그 라이브러리를 사용하고자 할 때 사용
- attribute     태그 파일에 속성 선언할 때 사용
- variable     호출하는 JSP 페이지로 넘겨줄 변수를 정의할 때 사용

tag 지시자의 속성
- display-name      XML 툴에 의해 보여질 간단한 이름. 기본값은 .tag를 짤라버린 태그 파일이름.
- body-content     이 태그의 몸체 컨텐츠에 대한 정보. The value can be empty, tagdependent, or scriptless (default).
- dynamic-attributes     동적인 속성의 지원 여부 알려줌. The value identifies a scoped attribute in which to place a Map containing the names and values of the dynamic attributes passed during this invocation.
- small-icon     보통 사용하지 않는다니까 패스.
- large-icon     보통 사용하지 않는다니까 패스.
- description     태그에 대한 설명.
- example     이 액션을 사용하는 방법에 설명.
- language     태그 파일에서 사용되는 스크립트 언어. The value for this attribute for the current version of JSP must be "java".
- import     page의 import와 같다.
- pageEncoding     page의 속성과 같다.
- isELIgnored     기본값은 false. page의 속성과 같다.
- 사용예
<%@ tag body-content="empty"
import="java.util.Enumeration" %>
<%@ tag import="java.sql.*" %>
- import 빼고는 한 번만 나올 것이다.(모든 속성이 optional이다.)

include 지시자
- 여러 태그 파일에서 공통으로 사용되는 코드가 있을 때 사용한다.
- 사용예
<%@ include file="included.tagf" %>

taglib 지시자
- <%@ taglib uri="tagLibraryURI" prefix="tagPrefix" %> 이런 문법 사용한다.
- 사용예
<%@ taglib prefix="simple" tagdir="/WEB-INF/tags" %>
The server's date: <simple:firstTag/>

attribute 지시자 속성
- name      이 태그 파일이 받아들일 때 사용할 속성 이름. 이 이름은 해당 태그 파일에서 유일 해야 한다.
- required     필수 속성인지 아닌지. false가 기본값.
- fragment     태그 핸들러에 의해 계산되는 fragment인지 아닌지 컨테이너가 그냥 처리할 녀석인지 알려준다. 기본값은 false. 속성의 값을 태그 핸들러가 먼저 처리해야 되면 true로 설정하라.
- rtexprvalue     속성의 값이 scriptlet expression에 의해 동적으로 계산되는 값인지 알려준다. true가 기본값.
- type     속성의 타입. java.lang.String이 기본값.
- description     속성에 대한 설명.

variable 지시자 속성
- atttibute 지시자와 반대로, JSP로 태그 파일안에 있는 어떤 값을 넘겨 줄 수 있고, 여러개를 선언할 수 있으니까 여러 개의 값을 이 태그를 사용한 JSP로 넘길 수 있다.
- name-given      호출한 JSP에 있는 스크립트 언어나 EL 표현식에서 사용할 수 있는 변수 이름. name-from-attribute와 이 속성 둘 중 하나만 존재해야 한다. 태그 파일 내에서 유일해야 한다.
- name-from-attribute     name-given과 동일한데, 다만 이 속성의 값이 attribute의 이름이다.
- alias     이 변수의 값을 가지고 있을 로컬 attriute
- variable-class     이 변수의 타입. java.lang.String이 기본값.
- declare     이 것을 호출하는 페이지나 태그 파일에서 변수가 선언되어 있는지 알려준다. true가 기본값.
- scope     The scope of the scripting variable defined. The possible values are AT_BEGIN, AT_END, and NESTED (default).
- description     변수에 대한 설명.
- 예제

<%@ tag import="java.util.Date"
import="java.text.DateFormat"%>
<%@ variable name-given="longDate" %>
<%@ variable name-given="shortDate" %>
<%
  Date now =
new Date(System.currentTimeMillis());
  DateFormat longFormat =
DateFormat.getDateInstance(DateFormat.LONG);
  DateFormat shortFormat =
DateFormat.getDateInstance(DateFormat.SHORT);
  jspContext.setAttribute(
"longDate", longFormat.format(now));
  jspContext.setAttribute(
"shortDate", shortFormat.format(now));
%>
<jsp:doBody/>

<%@ taglib prefix="tags"
tagdir="/WEB-INF/tags" %>
Today's date:
<br/>
<tags:varDemo>
In long format: ${longDate}
<br/>
In short format: ${shortDate}
</tags:varDemo>

jsp:doBody
- 오직 태그 파일 안에서만 사용할 수 있다.
- 태그의 몸체를 실행할 때 사용한다.
- 몸체를 호출한 결과를 특정 변수에 담고 싶을 때는 var(값을 String으로 받는다.)나 varReader(값을 Reader로 받는다.) 속성을 사용한다.
- 예제
<jsp:doBody var="referer"
scope="session"/>
저렇게 정의해둔 태그로 둘러 쌓인 부분을 실행한 결과를 String 타입으로 refer라는 변수에 session 스콥으로 가지고 있는다.

jsp:invoke
- fragment attribute를 호출할 때 사용한다.
- attribute를 fragment로 설정했다면, 태그 파일 안에서 원하는 만큼 여러번 호출할 수 있다.
- 이것도 jsp:doBody과 같은 역할을 하는 속성을 가질 수 있고, fragment는 필수 속성이다.
- 예제

<%@ attribute name="productDetails"
fragment="true" %>
<%@ variable name-given="productName" %>
<%@ variable name-given="description" %>
<%@ variable name-given="price" %>
<%
  jspContext.setAttribute(
"productName", "Pelesonic DVD Player");
  jspContext.setAttribute(
"description",
    "Dolby Digital output through
coaxial digital-audio jack," +
    " 500 lines horizontal
resolution-image digest viewing");
  jspContext.setAttribute("price", "65");
%>
<jsp:invoke fragment="productDetails"/>

<%@ taglib prefix="easy"
tagdir="/WEB-INF/tags" %>
<html>
<head>
<title>Product Details</title>
</head>
<body>
<easy:invokeDemo>
  <jsp:attribute name="productDetails">
    <table width="220" border="1">
    <tr>
      <td><b>Product Name</b></td>
      <td>${productName}</td>
    </tr>
    <tr>
      <td><b>Description</b></td>
     <td>${description}</td>
    </tr>
    <tr>
      <td><b>Price</b></td>
      <td>${price}</td>
    </tr>
    </table>
  </jsp:attribute>
</easy:invokeDemo>
</body>
</html>

태그 파일 패키징하기
- 태그 라이브러리 서술자. 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 web-jsptaglibrary_2_0.xsd"
  version="2.0">
 
  <description>JSP 2.0 tag files</description>
  <tlib-version>1.0</tlib-version>
  <short-name>My Tag Files</short-name>
  <uri>http://www.brainysoftware.com/tagfiles</uri>
  <tag-file>
    <name>encode</name>
    <path>/META-INF/tags/encode.tag</path>
  </tag-file>
</taglib>

- 루트 폴더 밑에 META-INF 폴더를 만들고 그 안에 서술자 파일을 넣는다.
- 태그 파일들은 META-INF 폴더 밑에 tags폴더를 만들고 그 안에 넣는다.
- JAR파일로 묶는다. ex) jar cvf mytagfiles.jar *
- 사용한다.

<%@ taglib prefix="easy"
uri="http://www.brainysoftware.com/tagfiles" %>
<easy:encode input="<br/> means changing line"/>