티스토리 뷰

JavaServer PagesTM (JSPTM)가 점점 널리 웹기반 어플리케이션으로 자리잡아가면서, 개발과 유지보수에 종사하는 많은 JSP 프로그래머들과 웹 개발자들은, 예전에 자바프로그래머들이 겪었던 것과 같은 딜레마에 직면했다. "어떻게 JSP 코드를 짜면 읽기, 쓰기, 유지보수하기를 일관적으로 쉽게 할 수 있을까?"

이 글은, 웹 컴포넌트를 사용하는 전형적인 소프트웨어 프로젝트에서 준수해야 할 JSP(1.1 과 1.2버전) 표준 작성요령을 제안한다. 이 문서의 모체는 자바 언어 코드 작성요령이다. (JSP 와 관련된) 코드 작성 방법 스펙에 소개된 다양하고 중요한 요소들을 확인할 수 있는 템플릿으로 삼았다. 특히, 파일명, 구성, 들여쓰기, 주석, 지시자, 선언문, 스크립틀릿, 표현식, 공백, 명명법(이름 짓는 법), 프로그래밍 습관 등을 소개한다. 처음으로 시도되는 JSP 코드 작성요령이기 때문에, 이 권고 문서에 대한 여러분들의 관심과 피드백을 기다린다. 연락처는 jsp-codeconv-comments@sun.com이다.

JSP 2.0 스펙에서는 1.2 버전을 모두 포용하지만, 스크립트가 없는 프로그래밍 스타일(선언문, 스크립틀릿, 표현식이 없는)을 지향하고, 수많은 새 특징들을 갖고 있어서, 이 작성요령을 더 진보시켜야 될 필요가 있다. 가능한 한, 이 문서는 새로운 JSP 2.0 특징에 도움을 주는 작성방식을 선택했다.

마지막으로, 이 글을 읽는 수준은 JSP, Java, 자바 코드 작성요령에 익숙해야 하고, 이미 프로젝트를 수행하는 팀에 적용이 되어 있어야 된다. 그렇지 않다면, 이 링크를 읽어 보기를 추천한다. Java 링크 JSP 링크.

 

왜 코드 작성요령이 필요한가? Why Have Code Conventions?

코드 작성요령은 프로그래머와 웹 컨텐츠 개발자에게 여러 가지 이유로 중요하다:

  1. 소프트웨어 산출물의 가독성을 향상시킨다.
  2. 견습 관리와 노력을 경감한다.
  3. 표준화에 대한 조직적 참여도를 배가시킨다.

파일 이름과 위치 File Names and Locations

파일 이름짓기는 툴 벤더와 웹 컨테이너로 하여금 파일 타입을 인식하고, 각각에 맞게 해석할 수 있는 방법을 제공한다. 다음 테이블은 추천하는 방식의 파일 확장자와 위치 목록이다. 

File Type File 확장자 추천 위치
JSP .jsp <context root>/<subsystem path>/
JSP fragment .jsp <context root>/<subsystem path>/
.jspf <context root>/WEB-INF/jspf/<subsystem path>/
cascading style sheet .css <context root>/css/
javascript .js <context root>/js/
HTML page .html <context root>/<subsystem path>/
web resource .gif, .jpg, etc. <context root>/images/
tag library descriptor .tld <context root>/WEB-INF/tld/

위 테이블을 볼 때 몇 가지 유념할 것이 있다. 우선, <context root> 는 웹 어플리케이션(.war 파일 내의 루트 디렉토리) 컨텍스트의 루트이다. 둘째로, <subsystem path> 는 동적, 정적 웹페이지 컨텐츠의 논리적인 그룹으로 나누도록 한다. 작은 웹 어플리케이션일 경우, 이게 필요하지 않을 수도 있다. (한 곳에 모두 놓아도 된다.)

세째로, 다른 JSP 파일에 포함되는 JSP 를 언급할 때 JSP fragment (JSP 프래그먼트 조각)라는 용어를 사용한다. 주의할 것은 JSP 2.0 에서는 "JSP fragment" 용어가 겹치기 때문에 "JSP 세그먼트(JSP segment)" 용어가 대신 사용된다. JSP fragment 는 확장자로 .jsp 또는 .jspf 를 사용하고, /WEB-INF/jspf나 다른 정적인 컨텐츠와 함께 각각 위치하면 된다. 불완전한 JSP fragment는 언제나 .jspf 확장자를 사용하고, /WEB-INF/jspf에 위치해야 된다. 네째로, JSP 스펙에서는 JSP fragment 확장자로 .jspf.jsp 양쪽 모두를 권장하지만, 추천하는 것은 .jspf 인데, .jsfJavaServer Faces™ 스펙에서 사용될 것이기 때문이다.

끝으로, 태그 라이브러리 디스크립터 파일이나 다른 비공개적인 컨텐츠는 WEB-INF/ 또는 이 하위 디렉토리에 놓아두는 것은 보편적으로 좋은 습관이다. 웹 컨테이너는 WEB-INF/ 아래 있는 어떤 파일도 송출하지 않기 때문에, 이 방법을 사용하면, 클라이언트가 접근하거나 볼 수 없게 된다.

배치 설명자(web.xml)의 welcome-file 엘리먼트에 선언되어 있는 웰컴 파일의 이름은 동적인 컨텐츠를 생성하려면, index.jsp 가 되어야 되고, 정적인 웰컴 페이지라면 index.html 로 해야 한다. 

JSP 파일을 다국어로 작성할 때, 로케일에 따라 디렉토리를 나누어 그룹 짓기를 추천한다. 예를 들어서 index.jsp 의 US English 버전은 /en_US/index.jsp 에, 같은 파일의 일본어판은 /ja_JP/index.jsp  에 있게 한다. 일반적으로 자바 코드의 국제화에 관한 추가적인 정보는 Java Tutorial 에 있고, 웹 어플리케이션의 국제화에 대한 정보는 Designing Enterprise Applications with the J2EETM Platform 책에 나와있다.

파일 구조 File Organization

구조가 잘 갖춰진 소스 코드 파일은 읽기 쉽고, 파일 사이에 정보를 더 빨리 놓아둘 수 있다. 이 섹션에서, JSP와 태그 라이브러리 디스크립터 파일 모두를 위한 구조를 소개하려한다.

JSP 파일 / JSP Fragment 파일

JSP 파일은 다음의 섹션들이 나열한 순서대로 구성된다:

  1. 도입 주석
  2. JSP 페이지 지시자(directive)
  3. 선택적 태그 라이브러리 지시자
  4. 선택적 JSP 선언문
  5. HTML 과 JSP 코드

도입 주석 Opening Comments

JSP 파일 또는 프래그먼트 파일은 서버측 주석으로 시작한다:

