열심히 끝까지
디바이스 융합 자바(Java) day45 - 표현언어(EL식),커스텀태그(태그파일 기반의 커스텀태그,태그핸들러클래스 기반의 커스텀태그) 본문
디바이스 융합 자바(Java) day45 - 표현언어(EL식),커스텀태그(태그파일 기반의 커스텀태그,태그핸들러클래스 기반의 커스텀태그)
노유림 2022. 8. 12. 17:21[오늘 수업]
- [표현언어, EL식]
: V에서 (브라우저, .jsp, .html페이지) 활용
형태 : ${표현식}
${변수명} ${객체명.멤버변수명} ${컬렉션객체[인덱스]}
${mid} ${member.id} ${member["id"]} ${data[0]}
ex ) V에서 어떤 데이터를 보고싶어요...
>> Controller에서 M에게 데이터를 요구해서 데이터를 보내줘야 함
즉, request, session, application scope 내장객체에
setAttribute() 해야 함!
★결론
- V에서 EL식을 사용하기 위해서는
사전에 C에서 request, session, application scope 내장객체에 setAttribute()해야함
: 숫자, 문자열, boolean, null과 같은 상수값도 작성 가능
기본연산 가능
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>연산자 계산</title>
</head>
<body>
<!-- 출력 방법 -->
${10}
<hr>
<!-- 기본 연산자 -->
<!-- 나누기 -->
${1/1}<br>
${1 div 1}<br>
<!-- 나머지 -->
${1%1 }<br>
${1 mod 1}<br>
<hr>
<!-- 연산자 boolean 값으로 나옴 -->
${1==1}<br>
${1 eq 1}<br>
${1 ne 1}<br>
${1 lt 1}<br>
${1 ge -1}<br>
<hr>
<!-- && || 도 쓰지만 and or 도 쓰임 -->
${1>3 and 1<-1}<br>
${1>3 or 1>-1}<br>
${not (1>3)}<br> <!-- not은 연산자 우선순위로 괄호 써줄 것 -->
<hr>
<!-- 조건연산자 -->
${1>2 ? 1:2}
</body>
</html>
>> 사용방법
1)
(1)<%=request.getParameter("sel") %>
(2)test.getNum1() + test.getNum2() = ???
(3)Test test=(Test)session.getAttribute("test");
2)
(1)${param.sel}
(2)(3)${test.num1} + ${test.num2} = ${test.num1+test.num2}
>> EL식 예시
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="test" class="test.Test" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EL식 - 1</title>
</head>
<body>
<!-- 데이터를 정해주기 위한 작업 -->
<form aciton="El2.jsp" method="post">
<select name="sel">
<%
// 테스트 클래스를 가져오려면 객채화 진행 위에 useBean을 통해 진행
for(String v : test.getDatas() ){ // for(String v : Test클래스의 datas 멤버변수)
%>
<option><%=v %></option>
<%
}
%>
</select>
<input type="submit" value="선택">
</form>
</body>
</html>
>> EL식 예시를 위한 testVO : 값을 미리 정해놓았기 때문에 getter만 가져옴
package test;
public class Test {
private String[] datas= {"apple","banana","kiwi"};
private int num1=10;
private int num2=20;
public String[] getDatas() {
return datas;
}
public int getNum1() {
return num1;
}
public int getNum2() {
return num2;
}
}
>> EL-1 선택하면 출력하는 EL-2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EL식 - 2</title>
</head>
<body>
sel이라는 파라미터에 저장된 값 : <%=request.getParameter("sel") %><br>
현재 session scope 내장객체에는 test라는 이름의 객체가 저장된 상태.<br>
test.getNum1() + test.getNum2() = ???
Test test=(Test)session.getAttribute("test"); << object로 돌려줌 >> 캐스팅 진행
=> <jsp:useBean scope="session" id="test" class="test.Test"/>
<% // => 뒤에 값이 나오는 곳
int res=test.getNum1() + test.getNum2();
out.println(res);
%>
<br>
<hr>
<!-- EL식 방법 : 위의 과정 동일 -->
sel이라는 파라미터에 저장된 값 : ${param.sel}
현재 session scope 내장객체에는 test라는 이름의 객체가 저장된 상태.<br>
${test.num1} + ${test.num2} = ${test.num1+test.num2}
</body>
</html>
>> 예제
어제 본 능단평의
V부분에 존재하는 <%= %>을 전부 EL식으로
>> board.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%request.setCharacterEncoding("UTF-8");%>
<jsp:useBean id="data" class="model.vo.BoardVO" scope="request"/>
<jsp:useBean id="member" class="model.vo.MemberVO" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세페이지</title>
</head>
<body>
<script type="text/javascript">
function del(){
ans=confirm('정말 삭제할까요?');
if(ans==true){
document.bForm.action.value="bdelete";
document.bForm.submit();
}
else{
return;
}
}
function update(){
ans=confirm('글을 변경하시겠습니까?');
if(ans==true){
document.bForm.action.value="bupate"
document.bForm.submit();
}else{
return;
}
}
</script>
<form name="bForm" action="controller.jsp" method="post">
<input type="hidden" name="action" value="bupdate">
<input type="hidden" name="bid" value="${data.bid} ">
<table border="1">
<tr>
<td>제 목</td>
<td><input type="text" name="title" value="${ data.title}" required></td>
</tr>
<tr>
<td>내 용</td>
<td><input type="text" name="content" value="${ data.content}" required></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" value="${ data.writer}" required readonly></td>
</tr>
<%
if(member.getMid()!=null && (member.getRole().equals("ADMIN") || member.getMname().equals(data.getWriter()))){ // 관리자 of 현재 로그인한 사람==작성자
%>
<tr>
<td colspan="2" align="right">
<%-- 를 사용하여 칸 띄우기 --%>
<input type="button" value="변경하기" onclick="update()"> <input type="button" value="삭제하기" onclick="del()">
</td>
</tr>
<%
}
%>
</table>
</form>
<hr>
<a href="controller.jsp?action=main"><input type="button" value="메인으로"></a>
<button onclick="history.back()">뒤로가기</button>
</body>
</html>
>> form.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%request.setCharacterEncoding("UTF-8");%>
<jsp:useBean id="member" class="model.vo.MemberVO" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시글 작성페이지</title>
</head>
<body>
<form action="controller.jsp" method="post">
<input type="hidden" name="action" value="binsert">
<table border ="1">
<tr>
<td>제목</td>
<td><input type="text" name="title" required ></td>
</tr>
<tr>
<td>내용</td>
<td><input type="text" name="content" required ></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" value="${member.mname} " required readonly></td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="글 작성하기">
</td>
</tr>
</table>
</form>
<hr>
<button onclick="history.back()">뒤로가기</button>
</body>
</html>
>> main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%request.setCharacterEncoding("UTF-8");%>
<jsp:useBean id="member" class="model.vo.MemberVO" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시글 작성페이지</title>
</head>
<body>
<form action="controller.jsp" method="post">
<input type="hidden" name="action" value="binsert">
<table border ="1">
<tr>
<td>제목</td>
<td><input type="text" name="title" required ></td>
</tr>
<tr>
<td>내용</td>
<td><input type="text" name="content" required ></td>
</tr>
<tr>
<td>작성자</td>
<td><input type="text" name="writer" value="${member.mname} " required readonly></td>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" value="글 작성하기">
</td>
</tr>
</table>
</form>
<hr>
<button onclick="history.back()">뒤로가기</button>
</body>
</html>
>> mypage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%request.setCharacterEncoding("UTF-8");%>
<jsp:useBean id="data" class="model.vo.MemberVO" scope="request" />
<!-- 세션정보를 바꾼거지 db정보를 바꾼 것은 아니다! -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>마이페이지</title>
</head>
<body>
<script type="text/javascript">
function del() {
ans = prompt('아이디를 입력하세요.');
if(ans=='${data.mid}'){
ans = prompt('비밀번호를 입력하세요.');
if (ans =='${data.mpw}') {
ans2 = confirm('정말 삭제할까요?');
if (ans2 == true) {
document.mForm.action.value = "mdelete";
document.mForm.submit();
} else {
alert('삭제를 취소했습니다.');
return;
}
} else {
alert('잘못된 비밀번호입니다.');
return;
}
}else{
alert('잘못된 아이디입니다.');
return;
}
}
function update(){
ans=confirm('정보를 변경하시겠습니까?');
if(ans==true){
document.mForm.action.value="mUpdate";
document.mForm.submit();
}else{
return;
}
}
</script>
<form name=mForm action="controller.jsp" method="post">
<input type="hidden" name="action" value="mUpdate">
<%-- bid도 숨겨서 보내는 것이 가능!! --%>
<table border="1">
<tr>
<td>아이디</td>
<td><input type="text" name="mid" value="${data.mid }"
required readonly></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" name="mpw"
value="${data.mpw }" required pattern="^[a-z0-9_-]{4,8}$"
title="4~8자의 영문 소문자, 숫자, 특수기호(_),(-)만 사용 가능"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="mname"
value="${data.mname }" required pattern="^[가-힣]{2,5}$"
title="2~5자의 한글만 사용 가능"></td>
</tr>
<tr>
<td>계정권한</td>
<td>${data.role }</td>
</tr>
<tr>
<td colspan="2" align="right"><input type="button"
value="회원정보변경" onclick="update()"> <input type="button" value="회원탈퇴"
onclick="del()"></td>
</tr>
</table>
</form>
<hr>
<a href="controller.jsp?action=main"><input type="button" value="메인으로"></a>
</body>
</html>
>> 뒤로 돌아갈때 다음과 같이 진행한다고 함
<a href="javascript:history.go(-1);">돌아가기</a>
※ 참고
: java단의 내용을 가져온 것은 EL식으로 바꾸는 것이 불가능
: controller도 바꿀 수 있나?
있긴한데... 굳이 힘들게 바꿀필요가 있나 싶음
- [커스텀태그]
: 개발자가 작성한 태그
- 장점
1) V에 존재하는 로직코드(Java)를 분리 가능
2) 로직코드를 캡슐화(모듈화)
3) 보다 완벽한 MVC 구조 구축 가능
- 커스텀태그 종류
1) 태그파일 기반의 커스텀태그
: Java 아님
: 프로젝트의 규모가 작을 때 사용
: 간단한 기능
2) 태그핸들러클래스 기반의 커스텀태그
: Java를 통해 만들어 내는 것
: 핸들러 기반의 커스텀태그
: 프로젝트의 규모가 클 때 사용
: 배포(공개, 공유)를 하는 것이 주된 목적일 때 사용
: 다른 사람의 코드를 분석할 수 있어야 함
>> 1번을 많이 활용하게 될 것
>> 기본 용어
* 태그
: 주로 쌍으로 이루어져 있음
ex ) <table></table> | <a></a>
* 태그 바디
: 비울 경우(사용하지 않을 경우) < /> 닫는 것을 권장
ex ) <jsp:useBean />
* 속성
: 속성값들을 작성할 때에는 ""로 묶는 것을 권장
태그 언어가 전 세계에서 동시다발적으로 개발했지만
html은 특징이 좀 다름..
여러 국가에서 같이 다루다보니 어떻게 써도 다 돌아가는 경우 존재
>> 우리나라는 안 쓰면 가독성이 떨어진다고 생각함
> 꼭 쓸 것!
* ojdbc를 properties에 추가하여 쓸테니 가져와! 라고 하는 것처럼
<%@ taglib %> 로 내가 만든 태그라고 기술해줘야 함
: <%@ taglib %> 이것을 'taglib 지시어' 라고 함(Back to the Basic)
* taglib 지시어
기술 방법
>> uri : 남이 만든 (핸들러클래스기반의) 커스텀 태그를 사용하는 경우
ex )
<%@ taglib uri="커스텀태그 파일의 위치" prefix="커스텀태그명" %> - 태그 라이브러리
>> 태그 라이브러리 꼭 기술!!
<prefix:커스텀태그명>태그 바디</prefix:커스텀태그명>
<prefix:커스텀태그명 />
>> tagdir : 내가 만든 (파일기반의) 커스텀태그를 사용할 때
+ "/WEB-INF/tags 저장한 위치까지만 사용
ex )
<%@ taglib tagdir="커스텀태그 파일의 위치" prefix="커스텀태그명" %> - 태그 라이브러리
>> '태그 라이브러리' 꼭 기술!!
<prefix:파일명>태그 바디</prefix:파일명>
<prefix:파일명 />
- [태그파일 기반의 커스텀태그]
태그파일들은 WEB-INF/tags 폴더에 저장, 관리
** tagdir을 이용한 커스텀태그
>> print.tag
<%@ tag language="java" pageEncoding="UTF-8"%>
커스텀태그입니다. HELLO! :D
>> Customtag1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 태그 라이브러리 지시어 꼭 쓸 것! -->
<%@ taglib tagdir="/WEB-INF/tags" prefix="ryo" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>커스텀태그 - 1</title>
</head>
<body>
<h1><ryo:print/></h1>
</body>
</html>
>> .tag 파일 기반의 커스텀태그
이 커스텀태그를 사용하는 사람이 태그바디에 작성한 내용
<%@ attribute name="border" %>
${border}
이 커스텀태그에서 속성값을 줄 수 있고,
해당 속성값은 태그 내부에서 사용 가능
>> test.tag
<%@ tag language="java" pageEncoding="UTF-8"%>
<!-- 외부 속성을 받을 때 사용 -->
<%@ attribute name="border" %>
<%@ attribute name="bgcolor" %>
<jsp:useBean id="test" class="test.Test"/>
<!-- 이 커스텀태그를 사용하는 사람이 태그바디에 작성한 내용 출력 -->
<h1><jsp:doBody /></h1>
<table border="${border}" bgcolor="${bgcolor}">
<!-- 속성이 외부에서 꼭 들어와야 border, bgcolor를 받아야 함 -->
<%
for(String v:test.getDatas()){
%>
<tr>
<td><%=v %></td>
</tr>
<%
}
%>
</table>
>> NewFile.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib tagdir="/WEB-INF/tags" prefix="ryo" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<ryo:test border="5" bgcolor="lightpink">과일 목록</ryo:test>
<br>
</body>
</html>
<!-- 예시(비슷하게 사용해도 괜찮지만 똑같이 사용하는 것은 비추천) -->
<% if(로그인한 상태면?) { %>
<ryo:로그인상태>
<% } else { %>
<ryo:비로그인상태>
<% } %>
>> 똑같이 사용은 비추천이지만 한번 짜보려고 만들어 본 코드
<%@ tag language="java" pageEncoding="UTF-8"%>
<% if("<jsp:doBody/>"==null) { %>
<h1><a href="#">로그인</a>해주세요!</h1>
<% } else {%>
<h1><a href="#"><jsp:doBody/></a>님 환영합니다!</h1>
<% }%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib tagdir="/WEB-INF/tags" prefix="ryo" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<hr>
<ryo:header>티모</ryo:header>
</body>
</html>
>> 로그인, 비로그인 시 사용 가능할 것으로 예상
>> 방법을 찾아 해볼 것
- [태그핸들러클래스 기반의 커스텀태그]
: 태그핸들러클래스 - Java 파일(.java)
: 태그라이브러리기술자(작성했는지를 기술하는 자) - tld파일(.tld)
-> WEB-INF 하위에 tld라는 폴더를 만들어서 사용
>> 본질이 xml이기에 tld검색이 아닌 .xml파일 검색
.xml 파일 => 설정과 관련된 파일
이때, .xml로 하지 않고 .tld로 해야함
+ next로 가서 위에 있는 Create file using~~ 쓸 것
+ next로 가서 select XML Catalog 선택
>> 위 화면에서 finish 누르면 다음 화면이 생성
<?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>NMTOKEN</short-name>
</taglib>
>> 기본 설정이 엄청 많은데 이게 설정을 안하면 내가 직접 쳐야하는 사태 발생
>> 예제파일이라서 가만히 놔두기도 하지만
누가 분석할 때, shrot-name에 이름이 있으면 분석하기 쉬움
<!-- 하위 태그로 3가지 필요 name, tag-class, body-content -->
<tag>
<name>커스텀태그명</name>
<tag-class>패키지경로명.핸들러클래스명</tag-class>
<body-content>태그바디의 형태</body-content>
</tag>
<body-content>태그바디의 형태</body-content>
>> 이런 형태가 태그바디의 형태에 작성됨
-> empty(비어있을 때), JSP, tagdependent
* 태생부터 태그바디가 없는 형태
<br>
<hr>
<img>
* 반드시 짝을 지어서 줘야하는 형태
<ul></ul>
<ol></ol>
>> MsgTagHandler.java
package test;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
// 핸들러클래스를 만들고 싶어용...
// "핸들러" 클래스가 어딘가에 존재한다고 함!!
// => "상속" 받아와야함
public class MsgTagHandler extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspWriter out=getJspContext().getOut(); // 흔한 형태는 아니지만 글 한번 써보기 위해 만든 것
out.println("핸들러클래스기반으로 출력하는 메세지! :D ");
} // 핸들러클래스 상속받음
// 시작태그를 만나면 자동으로 호출되어 수행되는 메서드
}
doTag 메서드 오버라이딩
>> 시작 태그를 만나면 자동으로 호출되어 수행되는 메서드
>> MsgTag.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>MsgTag</short-name>
<!-- 이름 설명을 잘 설정 안하지만 설정 -->
<!-- 하위 태그로 3가지 필요 name, tag-class, body-content -->
<tag>
<name>message</name>
<tag-class>test.MsgTagHandler</tag-class>
<body-content>empty</body-content>
<!-- 비어있을 때는 empty -->
</tag>
</taglib>
>> NewFile1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/tld/MsgTag.tld" prefix="mytag" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 형태에 empty로 해놓으면 자동으로 /> 지정 body없어서 자동으로 지정 -->
<h1><mytag:message/></h1>
</body>
</html>
>> TestTagHandler.java
package test;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class TestTagHandler extends SimpleTagSupport{
// 태그 속성을 저장할 멤버변수
private String border;
private String bgcolor;
public String getBorder() {
return border;
}
public void setBorder(String border) {
this.border = border;
}
public String getBgcolor() {
return bgcolor;
}
public void setBgcolor(String bgcolor) {
this.bgcolor = bgcolor;
}
@Override
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
// 태그 바디의 내용을 받아오는 코드 : <jsp:doBody />에 해당하는 코드
JspFragment body = getJspBody(); // output = JspFragment
if(body!=null) { // body가 null이면 안 되기 때문에 등록(null이면 에러 발생)
// out.println("<h1>태그바디내용</h1>");
out.println("<h1>");
body.invoke(null);
out.println("</h1>");
}
// Test test = new Test();
// String v : test.getDatas() 로 써도 괜찮음
// 내 멤버변수 넣을 건데 this. 생략 가능
out.println("<table border="+border+" bgcolor="+bgcolor+">");
for(String v : new Test().getDatas()) {
out.println("<tr><td>"+v+"</td></tr>");
}
out.println("</table>");
}
}
doTag 메서드 오버라이딩
>> 시작 태그를 만나면 자동으로 호출되어 수행되는 메서드
>> TestTag.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>NMTOKEN</short-name>
<tag>
<name>test</name>
<tag-class>test.TestTagHandler</tag-class>
<!-- 태그를 쓸 수도 있고 안 쓸수도 있는 상황에는 scriptless 사용 -->
<body-content>scriptless</body-content>
<attribute>
<name>border</name>
<required>true</required>
</attribute>
<attribute>
<name>bgcolor</name>
<required>true</required>
</attribute>
</tag>
</taglib>
>> NewFile2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/tld/TestTag.tld" prefix="mytag" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<mytag:test bgcolor="lightblue" border="1">목록</mytag:test>
</body>
</html>
작성하는 순서
>> 핸들러 클래스 완성하고
>> tld 완성 하고
>> tld에 있는 내용을 mytag라는 이름으로 불러 올 수 있음
msg 태그를 만들어놓으면 자동으로 msg 불러옴
<msg에 오류가 자꾸 생겨 message로 스펠링을 맞춰주니 오류 사라짐>
순서 결론 : handler.java -> tld -> jsp