'커스텀태그'에 해당하는 글 3건

그냥 정기적으로 보내주는 형식의 메일을 잘 확인 안해보는 습관이 있어서, 썬에서 보내주는 메일도 확인도 안해보고 넘기다가 오늘 우연치 않게 지메일을 확인하다 아래 내용을 발견 했네요.
별볼일 없는, 그냥 Head & First 책에 나오는 내용을 정리한 포스팅인데, 그 내용이 뉴스레터에 실리다니...
참으로 창피하네요 ^^;;
내용도 기초적인 내용이고 ㅎㅎ

"커스텀 태그 사용하기"란 포스팅

"커스텀 태그 사용하기"란 포스팅


이메일에 실린 포스트는 http://www.4te.co.kr/566 입니다.
나중에 고수가 된다면, 기초적인 내용이 아닌 정말로 유익한 정보를 블로그에 포스팅을 쓸수 있겠죠 ㅎ

하지만 이 놈의 귀차니즘 때문에 진도가 느려서 탈입니다. ㅎㅎ


신고

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글  2개가 달렸습니다.
  1. 잘지내죠? 자바 공부 열심히 하고 있나바요~~ ㅋㅋ
secret
커스텀 태그 안에 커스텀 태그가 위치해 있을 경우 서로간에 필요한 속성이라던가 내용 등을 읽어올 필요가 있다. 이럴 경우에는 다음과 같은 방법으로 접근할 수 있다.

myCustomTag3.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">

<tlib-version>0.1</tlib-version>

<uri>Nested</uri>
<tag>
    <description>NestedLevel Check</description>
    <name>NestedLevel</name>
    <tag-class>com.example.tag.NestedLevelTag</tag-class>
    <body-content>JSP</body-content>
</tag>
</taglib>

NestedLevelTag.java

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

public class NestedLevelTag extends TagSupport {
    private int nestLevel = 0;
   
    public int doStartTag() throws JspException {
        nestLevel = 0;
        Tag parent = getParent();
       
        while(parent != null) {
            parent = parent.getParent();
            nestLevel++;
        }
       
        try {
            pageContext.getOut().println("<br>Tag nested level : " + nestLevel);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
       
        return EVAL_BODY_INCLUDE;
    }
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="Nested" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:NestedLevel>
    <mine:NestedLevel>
        <mine:NestedLevel/>
    </mine:NestedLevel>
</mine:NestedLevel>
</body>
</html>

결과물

Insert title hereTag nested level : 0
Tag nested level : 1
Tag nested level : 2

getParent 메소드를 반복해서 호출해서 depth가 몇단계인지 알아내는 예제이다.

SimpleTag 인터넾이스와 Tag인터페이스는 JspTag 인터페이스를 구현한 것이다. SimpleTag의 getParent 메소드는 JspTag를 리턴하는데 반해 Tag(클래식 커스텀 태그)의 getParent 메소드는 Tag를 리턴한다.
이 점은 중요한데 왜냐하면 이 차이로 인해 Tag가 SimpleTag의 부모 태그가 될 수 있지만, SimpleTag가 Tag의 부모 태그가 될 수 없기 때문이다.
아래 내용은 Tag가 SimpleTag의 부모 태그로서 사용 되어질 경우 부모 태그의 attribute를 알아오는 예제이다.

classicParent.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">

<tlib-version>0.1</tlib-version>

<uri>ClassicParentTag</uri>
<tag>
    <description>classic parent</description>
    <name>ClassicParent</name>
    <tag-class>com.example.tag.MyClassicParent</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>name</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
<tag>
    <description>Simple Inner Tag</description>
    <name>SimpleInner</name>
    <tag-class>com.example.tag.SimpleInner</tag-class>
    <body-content>empty</body-content>
</tag>
</taglib>

SimpleInner.java

package com.example.tag;

import java.io.IOException;

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

public class SimpleInner extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        MyClassicParent parent = (MyClassicParent) getParent();
        getJspContext().getOut().print("Parent attribute is : " + parent.getName());
    }
}

MyClassicParent.java

package com.example.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class MyClassicParent extends TagSupport {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
    public int doStartTag() throws JspException {
        return EVAL_BODY_INCLUDE;
    }
}

classicParentTag.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="ClassicParentTag" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:ClassicParent name="aaa">
    <mine:SimpleInner/>
</mine:ClassicParent>
</body>
</html>

결과물

Insert title hereParent attribute is : aaa

tld 파일에서는 ClassicParent 부모 태그와 SimpleInner 자식 태그를 정의 한다. ClassicParent 에는 name 이란 attribute가 존재 한다.
ClassicParent와 SimpleInner태그를 구현한 각 Java 파일은 위 소스와 같이 구현한다.
SimpleInner.java 파일에서 눈여겨 볼 것은 getParent 메소드를 통해 리턴 받은 JspTag형 객체를 ClassicParent로 형변환 해서 사용하는 것이다.
ClassicParent.java 파일에는 setter와 getter가 있는데, 자동으로 setter는 tld 에서 정의한 name이란 attribute에 값을 할당해 주며, getter는 SimpleInner.java에서 사용한다.
물론 ClassicParent.java의 doStartTag()에서 EVAL_BODY_INCLUDE를 리턴해 주어야지만 자식 태그인 SimpleInner가 실행 되게 된다.

중요한 것은 자식 태그에서 부모 태그의 정보를 읽을 수는 있어도 부모에서 자식 태그의 정보를 읽을 수는 없다.
따라서 부모에서 자식 태그를 알기 위해서는 반대로 자식에수 부모 쪽에 값을 셋팅 하는 방법을 사용해야 한다.
다음 예제를 통해서 부모가 자식의 속성 값을 알아내는 방법을 살펴보자.

menuTag.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">

<tlib-version>0.1</tlib-version>

<uri>MenuTag</uri>
<tag>
    <description>parent menu tag</description>
    <name>Menu</name>
    <tag-class>com.example.tag.Menu</tag-class>
    <body-content>JSP</body-content>
</tag>
<tag>
    <description>child menu tag</description>
    <name>MenuItem</name>
    <tag-class>com.example.tag.MenuItem</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>itemValue</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
</taglib>

Menu.java

package com.example.tag;

import java.util.ArrayList;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class Menu extends TagSupport {
    private ArrayList<String> items;
   
    public void addMenuItem(String item) {
        items.add(item);
    }
   
    public int doStartTag() throws JspException {
        items = new ArrayList<String>();
       
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        try {
            pageContext.getOut().println("Menu items are : " + items);
        } catch (Exception e) {
            // TODO: handle exception
            throw new JspException("Exception : " + e.toString());
        }
        return EVAL_PAGE;
    }
}

MenuItem.java

package com.example.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class MenuItem extends TagSupport {
    private String itemValue;

    public void setItemValue(String itemValue) {
        this.itemValue = itemValue;
    }
   
    public int doStartTag() throws JspException {
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        Menu parent = (Menu) getParent();
        parent.addMenuItem(itemValue);
        return EVAL_PAGE;
    }
}

menuItem.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="MenuTag" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:Menu>
    <mine:MenuItem itemValue="Dogs"></mine:MenuItem>
    <mine:MenuItem itemValue="Cats"></mine:MenuItem>
    <mine:MenuItem itemValue="Horses"></mine:MenuItem>
</mine:Menu>
</body>
</html>

결과물

Insert title hereMenu items are : [Dogs, Cats, Horses]

menuTag.tld 파일에선 Menu태그와 MenuItem 태그를 정의한다. MenuItem 태그가 child 태그이며, itemValue라는 attribute를 가지고 있다.
Menu 태그를 정의한 Menu.java 파일에서는 ArrayList 변수 addMenuItem 메소드를 하나 만들고 값을 받아 하나씩 추가할 수 있도록 한다. addMenuItem 메소드는 child 태그인 MenuItem 클래스에서 사용할 메소드이다.
MenuItem 태그를 정의한 MenuItem.java에서는 doEndTag 부분에서 parent 객체를 하나 생성한 후 Menu 클래스에 있는 addMenuItem 메소드를 호출해 자신이 가지고 있는 itemValue라는 속성을 넘겨준다.
마지막으로 Menu 클래스의 doEndTag 메소드에서는 child 태그로부터 넘겨 받게 된 값을 화면에 보여준다.



신고

'Java > Servlet & JSP' 카테고리의 다른 글

웹 애플리케이션 보안  (4) 2009.04.10
웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
JSP2.0 이전 버젼에서의 커스텀 태그는 심플 방식이 아닌 클래식 방식을 사용한다. simple 방식에서는 doTag() 메소드 하나로 모든 작업을 하고, exception 처리도 JspException, IOException를 throw 해서 catch 블럭이 없지만, 클래식 방식에는 doStartTag(), doEndTag() 메소드를 사용하며, JspException만을 throw 해서 catch 블럭에서 IOException을 잡을 필요가 있다.
간단하게 아래 예제를 통해 알아보자

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">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>classicOne</name>
    <tag-class>com.example.tag.Classic1</tag-class>
    <body-content>empty</body-content>
</tag>
</taglib>

