참고글



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

대표적인 액션태그에는 <jsp:useBean>, <jsp:include>, <jsp:forward>가 있습니다. 이러한 액션태그는 상당수의 Java 코드를 줄여주고 마크업 형태를 띄고 있기 때문에 JSP 페이지 내에서의 다른 HTML 마크업과 친화적이고 가독성을 좋게 해줍니다.

그러나 기본적으로 제공되는 액션태그의 종류가 그렇게 많지는 않기 때문에 Servlet/JSP 개발자들은 필요한 액션태그를 직접 만들게 되었고 이렇게 직접 만든 액션태그를 커스텀 태그라 하는 것입니다. JavaEE는 개발자들이 직접 커스텀 태그를 개발할 수 있도록 여러가지 API를 제공하고 있기에 손쉽게 개발할 수 있습니다.

추가적으로 JSTL(JSP Standard Tag Library)이라는 것이 있는데, 이는 세계적으로 많은 개발자들이 중복으로 개발하는 커스텀태그들이 있다는것을 알게되어 공통적으로 자주 사용되는 커스텀태그들을 묶어 라이브러리 형태로 만들어 배포하는 태그 라이브러리입니다.




액션태그, 커스텀 태그 사용시의 장점
과거에는 Servlet만을 사용하여 개발하였고 Java 코드에 HTML 출력문이 들어가 있는 형태의 구조를 띄는 Servlet 기술의 특성상 디자이너의 협업과 유지보수에 좋지 못하다는점으로 인해 JSP가 등장하였습니다.

JSP는 HTML 사이에 Java코드가 포함되어 있는 구조를 띄는데, Java코드가 늘어날수록 가독성이 나빠진다는 단점이 있습니다.

그러나 자주 사용되는 Java 코드를 태그로 만들어 사용하면 가독성이 증가되고 중복코드를 없앰으로써 유지보수성이 좋아진다는 장점이 있습니다. Java 코드가 중복되는 경우 코드가 수정될때 각각의 중복코드들을 동시에 바꾸어 주어야 하지만 태그를 사용하는 경우 태그 구현 클래스만 변경해주면 되기 때문이지요.





커스텀 태그 개발 방법
커스텀 태그를 개발하는 방법에는 세가지가 있습니다. 태그파일(*.tag)을 이용하는 방법이 있고 태그 클래스를 이용하는 방법이 있는데 태그 클래스 방식의 경우에는 JSP 1.2 버전인 경우의 방식과 JSP 2.0 버전 이상일때의 방식으로 나뉩니다.

그러나 태그 파일 방식을 통해 작성된 *.tag파일 또한 태그 클래스 방식과 마찬가지로 최종적으로는 *.class파일로 컴파일되어 동작합니다. 마치 JSP가 최종적으로 Servlet으로 변환되어 동작하는것과 같습니다.
커스텀 태그 개발 방식
설명
링크
태그파일 이용 방식
*.tag 형태의 파일을 작성하는 방식으로 최종적으로는 JSP 컨테이너에 의해 *.class 태그 구현체로 컴파일되어 실행되는 방식
클래스 작성 방식
JSP 1.2 스펙을 통해 구현하는 방식
JSP 2.0 스펙을 통해 SimpleTagSupport 클래스를 상속받아 사용하는 방식
현재 포스팅글

이번글에서는 JSP 2.0 이상에서 사용할 수 있는 SimpleTagSupport 클래스를 이용한 태그 개발 방법을 알아보도록 하겠습니다.





JSP 2.0 이상의 SimpleTagSupport 클래스 이용 구현 방식
servlet/jsp 환경에서 커스텀태그와 관련된 패키지는 javax.servlet.jsp.tagext 패키지 하위에 제공됩니다. 그중 JSP 2.0 버전 이상인 경우 클래스파일을 이용한 커스텀태그 개발은 SimpleTagSupport 태그 핸들러를 상속받아 구현하면 됩니다.

