[ JSP 태그 ]
- HTML 기반의 JSP 코드 내에 JAVA 코드를 삽입할 수 있게 해주는 태그
JSP는 HTML 기반으로 되어 있기 때문에 JAVA 코드를 넣어서 동작시키려면 JSP 태그 사이에 삽입해야 합니다. HTML, CSS, Javascript 등으로 클라이언트단에서 보여지고 동작할 뼈대를 만든 후 JSP 태그로 JAVA 코드를 넣어 특정 로직을 수행할 수 있도록 합니다.
JSP는 서블릿으로 변환된 후 사용자에게는 HTML 형태의 코드만 전송하므로 JSP 태그의 내용은 사용자에게 노출되지 않습니다.
구분 | JSP 태그 | 용도 |
지시자 | <%@ %> | 페이지 속성 지정 |
주석 | <%-- --%> | 주석 처리 |
선언 | <%! %> | 변수, 메소드의 선언 |
표현식 | <%= %> | 결과값 출력 |
스크립트릿 | <% %> | JAVA 코드 삽입 |
액션태그 | <jsp:action> </jsp:action> | 페이지 삽입, 공유, 자바빈 사용 등 |
[ 지시자 : <%@ %> ]
- JSP 페이지가 컨테이너에게 필요한 메세지를 보내기 위한 태그
- page : JSP 페이지의 전체적인 속성을 지정
- include : 다른 페이지를 현재 페이지에 삽입
- taglib : 태그라이브러리의 태그 사용
- 범위 : JSP 파일 전체 (클래스를 import 할 경우 파일 내 어디서든 접근할 수 있음)
이클립스에서 처음 JSP 파일을 생성하면 가장 윗부분에 생성되는 부분이 JSP 지시자 태그입니다. JSP 페이지의 기본 성격을 나타내는 부분이며, 컨테이너가 JSP파일을 서블릿으로 변환시킬 때 필요한 정보를 기술합니다. 자바 클래스를 import 시켜서 사용한다거나 다른 페이지를 삽입한다거나 할 때 사용됩니다.
<%@page import="java.util.Arrays"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
page는 대부분 import나 에러 페이지 삽입 등의 용도로 많이 사용되고 taglib(태그라이브러리)는 커스터마이징 태그나 JSTL 같은 태그라이브러리를 삽입해 사용하는 용도인데 별도로 다루도록 하겠습니다.
include(디렉티브)는 아래와 같은 코드 형태로 사용되는데, 다른 JSP 페이지의 소스코드를 가져와서 그대로 붙여줍니다. 해당 JSP 파일을 변환해서 컴파일할 때 include된 페이지도 같이 컴파일돼 삽입한 순서대로 로직을 수행해서 최종 HTML 코드를 생성해줍니다. 좀 더 자세한 설명과 액션 태그 include와의 차이점은 아랫쪽 액션태그란에서 추가로 정리해두었으니 아랫쪽 내용을 참조하시면 됩니다.
include 에서 파일의 위치는 상대 경로를 사용하기 때문에 같은 폴더에 있다면 그냥 파일 이름을 써주면 되지만 다른 폴더에 있다면 상대경로로 파일 위치를 지정해줘야 합니다. 폴더 내의 하위 경로에 있다면 "/폴더/파일명" 형태로 사용해주면 되고 현재 폴더보다 한 칸 위에 있다면 "../파일명", 두 칸 위에 있다면 "../../파일명" 형태로 사용해주면 됩니다.
본래 페이지 <br/>
<%@ include file = "include1.jsp" %>
<%@ include file = "../include2.jsp" %>
본래 페이지 <br/>
소스코드를 확인해보면 그냥 세 개의 HTML 페이지가 순서대로 쭉 붙어있는 것을 알 수 있습니다. 아래에서 추가적으로 설명하겠지만, JSP 파일에서부터 소스코드를 그대로 가져와서 붙여주기 때문에 발생하는 결과입니다. 따라서 변수와 메소드 등 include 시킨 파일의 모든 부분을 가져다 쓸 수 있습니다. 자세한건 아래의 액션태그 설명란에서 확인 부탁드립니다.
[ 선언 : <%! %> ]
- 변수와 메소드를 선언함
- 범위 : 페이지 내 어디서나 접근할 수 있는 전역 변수 및 메소드
변수는 클래스의 필드와 같은 역할입니다. 선언된 변수나 메소드는 어디서든 접근해서 사용 가능합니다. JSP는 HTML 기반이지만 JSP 태그만 간단히 쓸 때는 클래스를 작성할 때와 크게 다른 점은 없습니다. 표현식 <% %>에서 변수를 선언하는 것과 다르지 않지만 메소드를 작성할 수 있다는 점에서 다릅니다.
<%-- 변수 및 메소드 선언 --%>
<%!
int a;
int b;
public int sum(int a, int b) {
return a + b;
}
%>
<%-- 자바 코드 삽입 --%>
<%
a = 10;
b = 20;
out.println(sum(a, b));
%>
[ 표현식 : <%= %> ]
- 변수 또는 메소드의 결과값을 출력
- 자바 코드를 삽입하는 것보다 더 간단하게 출력 가능
- 변수나 메소드를 사용할 때 세미콜론(;)을 사용하지 않음
위의 선언 태그 코드에서 sum() 메소드의 결과값을 출력하기 위해 out.println() 메소드를 사용했습니다. 출력에 대한 코드를 줄일 수 있는 태그가 표현식입니다. 아래와 같이 코드를 바꿀 수 있습니다.
<%-- 변수 및 메소드 선언 --%>
<%!
int a;
int b;
public int sum(int a, int b) {
return a + b;
}
%>
<%-- 자바 코드 삽입 --%>
<%
a = 10;
b = 20;
%>
<%-- 표현식을 사용해 출력 --%>
<%= sum(a,b) %>
위 코드의 예시만으로는 별 다른게 없어보이지만 아래와 같이 만약 HTML 코드 중간에 간단히 사용해야 하는 경우라면 코드를 짧게 사용할 수 있어 가시성도 좋아지고 편리하게 쓸 수 있습니다. 세미콜론을 사용해서 코드 간의 구분을 해줄 수 없기 때문에 하나의 변수나 메소드만 간단히 삽입할 때 사용합니다.
<%-- 변수 및 메소드 선언 --%>
<%!
int a;
int b;
public int sum(int a, int b) {
return a + b;
}
%>
<%-- 자바 코드 삽입 --%>
<%
a = 10;
b = 20;
%>
<%-- 표현식을 사용해 출력 --%>
표현식의 결과값은 <%= sum(a,b) %> 입니다. <br/>
<%-- 스크립트릿(자바 코드 삽입)을 사용해 출력 --%>
스크립트릿의 결과값은 <% out.println(sum(a,b)); %> 입니다.
[ 스크립트릿 : <% %> ]
- 자바 코드를 삽입하기 위한 태그
- 기존 자바 언어를 동일하게 사용할 수 있음
위의 예시 코드에서 계속 나온대로 자바 코드를 삽입하는 태그입니다. 자바 언어를 사용해서 JSP를 구성하기 위해 가장 많이 쓰이는 태그입니다. 뷰 역할의 JSP에 자바 코드를 최대한 줄이기 위해 JSTL을 대신 사용하는 경우도 많습니다. JSTL은 별도로 다루도록 하겠습니다.
아래 코드와 같이 자바 코드와 HTML을 섞어서 사용할 수도 있습니다. 반복문 사이에 HTML 코드를 섞어서 사용한 예시입니다.
<%
int i = 0;
while (true) {
out.println(i + " 번째 줄");
i++;
%>
<br/>============== <br/>
<%
if (i > 5)
break;
}
%>
[ 액션태그 : <jsp:action> </jsp:action> ]
- <jsp:include> : 다른 페이지의 실행 결과를 현재 페이지에 포함시켜줌
- <jsp:forward> : 페이지 간의 제어를 이동시켜줌
- <jsp:useBean> : 자바빈(java bean)을 페이지에서 사용할 수 있게 해줌
- <jsp:setProperty> : Property 값을 세팅할 때 사용
- <jsp:getProperty> : Property 값을 가져올 때 사용
- <jsp:param> : include, forward 안에서 사용되며, 인자를 추가할 때 사용
액션 태그를 사용할 때는 바디가 따로 있는 경우는 </jsp:action>으로 닫아줘야 하고, 바디가 따로 없는 경우에도 <jsp:action ~~ /> 형태로 닫아줘야 합니다.
* <jsp:include> (지시자의 include 디렉티브와 액션태그 include의 차이)
지시자의 include 디렉티브는 위에서 설명했듯이 소스파일의 내용을 그대로 가져다 붙이는 방식입니다. 따라서 다른 페이지를 include 하게 되면 결과물인 HTML 코드만 합쳐지는게 아니라 그냥 JSP 파일의 코드가 합쳐진다고 생각하면 됩니다. include된 페이지의 자원을 가져다쓸 수 있다는 의미입니다. 아래 예시를 보시면 test.jsp 파일에는 "String str" 이라는 변수를 생성한 적이 없음에도 include.jsp 파일을 include 해줌으로써 해당 파일에 있는 변수를 사용할 수 있습니다. 즉, include.jsp의 코드가 그대로 붙어있어서 컴파일할 때 컨테이너가 처리해준다는 뜻입니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%@ include file = "include.jsp" %>
<%
out.println(str + "<br/>");
str = "바꿀 수도 있다!";
out.println(str + "<br/>");
%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%!
String str = "나는 include 된 페이지다아~!";
%>
<% out.println(str + "<br/>"); %>
</body>
</html>
실행 결과를 보면 한가지 재밌는 결과를 얻을 수 있습니다. 첫 실행에는 아래와 같이 실행됩니다.
그런데 새로고침을 해보면 아래와 같이 실행됩니다.
이는 서블릿의 기본 원리에 입각하여, 한 번 컴파일된 서블릿(JSP 포함)은 메모리에 올라간 뒤 서블릿을 수정하거나 컨테이너(WAS)를 다시 실행하지 않는 이상 계속 해당 객체를 재활용하기 때문입니다. 즉, 컴파일된 코드에서 처음엔 "나는~~" 문자열을 출력하고 str의 내용을 "바꿀 수도 있다!"로 바꿔놨기 때문에 str의 내용은 바뀐 상태로 존재합니다. 그 상태로 새로고침을 하면 out.println(str) 메소드가 실행될 때 str은 이미 내용이 바뀐채로 계속 남아있어 저렇게 바껴서 출력되게 되는 것입니다. 컴파일된 서블릿 객체의 재활용이라는 점을 염두하면서 코딩을 해야하는 이유입니다.
그리고 이 상태에서 include 해줬던 include.jsp에 접속해봅니다. 해당 페이지의 문자열은 바껴있지 않습니다. 즉, include했을 때 test.jsp에서 코드만 가져갔을 뿐 본래 있던 include.jsp 파일과는 전혀 무관하게 작동한다는 것을 알 수 있습니다. 따라서 상호 간에 교류 없이 "코드만 가져와서 사용한다"라는 점에서 include 디렉티브는 정적인 페이지 또는 변하지 않는 로직을 모듈화해서 사용한다고 할 수 있습니다. 고정된 메세지를 출력하거나 혹은 고정된 메소드를 실행하는 용도로 활용할 수 있습니다.
include 디렉티브와 달리 액션태그의 include는 삽입을 요청한 파일의 코드를 가져오는 것이 아니라 해당 파일로 가서 로직을 수행한 뒤 다시 돌아와서 남은 로직을 마저 수행하는 방식입니다. 코드를 가져오는게 아니라 해당 페이지로 가서 내용을 수행한다는 의미에서 file = "xx.jsp" 형식이 아닌 page = "xx.jsp" 형식으로 기술됩니다. 사실 이건 저의 생각입니다.ㅎㅎ 따라서 아까 같은 상황에서 액션 태그를 사용할 경우 str이라는 변수가 없기 때문에 사용할 수 없게 됩니다.
flush = "false" 는 <jsp:include>가 실행돼서 다른 페이지로 넘어가기 전에 출력 버퍼를 모두 클라이언트에게 보낸 후 넘어갈 것이지에 대한 여부를 결정합니다. jsp는 HTML로 변환되기 때문에 순서대로 데이터를 전송하는게 아니라 버퍼에 모두 모았다가 한번에 전송해주기 때문입니다. 버퍼 스트림과 비슷한 구조라고 보면 됩니다. 만약 include된 페이지에서 뭔가 오래걸리는 작업이 있다면 클라이언트는 일단 그 전까지의 내용을 받아보고 기다리게 됩니다. 대부분 한 번에 받아보는걸 좋아하니 false로 두고 쓰는 경우가 많은데 필요에 따라 결정하면 될 것 같습니다.
대신 액션태그의 include를 사용하면 include 되는 파일에 파라미터를 전달할 수 있습니다. <jsp:param> 태그가 이 때 사용됩니다. 아래 코드와 같이 include 해주면서 파라미터를 넘겨주면 해당 파일에서는 이 값을 받아서 로직을 전개할 수 있습니다. 이 때 파라미터를 받아서 처리해주는 JSP 파일은 파라미터 없이 단독 실행할 경우 정상 작동이 어렵습니다. 그래서 사용자의 페이지 접근을 막기 위해 ".jspf" 확장자로 지정할 수 있습니다. 이 확장자는 다른 JSP에 삽입되기 위한 용도로 쓰이는 파일을 의미합니다.
파라미터를 전달할 때 name값은 직접 써줘야 하지만 value 값은 표현식(<%=uid>) 형태로 변수 사용이 가능합니다. include 할 파일 이름도 표현식으로 지정 가능합니다. 디렉티브와 달리 동적으로 사용할 수 있습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:include page = "include.jsp" flush = "false">
<jsp:param name = "id" value = "codevang"/>
<jsp:param name = "pw" value = "12345"/>
</jsp:include>
include된 페이지 작동이 끝나고 다시 넘어왔네요~
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%!
String id;
String pw;
%>
<%
id = request.getParameter("id");
pw = request.getParameter("pw");
out.println(id + " : " + pw + "<br/>");
%>
</body>
</html>
이러한 특성으로 액션태그 include는 주로 많은 곳에서 반복되는 코드를 모듈화해두고 해당 페이지에 파라미터를 제공해서 동적으로 구성되는 페이지를 만들 때 자주 사용됩니다. 페이지에서 반복되는 레이아웃이 있는데 미묘하게 출력되는 문구만 다르다던가 할 때 유용하게 쓸 수 있습니다.
정리하자면 include 디렉티브는 여러 JSP 파일에서 공통적으로 쓰는 정적인 변수, 메소드 등을 모듈화해서 재활용하기 위한 목적으로 사용되고 액션태그의 include는 여러 JSP 파일에서 공통적으로 쓰는 동적인 로직을 모듈화해서 재활용하기 위해 주로 활용된다고 보면 될 것 같습니다. 특성만 알면 본인 입맛대로 사용하면 되겠죠!
* <jsp:forward>
위에서 설명한 <jsp:include>와 비슷하지만 다르게 작동합니다. 실행되고 있는 페이지를 다른 페이지로 옮겨준다는 점에서는 비슷하지만, forward를 호출한 쪽의 페이지에서 출력한 내용은 클라이언트에게 전달되지 않습니다. 다시 이전 페이지로 돌아오지도 않습니다. JSP는 최종 출력물인 HTML 코드가 완성될때까지 내용을 버퍼에 담았다가 한 번에 출력합니다. 따라서 <jsp:forward>를 만나게 되면 기존까지 출력을 위해 버퍼에 담았던 내용을 싹 없애버리고 forward된 페이지로 넘어갑니다. 로직은 수행할 수 있되 클라이언트에게 뭔가 내용을 전달할 수는 없다는 것입니다. 따라서 forward는 주로 조건에 따라 다른 페이지에 요청객체를 넘겨주고 추가 파라미터를 넘겨주기 위해 사용됩니다.
include와 마찬가지로 forward 시킬 파일 이름과 param 태그의 value 값은 표현식으로 지정이 가능합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
여기있는 글자는 출력되지 않습니다~~
<%!
int a = 10;
String id;
String pw;
String pageName;
%>
<%
if (a > 1) {
id = "codevang";
pw = "12345";
pageName = "include.jsp";
} else {
id = "coconut";
pw = "54321";
pageName = "xxxx.jsp";
}
%>
<jsp:forward page = "<%= pageName %>">
<jsp:param name = "id" value = "<%= id %>"/>
<jsp:param name = "pw" value = "<%= pw %>"/>
</jsp:forward>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%!
String id;
String pw;
%>
<%
id = request.getParameter("id");
pw = request.getParameter("pw");
out.println(id + " : " + pw + "<br/>");
%>
</body>
</html>
* <jsp:useBean> / <jsp:setProperty> / <jsp:getProperty>
자바빈을 사용하기 위한 액션태그입니다. 자바빈은 간단히 DTO(데이터 저장을 위한 객체)와 같이 필드와 getter, setter로만 이루어진 자바 클래스입니다. 그냥 필드만 만들고 이클립스에서 클릭만 몇 번 하면 getter와 setter가 자동으로 생성됩니다. 데이터를 저장해서 운반하기 위한 용도로 많이 쓰고, 특히 DB 작업을 할 때 많이 사용됩니다. 클래스를 지시자로 <%@ import ~ > 시킨 뒤 new를 사용해서 클래스 인스턴스를 하나 생성해주는 것과 동일한 개념이라고 보면 됩니다. 다만 JSP는 뷰(View)의 용도로만 활용되는 경우가 많고 데이터 작업을 직접 할 일은 많이 없을 것 같습니다.
import로 해도 될 것을 자바빈을 사용하는 이유는 조금 더 편하게 사용할 수 있는 기능도 있고 코드도 짧아지는 이점이 있기 때문입니다. userBean은 아래와 같은 방법으로 사용합니다.
- id : 인스턴스 이름 (user.getID() 등으로 사용할 인스턴스의 이름 지정)
- class : '패키지.클래스' 전체 경로
- scope : page, request, session, application의 4가지 중 자바빈 객체를 저장할 곳
scope의 경우 지정하지 않으면 page가 디폴트입니다. 그냥 해당 페이지 내에서 적용된다고 생각하면 됩니다. 각 내장 객체의 특성에 따라 필요한 곳에 저장하면 됩니다.
<jsp:useBean id = "user" class = "join.TestBean" scope = "request" />
<jsp:setProperty> 태그는 setter와 동일합니다. 다만 아래 코드와 같이 클라이언트가 전송한 정보(request)를 한번에 담아주는 기능이 있습니다. 대신 Bean 클래스의 필드명(Property)과 <Form> 태그의 name이 일치해야 합니다. 변수 이름이 같은 파라미터를 모두 찾아서 자동 저장해주는 기능이라 하나씩 일일이 저장하지 않아도 됩니다.
<jsp:setProperty name = "user" property = "*" /> <%-- 한번에 자동 저장 --%>
<jsp:setProperty name = "user" property = "id" value = "codevang"/>
<jsp:setProperty name = "user" property = "pw" value = "12345" />
<jsp:getProperty>는 반대로 Bean에 저장된 필드값(Property)을 가져오는 기능입니다. 하지만 <%= user.getID %> 형식보다 오히려 코드가 길어지기 때문에 그리 효율적인 기능은 아닙니다.
<jsp:getProperty name = "user" property = "id"/>
<jsp:getProperty name = "user" property = "pw"/>
'▸JSP & Servlet > 기본 문법' 카테고리의 다른 글
JSP 내장 객체_pageContext / exception [3/4] (2) | 2020.02.16 |
---|---|
JSP 내장 객체_page / config / application [2/4] (2) | 2020.02.16 |
JSP 내장 객체_request, response, out [1/4] (2) | 2020.02.14 |
JSP, Servlet(서블릿)의 URL 주소 매핑 (2) | 2020.02.13 |
서블릿(Servlet) 생성과 생명주기 (2) | 2020.02.13 |
댓글