[Java] Tag라이브러리(JSTL) 사용하기

자꾸 까먹는 경향이 있어 기록용으로 저장해 둡니다. 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/