<%--
  - 작성자:
  - 일자:
  - 저작권 표시:
  - @(#)
  - 설명:
  --%>

이 주석은 서버측에서만 볼 수 있다. JSP 변환 과정에서 제거되기 때문이다. 여기에는 웹 개발자를 위한 JSP에 대한 작성자, 일자, 개정판의 저작권, 증명과 설명이 포함된다. "@(#) " 문자 조합은 증명의 시작을 지시하는 것으로 어떤 프로그램에서 인식된다. 이런 표식을 사용하는 프로그램들은 많이 사용되지 않지만, 있어도 해가 될 것은 없다. 추가로, 이 조합은 때때로 "$Id$" 를 덧붙여서, 어떤 종류의 버전 관리 프로그램에서는 자동으로 증명 정보를 JSP에 기록하도록 한다. 설명 부분은 JSP의 목적에 관한 축약된 정보를 제공한다. 한 문단 이상 넘어가지 않도록 한다.

어떤 상황에서는, 도입 주석이 JSP 변환과정을 지나서 출처가 확실하다는 뜻과 법적인 목적으로 클라이언트의 브라우저에 보여질 필요가 있다. 이럴 경우 주석 부분을 두개로 나눠서 우선 클라이언트측 스타일의 주석을 단다:

<!--
  - Author(s):
  - Date:
  - Copyright Notice:
  --%>

그리고 나서 짧아진 나머지 서버측 스타일의 주석을 단다:

<%--
  - @(#)
  - Description:
  --%>

JSP 페이지 지시자 JSP Page Directive(s)

JSP 페이지 지시자는 JSP 변환 시점에 관련된 속성을 정의한다. JSP 스펙은 같은 페이지에 JSP 페이지 지시자의 수량을 제한하지 않는다. 그래서 다음 두 개의 코드 예제는 똑같다.(다른 점이 있는데, 첫 예제는 출력시에 맨 위에 두 개의 빈 줄이 포함된다):

코드 예제 1:

<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page errorPage="/common/errorPage.jsp" %>

페이지 지시자 같이 지시자의 길이가 일반적인 JSP 폭(80 문자)을 넘어갈 경우 여러 줄로 나눠진다:

코드 예제 2:

<%@ page    session="false"
            import="java.util.*"
            errorPage="/common/errorPage.jsp"
%>

일반적으로, 코드 예제 2는 코드 예제 1보다 즐겨 사용된다. 예외가 있는데, 매우 긴 import 속성을 쓰게 되는, 여러 개의 자바 패키지가 JSP페이지에서 필요할 경우이다:

<%@ page    session="false"
               import="java.util.*,java.text.*,
                   com.mycorp.myapp.taglib.*,
                       com.mycorp.myapp.sql.*, ..."
...
%>

이런 경우, 페이지 지시자를 다음과 같이 나누는 것이 즐겨사용된다:

<%-- import를 제외한 모든 속성 --%>
<%@ page
...
%>
<%-- import 속성들은 여기부터 시작 --%>
<%@ page import="java.util.*" %>
<%@ page import="java.text.*" %>
...

주의할 점은, 일반적으로 import문은 자바의 지역 코드 작성요령을 준수한다. 예를 들어, 같은 패키지에서 세 개의 클래스까지만 사용되면, import 는 패키지를 선언하기 보다는, 클래스를 일일이 선언한다. 세 개를 넘어가면, 클래스를 일일이 지정할 것인지 아니면, ".*" 표시를 사용할 것인지는 웹 개발자 마음이다. 전자의 경우, 외부 클래스가 무엇이 사용되는지를 쉽게 알수 있다. 특히 버그가 많은 클래스를 위치시키려고 하거나, JSP 가 자바 코드와 어떻게 상호작용하는지를 이해하려할 경우에 유용하다. 예를 들어서, 아래처럼 임포트한 자바 패키지들에 관해 알지 못하면, 웹 개발자는 Customer 클래스를 찾기 위해서 이 모든 패키지들을 검색해봐야 된다:

<%@ page import="com.mycorp.bank.savings.*" %>
<%@ page import="com.thirdpartycorp.cashmanagement.*" %>
<%@ page import="com.mycorp.bank.foreignexchange.*" %>
...

후자의 경우, 작성된 JSP 가 깔끔하지만, 사용한 클래스가 무엇인지 아는 것은 어려워진다. 일반적으로, JSP 에 임포트 지시자가 너무 많으면, 자바 코드가 너무 많이 들어가 있기 쉽다. 보다 나은 선택은 JSP 태그를 더 사용하는 것이다.(후에 언급하겠다).

선택적 태그 라이브러리 지시자 Optional Tag Library Directive(s)

태그 라이브러리 지시자는 JSP 에서 사용하는 커스텀 태그 라이브러리를 선언한다. 짧은 지시자는 하나의 줄에 선언할 수 있다. 여러 개의 태그 라이브러리 지시자들은 JSP 의 한 곳에 같이 모아둔다:

<%@ taglib uri="URI1" prefix="tagPrefix1" %>
<%@ taglib uri="URI2" prefix="tagPrefix2" %>
...

페이지 지시자처럼, 태그 라이브러리 지시자의 길이가 일반적인 JSP 폭(80 문자)을 넘어갈 경우 여러 줄로 나눠진다:

<%@ taglib
    uri="URI2"
    prefix="tagPrefix2"
%>

오직 페이지에서 사용하는 태그 라이브러리만 임포트되어야 한다.

JSP 1.2 부터, 웹 어플리케이션의 JSP에 JSTL;JSP 표준 태그 라이브러리사용하기를 적극 권장한다. 페이지에서 JSP 스크립틀릿 사용할 필요를 줄여주기 때문이다. 일반적으로, JSTL을 사용하는 페이지는 소스읽기와 유지보수가 보다 편하다.

선택적 JSP 선언문 Optional JSP Declaration(s)

JSP 선언문은 JSP에서 소속된 메소드와 변수를 선언한다. 이들 메소드와 변수는 자바 프로그램에서의 선언문과 다를바 없다. 그래서 적절한 코드 작성요령을 따르기만 하면 된다. 선언문은 <%! ... %> JSP 선언문 블록 하나에 모두 몰아서 한 곳에 집중해 놓는 것이 좋다. 예를 들면:

다른 선언문 블록들 바람직한 선언문 블록
    <%! private int hitCount; %>
    <%! private Date today; %>
    ...
    <%! public int getHitCount() {
            return hitCount;
        }
    %>
    
    <%!
        private int hitCount;
        private Date today;

        public int getHitCount() {
            return hitCount;
        }
    %>

HTML 과 JSP 코드 HTML and JSP Code

이 섹션은 JSP 코드와 HTML 이 섞여있는 페이지에 대해 설명한다. JSP 표현식, 스크립틀릿, 자바빈즈 지시자 등이 해당된다.

태그 라이브러리 설명서 Tag Library Descriptor

태그 라이브러리 설명서(TLD)는 적당한 XML선언과 올바른 DTD 문으로 시작한다. 예를 들어서, JSP 1.2 TLD 는 다음과 같이 시작해야 된다:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
    "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

바로 뒤이어 서버측 주석과 같은 스타일의 주석을 기입한다. 작성자, 일자, 저작권, 증명 정보, 라이브러리에 대한 짧은 설명이다:

<!--
  - 작성자:
  - 일자:
  - 저작권 표시:
  - @(#)
  - 설명:
  -->
 

여기에 관한 규칙과 가이드라인은 JSP 파일/프래그먼트 파일에서 정의된 것과 동일하다.

태그 라이브러리 파일의 나머지는 다음에 나오는 순서대로 이루어져 있다:

  • 태그 라이브러리 검증기 하나의 선택적 선언문
  • 이벤트 리스너들의 선택적 선언문
  • 하나 이상의 가능한 태그들의 선언

TLD 에서 엘리먼트 마지막에 선택적 서브 엘리먼트를 항상 덧붙이기를 추천한다. 이 선택적 서브 엘리먼트는 태그 디자이너가 TLD의 습성과 추가적인 정보를 문서화할 장소를 제공한다. 이것은 웹 컴포넌트 개발자들에게는 보이지 않게 된다.

TLD Element JSP 1.2 Recommended
Sub-element
JSP 1.1 Recommended
Sub-element
attribute (JSP 1.2) description  
init-param (JSP 1.2) description  
tag display-name, description, example name, info
taglib uri, display-name, description uri, info
validator (JSP 1.2) description  
variable (JSP 1.2) description  

들여쓰기 Indentation

들여쓰기는 반드시 공백문자로 채워야한다. 탭은 사용하는 에디터마다 표시하는 공백의 수가 다르기 때문에 JSP 내에서 들여쓰기로 사용하기에는 적합하지 않다. 특별히 통합개발환경(IDE) 툴에서 제한되지 않았다면, 기본 들여쓰기 단위는 4개의 공백문자로 한다. 다음은 그 사용예이다:

<myTagLib:forEach var="client" items="${clients}">
    <myTagLib:mail value="${client}" />
</myTagLib:forEach>

연속 들여쓰기는 이전 줄의 적당한 지점에서 시작한다. 연속 들여쓰기의 공백은 기본 들여쓰기 공백의 배수이다. (4개의 공백문자의 배수):

<%@ page    attribute1="value1"
            attribute2="value2"
            ...
            attributeN="valueN"
%>

스크립트 엘리먼트의 들여쓰기 Indentation of Scripting Elements

JSP 스크립트 엘리먼트(선언문, 스크립틀릿, 표현식과 같은)가 한 줄에 맞지 않는 경우, 스크립트 언어의 들여쓰기 작성요령이 엘리먼트 내에 적용된다. 몸체는 엘리먼트의 여는 기호 <%=와 같은 줄에서 시작한다. 다음줄의 기준도 여는 기호 <%=가 된다. 몸체의 끝은 다른 줄에 있는 엘리먼트의 닫는 기호(%>)로 마무리된다. 예제이다:

<%= (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
        = Calendar.SUNDAY) ?
    "Sleep in" :
    "Go to work"
%>

첫줄과 마지막 줄을 제외한 몸체의 가운데 줄들은 단위 들여쓰기 공백(앞 예제에서  로 보인다)이 앞에 있기 때문에 나머지 JSP 보다 확연히 드러나게 된다.

JSP, HTML, JAVA의 복합 들여쓰기 Compound Indentation with JSP, HTML and Java

자바의 스크립트 코드와 템플릿 텍스트(HTML)가 섞여있는 JSP 엘리먼트를 위해서 복합 들여쓰기가 필요한 이유는 JSP 소스를 이해하기 위해 드는 노력을 덜어주기 위해서이다. 기존의 들여쓰기 요령은 JSP 소스파일을 더 알아보기 어렵게 할 수 있기 때문이다. 보편적인 규칙에 따라서, 다른 소스 사이에 끼어 있을 경우마다 보통 들여쓰기에 특별한 단위를 할당한다. 클라이언트에 보여지는 들여쓰기에 영향을 준다. 추가적인 들여쓰기는 (브라우저에 의해) 보통 무시되고, 브라우저에 나타나는 결과는 차이가 없다. 예를 들어, <TABLE> 태그 앞에 공백이 몇 개 더 추가된다고 해서, 브라우저에서 보여지는 테이블의 위치가 달라지는 것은 아니다. 그래서 이러한 작성요령을 사용하는 것이 더 좋아 보인다:

    <table>
        <%  if { tableHeaderRequired ) { %>
            <tr>
                <th>Last Name</th>
                <th>First Name</th>
            </tr>
        <%  } %>
        <c:forEach var="customer" items="${customers}">
            <tr>
                <td><c:out value="${customer.lastName}"/></td>
                <td><c:out value="${customer.firstName}"/></td>
            </tr>
        </c:forEach>
    </table>

위 방식보다는 아래 방식이 낫다:

    <table>
        <%  if { tableHeaderRequired ) { %>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
        </tr>
        <% } %>
        <c:forEach var="customer" items="${customers}">
        <tr>
            <td><c:out value="${customer.lastName}"/></td>
            <td><c:out value="${customer.firstName}"/></td>
        </tr>
        </c:forEach>
    </table>

주석 Comments

주석은 추가 정보 전달이나 코드를 둘러쌀 목적으로 사용한다. 여기서는 JSP에서 사용하는 두가지 형태의 주석을 볼 것이다: JSP 측과 클라이언트 측 주석이다.

JSP 주석 JSP Comments

JSP 주석(또는 서버 측 주석)은 서버에서만 볼 수 있다(즉, 클라이언트로 전파되지 않는다). 순수 JSP 주석을 스크립팅 언어와 섞여있는 JSP 주석보다 즐겨 사용한다. 전자가 기반 스크립트 언어에 덜 종속적이기 때문이고, JSP 2.0 으로 진화하기 더 쉽기 때문이다. 다음 도표는 이것을 설명한다:

Line JSP 스크립틀릿과 스크립트 언어 주석 순수 JSP 주석
한 줄
    <% /**  ...  */ %>
    <% /*  ...  */ %>
    <% //  ...  %>
    
    <%--  ...  --%>
    
여러 줄
    <%
    /*
     *
    ...
     *
     */
    %>
    
    <%--
      -
     ...
      -
      -- %>
    <%
    //
    //
    ...
    //
    %>
    

클라이언트 측 주석 Client Side Comments

클라이언트 측 주석(<!-- ... -->)은 응답에 대해서 부가적인 정보를 클라이언트로 보내기 위해 응답에 주석을 다는 것이다. 서버 어플리케이션의 행동이나 내부적인 구조에 대한 것과 응답 내용을 생성하는 코드가 포함되어서는 안된다.

클라이언트/사용자의 입장에서 서버에서 보내온 응답을 해석하기 위해서 이런 종류의 주석을 직접 볼 필요가 없기 때문에, 클라이언트 측 주석은 보편적으로 사용되지 않는다. 앞서 얘기한대로 증명이나, 저작권 정보 등의 법적인 목적의 증명에 사용될 경우는 예외가 되겠다. 다른 예외적인 경우는 HTML 저작도구들이 HTML 문서 구조의 틀을 잡아주기 위해 작은 양의 HTML 주석들을 사용하는 경우가 되겠다. 예를 들면 다음과 같다:

<!-- 툴바 섹션 -->
    ...
<!-- 왼쪽 네비게이션 메뉴 -->
    ...
<!-- main body -->
    ...
<!-- footer -->
    ...

여러 줄의 주석 Multiline Comment Block

JSP 또는 클라이언트 측 모두, 여러 줄의 주석은 대시 문자 "-" 로 꾸며진다. XML 스펙에서, 더블-대시 문자열 "--"은 XML 주석 문 내에 허용되지 않는다. 그러므로, 이 스펙에 호환성과 일관성을 갖기 위해서, 더블-대시 문자열은 여러줄의 주석문 내에 사용되면 안된다. 다음 도표는 클라이언트 측 여러 줄 주석 사용법을 보여준다:

권장 XML과 맞지 않는 법
    <!--
      - line 1
      - line 2
    ...
      -->
    
    <!--
      -- line 1
      -- line 2
    ...
      -->
    

JSP 선언문 JSP Declarations

자바 코드 작성요령에 따라서, 같은 타입의 변수 선언문은 다른 줄에서 이루어져야 된다:

비 추천 추천
    <%! private int x, y; %>
    
    <%! private int x; %>
    <%! private int y; %>
    

자바빈즈는 <jsp:useBean> 액션 태그를 사용하는 대신, JSP 선언문을 통해서 선언되고 인스턴스화되면 안된다.

일반적으로, 변수를 위한 JSP 선언문은 그 자체가 스크립트 언어의 사용을 부추기기 때문에 사용하지 않는 것이 좋다. JSP 는 프리젠테이션 목적으로 설계되었는데, 여기에 비지니스 로직과 자바코드를 섞어놓기 때문이다. 그리고, 변수의 스코프 관리에 따른 부담도 생기게 된다.

JSP 스크립틀릿 JSP Scriptlets

가급적, 태그라이브러리로 동일한 기능을 구현할 수 있으면, JSP 스클립틀릿은 피하기 바란다. 이렇게 하면 페이지 가독성도 높이고, 유지보수도 쉬워진다. 비지니스 로직을 프리진테이션 로직에서 분리하는데 일조하며, JSP 2.0 스타일의 페이지로 쉽게 옮겨갈 수 있다(JSP 2.0 도 스크립틀릿을 지원하지만 덜 강조한다). 다음 예제는 customers 표시 방법이 데이터 형에 따라서 다른 스크립틀릿을 사용하는 것을 보여준다:

customers 는 Customers의 배열

    <table>
        <%  for ( int i=0; i<customers.length; i++ ) { %>
            <tr>
                <td><%= customers[i].getLastName() %></td>
                <td><%= customers[i].getFirstName() %></td>
            </tr>
        <%  } %>
    </table>

customers 는 Enumeration

    <table>
        <%  for ( Enumeration e = customers.elements();
                e.hasMoreElements(); ) {
                Customer customer = (Customer)e.nextElement();
        %>
            <tr>
                <td><%= customer.getLastName() %></td>
                <td><%= customer.getFirstName() %></td>
            </tr>
        <%  } %>
    </table>

그러나, 공통 태그라이브러리를 사용하면, customers 의 데이터 형이 달라도 보다 높은 유연성이 생긴다. 예를 들어서, JSTL 에서는customers 를 나타내기 위해서 배열과 Enumeration 양쪽 모두 지원하는 다음과 같은 코드로 표시할 수 있다:

    <table>
        <c:forEach var="customer" items="${customers}">
            <tr>
                <td><c:out value="${customer.lastName}"/></td>
                <td><c:out value="${customer.firstName}"/></td>
            </tr>
        </c:forEach>
    </table>

비지니스 로직과 프리젠테이션 층과의 결합도을 줄이기 위한 모델-뷰-컨트롤러(MVC) 디자인 패턴을 적용하려고 한다면, JSP 스크립틀릿은 비지니스 로직을 구현하기 위해서 사용되어서는 안된다. 오히려, JSP 스크립틀릿은 클라이언트의 요청을 처리한 뒤에 나오는 데이터("가치 객체 value objects"로 불리는)를 적절한 클라이언트의 준비된 형식에 전송하기 위해 필요하다면 사용된다. 심지어 그럴 경우에도, 프론트 컨트롤러 서블릿이나 커스텀 태그로 하는 게 더 낫다. 예를 들면, 다음의 코드는 데이터베이스에서 직접 customers 의 이름을 가져와 클라이언트에 보여준다:

<%
    // 스크립틀릿을 이용하는 것은 추천하지 않음!

    Connection conn = null;
    try {
        // Get connection
        InitialContext ctx = new InitialContext();
        DataSource ds = (DataSource)ctx.lookup("customerDS");
        conn = ds.getConnection();

        // Get customer names
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT name FROM customer");

        // Display names
        while ( rs.next() ) {
            out.println( rs.getString("name") + "<br>");
        }
    } catch (SQLException e) {
        out.println("Could not retrieve customer names:" + e);
    } finally {
        if ( conn != null )
            conn.close();
    }
%>

다음의 JSP 코드는 데이터베이스 처리부분을 내부적으로 데이터베이스 코드의 의존성을 숨기고 캡슐화한 커스텀태그myTags:dataSource에 위임하고 있기 때문에 더 보기 좋다:

<myTags:dataSource
    name="customerDS"
    table="customer"
    columns="name"
    var="result" />
<c:forEach var="row" items="${result.rows}">
    <c:out value="${row.name}" />
    <br />
</c:forEach>

result 는 커스텀 태그 myTags:dataSource가 customer 데이터베이스에서 customer의 이름들 뽑아낸 결과를 담으려고 만들어 낸 스크립팅 변수이다. JSP 코드는 클라이언트의 요구에 따라 동적으로 다른 종류의 출력(HTML, XML, WML)을 생성하기 위해 확장할 수 있다. 그것도 백엔드 코드(dataSource 태그를 위한)를 변경하지 않고도 가능하다. 더 나은 선택은 이것을 프론트 컨트롤러 서블릿에 위임하는 것이다. 이 서블릿은 데이터를 불러와서 그 결과를 request 스코프의 속성을 통해서 JSP에 제공한다. 예제는 자바 BluePrint의 엔터프라이즈 섹션을 참고하기 바란다.

요약하면 :

  • 이상적으로, 스크립트 언어로부터 독립하기 위해서 JSP 스크립틀릿은 JSP 내에서 사라져야 되고, JSP 내의 비지니스 로직 구현은 피해야 된다.
  • 그것이 불가하면, 서버 측에서 정보를 전달하는데 값 객체(자바빈즈)를 사용하고, JSP 스크립틀릿은 클라이언트 출력에 이 값 객체를 전달하는 데 사용한다.
  • 가능하면 커스텀 태그(태그 핸들러)를 사용해서 서버측에서 정보를 처리하도록 한다.

JSP 표현식 JSP Expressions

JSP 표현식은 JSP 스크립틀릿처럼 가능하면 삼가는 것이 좋다. 동일한 작업을 수행하는 다음 3가지 예제가 잘 설명해준다:

Example 1 (자바 코드 사용):

    <%= myBean.getName() %>

Example 2 (JSP 태그 사용):

    <jsp:getProperty name="myBean" property="name" />

Example 3 (JSTL 태그 사용):

    <c:out value="${myBean.name}" />

Example 1 은 myBean 이라는 스크립트 변수가 선언된 것이라고 가정한다. 다른 두 예제에서 myBean은 어떤 스코프의 속성으로 PageContext.findAttribute()을 통해서 접근할 수 있다고 가정한다. 두 번째 예제는 또한 <jsp:useBean> 에 의해서 페이지에 소개된 myBean이라고 가정한다.

셋 중에서 JSTL 태그 예제가 낫다. JSP 표현식 만큼 짧고, 가독성도 좋고, 유지보수하기도 보다 편하다. 그리고, 자바 스크립틀릿에 의존하지 않는다(스크립틀릿은 자바 언어와 API 함수들에 익숙해야 다룰 수 있다.) 더우기, JSP 2.0 스타일 프로그램으로 쉽게 이동할 수 있는 장점이 있다. 어떤 선택이 채택되든, 모든 개발자들의 동의를 얻어서, 같은 프로젝트에 있는 JSP 결과물들은 전체적으로 일관된 방식을 사용해야 된다.  주의할 점은, JSTL 예제는 로컬 자바 스크립트 변수로부터가 아닌, page 컨텍스트로부터 myBean 의 값을 가져온다는 것이 실질적으로 조금 다른 점이다.

마지막으로, JSP 표현식은 기반 스크립팅 언어의 문법에 의존하는, 같은 기능의 JSP 스크립틀릿보다 낫다. 예를 들어,

    <%= x %>

로 하는 게 아래 방법보다 좋다.

    <% out.print( x ); %>

공백 White Space

코드의 이해와 유지보수에 드는 노력을 줄이기 위해서 JSP 코드를 보기 좋게 들여쓰기하는데 공백을 사용한다. 특히, 빈 줄과 공백은 필요한 곳에서 JSP 의 여러 곳에 삽입되어야 한다.

빈 줄 Blank Lines

빈 줄은 출력에 원하지 않는 영향만 주지 않는다면 JSP의 가독성을 높이기 위해서 가끔 사용된다. 아래 예제에서, HTML <PRE> 블록 내에 두 개의 JSP 표현식 사이에 있는 빈 줄은 클라이언트의 브라우저에 HTML 출력 결과에서 한줄 더 생기게 만든다. 그러나 빈 줄이 <PRE> 블록 사이에 있지 않다면, 브라우저의 출력에 나타나지 않는다.

JSP 구문 클라이언트의 HTML 출력
    <pre>
    <%= customer.getFirstName() %>
    <%= customer.getLastName() %>
    </pre>
    
    Joe
    Block
    
    <pre>
    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>
    </pre>
    
    Joe

    Block
    
    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>
    
    Joe Block
    

빈 문자열 Blank Spaces

공백 문자( ; 역자주:공백은 길이가 1, 빈 문자열은 ""처럼 길이가 0)는 JSP 태그와 몸체 사이에 쓰여져야 된다. 예를 들어 다음

    <%= customer.getName() %>

코드는 아래 것보다 좋다.

    <%=customer.getName()%>

JSP 주석 태그와 주석을 분리하는 공백 문자들이 있어야 된다:

<%--
  - 여러 줄의 주석이 나뉘어지면, 각각의 줄은
  - 한 줄씩 차지한다.
  --%>
<%-- 짧은 주석 --%>

이름짓는 요령 Naming Conventions

이름짓는 요령을 적용하면, 프로젝트 내의 웹 컴포넌트 엘리먼트들을 쉽게 확인, 분류, 통합할 수 있다. 이 섹션에서, JSP에 적합한 요령을 살펴보자.

JSP 이름 JSP Names

JSP (파일) 이름은 언제나 소문자로 시작해야 한다. 여러 개의 단어로 구성될 수 있고, 이러한 경우 단어들은 모두 붙여쓰고, 이어지는 단어의 첫글자는 대문자로 쓴다. JSP 이름은 간단한 명사나 짧은 문장이 될 수 있다. 동사뿐인 JSP 명은 개발자에게 충분한 의미를 전달하지 못하기 때문에, 피하도록 한다. 예를 들면:

    perform.jsp

파일은 다음 파일보다 명확하지 않다.

    performLogin.jsp

JSP 이름에 동사가 들어가는 경우, 은연 중에 뒷쪽에서 처리하고 있다는 표시로 현재형을 쓴다:

    showAccountDetails.jsp

로 쓰는 게 아래 파일명 보다 좋다

    showingAccountDetails.jsp

태그 이름 Tag Names

태그 핸들러와 관련된 클래스에 대한 이름짓는 요령은 다음과 같다:

설명 클래스 명
XXX tag extra info (javax.servlet.jsp.tagext.TagExtraInfo를 상속함) XXXTEI
XXX tag library validator (javax.servlet.jsp.tagext.TagLibraryValidator를 상속함) XXXTLV
XXX tag handler interface (javax.servlet.jsp.tagext.Tag/IterationTag/BodyTag를 상속함) XXXTag
XXX tag handler implementation XXXTag

덧붙여, 태그 이름은 자바에 관련된 코드작성법에서 정한 클래스와 인터페이스 이름 짓는 요령을 따라서 정해야 된다.

태그 관련된 클래스와 다른 클래스와 더 분명하게 구분하기 위해서, 패키지 접미사(tags 또는 taglib)를 클래스의 패키지명에 적용한다. 예를 들면:

    com.mycorp.myapp.tags.XXXTag

태그 prefix 이름 Tag Prefix Names

태그 prefix 는 짧지만 의미가 담긴 명사를 사용해야 하고, 첫문자는 소문자로 해야한다. 태그 prefix 는 알파벳 문자만 포함해야 된다. 몇 가지 예를 들면 다음과 같다:

OK?
mytaglib no
myTagLib yes
MyTagLib no
MyTagLib1 no
My_Tag_Lib no
My$Tag$Lib no

XML 문법의 JSP 페이지 JSP Pages in XML Syntax

JSP 는 두가지 다른 문법을 제공한다: JSP 페이지를 작성하는 '표준 문법'과 JSP를 XML문서로 작성하는 'XML 문법'이 있다. 표준 문법을 사용하는 JSP 페이지들이 'JSP 페이지'로 많이 쓰인다. XML 문법으로 작성된 JSP는 'JSP 문서'라고 일컫는다. 이 기사는 우선적으로 JSP 페이지를 소개하지만, 많은 부분의 개념들이 JSP 문서에도 역시 적용될 수 있다. XML이 좀 더 유행하면 JSP 문서 사용도 많아질 것이라고 기대된다. JSP 2.0 스펙에서는 더 많은 XML 문법 친화적인 것들이 소개될 것이다.

주의할 것은 XML 문법을 이용해서 JSP를 만드는 것과 JSP로 XML 결과(view)를 만들어 내는 것과 혼동해서는 안된다. 페이지 제작도구는 JSP를 만들기 위해 표준 또는 XML 문법을 사용한다. 그리고 나서 컨테이너는 JSP를 XML 결과로 변환하고, 이것은 태그 라이브러리 밸리데이터(유효성 검증기)에서 확인한다.

JSP 문서 구조 JSP Document Structure

JSP 문서는 다음과 같은 기본 구조를 갖는다:

    <? xml version="1.0" ?>
    <!--
      - Author(s):
      - Date:
      - Copyright Notice:
      - @(#)
      - Description:
      -->
    <jsp:root   xmlns:jsp="http://java.sun.com/JSP/Page"
                xmlns:prefix1="URI-for-taglib1"
                xmlns:prefix2="URI-for-taglib2"
                version="1.2">
        JSP Document ...
    </jsp:root>

첫 줄은, 이 페이지가 XML 문서라고 정의하는 선택적 XML 프롤로그이다. 다음으로 오는 것은 문서에 대한 주석이다. <jsp:root> 엘리먼트는 이것이 JSP 문서임을 정의하고, 반드시 이 엘리먼트가 루트 엘리먼트로 나타나야 된다. jsp 이름공간은 반드시 가져와야 되고, 모든 태그 라이브러리는 이 루트 엘리먼트를 사용해서 가져와야 된다. 버전 속성이 필요하고, 어떤 버전을 사용할 지를 정해준다. JSP 문서의 실제 내용은 <jsp:root> 엘리먼트의 서브엘리먼트에 나타난다. 표준 XML 들여쓰기 룰에 따라서 문서 전체적으로 일관되게 적용하는 들여쓰기 단위는 4개의 공백문자이다.

JSP 문서는 형식이 잘 갖춰진 XML 문서이기 때문에, <% %> 와 같은 엘리먼트는 <jsp:scriptlet /> 같이 XML로 바꿔서 표기해야 된다. 자세한 것은 JSP 스펙을 보기 바란다.

XML 주석 XML Comments

JSP 스펙은 XML 스타일의 주석을 어떻게 처리할 지에 대해 불분명하기 때문에, 주석이 클라이언트로 안전하게 전달되기 위해서는, <jsp:text>로 다음과 같이 감싸주어야 된다:

    ...
    <jsp:text><![CDATA[
        <!--
          - Multiline comment
          - to be sent to client.
          -->
    ]]></jsp:text>
    ...

JSP 문서 내의 자바 코드 Java Code in JSP Documents

선언문, 스크립틀릿, 표현식에서 자바 코드를 쓰려고 할 때, 코드가 문서의 구조를 망가뜨리지 않는다면, CDATA엘리먼트를 사용한다.

    ...
    <jsp:scriptlet>
        for( int level = 0; level < 3; level++ ) {
    </jsp:scriptlet>
    <tr>
        <td>
            <jsp:expression><![CDATA[
                "<h" + level + ">Text</h" + level + ">"
            ]]></jsp:expression>
        </td>
    </tr>
    <jsp:scriptlet>
        }
    </jsp:scriptlet>
    ...

표준 문법에서와 다르게, XML 들여쓰기 법칙은 엘리먼트의 내용과 상관없이 준수되어야 한다.

프로그래밍 습관 Programming Practices

일반적으로, 다음과 같은 이유로 JSP 페이지에 자바 코드(선언문, 스크립틀릿, 표현식) 쓰기를 피한다:

  • JSP 페이지의 자바 코드 문법 에러는 페이지가 배치되기 전까지 발견되지 않는다. 반면에, 태그 라이브러리와 서블릿에 있는 문법 에러는 배치 이전에 발견된다.
  • JSP 페이지 내의 자바 코드는 디버깅하기 힘들다.
  • JSP 페이지 내의 자바 코드는 유지보수하기 힘들다. 특히 자바 전문가가 아니라면 더욱 더 그렇다.
  • 보통 복잡한 비즈니스 로직과 프리젠테이션 로직을 섞어놓지 않는 것이 납득이 가는 습관이다. JSP는 우선적으로 프리젠테이션 로직을 목적으로 한다.
  • 자바 코드가 포함된 코드와 HTML과 다른 스크립트 명령어가 섞여있다면 더 읽기 어려워진다.
  • JSP 2.0 은 더 단순한 표현 언어를 덕분에 스크립틀릿의 중요도를 낮추었다. JSP 에서 JSP 2.0 스타일로 쉽게 옮기기 위해서는 페이지에서 자바 코드를 사용하지 않는 것이 좋다.

자바 BluePrints의 엔터프라이즈 섹션에 있는 더 자세한 정보와 가이드라인을 참고하기 바란다.

자바빈즈 초기화 JavaBeans Initialization

JSP는 JavaBeanTM의 프로퍼티로 증명되는 모든 PropertyDescriptor를 초기화하기 위해 편리한 엘리먼트를 제공한다. 예를 들면:

    <jsp:setProperty name="bankClient" property="*"/>

그러나, 주의해서 사용해야 한다. 첫째로, 빈이 프로퍼티를 갖고 있다, 즉 amount 프로퍼티가 있다고 하고, 현재 ServletRequest 객체에 파라미터(amount)가 없거나 파라미터 값이 ""라고 한다면, 아무것도 하지 않는다: JSP는 빈의 특정 프로퍼티에 null를 할당하지도 않는다. bankClient 빈에 amount의 기존 값이 무엇이든지 간에 영향을 받지 않는다. 둘째로, PropertyEditors를 선언하지 않은 비-요소적인 프로퍼티는 ServletRequest 객체의 스트링 값에서 암묵적으로 초기화 되지 않기 때문에, 명시적인 변환이 필요하다. 세째로, 만일 어플리케이션이 주의 깊게 설계되지 않았다면, 악의를 가진 사용자는 추가적으로 요청 파라미터를 덧붙여서 빈의 사용하지 말아야할 프로퍼티 값을 설정할 수 있다.

깔끔한 코드를 위해서 jsp:setProperty 태그에 property="*"를 사용한다면, jsp:setProperty 태그 이전에 ServletRequest 객체를 통해서 받아와야 할, 빈을 초기화하기 위한 파라미터들에 대해 주석을 달기를 권한다. 다음 예제에서는 bankClient 빈을 초기화하기 위해서 firstNamelastName 파라미터가 필요하다는 것을 주석에서 읽을 수 있다:

<%--
  -  ServletRequest에서 firstName와 lastName를 요구
  --%>
<jsp:setProperty name="bankClient" property="*" />

JSP 내장 객체 JSP Implicit Objects

API 호출을 통해서 객체를 참조하기 보다는 JSP 내장 객체를 직접 사용하는 것이 좋다. 그래서 ServletContext 인스턴스에 의해 제공되는 초기 파라미터에 접근하기 위해 다음을 쓰는 대신에

    getServletConfig().getServletContext().getInitParameter("param")

기존 내장 객체를 사용하는 게 낫다:

    application.getInitParameter("param")

초기 파라미터 값이 출력이 되어야 하는 경우에는, JSTL로 접근해서 출력하는 것이 더 좋다:

    <c:out value="${initParam['param']}" />

인용부호 Quoting

일정한 인용부호의 사용을 채택한다. 인용부호는 작은따옴표 ' 대신 큰따옴표 " 를 사용한다.

불규칙한 인용부호 좋은 인용부호 사용
<%@ page import='javabeans.*'%>
<%@ page import="java.util.*" %>
<%@ page import="javabeans.*" %>
<%@ page import="java.util.*" %>

예외적인 경우는 작은따옴표가 필요할 때이다. 예를 들어서 스크립트 언어에서 큰따옴표를 사용하는 경우를 들 수 있다:

    <jsp:include page='<%= getFoodMenuBar("Monday") %>' />

커스텀 태그 사용하기 Using Custom Tags

만일 커스텀태그가 몸체가 없다면, 컨텐트는 (생략해서 "JSP" 기본값으로 하지 말고) empty라고 명확하게 선언되어야 한다. 태그 라이브러리 설명서에서 다음과 같이 정해준다:

<tag>
    <name>hello</name>
    <tag-class>com.mycorp.util.taglib.HelloTagSupport</tag-class>
    <body-content>empty</body-content>
    ...
</tag>

이렇게 하면 JSP 컨테이너는 태그 몸체가 무조건 비어야 되며 파싱할 어떤 JSP 문법도 포함하지 않아야 된다고 인식한다. 효과는 빈 몸체를 파싱하기 위해서 불필요하게 자원의 할당이 이뤄지는 것을 제거한다.

빈 태그는, 가독성향상을 위해 열고 닫는 XML 엘리먼트 쌍으로 표시하기보다는, 짧은 XML 엘리먼트로 표시한다. 그래서

    <myTag:hello />

라고 표기하는 것이 아래보다 낫다.

    <myTag:hello></myTag:hello>

TagExtraInfo와 TagLibraryValidator 사용 Use of TagExtraInfo and TagLibraryValidator

때때로, 태그 라이브러리를 사용하는데 TLD 하나로 유효성을 검증할 수 없는 경우가 있다. 그 때는 TLD에 등록된 TagExtraInfo 클래스나 TagLibraryValidator 클래스를 사용해서, 변환할 때 태그 라이브러리에 있는 에러를 잡아낼 수 있다.

자바스크립트 사용 Use of JavaScriptTM

스크립트가 제대로 돌아가기 위해서는 자바스크립트는 브라우저 타입의 특성과 관계없어야 된다.

동작을 한다면, JSP에서 자바스크립트 코드를 독립적인 파일로 분리하고, 다음과 같이 JSP에서 자바스크립트를 불러쓰는 방식은 좋은 생각이다:

<script language=javascript src="/js/main.js">

이렇게 하면 자바스크립트의 재사용성도 향상되고, 여러 JSP 사이에 일관된 습성의 자바스크립트를 유지할 수 있고, JSP페이지의 복잡성을 줄여준다.

캐스케이딩 스타일 시트 CSS Cascading Style Sheets

CSS를 사용해서 헤딩, 테이블 등의 공통적인 특성을 중앙에서 제어하도록 한다. 이 방법은 사용자들에게 프리젠테이션의 일관성을 향상시키고, 유지보수 노력과 JSP 페이지의 코드 사이즈를 줄여준다. 그래서, 다음과 같이 HTML 태그에서 스타일 정보를 끼어쓰지 말고:

<H1><FONT color="blue">Chapter 1</FONT></H1>
...
<H1><FONT color="blue">Chapter 2</FONT></H1>
...

하나의 스타일 시트 파일myJspStyle.css에 다음과 같은 스타일 정보를 정의한다:

H1 { color: blue }

그리고 JSP 페이지에 스타일 시트를 적용한다:

<link rel="stylesheet" href="css/myJspStyle.css" type="text/css">
...
<H1>Chapter 1</H1>
...
<H1>Chapter 2</H1>
...

컴포짓 뷰 패턴 사용 Use of Composite View Patterns

여러 JSP 페이지에서 반복되는 고정되고 복잡한 구조가 요구될 때, 이것을 다루는 방법으로 컴포짓 뷰 패턴(Composite View pattern;자바 Blueprints 의 패턴 섹션 참고)을 사용해서, 조각조각으로 나눠서 처리하는 법이 있다. 예를 들어, 프리젠테이션 구조에서 JSP 는 때때로 다음과 같은 로직 레이아웃을 갖고 있다:

header
menu bar main body
footnote
footer

이런 방식으로, 컴포짓 JSP 는 각각 분리된 JSP로 구현되는 다른 모듈로 나뉠 수 있다. 구성성분이 되는 JSP는 서블릿으로 변환할 때나 요청시에 include JSP 태그를 사용해서 컴포짓 JSP 의 적당한 위치에 놓이게 된다. 보편적으로, 독립적으로 요청되지 않는 페이지를 불러쓰는, 정적인 include 지시자를 사용할 때는 .jspf 확장자를 사용하고, 웹 어플리케이션 (war)에서 /WEB-INF/jspf/ 디렉토리에 놓아둘 것을 기억하기 바란다. 예를 들면 다음과 같다:

<%@ include file="/WEB-INF/jspf/header.jspf" %>
...
<%@ include file="/WEB-INF/jspf/menuBar.jspf" %>
...
<jsp:include page="<%= currentBody %>" />
...
<%@ include file="/WEB-INF/jspf/footnote.jspf" %>
...
<%@ include file="/WEB-INF/jspf/footer.jspf" %>
...

다른 추천사항 Other Recommendations

이 문서에서, JSP 코드와 웹 컴포넌트를 작성하는데 보다 유지보수하기 쉽고, 일관된 추천 코드 작성법 한 세트를 제시했다. 이 주제에 보다 더 관심있다면, 더 많은 최고의 작성법이 존재한다. 예를 들어, JSP 1.2 스펙에서는 다음을 추천한다:

  • 새로운 내장 객체 선언하기
  • 벤더 고유의 안내서 읽기
  • 커스텀 태그 라이브러리 사용하기

덧붙여서, 자바 BluePrints 는 더 큰 스케일에서 최고의 작성법을 제공한다. (패턴 섹션에서 보여지는) 모델-뷰-컨트롤러 패턴과 같은 것을 예로 들 수 있다.

우리는 이 문서에서 제시한 작성요령에 대한 여러분의 의견에 관심이 있습니다. JSP 코드 작성요령에 대해서 여러분의 다른 의견이 있다면 나누면 좋겠습니다. 피드백은 여기로 보내기 바랍니다. jsp-codeconv-comments@sun.com.

아래에, 위에서 설명한 코드 작성요령을 적용해 놓은 완전한 웹 어플리케이션의 소스를 소개한다. 이 어플리케이션의 WAR 파일을 여기 에서 다운로드 받을 수 있다.

코드 예제 Code Examples

여기에 있는 웹 어플리케이션 예제는 이 문서에 있는 내용이 어떻게 적용되는지 보여주기 위한 것이다. .war 파일에는 다음의 소스코드 파일과 디렉토리 구조로 되어 있다:

/index.jsp
/WEB-INF/classes/codeconv/GetResultsTag.class
/WEB-INF/jspf/footer.jspf
/WEB-INF/lib/jstl.jar
/WEB-INF/lib/standard.jar
/WEB-INF/tld/lotterylib.tld
/WEB-INF/web.xml

index.jsp 페이지에서는 오늘까지 포함된 이번 달의 모의 복권 추첨결과를 보여주는 커스텀 태그 라이브러리( lotterylib.tld )를 사용한다. 그리고, HTML 에 보여질 결과를 형식화하고, 반복하기 위해서 JSTL을 사용한다.

예제는 JSP 1.2 과 JSTL 1.0 을 사용한다.

/index.jsp 파일 소스

<%--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Renders fake lottery results for the current month.
  --%>

<%@ taglib prefix="c"
    uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt"
    uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="lottery"
    uri="http://codeconv/lotterylib" %>

<html>
    <head>
        <title>Fake Lottery Results for this Month
        </title>
    </head>
    <body>
        <jsp:useBean id="now" class="java.util.Date" />
        <h1>
            Fake Lottery Results for
            <fmt:formatDate value="${now}"
                pattern="MMMM yyyy" />
        </h1>
        <hr />
        <table border="1" cellpadding="5">
            <%-- Store current month and year --%>
            <c:set var="currentMonth">
                <fmt:formatDate value="${now}" pattern="M" />
            </c:set>
            <c:set var="currentYear">
                <fmt:formatDate value="${now}"
                    pattern="yyyy" />
            </c:set>

            <%-- Determine last day to report results for --%>
            <c:set var="endDay">
                <fmt:formatDate value="${now}" pattern="d" />
            </c:set>

            <%-- Display one row for each day --%>
            <c:forEach var="day" begin="1" end="${endDay}">
                <%-- Construct date --%>
                <c:set var="dateString">
                    <c:out value="${currentMonth}/${day}/${
                        currentYear}" />
                </c:set>

                <fmt:parseDate  var="date"
				    value="${dateString}"
                        pattern="M/d/yyyy" />
                <jsp:useBean id="date" class="java.util.Date"
                    />

                <tr>
                    <td>
                        <c:out value="${dateString}" />
                    </td>
                    <%-- Retrieve and display fake results
                            for this day --%>
                    <lottery:getResults var="numbers"
                        date="<%= date %>" />
                    <c:forEach var="number" items="${numbers}">
                        <td>
                            <c:out value="${number}" />
                        </td>
                    </c:forEach>
                </tr>
            </c:forEach>
        </table>
        <%@ include file="/WEB-INF/jspf/footer.jspf" %>
    </body>
</html>

/WEB-INF/classes/codeconv/GetResultsTag.java 소스

/*
 * codeconv.GetResultsTag
 *
 * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
 *
 * This software is the proprietary information of
 * Sun Microsystems, Inc.
 * Use is subject to license terms.
 *
 * Version: @(#)
 *
 * Date: January 13, 2003
 *
 */

package codeconv;

import java.util.Date;
import java.util.Random;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * Retrieves fake lottery results for the given date and
 * returns the result in the given attribute
 *
 * @version @(#)
 * @author Mark Roth
 */
public class GetResultsTag extends TagSupport {

    /** The maximum number that can be drawn */
    private static final int MAX_NUMBER = 58;

    /** The number of numbers that are drawn */
    private static final int NUMBER_COUNT = 6;

    /** The variable to store results to */
    private String var;

    /** The date on which the numbers were drawn */
    private Date date;

    /** The PageContext, used to return the result */
    private PageContext pageContext;

    /**
     * Remember the PageContext so it can be used later
     * to return the result.
     *
     * @param pageContext The page context of the calling page
     */
    public void setPageContext( PageContext pageContext ) {
        this.pageContext = pageContext;
    }

    /**
     * Returns fake lottery results for the given date.
     *
     * @return EVAL_PAGE so the rest of the page is evaluated.
     */
    public int doEndTag() throws JspException {
        // Generate the (fake) results.
        Random random = new Random( this.date.getTime() );
        int[] result = new int[NUMBER_COUNT];
        for( int i = 0; i < NUMBER_COUNT; i++ ) {
            result[i] = random.nextInt( MAX_NUMBER ) + 1;
        }

        // Place the result in the scoped attribute named by 'var'.
        pageContext.setAttribute( this.var, result );

        return EVAL_PAGE;
    }

    /**
     * Setter for date
     *
     * @param date The fake date on which the lottery numbers
     * were drawn
     */
    public void setDate( Date date ) {
        this.date = date;
    }

    /**
     * Getter for date
     *
     * @return The fake date on which the lottery numbers
     * were drawn
     */
    public Date getDate() {
        return this.date;
    }

    /**
     * Setter for var
     *
     * @param var The name of the variable to store the result in
     */
    public void setVar( String var ) {
        this.var = var;
    }

    /**
     * Getter for var
     *
     * @return The name of the variable to restore the result in
     */
    public String getVar() {
        return this.var;
    }
}

/WEB-INF/jspf/footer.jspf 소스

<%--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Sample Footer that can be included on pages.
  - Assumes JSTL fmt taglib is imported.
  --%>
<!-- common footer -->
<hr />
<jsp:useBean id="footerNow" class="java.util.Date" />
<i>
    Last Updated:
    <fmt:formatDate type="both" value="${footerNow}"
                    dateStyle="full" timeStyle="full" />
</i>

/WEB-INF/tld/lotterylib.tld 파일 소스

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
    "http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">

<!--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Tag Library for fake lottery results.
  -->

<taglib>
    <tlib-version>1.0</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>lottery</short-name>
    <uri>http://codeconv/lotterylib</uri>
    <display-name>FakeLotteryTaglib</display-name>
    <description>
        Tag Library for fake lottery results.
    </description>

    <tag>
        <name>getResults</name>
        <tag-class>codeconv.GetResultsTag</tag-class>
        <body-content>empty</body-content>
        <display-name>getResults</display-name>
        <description>
            Retrieve an array of fake lottery results for the given
            date and store them in the given scoped attribute.
        </description>
        <variable>
            <name-from-attribute>var
                </name-from-attribute>
            <declare>true</declare>
            <description>
                The fake lottery results for the given date.
            </description>
        </variable>
        <attribute>
            <name>var</name>
            <required>true</required>
            <description>
                The name of the variable to store the results in.
            </description>
        </attribute>
        <attribute>
            <name>date</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.util.Date</type>
            <description>
                The date on which the fake lottery numbers
                    were drawn.
            </description>
        </attribute>
        <example><![CDATA[
            <lottery:getResults var="numbers"
                date="${date}" />
        ]]></example>
    </tag>
</taglib>

/WEB-INF/web.xml 소스

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<!--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Web Deployment Descriptor for JSP 1.2 fake
  - lottery example
  -->

<web-app>
    <display-name>FakeLotteryExample</display-name>
    <description>
        JSP 1.2 example application that illustrates correct JSP
        coding style.
    </description>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <taglib>
        <taglib-uri>http://codeconv/lotterylib</taglib-uri>
        <taglib-location>/WEB-INF/tld/lotterylib.tld
            </taglib-location>
    </taglib>
</web-app>

감사의 말 Acknowledgments

이 문서의 이전 드래프트에 소중한 조언을 제공해 주신 Gregory Murray (Java BluePrints Team), Damian Fauth (Sun Java Center), Kate Morris (Sun Java Center) 님들께 감사드립니다.

References

  1. Code Conventions for the Java Programming Language.
  2. JSP best practices.
  3. Hans's Top Ten JSP Tips.
  4. JavaServer Pages Specification version 1.2.
  5. Alur D., Crupi J., Malks D., Core J2EE Patterns: Best Practices and Design Strategies, Sun Microsystems Press, Prentice Hall Inc., 2001.
  6. Naming Conventions for Enterprise Applications.
  7. JavaServer Pages Standard Tag Library.
  8. Gamma E., Helm R., Johnson R., Vlissides J., Design Patterns: Elements of Reusable Software, Addison-Wesley, 1995.
  9. JavaServerTM Faces Technology.
  10. Java BluePrints.
  11. Designing Enterprise Applications with the J2EETM Platform, 2nd ed..
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함