#040 사용자 정의 태그 개발

JSTL 만으로 만족스럽지 않을때
<jsp:include>와 <c:import>로 코드가 엉망일수 있습니다.

태그파일:include 철머 행동하지만, 좀더 개선된 방식
1. 포함할 파일(Header.jsp)을 복사해서 확장자를 .tag로 바꿉니다.
<img src=”images/web-services.jpg”><br>
2. “WEB-INF” 밑에 tags 디렉토리를 새로 만들고 여기에 태그파일 (Header.tag)을 옮깁니다.
3. 태그 파일을 호출할 JSP를 만들고 taglib 지시자를 아래와 같이 작성합니다.
<%@ taglib prefix=”myTags” tagdi”/WEB-INF/tags” %>
<html><body>
<myTags:Header/>
</body></html>

파라미터를 보낼 방법은 있습니까?
<jsp:include>를 사용해서 파일을 포함할때 포함할 파일에 정보를 제공하기 위하여 <jsp:param 태그를 사용했었죠 복습삼아<jsp:incldue>가 어떻게작동하는지 다시 한번 짚어보도록 하죠

<strong>${param.subTitle}</strong>

이전방식 : <jsp:include>, <jsp:param>코드
<jsp:include apge=”header.jsp”>
<jsp:param name=”subTitle” value=yes we can”/>
</jsp:include>

태그파일에서는 요청 파라미터를 사용하지 않고 태그 속성으로 정보를 넘깁니다.
JSP에서 태그 호출
<jsp:include apge=”header.jsp”>
<jsp:param name=”subTitle” value=yes we can”/>
</jsp:include>

이후
<myTags:Header subtitle=”yes we can”/>

태그파일에서 속성 사용하기
이전 요청 <strong>${param.subtitle}</strong>
이후 요청 <strong>${subtitle}</strong>

태그파일은 attribute 지시자를 사용합니다.
여기 새로운 타입의 지시자가 있으니, 그 이름하여 attribute 지시자 입니다. 이건 태그 파일에서만 사용합니다.

태그파일 (header.tag)
<%@ attribute name=subtitle” required =”ture” rtexprvalue=”true” %>
<strong>${subtitle}</storng>

태그를 사용하는 JSP
<%@ taglib prefix =”myTags” tagdir=”.WEB-INF/tags” %>
<html>
<body>
<myTags:header subTitle=”yes we can”>
<br>
</body>
</html>