SimpleTagSupport 태그 핸들러 클래스는 다음과 같은 상속 관계도를 가지고 있습니다.







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

  1. SimpleTagSupport태그 핸들러를 상속받아 원하는 기능을 구현합니다.
  2. TLD는 Tag Library Descriptor로 작성한 태그에 대한 uri태그명 등을 정하는 설정파일이며 *.tld파일을 작성하여 서블릿컨테이너가 인식하는 webapp/WEB-INF/ 하위 경로에 넣습니다. (JSP 1.2 버전 이하에서는 web.xml에 추가적인 설정을 통해 인식을 시켜주어야 하지만 JSP 2.0부터는 경로에만 넣어주면 자동 인식됩니다.)
  3. JSP에서 커스텀 태그를 사용하기 위해 taglib 디렉티브(<%@ taglib %>) 를 상단에 선언하고 사용합니다.






실습 예제
실습 예제를 통해 어떤식으로 커스텀태그가 개발되는지 알아보도록 하겠습니다. 아래의 toSpan태그는 제가 만든 커스텀 태그입니다.
<body>
    <dololak:toSpan color="blueviolet" iterNum="5">
        hello
    </dololak:toSpan>
</body>
cs



위의 코드와 같이 사용하면 아래와 같이 원하는 색상을 속성으로 지정해 배경으로 들어가고 태그의 몸체로 입력한 텍스트를 여러번 반복해서 출력해주는 태그를 구현해보도록 할것입니다.






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


이번 예제에서 필요한 파일은 사실상 아래 세개의 파일뿐입니다.
  • CustomTag.java - 실질적인 처리를 하는 태그 핸들러 클래스
  • WEB-INF/tld/custTag.tld - 개발한 CustomTag.java에 대한 태그 설정 정의파일
  • customTagTest.jsp - 테스트를 실행해볼 JSP





태그 핸들러 CustomTag.java 작성
앞서 설명했지만 JSP 2.0이후 클래스를 이용한 태그 개발은 SimpleTagSupport를 상속받아 doTag() 메서드를 오버라이딩하여 구현하는 방식을 사용합니다.
package tag;
 
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
 
public class CustomTag extends SimpleTagSupport{
    
    private String color;
    private int iterNum;
    
    //doTag()를 오버라이딩 하여 커스텀 태그 처리 내용을 개발한다.
    @Override
    public void doTag() throws JspException, IOException {
        //JspContext는 이 태그를 사용한 JSP 페이지에 대한 정보를  담고 있다.  
        PageContext context = (PageContext)this.getJspContext();
        
        //태그가 호출된 JSP에 대해 요청 정보를 가져온다.
        HttpServletRequest request =  (HttpServletRequest)context.getRequest();
        System.out.println("태그가 호출된 JSP URI : " +  request.getRequestURI());
        
        
        //Jsp 페이지의 결과를 브라우저로 출력할 출력스트림를 얻는다.
        //JSP의 out 객체와 같음.
        JspWriter out = context.getOut();
        
        //커스텀 태그의 몸체를 담을 StringWriter
        StringWriter stringWriter = new StringWriter();
        
        //태그를 사용할때 지정한 속성값들
        String color = this.getColor();
        int iterNum = this.getIterNum();
        
        //invoke()가 실행되면 StringWriter의 몸체 텍스트가 담긴다.
        getJspBody().invoke(stringWriter);
        String bodyText = stringWriter.toString();
        
        out.print("<span style=\" background-color: "+ color + ";  \">");
        
        for(int i=0; i < iterNum; i++ ) {
            //out으로 내용 출력
            out.print("♥" + bodyText + "♥");
        }
        
        out.print("</span>");
    }
    
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public int getIterNum() {
        return iterNum;
    }
    public void setIterNum(int iterNum) {
        this.iterNum = iterNum;
    }
}
cs






PageContext 인스턴스 얻기
JSP에는 pageContext라는 기본 내장객체가 있습니다. 커스텀 태그 핸들러에서도 커스텀태그가 호출된 JSP페이지에 대한 PageContext의 인스턴스를 구할 수 있도록 getJspContext() 메서드를 제공합니다. 이는 상속받은 SimpleTagSupport에 구현된 메서드이므로 사용할 수 있습니다.
        //JspContext는 이 태그를 사용한 JSP 페이지에 대한 정보를  담고 있다.  
        PageContext context = (PageContext)this.getJspContext();
        
        //태그가 호출된 JSP에 대해 요청 정보를 가져온다.
        HttpServletRequest request = (HttpServletRequest)context.getRequest();
        System.out.println("태그가 호출된 JSP URI : " +  request.getRequestURI());
cs


