백엔드 자바 웹 프로그래밍

2.2. JSP

들어가면서

이번 장에서는 JSP에 대해 살펴본다. JSP는 자바 서블릿 기반의 동적 웹페이지 개발을 위한 기술이다.

JSP 학습을 통해

등에 대해 배우고 뷰(View) 개발에 활용할 수 있다.



JSP(Java Server Pages) 개요

JSP는 서블릿의 화면처리 어려움을 해결하기 위해 나왔으며 HTML 과 데이터를 조합하기 위해 다음과 같은 주요 기능적 특징을 가진다.

JSP 개발 및 동작 구조

JSP는 기본적으로 HTML 문서의 형식을 가진다. 물론 확장자는 .jsp여야 하며 page 지시어를 포함해야 한다. page 지시어를 포함한 JSP의 문서 구조는 뒤에서 다시 다룬다.

서블릿 컨테이너는 JSP 파일을 서블릿 구조의 .java 소스코드로 변환하며 컴파일을 수행한다. 컴파일이 완료되면 JSP는 더이상 파일로 부터 처리되는 구조가 아니라 컨테이너에 로드된 서블릿으로 동작하는 구조이다.

[그림: JSP 개발과 동작 과정]
  1. jsp 소스 코드 작성 -> 웹 애플리케이션 배포
  2. 사용자 요청시 컨테이너는 해당 jsp 의 클래스 변환 여부 확인
  3. 변환되지 않았다면 xxx_jsp.java 파일 생성 및 .class로 컴파일
  4. jspInit() 메서드를 통해 서블릿 실행
  5. _jspService() 메서드를 통해 사용자 요청 처리
  6. 이후 요청에 대해 메모리상의 서블릿으로 서블릿과 같이 서비스
  7. 컨테이너 종료 혹은 관리도구에의해 서블릿 jspDestroy() 호출로 종료

JSP 장단점

JSP의 장점은 다음과 같다.

반면 단점으로는

전반적으로 JSP 자체의 단점이라기 보다는 SSR(Server Side Rendering) 방식의 백엔드 웹 개발의 문제라 볼 수 있다.

JSP 구성 요소

JSP 파일의 구성 요소는 다음과 같다.

위와 같은 구성요소들은 각각 고유의 표기법과 속성등으로 구성되지만 결국에는 서블릿 형태의 소스로 변환되는 과정에서 자바 코드로 바뀌게 된다.



지시어(Standard directives)

지시어(Directives)는 해당하는 JSP 파일의 속성을 기술하는 곳으로, JSP 컨테이너에게 해당 페이지를 어떻게 처리해야 하는지 전달하기 위한 내용을 담고 있다. 지시어는 크게 page, include, taglib으로 나눌 수 있으며, 각각의 속성이 다르다.

지시어의 기본 형식은 다음과 같다.

<%@ directive attribute="value" %>  

page 지시어

page 지시어는 현재의 JSP 페이지를 컨테이너에서 처리(서블릿으로 변환)하는 데 필요한 각종 속성을 기술하는 부분으로, 소스코드 맨 앞에 위치하며 이클립스에서 jsp 파일을 생성할때 자동으로 포함되며 구문과 일반적인 사용예는 다음과 같다.

<%@ page page_directive_attr_list %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" import="java.util.*" errorPage="error.jsp"%>

대부분의 경우 위의 예시 정도만 알면 충분하다. 전체 속성의 확인이 필요하다면 000에서 찾아보기 바란다.

include 지시어

다른 파일을 포함하기 위한 지시어로 include 지시어가 사용된 위치에 해당 파일(html, jsp)을 불러온다. 컨테이너에서는 포함된 파일들을 하나로 처리하며 java 소스를 생성한 뒤 서블릿으로 컴파일 하게 된다.

따라서 포함되는 파일의 경우 단독 실행(해당 파일을 직접 요청해서 사용)을 하지 않는다고 하면 개별 구성요소(page 지시어, html 기본 태그 구성요소들)들을 갖출 필요가 없다.

include 액션은 include 지시어와 유사하게 동작하지만 지시어와 달리 각각의 파일들을 실행 시점에서 요청해 결과만 포함하는 구조이다.

