본문 바로가기

학원/복기

[MVC] 커스텀 태그(Cutom Tag)

커스텀 태그(Cutom Tag) 

커스텀 태그는 JSP 문서에서 스크립트 요소 대신 사용하기 위해 프로그래머가 생성한 태그이다.
 

순서

1.태그 클래스를 작성 

2.TLD 파일에 커스텀 태그를 등록

3.JSP 문서에서 커스터 태그 사용
 


 

1 .태그 클래스를 작성한다.

 
태그 클래스는 JSP 문서에서 커스텀 태그를 사용할 경우 호출될 메소드가 선언된 클래스이다.
태그 클래스는 TagSupport 클래스, BodyTagSupport 클래스, SimpleTagSupport 클래스 중 하나를 상속받아 작성한다.
커스텀 태그 사용시 호출되는 메소드는 부모클래스의 메소드를 오버라이드 선언하여 작성한다.
 
태그 속성과 태그 내용이 없는 커스텀 태그의 클래스 HelloTag를 작성해보자.

//태그 속성과 태그 내용이 없는 커스텀 태그의 클래스
public class HelloTag extends TagSupport {
	private static final long serialVersionUID = 1L;
	
    //코드 작성
    // ...
	
	
}

 
1) 생성자 생성

    //JSP 문서에서 커스텀 태그를 최초로 사용할 경우 태그 클래스를 객체로 생성하기 위해 한번만 호출된다.
    public HelloTag() {
        System.out.println("HellogTag 클래스의 기본 생성자 호출 - 객체 생성");
    }

 
2) 태그를 사용할 때 호출될 메소드 선언
 
아래 3가지의 메소드를 모두 오버라이드 할 필요는 없고, 필요한 것만 오버라이드 해주면 된다.

	//JSP 문서에서 커스텀 태그의 시작태그를 사용할 때마다 호출되는 메소드
	@Override
	public int doStartTag() throws JspException {
		System.out.println("HellogTag doStartTag() 메소드 호출");
		return super.doStartTag();
	}
	
	//JSP 문서에서 커스텀 태그의 태그내용을 사용할 때마다 호출되는 메소드
	@Override
	public int doAfterBody() throws JspException {
		System.out.println("HellogTag doAfterBody() 메소드 호출");
		return super.doAfterBody();
	}
	
	//JSP 문서에서 커스텀 태그의 종료태그를 사용할 때마다 호출되는 메소드
	@Override
	public int doEndTag() throws JspException {
		System.out.println("HellogTag doEndTag() 메소드 호출");
		return super.doEndTag();
	}

 
 

2. TLD 파일에 커스텀 태그를 등록한다.

 
tag : 커스텀 태그를 등록하기 위한 엘리먼트 
name : 커스텀 태그의 이름을 설정하기 위한 엘리먼트 
tag-class : 커스텀 태그 사용시 생설될 객체의 태그 클래스를 설정하기 위한 엘리먼트
body-content : 커스텀 태그에서 사용할 태그내용을 설정하기 위한 엘리먼트
→ empty : 태그내용이 없는 커스텀 태그를 생성하기 위한 엘리먼트 값
 