com.example.tag.Classic1.java 파일

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic1 extends TagSupport {
    JspWriter out;
   
    public int doStartTag() throws JspException {
        out = pageContext.getOut();
        try {
            out.println("in doStartTag()");
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return SKIP_BODY;
    }
   
    public int doEndTag() throws JspException {
        try {
            out.println("in doEndTag");
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return EVAL_PAGE;
    }
}

closeTag1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
Classic Tag One : <br>
<mine:classicOne/>
</body>
</html>

Classic1 클래스를 보면 SimpleTagSupport가 아닌 TagSupport를 확장한다. 또한 getJspContext 대신에 pageContext를 사용한다.

doStartTag() 메소드에서 SKIP_BODY를 리턴 하는 것은 컨테이너가 다음에 어떤 일을 수행하도록 알려주는 것이다. 이 뜻은 body가 있더라도 실행하지 말고 곧바로 doEndTag()로 가라는 뜻이다.
화면에 print 해보면 해당 값이 0이라는 것을 알 수 있다.

또한 doEndTag() 메소드에서는 EVAL_PAGE를 리턴 하는데, 이 뜻은 작업이 끝났으니 페이지 뒷 부분을 실행하라는 의미이다.
심플 태그 핸들러의 SkipPageException과 비슷한 의미이다.

태그에 몸체가 있는 경우 몸체 안의 내용은 다음처럼 사용할 수 있다.

<?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">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>classicOne</name>
    <tag-class>com.example.tag.Classic1</tag-class>
    <body-content>tagdependent</body-content>
</tag>
</taglib>

com.example.tag.Classic1.java 파일

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic1 extends TagSupport {
    JspWriter out;
   
    public int doStartTag() throws JspException {
        out = pageContext.getOut();
        try {
            out.println("in doStartTag()");
            out.println("SKIP_BODY : " + SKIP_BODY);
            out.println("EVAL_BODY_INCLUDE : " + EVAL_BODY_INCLUDE);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        //return SKIP_BODY;
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        try {
            out.println("in doEndTag");
            out.println("EVAL_PAGE : " + EVAL_PAGE);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return EVAL_PAGE;
    }
}


closeTag1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
Classic Tag One : <br>
<mine:classicOne>
This is the body
</mine:classicOne>
</body>
</html>

Insert title here결과물

Insert title hereClassic Tag One :
in doStartTag() SKIP_BODY : 0 EVAL_BODY_INCLUDE : 1 This is the body in doEndTag EVAL_PAGE : 6

EVAL_BODY_INCLUDE는 몸체를 실행 시키라는 내용이며, 화면에 print 해 보면 1이라는 것을 알 수 있다. EVAL_PAGE의 값은 6이다.

심플 태그에서는 doTag 안에서 iterator를 실행 하면서 getJspBody().invoke(null)을 실행하면 루핑을 돌리면서 반복적인 작업을 할 수 있었다.
클래식 커스텀 태그에서는 doStartTag와 doEndTag로는 iterator 작업을 할 수 없으므로, doAfterTag를 이용할 수 밖에 없다. doAfterTag는 doStartTag에서 EVAL_BODY_INCLUDE를 리턴 하는 경우에만 실행 된다.
관련 소스는 아래를 참고하면 된다.

myCustomTag2.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">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags2</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>iterateMovies</name>
    <tag-class>com.example.tag.Classic2</tag-class>
    <body-content>scriptless</body-content>
</tag>
</taglib>

Classic2.java

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic2 extends TagSupport {
    String[] movies = new String[] {"Spiderman", "Saved!", "Amelie"};
    int movieCounter;
   
    public int doStartTag() throws JspException {
        movieCounter = 0;

        pageContext.setAttribute("movie", movies[movieCounter]);
        movieCounter++;
       
        return EVAL_BODY_INCLUDE;
    }
   
    public int doAfterBody() throws JspException {
        if(movieCounter < movies.length) {
            pageContext.setAttribute("movie", movies[movieCounter]);
            movieCounter++;
            return EVAL_BODY_AGAIN;
        } else {
            return SKIP_BODY;
        }
    }
   
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags2" %>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<mine:iterateMovies>
    <tr><td>${movie}</td></tr>
</mine:iterateMovies>
</table>
</body>
</html>

doStartTag()에서는 EVAL_BODY_INCLUDE를 리턴하며 따라서 doAfterBody()를 호출하게 된다. doAfterBody 안에서는 movies 배열을 이용해 iterator 하면서 movie 객체에 값을 담는다. movieCounter가 movies의 길이만큼 루프를 돌게 되면 SKIP_BODY를 리턴 하면서 doEndTag를 호출하게 된다.
유의 할 점은 doAfterTag는 body가 한번 호출된 후부터 호출 되므로, doStartTag에서 "pageContext.setAttribute("movie", movies[movieCounter]);"를 한번 호출 한다.
doStartTag에서 호출하지 않을 경우 빈 값으로 <tr> 부분이 한번 iterator를 하기 때문에 빈 row가 하나 들어가게 된다.

movieCounter를 doStartTag 안에서 0으로 초기화 하는 것은 컨테이너가 풀(pool)로 관리하기 때문이다. 선언하면서 바로 초기화를 하게 되면, 재사용 될 경우에는 0으로 시작하지 않고 doAfterTag 의 iterator가 끝날 때 가지고 있는 값을 사용하게 될 것이기 때문이다.









신고

'Java > Servlet & JSP' 카테고리의 다른 글

웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17
JSTL 사용하기 (2)  (0) 2009.03.16

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret