커스텀 태그(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 |