이렇게 얻은 PageContext 객체를 통해 ServletRequest 객체를 얻어 요청 URI를 콘솔로 출력했습니다. 따라서 태그가 호출되는 시점에 콘솔에는 다음과 같이 출력됩니다.






속성과 getter, setter
코드에 color, iterNum이라는 속성이 있고 그에 맞는 getter, setter 메서드가 있습니다. 이는 태그의 속성을 처리하기 위한 것으로 java bean 규약에 맞게 메서드 규칙을 지켜주어야 합니다. 이후 custTag.tld파일에 속성에 대한 설정을 정의해주어야 합니다.




태그 몸체 처리
작성한 태그 핸들러의 소스를 자세히 보면 아래와 같은 코드가 있습니다.
getJspBody().invoke(stringWriter);
cs


이는 태그의 몸체(body)로 넘겨준 "hello"를 해석하고 문자열로 처리하기 위한 메서드입니다. 즉 invoke()가 호출되기 전까지는 태그의 몸체를 읽기 전이며 그 이후에는 태그의 몸체를 읽은 후입니다. invoke()에 StringWriter를 매개변수로 넘겨주면 태그 몸체의 문자열이 담겨 리턴됩니다.




결과 출력
아래와 같이 클라이언트와 연결된 출력 스트림을 얻을 수 있습니다. 출력스트림은 JSP의 out객체나 Servlet에서 response.getWriter()를 통해 얻은것을 생각하면 됩니다. 따라서 이를 응용하면 태그사용시 넘겨준 속성과 몸체를 이용해서 다양한 처리가 가능합니다.
        //JspContext는 이 태그를 사용한 JSP 페이지에 대한 정보를  담고 있다.  
        PageContext context = (PageContext)this.getJspContext();
        
        //Jsp 페이지의 결과를 브라우저로 출력할 출력스트림를 얻는다.
        //JSP의 out 객체와 같음.
        JspWriter out = context.getOut();
cs

이번 예제에서는 몸체로 넘겨준 텍스트를 원하는 횟수만큼 반복하고 하트를 붙여 출력하도록 했습니다.
        for(int i=0; i < iterNum; i++ ) {
            //out으로 내용 출력
            out.print("♥" + bodyText + "♥");
        }
cs


더욱 자세한 설명은 다음 링크를 참고하도록 합니다.







태그 설정 정의를 위한 custTag.tld 작성
이번에는 WEB-INF/tld 디렉터리에 tld 파일을 작성합니다. tld 파일은 *.tld라는 확장자를 가진 파일로 Tag Library Descriptor의 약자입니다. 개발한 태그라이브러리에 쓰이는 속성이나 uri 태그명, 옵션 등을 정의하여 서블릿 컨테이너가 인식할 수 있도록 하기 위한 파일입니다. 서블릿을 작성하고 그에 대한 설정을 web.xml이라는 설정파일에 등록하는것과 비슷합니다.

파일명을 custTag.tld로 하여 다음과 같이 작성하도록 합니다.
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xml="http://www.w3.org/XML/1998/namespace"  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 ">
    
    <tlib-version>0.0</tlib-version>
    <short-name>customTag</short-name>
    <uri>http://customTag.com</uri>
    
    <tag>
        <name>toSpan</name>
        <tag-class>tag.CustomTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <name>color</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.lang.String</type>
        </attribute>
        <attribute>
            <name>iterNum</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.lang.Integer</type>
        </attribute>
    </tag>
</taglib>
cs


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





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

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





테스트 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 color="blueviolet" iterNum="5">
        hello
    </dololak:toSpan>
</body>
</html>
cs

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

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


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




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




태그 핸들러 클래스를 자세히 보면 HttpServletRequest 객체를 가져와 URI를 출력하는 부분이 있습니다.
        //태그가 호출된 JSP에 대해 요청 정보를 가져온다.
        HttpServletRequest request =  (HttpServletRequest)context.getRequest();
        System.out.println("태그가 호출된 JSP URI : " +  request.getRequestURI());
cs



콘솔창을 보게되면 호출 URI가 출력되어있습니다.






다음글


블로그 이미지

도로락

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

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

  • ㅇㅇ 2021.06.29 15:50  댓글주소  수정/삭제  댓글쓰기

    혹시 SimpleTagSupport클래스 자체의 생성자에 doTag메서드호출이 포함되어 있기때문에 오버라이딩해서 사용할수있는건가요?