include 지시어는 원하는 위치에 자유롭게 사용할 수 있으며 사용예는 다음과 같다.

<%@ include file="relativeURLspec" %>
<%@ include file="header.jsp" %>
<%@ include file="body.jsp" %>
<%@ include file="footer.html" %>

taglib 지시어

taglib 지시어는 jsp 의 태그 확장 메커니즘인 커스텀 태그를 사용하기 위한 지시어 이다. 커스텀 태그와 관련해서는 뒤에서 자세히 살펴보도록 한다.

taglib 지시어의 구문과 사용예는 다음과 같다.

<%@ taglib ( uri=”tagLibraryURI” | tagdir=”tagDir” ) prefix=”tagPrefix” %>
<%@ taglib tagdir="/WEB-INF/tags" prefix="m" %>
...
<h2><m:printData /></h2>


액션(Stardard actions)

액션은 커스텀 태그 기반으로 만들어졌으며 자바 빈즈 객체와의 연동이나 페이지간 연동 태그 파일 작성에 필요한 기능들을 제공한다. 표준 액션이라고도 불리우며 커스텀 태그 기반이지만 별도의 taglib 지시어 사용없이 jsp접두어를 사용한다.

주요 액션 태그는 다음과 같다.

액션 태그 설 명
jsp:forward request와 response 객체를 포함해 다른 페이지로 포워드.
jsp:include 다른 페이지의 실행결과를 포함 시킴.
jsp:useBean 자바 빈즈 객체를 생성하거나 불러옴.
jsp:setProperty 자바 빈즈 객체의 속성(멤버변수)에 값을 할당.
jsp:getProperty 자바 빈즈 객체의 속성값을 출력.
jsp:param include, forward 액션 사용시 파라미터 값을 수정하거나 추가.
[테이블: 주요 액션 태그]

자바 빈(Java Bean)

자바 빈은 자바의 재활용 가능한 컴포넌트 모델을 말하는 것으로 다음과 같은 기본 요구사항을 준수해야 한다.

단순하지만 정형화된 구조를 통해 여러 프로그램에서 동일한 방식으로 객체를 다루는 방법을 제공할 수 있다. 예를 들어 데이터베이스의 테이블 구조와 연동되어 데이터 매핑을 위한 엔티티 클래스로 사용하기 위한 Member 클래스는 다음과 같이 정의할 수 있다.

class Member {
  private int id;
  private String name;
  private String email;
  ...
  public void setId(int id) {
    this.id = id
  }
  public int getId() {
    return id;
  }
  ...
}

useBean 액션

jsp 에서 java bean 객체를 생성하거나 참조하기 위한 액션 이다. MVC 패턴의 컨트롤러를 jsp로 구현한다면 컨트롤러 jsp 에서 사용할 수 있지만 단순히 뷰의 역할을 하는 jsp 에서는 사용할 일이 없다.

기본적으로 특정 scope 에 주어진 id의 객체가 있으면 가지고 오고 아니면 생성하고 해당 scope에 저장합니다.

scope

useBean 에서 자바 빈 객체를 저장하기 위한 범위는 총 4개가 있다. 이들은 모두 내장객체와 동일한 이름을 사용하며 해당 내장 객체들은 빈 객체를 저장하거나 참조하기 위해 일종의 Map 형태의 구조를 가지고 있으며 각각 getProperty(), setProperty() 메서드를 사용한다.

scope 설 명
page 현재 jsp 범위. 서블릿의 service() 호출이 종료되면 소멸. 기본값
request 서블릿의 doGet(), doPost() 의 인자로 전달되는 request 객체와 동일. 기본적으로는 현재 페이지에서 유효하나 include, forward 액션의 경우 포함, 전달되는 페이지 까지 유지
session 세션 범위로 브라우저를 종료하거나 일정시간이 지나면 소멸. 페이지가 바뀌어도 유지되며 사용자간 공유되지 않는 고유 공간
application ServletContext 객체를 가리키며 해당 웹 애플리케이션의 수명주기와 같음. 사용자들이 모두 공유하는 영역

useBean