태그파일
(header.tag>
<img src=”img/web.jpg”>
<strong><jsp:doBody/></strong>

태그를 사용하는 JSP
<%@ taglib prefix=”mytags” tagdir=”/WEB-INF”/tags” %>
<html><body>
<myTags:Header>
yes we can
</myTags:header>

컨테이너가 태그 파일을 찾는곳
태그 파일을 실행하기 위해서 컨테이너는 4개의 디렉토리를 뒤집니다.
1. /WEB-INF/tags 바로밑에
2. /WEB-INF/tags의 하위 디렉토리에
3. /WEB-INF/lib에 JAR 파일로 배포되었다면 JAR파일 META-INF/tags의 하위 디렉토리에
5. 태그파일이 JAR 파일로 배포되었다면, 반드시 TLD 파일이 있어야 합니다.

초간단 심플 태그 핸들러
1. SimpleTagSupport를 상속받아 클래스를 작성합니다.
package foo;
import javax.servlet.jsp.tagext.simpleTageSupport;
public class SimpleTagTest1 extends SimpleTagSupport{
}

2. doTag() 메소드를 구현합니다.
public void doTag() throws JSPExcpetion, IOException{
getJspContext(.getOut().print(“this is the lamest use of a custom tag”);

3. 태그를 위해서 TLD를 작성합니다.
<taglib..>
<tlib-version>1.2</tlib-version>
<uri>simpleTags</uri>
<tag>
<description>worst use of a custom tag</description>
<name>simple1</name>
<tag-class>foo.SimpleTagTest1</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>

4. 태그핸들러와TLD를 배포합니다.
WEB-INF 디렉토리에 TLD를 배포합니다. 그리고 태그 핸들러는 WEB-INF/classes에 패키지 구조에 맞추어 배포합니다. 태그 핸들러 클래스도 다른 웹 애플리케이션 자바 클래스와 같은 곳에 들어간다는 얘기죠.

5. 태그를 사용할 JSP를 작성합니다 .
<%@ taglib prefix=”myTags” uri=simpletags” %>
<html><body>
<mytags:simple1/>
</body></html>

심플태그 핸들러 일생
1. 클래스 인스턴스화(태그 핸들러 디폴트 생성자 실행)
2. SetJspContext(JspContext)메소드 호출 -> 실행하고 나면 apgeContext 참조 객체를 가짐
3. 다른태그 내부에서 태그를 호출했다면 setParent(JspTag) 메소드 호출 -> 내장 태그는 자신을 포함한 태그와 커뮤니케이션이 가능함
4. 속성이 있다면, 속성 설정자를 호출 -> 속성을 설정하여 태그를 호출했다면 자바 빈 명명규칙에 의거 속성 설정자를 호출함
5. <body-content>값이 “empty”가 아니고 몸체가 있다면 setjspbody 메소드를 호출-> 몸체가 있다면 몸체는 메소드 인자 JSPFragment를 통해 접근할수 있다.
6. doTag() 메소드 호출 -> 이제 태그가 실제 무엇을 할지 코딩 할 시점

태그몸체에 표현식이 있다면
속성값을 출력하는 EL표현식이 태그 몸체에 들어있다고 해봅시다. JSP에서 태그를 호출하는 시점에는 속성이 없느데, 태그 핸들러에서 이 속성을 설정하는걸 한번 만들어 보겠습니다.
JSP에서 태그 호출
<myTags:simple3>
Message is : ${message}
</myTags:simple3>

태그 핸들러 doTag()메소드

public void doTags() throws JspException, IOExcepiton{
getJspContext().setAttribute(“message”, “Wear sunscreen”);
getJspB Ody().invoke(null);
}

동적으로 테이블 행을 출력하는 태그 : 몸체 루핑
태그 몸체에 잇는 EL 표현식은 컬렉션 데이터 하나를 의미합니다. 그리고 지금 하고자 하는 바는 한번에 하나씩 컬렉션 데이터를 출력하는 태그를 만드는 것입니다.

JSP에서 태그 호출
<table>
<mytags:simple4>
<tr><td>${movie}</td></tr>
</myTags:simple4>
</table>

태그 핸들러 doGet() 메소드
String[] movie = {“Monsoon wedding”, “Saved”, “Fahrenheit 9/11”};
public void doTag() throws JspException, IOException{
for(int i = 0; i< movies.length; i++){
getJspContext().setAttribute(“movie”, movies[i]);
getJspBody().invoke(null);

JSPFragment가 정확히 뭐예요?
JSP코드가 나타내는 객체일 뿐입니다. 누군가 호출해주기만 기다리고 잇지요 호출하면 실행한뒤 출력을 만들어 내죠 심플태그핸들러가 호출하는 태그 몸체가 바로 이런것인데, 몸체 내용을 JSPFragment 객체로 캡슐화 하고 setJspBody(0 메소드로 설정하여 내부에서 사용하죠

———————————————————————-핵심정리:심플 태그 핵심정리
ㅇ 태그 핸들러는 태그 기능을 자바 태그 핸들러 클래스로 구현하지만, 태그 파일은 페이지로 태그 기능을 구현한다는 차이가 있습니다.
ㅇ 태그 핸들러는 다음 두가지 타입이 있습니다: 클래식, 심플
ㅇ 심플태그 핸들러를 만들려면, SimpleTagSupprot를 상속하면 됩니다.
ㅇ 심플태그핸들러를 배포하려면, JSTL이나 다른 커스텀 태그 라이브러리를 배포할때 사용하던 <tag>항목을 사용해서 TLD를 정의해야 합니다
ㅇ 몸체가 있는 태그를 사용하려면, TLD<tag> 항목의 <body-content>를 “empty” 가 아닌다른 값으로 설정해야 하니다. 그 다음 몸체를 실행하려면 getJspBody().invoke()를 호출하면 되지요
ㅇ사실 SimpleTag 인터페이스에 정의된 메소드 대부분이 SimpleTagSupport 클래스에 구현되어 있습니다. 여기에 추가로 getJspBody()를 포함한 3가지 편리한 메소드를 제공합니다. getjspBody()를 이요하여 태그 바디 내용을 읽을수 있습니다.
ㅇ 심플태그 생명주기 : 컨테이너는 심플태그 핸들러를 재사용하지 않습니다. 따라서 JSP에서 태그를 호출할때마다, 새로운 태그 핸들러 인스턴스가 생성되며, setJspContext() 메소드도 매번 호출됩니다. 그다음 다른 태그안에서 태그를 호출했다면, setParent() 메소드가 호출됩니다. 호출할때 태그 속성이 있다면 빈 스타일의 속성 설정자가 속성별로 호출됩니다. 태그 몸체가 있다면 setJspBody() 메소드가 호출됩니다 제일 마지막으로 doTag() 메소드가 호출되고 나면, 모든 작업이 끝이 납니다. 재상용 하지 않는다고 했으니 당연히 destroy()가 호출되겠죠
ㅇ 태그 몸체가 있을때만 setJspBody() 메소드가 호출됩니다. 태그 몸체가 없거나 빈태그라면 호출되지 않지요 한가지더 태가가 몸체를 가질수 있다는 말은, TLD에 <body-content>값이 “empty”가 아니라는 것을 의미합니다.
ㅇ 심플태그 doTag() 메소드에서도 태그 몸체에서 쓰도록 속성을 정의할수 있지요 어떻게 하냐면 getJspContext().setAttribute 메소드를 호출하면 되지요 그다음 getJspBody().invoke()를 호출하면 됩니다.
ㅇ doTag() 메소드를 보면 알겠지만 JspException 하고 IOException을 던지도록 되어 있습니다. 따라서 JspWriter의 write 메소드를 쓸때 try/catch로 둘러 쌀 필요가 없지요
ㅇ 심플태그에서 바디 내용을 반복해서 출력하려면, 루핑안에서 getjspbody().invoke()를 호출하면 됩니다.
ㅇ 태그 속성을 정의하려면, 먼저 TLD<attribute> 항목을 정의하고, 태그 핸들러 클래스에 빈 스타일 속성 설정자를 만들어야 합니다. JSP에서 태그를 호출하면, 컨테이너가 자동으로 doTag() 전에 설정자를 호출합니다.
ㅇ getJspBody()의 반호나값인 JspFragment 객체에는 다음 두 메소드가 있습니다. : invoke, getJspContext() 여기서 getJspContext() 메소드는 태그 핸들러가 pageContext API를 사용할수 있는 JSPContext를 리턴합니다.
ㅇ 응답 출력 스트림으로 그냥 출력하면, invoke() 메소드에 널을 넘기면 되고, 몸체 내용을 직접생성하려면 새로운 writer를 넘기면 됩니다.
ㅇ 현재 페이지의 처리를 중지라혀면 SkipPageException을 던지면 됩니다. 다른 페이지에서 이 페이지를 포함한다면, 포함된 파일의 처리가 중간에 멈추지만, 포함한 원 페이지는 끝까지 멈춤 없이 실행 됩니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

%d 블로거가 이것을 좋아합니다: