자꾸 까먹는 경향이 있어 기록용으로 저장해 둡니다. JSP에서 간단한 프로그램 로직을 구현하기 위해 JSTL을 사용하는데요 다양한 JSTL용 태그 라이브러리가 제공되지만 이 글에서는 플로우등을 조정하기 위한 core만을 보도록 하겠습니다.
1. JSTL을 사용하기 위한 라이브러리를 다운
[이곳] 에서 다운받을 수 있습니다. 현재 시점에서는 1.1.2가 최신버전이군요. 만약에 Gradle 기반 프로젝트에서 JSTL을 사용하고자 하신다면 다음을 추가하면 됩니다.
dependencies { compile 'javax.servlet:jstl:1.2' }
2. 라이브러리 추가
다운받은 파일을 열어보면 standard.jar 와 jstl.jar 두개의 파일이 존재합니다. 둘 모두를 개발중인 프로젝트에 추가합니다.
3. JSP 페이지의 맨 위에 taglib 정의 추가
프로젝트의 맨 위에 다음을 추가해 줍니다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
4. JSTL 문법을 사용 (몇가지 예시)
<c:forEach>를 사용한 특정 범위의 숫자값을 순환
<table> <tr> <th>Value</th> <th>Square</th> </tr> <c:forEach var="x" begin="0" end="10" step="2"> <tr> <td><c:out value="${x}"/></td> <td><c:out value="${x * x}"/></td> </tr> </c:forEach> </table>
위의 코드는 0부터 10까지 2씩 증가하는 순환문을 뜻합니다. 현재의 증가값은 변수 x에 저장됩니다. 결과는 다음과 같이 출력이 됩니다.
<c:forEach>태그를 이용한 Collection형 배열을 처리
forEach는 Collection, Map, Iterator, Enumeration, Array(Object/Primitive), 쉼표로 구분된 String, SQL쿼리 결과값(javax.servlet.jsp.jstl.sql.Result) 등의 순환을 지원합니다.
<table> <c:forEach items="${entryList}" var="blogEntry"> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach> </table>
위의 모드는 블로그 글을 순환하며 출력하는 예시입니다. ${entryList}는 title, text를 멤버 변수로 갖는 특정 객체의 집합 배열입니다. 현재 순환중인 객체가 blogEntry에 저장되며 .을 사용하여 title과 text를 출력하는 예시입니다.
여기에 새롭게 현재 순환중의 상태를 확인할 수 있는 varStatus라는 값을 사용할 수 있습니다. 말을 길게 할 필요없이 코드로 보여드리겠습니다.
<table> <c:forEach items= "${entryList}" var="blogEntry" varStatus="status"> <tr><td align="left" class="blogTitle"> <c:out value="${status.count}"/>. <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach> </table>
위에 추가된 ${status.count}에서는 현재 몇번째 순환중인지 값을 확인할 수 있습니다.
사용가능한 변수의 종류는 다음과 같습니다.
- current : 현재 순환중인 아이템을 가져옵니다.
- index : 현재 순환중인 아이템의 인덱스(0베이스)를 가져옵니다.
- count : 현재 순환중인 아이템의 인덱스(1베이스)를 가져옵니다.
- first : 현재 순환중인 아이템이 첫번째 아이템인지 여부를 확인합니다. (Boolean)
- last : 현재 순환중인 아이템이 마지막 아이템인지 여부를 확인합니다. (Boolean)
- begin : forEach에서 지정할 수 있는 begin값을 가져옵니다.
- end : forEach에서 지정할 수 있는 end값을 가져옵니다.
- step : forEach에서 지정할 수 있는 step값을 가져옵니다.
<c:if>를 사용한 조건문 활용
다음의 코드는 첫번째 아이템이 순환중일 경우 블로그글이 언제 작성되었는지 날짜를 출력하도록 수정된 코드입니다. test안에 Boolean형이 반환될 수 있는 어떤 수식을 사용해도 됩니다.
<table> <c:forEach items= "${entryList}" var="blogEntry" varStatus="status"> <c:if test="${status.first}"> <tr><td align="left" class="blogDate"> <c:out value="${blogEntry.created}"/> </td></tr> </c:if> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach> </table>
그런데 정말 희안하게도 위의 <c:if>에는 else가 존재하지 않습니다. 그래서 다음의 방법을 사용하곤 합니다.
<c:choose>를 사용한 다중 조건문 활용
다음의 예제는 pageContext라는 컨텍스트 객체에 접근하여 요청의 스킴을 읽어오는 예제입니다. HTTP로 접속했을때와 HTTPS를 통해 접속했을때 다른 메시지를 출력하는 예시입니다. 추가로 둘다 아닐경우 오류 메시지를 출력하도록 하였습니다.
<c:choose> <c:when test="${pageContext.request.scheme eq 'http'}"> This is an insecure Web session. </c:when> <c:when test="${pageContext.request.scheme eq 'https'}"> This is a secure Web session. </c:when> <c:otherwise> You are using an unrecognized Web protocol. How did this happen?! </c:otherwise> </c:choose>
<c:url>를 사용하여 주소 생성
JSTL에서는 <c:url>을 지원하는데요 이 태그는 현재의 서블릿 컨텍스트 이름을 자동으로 앞에 붙여주고 세션관리와 파라미터의 이름과 값의 인코딩을 자동으로 지원합니다. 기본적인 사용법은 다음과 같습니다.
<a href="<c:url value='/content/sitemap.jsp'/>">View sitemap</a>
간단하죠? 여기서 더 나아가 <c:param>을 사용하여 파라미터를 추가할 수 있습니다.
<c:url value="/content/search.jsp"> <c:param name="keyword" value="${searchTerm}"/> <c:param name="month" value="02/2003"/> </c:url>
위의 코드로써 생성되는 URL은 기본적으로 서블릿컨텍스트가 붙게 되며 세션쿠키를 사용중이라면 추가적으로 파라미터들만 추가되며 다음의 모습을 가지게 됩니다.
/blog/content/search.jsp?keyword=foo+bar&month=02%2F2003
만약에 세션 쿠키가 존재하지 않는다면 다음과 같은 결과를 나타내게 됩니다. 마찬가지로 파라미터들은 URL 인코딩되어 출력됩니다.
/blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290
?keyword=foo+bar&month=02%2F2003
<c:import>를 사용하여 페이지 첨부하기
JSP에는 기본적으로 두가지 방법의 페이지 안에 다른 컨텐츠를 추가하는 방법이 존재합니다. include지시자와 <jsp:include> 액션이 있는데요. 하지만 둘 모두 같은 웹 어플리케이션 또는 서블릿 컨텍스트 안에있는 페이지만을 불어들일 수 있습니다. core라이브러리에 있는 <c:import> 액션은 좀더 일반적이고 강력한 기능을 가진 <jsp:include>로 볼 수 있습니다. 사용 문법은 <c:url>과 매우 배슷하며 심지어 <c:param>도 그대로 사용할 수 있습니다.
<c:import url="ftp://ftp.example.com/package/README"/>
<c:import>에는 var와 scope 두가지 필수적이지 않은 속성이 존재하는데요. var의 경우에는 불러들인 페이지를 곧바로 출력하지 않고 String형 변수로 담아두기 위해 사용됩니다. scope는 이 변수의 스코프를 지정할 수 있습니다. 기본적으로 page로 되어있습니다.
<c:catch>로 예외처리 하기
길게 설명할 필요가 없을것 같네요. <c:import>는 ftp에도 접속이 가능합니다. 다음에 보여드릴 코드의 경우 만약에 해당 위치에 파일이 존재하지 않거나 네트워크의 문제로 페이지를 불러올 수 없는 상황이라면 예외가 발생할 것입니다. 예외가 발생할 경우 var에 예외가 저장됩니다. <c:if>를 통해 예외가 발생했는지 확인하는 예제입니다
<c:catch var="exception"> <c:import url="ftp://ftp.example.com/package/README"/> </c:catch> <c:if test="${not empty exception}"> Sorry, the remote content is not currently available. </c:if>
<c:redirect>를 이용한 페이지 리다이렉트 하기
이 액션은 <jsp:forward> 액션과도 매우 흡사합니다. 하지만 이 기능의 경우에는 서버사이드에서 구현된 요청형태만을 포워딩 합니다. 이게 무슨 말이냐면 포워딩의 경우에는 사용자 입장에서 보면 페이지의 이동 없이 다른 페이지를 띄워줄 수 있지만 리다이렉트의 경우에는 브라우저에 의해 페이지의 이동이 일어나게 됩니다. 하지만 <c:redirect>액션이 좀 더 유연합니다. <jsp:forward>의 경우에는 현재 같은 서블릿 컨텍스트 내의 다른 페이지로만 이동 할 수 있기 때문입니다.
참고 : http://www.ibm.com/developerworks/java/library/j-jstl0318/