기본 구문과 사용 예는 다음과 같다.

<jsp:useBean id="instanceName" scope="page | request | session | application"   
class="packageName.className" type="packageName.className"  
beanName="packageName.className" >
</jsp:useBean>  

앞의 자바빈 설명에서 만든 Member 클래스를 이용한 활용 예는 다음과 같다. 컨트롤러에 의해 session 에 저장하는 과정이 있었다고 가정한다.

<jsp:useBean id="m" scope="session" class="com.my.Member />
<h2>Member Information</h2>
Name: ${m.name} <br>
Name: <%= m.name %> <br>
Name: <jsp:getProperty name="m" property="name" /> <br>

또다른 주요 활용 방법은 HTML 폼에서 입력한 값들을 자바 객체로 연동하는 경우 이다. 예를 들어 회원 가입을 처리하는 컨트롤러 jsp에서 사용자 정보를 데이터베이스와 연동하는 코드는 다음과 같다.

<jsp:useBean id="m" class="com.my.Member />
<jsp:setProperty name="m" property="*" />

<%
  MemberDAO dao = new MemberDAO();
  dao.insertDB(m);
%>

include, forward 액션

다른 jsp 파일을 현재 페이지에 포함하거나 전달하는 액션이다. 기본적으로 request 와 response 내장객체를 포함하고 있으며 <jsp:param> 액션을 통해 파라미터 값을 수정하거나 추가하는 것이 가능하다.

include 액션이나 include 지시어는 다른 페이지를 포함한다는 것에서는 동일하지만 처리 과정에는 차이가 있다. include 지시어에서는 include 된 파일 구조를 모두 포함해 하나의 파일로 컴파일해 처리하지만 include 액션은 include 된 파일을 실행해 처리된 결과를 포함해 보여주는 형식이다. 즉 jsp 파일에 대한 소스나 서블릿 클래스는 각각 생성된다.

# main.jsp
<jsp:include page="header.jsp">
  <jsp:param name="title" value="My homepage" />
</jsp:include>

# header.jsp
<h2><%= request.getParameter("title") %></h2>
or
<h2>${param.title}</h2>


템플릿 데이터

JSP의 화면 구성요소를 말한다. 시작 부분의 page 지시어를 제외하면 jsp 파일의 전반적인 구조는 html 문서 구조를 따른다. 일반적인 html 파일과 같이 CSS 및 JavaScript 사용이 가능하다.

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <style></style>
  <script></script>
</head>
<body>

</body>
</html>


스크립트 요소(Script Element)

JSP 의 특징중 하나가 HTML 과 자바 코드를 섞어 쓸 수 있다는 점이다. 물론 지금은 JSP 파일에서 직접적인 자바 코드 사용은 거의 하지 않고 있으나 반드시 알고는 있어야 한다. JSP에서 스크립트(자바코드)를 사용하기 위한 태그는 3개가 있다.

<%! %>

<%= %>

<h2><%= member.getUserName() %></h2>
현재날짜와 시간: <%= java.time.LocalDateTime.now() %>

<% %>

<%
  String name = request.getParameter("uname");
%>
<h2><%= uname %></h2>
<hr>
<table>
    <% for(Member m : mlist) { %>
        <tr>
            <td><%=m.name %></td>
            <td><%=m.email %></td>
        </tr>
    <% } %>
</table>


커스텀 태그와 EL

커스텀 태그(Custom Tag)

커스텀 태그는 사용자 정의 태그를 말하며 스크립트릿 사용을 줄이고 태그와 같은 형태로 프로그램 코드를 대체 하거나 재활용 가능한 구조를 통해 태그 라이브러리로 활용하고자 개발된 규격이다.

외형적인 형태는 xml(html) 태그 구조를 가지지만 서블릿 형태로 변환될 때 자바 코드로 변경되어 통합되는 구조이다.

커스텀 태그 사용을 위해서는 taglib 지시어를 통해 커스텀 태그가 어디에 정의 되어 있는지를 선언해야 하며 태그에 사용할 접두어를 지정한다. 커스텀 태그를 직접 구현하는 것은 여러 방법이 있으며 잘 사용하면 매우 편리 하지만 커스텀 태그 자체가 서버에서 해석되는 구조 이며 프로젝트가 특정 커스텀 태그에 종속될 수 있어 사용자가 직접 커스텀 태그를 만드는 것은 점점 줄어들고 있다.

대신 커스텀 태그 기술로 만들어진 <jsp:useBean> 이나 <jsp:setProperty>와 같이 JSP 에 기본적으로 제공되는 action 태그는 JSP 개발에 꼭 알아야 하는 주요 요소 이다. 또한 몇몇 유용한 기능을 구현해 둔 JSTL(JSP Standard Tag Library)의 경우 개발에 꼭 필요한 요소가 된다.

다음은 커스텀 태그의 사용 예 이다.

<%@ taglib tagdir="/WEB-INF/tags" prefix="m" %>

<m:printData pid="87459989" />

커스텀 태그를 통해 만들어진 useBean 액션은 jsp 에서 객체의 생성과 내장객체의 라이프사이클을 이용해 페이지 전환등에도 객체 인스턴스를 유지하고 서로 다른 페이지에서 참고하기 위한 용도로 널리 사용 된다.

<jsp:useBean id="member" class="com.my.Member" scope="session" />

<h2><jsp:getProperty name="member" property="name" /></h2>

<jsp:getProperty>는 다음과 같이 두가지 방법으로 대체가 가능하며 EL 사용이 권장된다.

<!--JSP 표현식을을 이용한 출력-->
<h2><%= member.getName() %></h2>

<!--EL을 이용한 출력-->
<h2>${member.name}</h2>

표현언어(Expression Language, EL)

EL은 현재 페이지의 자바 객체 혹은 application, session, request, page 와 같은 내장객체에 저장된 자바 객체(Java Bean)를 손쉽게 접근하고 사용할 수 있게 해준다. 기본적으로 데이터를 표현하기 위한 용도로 설계된 구조로 제한된 객체참조가 가능하며 해당 객체의 메서드를 직접 호출하는것은 불가능 하다.

앞에서 ${member.name} 이 EL을 사용한 것이며 단순한 출력 이외에 사칙연산과 비교, AND, OR, 3항연산 등을 지원한다. JSP 에서 논리적인 처리를 하게 되면 코드가 분산되기 때문에 가능한 출력 용도로 사용하는 것이 좋다.

EL의 장점은 다음과 같다.

자바빈 접근

기본적으로 ${저장이름.변수명} 형태로 사용한다. 예를 들어 session scope 에 객체를 저장하는 방법은 다음과 같다.

<%
  Member m = new Member(request.getParameter("name"));
  session.setAttribute("member",m);
%>

<h2>${m.name}</h2>

동일 jsp내에서 선언된 변수나 객체는 EL을 통해 바로 사용이 가능하고 페이지가 바뀌는 경우 scope에 해당하는 내장객체를 사용해 저장후 참조해야 한다.

앞에서 저장된 객체는 다른 jsp에서 다음과 같이 출력할 수 있다.

<h2>${member.name}</h2>

내장객체 접근

자바빈 참조를 위한 JSP 내장객체 접근은 내장객체명Scope 형식의 이름으로 사용할 수 있으나 특정 scope 을 지정하는 것이 아니라면 EL 을 사용하면 되기 때문에 현실적으로 거의 필요가 없다. 그 외 request 파라미터를 가지고 올 수 있는 param, paramValues 가 있다.

즉, request.getParameter("uname") 대신 ${param.uname} 을 사용하면 된다. 그외 항목들은 잘 사용되지 않는다.

EL 연산

기본적인 사칙연산, 논리연산, 관계연산, 3항연산 등이 가능하다.

${10+20}  // 30
${10*20}  // 200
${true && false}   // false
${10 >= 20}   // false
${user.name == "홍길동"? "교수" : "학생"}  // 3항연산

배열, 맵 데이터 연동

참조하는 객체가 배열이나 맵 형태인 경우 다음과 같이 사용할 수 있다.

${myList[0]}
${myMap["name"]}


JSTL(Jsp Standard Tag Library)