[custom.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 ">
  <description>단순한 형태의 커스텀 태그 구현</description>
  <tlib-version>1.0</tlib-version>
  <short-name>simple</short-name>
  <uri>http://www.itwill.xyz/mvc/custom</uri>
  
  <tag>
  	<name>hello</name>
  	<tag-class>xyz.itwill.custom.HelloTag</tag-class>
  	<body-content>empty</body-content>
  </tag>
</taglib>

 

 
 3.JSP 문서에서 커스텀 태그 사용하기

 

 
taglib 디렉티브를 사용하여 TLD 파일을 제공받아야 JSP 문서에서 커스텀 태그를 사용할 수 있다.

<%@taglib prefix="simple" uri="http://www.itwill.xyz/mvc/custom"%>

 

메소드가 호출되는 것을 확인할 수 있다.

 
태그내용이 없는 태그는 시작태그와 종료태그를 같이 표현할 수 있다.

<!--<simple:hello></simple:hello>-->
<simple:hello/>

 


 
HelloTag 클래스에서 부모클래스로부터 제공받은 Pagecontext 객체(pageContext)를 이용하여, 웹프로그램 작성에 필요한 객체를 반환받아 명령을 작성해보자.
 
pageContext.getOut() : 응답문서를 생성하기 위한 출력스트림(JspWriter 객체)을 반환하는 메소드 
 
doStartTag() 메소드의 반환값(정수값)은 부모클래스에서 제공되는 상수를 사용하면 된다.
→ SKIP_BODY, EVAL_BODY_ENCLUDE 중 하나를 선택하여 반환하면 된다.
 
SKIP_BODY : 태그내용을 클라이언트에게 전달하지 않을 경우 사용하는 상수 (기본값) 
EVAL_BODY_ENCLUDE : 태그내용을 클라이언트에게 전달할 경우 사용하는 상수
 

		@Override
		public int doStartTag() throws JspException {
		//System.out.println("HellogTag doStartTag() 메소드 호출");
		
		try {
			//부모클래스로부터 제공받은 Pagecontext 객체를 이용하여 웹프로그램에 작성에
			//필요한 객체를 반환받아 명령 작성
			pageContext.getOut().println("<div>안녕하세요.</div>");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//doStartTag() 메소드의 반환값(정수값) : 부모클래스에서 제공되는 상수를 사용
		return SKIP_BODY;
	}

 
 
doAfterBody() 메소드의 반환값(정수값)은 부모클래스에서 제공되는 상수를 사용하면 된다.
→ SKIP_BODY, EVAL_BODY_AGAIN 중 하나를 선택하여 반환하면 된다.
 
SKIP_BODY : 태그내용을 다시 전달하지 않을 경우 사용하는 상수 (기본값)
EVAL_BODY_AGAIN : 태그내용을 클라이언트에게 다시 전달하는 경우 사용하는 상수 
 

//JSP 문서에서 커스텀 태그의 태그내용을 사용할 때마다 호출되는 메소드
	@Override
	public int doAfterBody() throws JspException {
		//System.out.println("HellogTag doAfterBody() 메소드 호출");
		
	
		return SKIP_BODY;
	}

 
 
doEndTag() 메소드의 반환값(정수값)은 부모클래스에서 제공되는 상수를 사용하면 된다.
→ SKIP_PAGE, EVAL_PAGE 중 하나를 선택하여 반환하면 된다.
 
SKIP_PAGE : 종료태그 실행 후 JSP 문서를 강제로 종료할 경우 사용하는 상수
EVAL_PAGE : 종료태그 실행 후 JSP 문서를 계속 실행할 경우 사용하는 상수 
 

	//JSP 문서에서 커스텀 태그의 종료태그를 사용할 때마다 호출되는 메소드
	@Override
	public int doEndTag() throws JspException {
		//System.out.println("HellogTag doEndTag() 메소드 호출");
		
		return EVAL_PAGE;
	}

 
HelloTag 클래스 전체 소스코드

package xyz.itwill.custom;

import java.io.IOException;

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

//태그 속성과 태그 내용이 없는 커스텀 태그의 클래스
public class HelloTag extends TagSupport {
	private static final long serialVersionUID = 1L;
	
	//JSP 문서에서 커스텀 태그를 최초로 사용할 경우 태그 클래스를 객체로 생성하기 위해 한번만 호출된다.
	public HelloTag() {
		//System.out.println("HellogTag 클래스의 기본 생성자 호출 - 객체 생성");
	}
	
	//JSP 문서에서 커스텀 태그의 시작태그를 사용할 때마다 호출되는 메소드
	@Override
	public int doStartTag() throws JspException {
		//System.out.println("HellogTag doStartTag() 메소드 호출");
		
		try {
			//부모클래스로부터 제공받은 Pagecontext 객체를 이용하여 웹프로그램에 작성에
			//필요한 객체를 반환받아 명령 작성
			pageContext.getOut().println("<div>안녕하세요.</div>");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//doStartTag() 메소드의 반환값(정수값) : 부모클래스에서 제공되는 상수를 사용
		
		return SKIP_BODY;
	}
	
	//JSP 문서에서 커스텀 태그의 태그내용을 사용할 때마다 호출되는 메소드
	@Override
	public int doAfterBody() throws JspException {
		//System.out.println("HellogTag doAfterBody() 메소드 호출");
	
		return SKIP_BODY;
	}
	
	//JSP 문서에서 커스텀 태그의 종료태그를 사용할 때마다 호출되는 메소드
	@Override
	public int doEndTag() throws JspException {
		//System.out.println("HellogTag doEndTag() 메소드 호출");
		
		return EVAL_PAGE;
	}
}

 
 
 
hello_tag.jsp 을 다시 실행해보자 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="simple" uri="http://www.itwill.xyz/mvc/custom"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MVC</title>
</head>
<body>
	<h1>Custom Tag - NoAttribute And NoBody</h1>
	<hr>
	<!--<simple:hello></simple:hello>-->
	<simple:hello/>
	<simple:hello/>
	<simple:hello/>
</body>
</html>

출력결과

 
 
 


이번엔 태그 속성이 있으며 태그 내용은 없는 커스텀 태그 클래스를 만들어보자.
 

public class HelloMessageTag extends TagSupport{
	private static final long serialVersionUID = 1L;
	
	//코드 작성
    	//...
	
}

 
 
1) 커스텀 태그의 속성값을 저장하기 위한 필드를 선언한다.
(이 때, 커스텀 태그의 속성명과 같은 이름으로 필드를 선언해야 한다.)

private String name;

 
2) 생성자에서 객체 생성에 필요한 초기화 작업 관련 명령을 작성해준다. - 필드의 초기값 설정 
→ 커스텀 태그 사용시 속성을 생략할 경우 기본적으로 사용될 속성값으로 필드에 저장하기 위해 사용한다.
하지만 커스텀 태그의 속성이 필수인 경우엔 필드 기본값 설정을 생략한다.
 

public HelloMessageTag() {
		//커스텀 태그 사용시 속성을 생략할 경우 기본적으로 사용될 속성값으로 필드에 저장하기 위해 사용
		// => 커스텀 태그의 속성이 필수인 경우 필드 기본값 설정 생략
		name = "홍길동";
	}

 
3) Setter Getter 메소드 생성
 
커스텀 태그 사용시 태그 속성을 사용하여 속성값을 설정할 경우엔 Setter 메소드가 자동 호출된다.

	public String getName() {
		return name;
	}
	
	//커스텀 태그 사용시 태그 속성을 사용하여 속성값을 설정할 경우엔 Setter 메소드가 자동 호출
	public void setName(String name) {
		this.name = name;
	}

 
 
4) 커스텀 태그 사용시 실행될 명령을 작성할 메소드(즉, 필요한 메소드)만 오버라이드 선언해준다.
오버라이드 선언하지 않은 메소드는 부모클래스의 명령이 없는 메소드를 호출한다. 

	@Override
	public int doStartTag() throws JspException {
		try {
			if(name.equals("홍길동")) {
				pageContext.getOut().println("<h3>관리자님, 안녕하세요.</h3>");
			} else {
				pageContext.getOut().println("<h3>"+name+"님, 안녕하세요.</h3>");
			}
		} catch (IOException e) {
			throw new JspException(e.getMessage());
		}
		return SKIP_BODY;
	}

 
HelloMessageTag 클래스 전체 소스코드

package xyz.itwill.custom;

import java.io.IOException;

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

public class HelloMessageTag extends TagSupport{
	private static final long serialVersionUID = 1L;
	
	private String name;
	
	public HelloMessageTag() {
		//커스텀 태그 사용시 속성을 생략할 경우 기본적으로 사용될 속성값으로 필드에 저장하기 위해 사용
		// => 커스텀 태그의 속성이 필수인 경우 필드 기본값 설정 생략
		name = "홍길동";
	}

	public String getName() {
		return name;
	}
	
	//커스텀 태그 사용시 태그 속성을 사용하여 속성값을 설정할 경우엔 Setter 메소드가 자동 호출
	public void setName(String name) {
		this.name = name;
	}
	
	
	//커스텀 태그 사용시 실행될 명령을 작성할 메소드만 오버라이드 선언
	@Override
	public int doStartTag() throws JspException {
		try {
			if(name.equals("홍길동")) {
				pageContext.getOut().println("<h3>관리자님, 안녕하세요.</h3>");
			} else {
				pageContext.getOut().println("<h3>"+name+"님, 안녕하세요.</h3>");
			}
		} catch (IOException e) {
			throw new JspException(e.getMessage());
		}
		return SKIP_BODY;
	}
	
}

 
 
tld 파일에 커스텀 태그를 추가해주자. 기존의 tld 파일에 추가해도 된다.
 
[custom.tld]
 
attribute : 태그 속성을 등록하기 위한 엘리먼트
name : 태그의 속성명을 설정하기 위한 엘리먼트
→ 태그 클래스의 필드명과 같은 이름으로 커스텀 태그의 속성명을 설정해주어야 한다.

<tag>
  	<name>helloMessage</name>
  	<tag-class>xyz.itwill.custom.HelloMessageTag</tag-class>
  	<body-content>empty</body-content>
  	<attribute>
  		<name>name</name>
  	</attribute>
 </tag>

 
 
JSP 문서를 생성해 커스텀 태그를 이용해보자.
 
[hello_message_tag.jsp]

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="simple" uri="http://www.itwill.xyz/mvc/custom"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MVC</title>
</head>
<body>
	<h1>Custom Tag - AnyAttribute And Nobody</h1>
	<hr>
	<!-- 커스텀 태그의 속성을 생략한 경우 태그 클래스의 생성자에서 설정한 기본값을 속성값으로 설정-->
	<simple:helloMessage/>
	
	<!-- 커스텀 태그의 속성을 사용하여 속성값을 변경한 경우 태그 클래스의 Setter 메소드를 자동 호출 -->
	<!-- => 커스텀 태그의 속성값을 저장하기 위한 필드의 Setter 메소드가 없는 경우 에러 발생 -->
	<simple:helloMessage name="홍길동"/>
	
	<simple:helloMessage name="임꺽정"/>
</body>
</html>

 

 

tld 파일에서 required 속성을 사용해보자
 
required 속성 : 커스텀 태그의 속성에 대한 필수 여부를 설정하기 위한 엘리먼트
  false : 선택적인 속성(기본값), true : 필수적인 속성

<tag>
  	<name>helloMessage</name>
  	<tag-class>xyz.itwill.custom.HelloMessageTag</tag-class>
  	<body-content>empty</body-content>
  	<attribute>
  		<name>name</name>
  		<required>true</required>
  	</attribute>
 </tag>

 
 
다시 JSP 문서에서 커스텀 태그를 사용해보자.
 
커스텀 태그의 속성을 필수로 설정한 경우에는 속성 생략시 에러가 발생한다. 

<simple:helloMessage/> <!--에러발생-->

 
존재하지 않는 속성을 사용하면 에러가 발생한다.

<simple:helloMessage name="임꺽정" class="aaa"/><!--에러발생-->

 


태그 속성과 태그 내용 모두 있는 커스텀 태그 클래스를 만들어보자.
 

package xyz.itwill.custom;

import java.io.IOException;

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

//태그 속성과 태그 내용이 있는 커스텀 태그 클래스
public class HelloBodyTag extends TagSupport {
	private static final long serialVersionUID = 1L;
	
	private boolean test;
	
	public boolean isTest() {
		return test;
	}

	public void setTest(boolean test) {
		this.test = test;
	}
	
	@Override
	public int doStartTag() throws JspException {
		try {
			if(test) {
				pageContext.getOut().println("<h3>");
			} else {
				pageContext.getOut().println("<p>");
			}
		} catch (IOException e) {
			throw new JspException(e.getMessage());
		}
		return EVAL_BODY_INCLUDE;
	}
	
	@Override
	public int doEndTag() throws JspException {
		try {
			if(test) {
				pageContext.getOut().println("님, 안녕하세요.</h3>");
			} else {
				pageContext.getOut().println("님, 반갑습니다.</p>");
			}
		} catch (IOException e) {
			throw new JspException(e.getMessage());
		}
		return EVAL_PAGE;
	}
	
}

 
 
tld 파일에서 커스텀 태그를 등록해주자
 
body-content 엘리먼트값으로 [JSP]를 설정하면 태그내용으로 JSP 명령 사용이 가능하다.

  <tag>
  	<name>helloBody</name>
  	<tag-class>xyz.itwill.custom.HelloBodyTag</tag-class>
  	<body-content>JSP</body-content>
  	<attribute>
  		<name>test</name>
  		<required>true</required>
  	</attribute>
  </tag>

 
 
JSP 문서에서 등록한 커스텀 태그를 사용해보자
 
[hello_body_tag.jsp]
 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="simple" uri="http://www.itwill.xyz/mvc/custom"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MVC</title>
</head>
<body>
	<h1>Custom Tag - AnyAttribute And Nobody</h1>
	<hr>
	<simple:helloBody test="true">홍길동</simple:helloBody>
	<simple:helloBody test="false">임꺽정</simple:helloBody>
	<hr>
	<%
		String name="전우치";
		request.setAttribute("name", name);
	%>
	<simple:helloBody test="true"><%=name %></simple:helloBody>
	<simple:helloBody test="false">${name }</simple:helloBody>
</body>
</html>

 
커스텀 태그의 속성값은 <%%> 나 ${} 를 사용하면 에러가 발생한다.

<%
	boolean result=true;
	request.setAttribute("result", false);
%>
<simple:helloBody test="<%=result %>">장길산</simple:helloBody>
<simple:helloBody test="${result }">홍경래</simple:helloBody>

 
만약 사용하고 싶으면 rtexprvalue 엘리먼트를 이용하면 된다.
rtexprvalue : 커스텀 태그의 속성값으로 JSP 표현식 또는 EL 사용 여부를 설정하기 위한 엘리먼트
-> false : 사용 불가능 (기본값) , true : 사용 가능

 <tag>
  	<name>helloBody</name>
  	<tag-class>xyz.itwill.custom.HelloBodyTag</tag-class>
  	<body-content>JSP</body-content>
  	<attribute>
  		<name>test</name>
  		<required>true</required>
  		<rtexprvalue>true</rtexprvalue>
  	</attribute>
 </tag>

 
 
rtexprvalue 엘리먼트 설정 후 다시 실행해보면 출력이 잘 되는것을 확인할 수 있다. 

 
 
 
 
 

'학원 > 복기' 카테고리의 다른 글

[MVC] Formatter 태그 라이브러리  (0) 2023.07.16
[MVC] JSTL(Java Standard Tag Library) / Core 라이브러리  (0) 2023.07.14
[MVC] EL 연산자  (0) 2023.07.13
[MVC] TLD 파일 / EL 함수  (0) 2023.07.13
[MVC] EL 내장객체  (0) 2023.07.13