JSTL 은 JSP에서 스크립트릿 즉, 자바 코드 블럭을 사용하지 않고 HTML 형식을 유지 하면서 조건문, 반복문, 간단한 연산과 몇몇 유용한 기능들을 손쉽게 사용할 수 있도록 지원하기 위해 만들어진 표준 커스텀태그 라이브러리 이다.

커스텀태그에서 언급한것 처럼 서버에서만 해석가능한 태그 구조로 인해 디자이너와의 협업에 불편한 부분이 있고 개발과정에서 UI확인을 위해 서버를 통해야만 하는 비효율적인 문제가 존재한다. 물론 일반 사용자 입장에서는 차이가 없지만 모바일 환경 중심의 프론트엔드 개발 트렌드와는 다소 거리가 있다.

규격상 JSTL은 core, xml, I18N(다국어 처리), 데이터베이스, 함수 등으로 구성되어 있으나 View 중심의 JSP구현에는 core 정도만 사용된다.

설치

JSTL은 표준 규격이므로 사용하기 위해서는 실제 구현된 라이브러리가 필요하다. 여러 구현 버전이 있지만 Apache Standard Taglib 을 주로 사용한다.

라이브러리 파일을 다운로드해서 WEB-INF/lib 폴더에 복사 하거나 maven, gradle 등의 빌드 도구를 사용할 경우 설정 파일에 해당 라이브러리 의존선을 추가하면 된다.

다운로드: http://tomcat.apache.org/download-taglibs.cgi

JSF(JavaServer Faces)는 JSTL과 유사하게 커스텀태그로 만들어진 표준 태그라이브러리로 Java EE 애플리케이션에서 컴포넌트 기반의 UI를 손쉽게 제작하고 활용하기 위해 나온것으로 사용 목적이 UI에 특화되어 있다는 점을 제외하고는 JSTL와 장단점을 같이 한다. 자세한 사항은 http://javaserverfaces.java.net 참조.

taglib 지시어 추가

JSTL 을 JSP에서 사용하려면 taglib 지시어를 추가해 주어야 한다. core 라이브러리 사용을 위해서는 다음과 같이 작성 한다.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

태그라이브러리 규격상 접두어는 원하는 대로 사용할 수 있지만 c 사용이 권장 된다.

core 라이브러리

주요 core 라이브러리 사용법을 알아 본다.

기능 태그 사용 예
Variable support remove, set 변수 지정과 삭제
Flow control choose/when/otherwise, forEach, forTokens, if 조건처리, 반복, 토큰 파싱
URL management import, redirect,url, param URL 핸들링
Miscellaneous catch, out 에러 처리, 출력

주로 사용하는 태그는 Flow control 이다.

해당 조건에 맞으면 태그 바디 부분을 실행한다. 자바의 if와 유사하지만 else 는 지원하지 않는다. 조건 테스트를 위한 속성을 참조할 범위(scope)를 지정할 수 있다.

<c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]>
body content
</c:if>

사용예는 다음과 같다.

<c:if test="${msg == 'user1'}" var="result">
test result : ${result}
</c:if>

가장 많이 사용하는 태그 이다. 반복해서 화면에 데이터를 출력할 때 주로 사용한다. java 의 for문과 같다고 이해하면 된다. 커스텀 태그 특성상 정밀한 설정이 가능하지 않기 때문에 제공되는 속성들을 잘 활용해야 한다. forEach 는 진행 상태를 확인하기 위한 몇몇 정보를 제공한다.

<c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin" end="end“
[step="step"]>
body content
</c:forEach>

사용예는 다음과 같다.

<c:forEach var="i" items="${members}" begin="0" varStatus="status" end="5">
index: ${status.index} /
count: ${status.count} <BR>
name: ${i.name} <BR>
email: ${i.email} <BR>
<HR>
</c:forEach>


실습-1: JSP 기본 종합 예제

JSP 주요 구성요소들에 대한 종합 실습 예제

실습 코드랩


실습-2: include 지시어와 액션

include 지시어와 액션의 차이점과 사용법 실습 예제

실습 코드랩


실습-3: JSTL과 EL 종합 예제

다양한 JSTL과 EL 사용 예제

실습 코드랩