2011년 6월 9일 목요일

JavaServer Faces 사용하기

저자: 안드레이 키오뢰아누(Andrei Cioroianu), 역 이상화

JSF는 자바 개발자에게 웹 기반의 사용자 인터페이스를 작성하기 위한 API와 태그 라이브러리를 제공한다. 아파치 스트럿츠 프레임워크를 만든 저작자이면서 썬의 JSF 프로젝트의 공동작업자로 활동하고 있는 크레이그 맥클라나한(Craig McClanahan)은 이러한 것들이 아파치 프로젝트를 JSF 표준으로 쉽게 갈 수 있게 해준다고 믿고있다. 스트럿츠 프레임워크와 같이 JSF는 자바 빈즈 속성에 연결된 HTML 폼 요소를 생성하는 JSP 태그 집합을 가지고 있다. 개발자의 관점에서는 이 두 프레임워크가 비슷해 보이지만 JSF는 자바 표준이기 때문에 좀더 많은 개발 도구의 지원을 받게 될 것이다. 앞으로는 모든 J2EE 애플리케이션 서버가 JSF를 지원하게 될 것으로 예상된다.

Sun은 최근 JSF 1.0 EA4 버전을 JWSDP 1.2(Java Web Services Developer Pack 1.2)에 포함하였다. EA4 버전은 액션, 빈즈 관리, 네비게이션 규칙과 같은 새로운 기능을 가지고 있다. 본 기사는 이러한 새로운 모습에 초점을 두고 폼을 작성하거나 사용자 입력을 검증하고 사용자 인터페이스 컴포넌트를 자바 빈즈에 연결하기 위한 JSF의 장점을 보여줄 것이다.
관련기사:
JavaServer Faces 입문 -- JSF는 서버측 프로그래밍의 차세대 주자이다. JSF는 프로그래밍환경을 좀더 편하고 즐겁게 그리고 유지보수가 쉽게 만들 것이다. Budi Kurniawan는 JSF가 유용성과 요구사항을 어떻게 만족 하는지 설명하고 있다.



본 기사는 4개의 메인 컴포넌트로 이루어진 웹 애플리케이션을 포함하고 있다. 자바 빈즈 클래스(PBean.java)는 폰트, 크기, 컬러, 정렬과 같은 속성을 가지고있는 데이터 모델 역할을 한다. JSF 기반의 폼(edit.jsp)은 사용자가 자바 빈즈의 속성값을 변경할 수 있게 해준다. 다른 자바 클래스(PBuilder.java)는 텍스트와 속성들로 구성된 HTML 문단을 생성해낸다. 마지막으로 JSP페이지(view.jsp)는 생성된 문단을 보여준다.
[그림 1] JSF 기반 폼
JSF 폼 만들기
소스 코드
여기에서 소스코드를 다운받을 수 있다.

HTML 폼을 처리하는 작업은 웹 애플리케이션 개발에 필수적인 일상작업 중 하나이다. 좋은 프레임워크의 경우 반복적인 작업들을 자동화 할 수 있거나 XML 파일 내에 관련 설정을 줄일 수 있기 때문에 개발시간을 단축시킬 수 있다. 또한 JSP 태그 라이브러리를 사용하여 웹 개발을 단순화시키는 것도 가능하다. JSF 프레임워크는 HTML 폼을 표현할 수 있는 JSP 태그 라이브러리를 제공하며, 폼의 상태를 유지하고 있거나, 사용자 입력을 검증하고, 자바빈즈 속성과 사용자 인터페이스 컴포넌트를 묶는 작업을 한다. 이런 사항들 외에도 생산성을 높이기 위해 다른 많은 일들을 한다. JSF는 또한 커스텀 사용자 인터페이스, 커스텀 검증 클래스, 서버측 이벤트 리스너를 위한 풍부한 API를 가지고 있다.

JSF는 Core와 HTML Basic의 두 가지 태그 라이브러리를 포함하고 있다. 전자는 UI 컴포넌트에 이벤트 리스너, 검증자를 등록하는 태그와 일반적인 태그들을 제공한다. 후자는 버튼, 텍스트 입력창, 체크박스와 같은 HTML UI 컴포넌트를 표현하는 JSP 태그를 가지고 있다. edit.jsp 페이지는 폼을 만들기 위해 이러한 많은 태그를 이용한다. 두개의 태그 라이브러리는 f와 h라는 표준 접두어를 갖고 edit.jsp 상단에 선언된다.
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<f:use_faces> 태그는 페이지에 쓰이는 모든 JSF 태그를 반드시 포함해야 하는 컨테이너 태그이다. HTML 내용을 만들어 내지는 않지만 내부 JSF 메커니즘을 호출한다. <h:form> 태그는 UI 컴포넌트를 포함하고 있는 <form> HTML 요소를 생성한다.
<html>
<head>
<title>Edit</title>
</head>
<body>

<f:use_faces>
   <h:form formName="pform">
   ..........
   </h:form>
</f:use_faces>

</body>
</html>

상단의 JSP 코드는 다음과 같은 HTML 코드를 만들어 낸다.
<html>
<head>
<title>Edit</title>
</head>
<body>
   <form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   </form>
</body>
</html>

다음 부분에서는 애플리케이션의 자바 빈즈 모델을 설명한다.

빈즈 다루기

다른 웹 프레임워크처럼 JSF는 데이터와 애플리케이션 로직을 캡슐화 하는 모델 객체로 부터 UI를 분리시킨다. HTML UI가 JSF 태그로 부터 생성되면 JSF 프레임워크는 자바 빈즈 모델으로 부터 데이터를 얻거나 HTML 폼을 만들어내는 UI 컴포넌트의 상태를 조정한다. 사용자가 폼을 제출하면 JSF는 사용자 입력을 검증한다. 검증 결과가 정상이면 JSF는 사용자 입력을 자바 빈즈에 저장하고 HTTP 요청은 "네비게이션 규칙"에 따라 다른 페이지로 이동하게 된다.

자바 빈즈 패턴을 따르고 java.io.Serializable를 상속받은 PBean 클래스는 속성들(텍스트, 크기, 폰트, 컬러, 정렬, 볼드체/이탤릭체/밑줄 등과 같은 폰트 종류: text, size, font, color, align, bold, italic, underline)의 get , set 메소드를 제공한다. JSF는 각각의 애플리케이션 사용자에 대해 faces-config.xml 파일에 설정된 PBean ID를 가지는 session 범위의 PBean 인스턴스를 만든다. 또한 JSF는 faces-config.xml 파일에 제공되어지는 값들을 가지고 자바 빈즈 인스턴스의 속성값을 초기화 한다. 이 파일은 다음 기사에서 소개할 네비게이션 규칙과 같은 JSF 설정 파라미터를 가지고 있다.

다음 XML 부분은 JSF에 의해 유지되는 자바 빈즈에 관련된 설정을 보여주고 있다.
<?xml version="1.0"?>

<!DOCTYPE faces-config PUBLIC
   "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
   "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

<faces-config>
   ..........
   <managed-bean>
      <managed-bean-name>pbean</managed-bean-name>
      <managed-bean-class>
           com.devsphere.articles.usingjsf.PBean
       </managed-bean-class>
       <managed-bean-scope>session</managed-bean-scope>
       <managed-property>
           <property-name>text</property-name>
           <null-value/>
       </managed-property>
       <managed-property>
           <property-name>size</property-name>
           <value>3</value>
       </managed-property>
       <managed-property>
           <property-name>font</property-name>
           <values>
               <value>Arial</value>
               <value>Courier New</value>
           </values>
       </managed-property>
       <managed-property>
           <property-name>color</property-name>
           <value>green</value>
       </managed-property>
       <managed-property>
           <property-name>align</property-name>
           <value>left</value>
       </managed-property>
       <managed-property>
           <property-name>bold</property-name>
           <value>false</value>
       </managed-property>
       <managed-property>
           <property-name>italic</property-name>
           <value>true</value>
       </managed-property>
       <managed-property>
           <property-name>underline</property-name>
           <value>false</value>
       </managed-property>
   </managed-bean>
</faces-config>

JSF에 의해 생성된 빈은 <managed-bean-scope> 요소에 따라 요청, 세션, 애플리케이션 범위 안에 저장될 수 있다. 정해진 범위 안에서 주어진 ID가 객체가 이미 등록되어 있다면 JSF는 자바 빈즈 인스턴스를 생성하지 않는다.

UI 컴포넌트와 검증

edit.jsp의 <h:form> 요소는 다음 부분에서 상세하게 설명할 몇몇 UI 컴포넌트를 포함하고 있다. 각 컴포넌트의 HTML 코드는 <h:input_textarea> 태그나 <f:validate_required>와 같이 사용자 입력의 검증여부를 JSF에게 알리는 역할의 태그에 의해 생성된다. 사용자 입력을 처리하는 컴포넌트들은 valueRef="pbean.property"를 통해 자바 빈즈 속성들과 연결되어 있다. JSF 는 이전에 설명한 빈즈 속성들을 위해 get, set 메소드를 사용한다. JSF 컴포넌트 태그들 중에서 사용자 입력을 처리하지 않는 것도 있다. 예를 들어 <h:output_text> 태그는 텍스트 출력이나 읽기 전용 자바 빈즈 속성값을 위해 사용된다. 각각의 컴포넌트는 id 속성에 의해 정의 되거나 JSF에 의해 자동 설정된 유일한 ID를 가지고 있다. 검증이 필요한 UI 컴포넌트는 에러를 출력하기 위한 <h:output_errors for="id"/> 태그를 사용하기 위해 id 속성이 필요하다.
[그림 2] 검증 에러들
텍스트 영역

JSF 폼의 텍스트 영역 컴포넌트는 PBuilder.java, view.jsp에 포함되어 사용자로 하여금 내용을 입력할 수 있게 한다. edit.jsp 페이지는 <h:output_text> 태그를 사용하여 라벨을 나타내고 30행 3열의 <textarea> HTML 요소를 표현하기 위해 <h:input_textarea> 태그를 사용하였다. <f:validate_required> 태그는 사용자가 텍스트 공간에 어떤 것도 입력하지 않을 때 에러를 보내는 JSF 검증자를 등록한다. 에러가 발생하면 <h:output_errors> 태그에 의해 에러가 출력되고 그렇지 않으면 화면에 아무것도 나타나지 않는다. <h:output_errors> 태그를 위한 속성은 <h:input_textarea> 태그의 id 속성과 같은 값을 갖는다.
<f:use_faces>
   <h:form formName="pform">
       <p><h:output_text value="Text:"/><br>
       <h:input_textarea id="text" valueRef="pbean.text"
               rows="3" cols="30">
           <f:validate_required/>
       </h:input_textarea>
       <br><h:output_errors for="text"/>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML을 만들어 낸다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   <p>Text:<br>
   <textarea name="text"
       cols="30" rows="3">JavaServer Faces</textarea>
   <br>
   ..........
</form>

<h:input_textarea> 태그의 valueRef="pbean.text" 속성은 JSF에게 자바 빈즈 인스턴스의 ID가 pbean인 것을 찾고 사용자가 입력한 텍스트를 인스턴스의 text 속성에 저장하는 것을 의미한다. HTML 폼이 생성되면 JSF는 <textarea> HTML 요소에 텍스트 속성의 값을 삽입한다. PBean 클래스는 속성의 값을 변경, 검색하기 위해 JSF에 의해 호출된 get, set 메소드를 실행한다.
public class PBean implements java.io.Serializable {

   private String text;

   public String getText() {
       return text;
   }

   public void setText(String text) {
       this.text = text;
   }

   ..........

}

<h:input_textarea> 태그와 더불어 JSF는 텍스트 필드를 생성하는 <input_text>, <h:input_number>, <input_secret> (패스워드용), <input_date>, <input_datetime>, <input_time>과 같은 몇몇 태그를 생성한다. <input_hidden> 태그는 숨겨진 폼 필드를 만든다.

텍스트 필드

edit.jsp의 텍스트 필드는 1부터 7까지의 숫자만을 입력받는다. <h:input_number> 태그에 의해 생성된 HTML 코드는 2개의 검증자를 가지고 있다. <f:validate_required> 태그는 이전에 설명하였다. <f:validate_longrange> 검증자는 사용자 입력이 주어진 범위의 값을 만족하는지 검사한다. 그렇지 않다면 <h:output_errors>를 사용하여 에러를 사용자에게 보여준다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <p><h:output_text value="Size: [1-7]"/><br>
       <h:input_number id="size" valueRef="pbean.size" size="2">
           <f:validate_required/>
           <f:validate_longrange minimum="1" maximum="7"/>
       </h:input_number>
       <br><h:output_errors for="size"/>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <p>Size: [1-7]<br>
   <input type="text" name="size" id="size" value="3" size="2">
   <br>
   ..........
</form>

텍스트 필드는 int형의 size 속성과 연결된다. value 속성의 값 3은 HTML 폼이 생성될 때 숫자 입력 값의 기본값을 의미한다. 검증을 통해 에러가 없었다고 가정하면 JSF는 value 속성 값을 포함하는 사용자 입력을 받을 때 자바 빈즈를 갱신 한다. <h:input_number> 태그의 size 속성은 텍스트 필드의 문자열 길이를 정의하고 자바 빈즈 속성에는 영향을 미치지 않는다.
public class PBean implements java.io.Serializable {


   ..........

   private int size;

   public int getSize() {
       return size;
   }

   public void setSize(int size) {
       this.size = size;
   }

   ..........

}

<f:validate_required>, <f:validate_longrange> 태그 이외에도 JSF는 <validate_doublerange>, <validate_stringrange>, <validate_length>, <validator> 태그들의 검증 관련 태그들을 제공한다. 마지막 태그는 UI 컴포넌트에 커스텀 검증자를 등록할 수 있게 한다. 또한 자신만의 검증 태그 라이브러리를 만들 수도 있다.

리스트 박스

<h:selectone_listbox> 태그와 <h:selectmany_listbox> 태그는 웹 브라우저에서 리스트 박스를 나타내는 <select> 요소를 생성한다. <h:selectone_listbox> JSF 태그는 사용자에게 단일 선택만 허용하고 <h:selectmany_listbox> 태그는 다중선택을 지원한다. edit.jsp 페이지는 여러 개의 폰트를 포함하고 있는 리스트 박스를 생성하기 위해 <h:selectmany_listbox> 태그를 사용한다. 리스트 아이템을 나타내는 HTML <option> 요소는 <h:selectitem> 태그에 의해 생성된다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <pgt;<h:output_text value="Font:"/gt;<br>
       <h:selectmany_listbox id="font" valueRef="pbean.font">
           <h:selectitem itemValue="Arial"
               itemLabel="Arial"/>
           <h:selectitem itemValue="Courier New"
               itemLabel="Courier New"/>
           <h:selectitem itemValue="Times New Roman"
               itemLabel="Times New Roman"/>
       </h:selectmany_listbox>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <pgt;Font: <br>
   <select name="font" multiple size="3">
       <option value="Arial" selectedgt;Arial</option>
       <option value="Courier New" selected>Courier New</option>
       <option value="Times New Roman">Times New Roman</option>
   </select>
   ..........
</form>

리스트 박스는 String[] 속성을 갖는 font 속성에 연결된다. 처음 getFont() 메소드는 외부 접근으로부터 보호 받아야 하는 내부 배열의 복사본을 반환하는 clone() 메소드를 사용한다. setFont() 메소드는 두 번째 setFont() 메소드가 수정할 수 있는 배열의 복사본을 유지하기 위해 clone()를 사용한다.
public class PBean implements java.io.Serializable {

   ..........

   private String fontArray[];

   public String[] getFont() {
       return (String[]) fontArray.clone();
   }

   public void setFont(String fontArray[]) {
       this.fontArray = (String[]) fontArray.clone();
   }

   public String getFont(int index) {
       return fontArray[index];
   }

   public void setFont(int index, String font) {
       if (fontArray == null)
           fontArray = new String[index+1];
       else if (fontArray.length <= index) {
           String oldFontArray[] = fontArray;
           fontArray = new String[index+1];
           for (int i = 0; i < oldFontArray.length; i++)
               fontArray[i] = oldFontArray[i];
       }
       fontArray[index] = font;
   }

   ..........

}

HTML 폼이 생성될 때 JSF는 selected HTML 속성을 자바 빈즈 모델의 폰트 속성 배열 값과 일치하는 리스트 아이템에 적용한다. 검증을 통해 에러가 없었다고 가정하면 JSF는 새로운 폰트를 선택할 때 자바 빈즈를 갱신한다.

드롭-다운 리스트

<h:selectone_menu> 태그는 몇 가지 색깔을 가지고 있는 드롭-다운 리스트를 생성하며, 리스트 박스에서처럼 <h:selectitem> 태그를 가지고 있다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <p><h:output_text value="Color:"/><br>
       <h:selectone_menu id="color" valueRef="pbean.color">
           <f:validate_required/>
           <h:selectitem itemValue="black" itemLabel="Black"/>
           <h:selectitem itemValue="red" itemLabel="Red"/>
           <h:selectitem itemValue="blue" itemLabel="Blue"/>
           <h:selectitem itemValue="green" itemLabel="Green"/>
       </h:selectone_menu>
       <br><h:output_errors for="color"/>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <p>Color:<br>
   <select name="color" size="1">
       <option value="black">Black</option>
       <option value="red">Red</option>
       <option value="blue">Blue</option>
       <option value="green" selected>Green</option>
   </select>
   <br>
   ..........
</form>

드롭-다운 리스트는 String 형을 갖는 color 속성과 연결된다.
public class PBean implements java.io.Serializable {

   ..........

   private String color;

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   ..........

}

HTML 폼이 생성될 때 JSF는 selected HTML 속성을 자바 빈즈 모델의 color 속성이 가지고 있는 값과 같은 리스트 아이템에 적용한다. 검증을 통해 에러가 없었다면 JSF는 새로운 색깔을 포함하는 사용자 입력을 받을 때 자바 빈즈를 갱신할 것이다.

라디오 버튼

<h:selectone_radio>, <h:selectitem> 태그는 라디오 버튼 그룹을 생성한다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <p><h:output_text value="Alignment:"/><br>
       <h:selectone_radio id="align" valueRef="pbean.align"
               layout="LINE_DIRECTION">
           <f:validate_required/>
           <h:selectitem itemValue="left" itemLabel="Left"/>
           <h:selectitem itemValue="center" itemLabel="Center"/>
           <h:selectitem itemValue="right" itemLabel="Right"/>
       </h:selectone_radio>
       <br><h:output_errors for="align"/>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음과 같은 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <p>Alignment:<br>
   <table border="0">
       <tr>
           <td><input type="radio" checked
               name="align" value="left"> Left</td>
           <td><input type="radio"
               name="align" value="center"> Center</td>
           <td><input type="radio"
               name="align" value="right"> Right</td>
       </tr>
   </table>
   <br>
   ..........
</form>

라디오 버튼은 align 속성에 연결되어 있다.
public class PBean implements java.io.Serializable {

   ..........

   private String align;

   public String getAlign() {
       return align;
   }

   public void setAlign(String align) {
       this.align = align;
   }

   ..........

}

HTML 폼이 생성될 때 JSF는 checked HTML 속성을 자바 빈즈 모델의 align 속성이 가지고 있는 값과 같은 라디오 버튼에 적용한다. 검증을 통해 에러가 없었다면 JSF는 새로운 정렬 값을 포함하고 있는 사용자 입력을 받을 때 자바 빈즈를 갱신한다.

체크박스

edit.jsp 페이지는 <h:selectboolean_checkbox> 태그에 의해 생성된 체크박스를 가지고 있다. 이것들은 <h:panel_grid>, <h:panel_group> 태그에 의해 생성된 HTML 테이블 내에 포함된다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <p><h:output_text value="Style:"/><br>
       <h:panel_grid columns="3" border="0" cellspacing="5">
           <h:panel_group>
               <h:selectboolean_checkbox id="bold"
                   valueRef="pbean.bold"/>
               <h:output_text value="Bold"/>
           </h:panel_group>
           <h:panel_group>
               <h:selectboolean_checkbox id="italic"
                   valueRef="pbean.italic"/>
               <h:output_text value="Italic"/>
           </h:panel_group>
           <h:panel_group>
               <h:selectboolean_checkbox id="underline"
                   valueRef="pbean.underline"/>
               <h:output_text value="Underline"/>
           </h:panel_group>
       </h:panel_grid>
       ..........
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <p>Style:<br>
   <table border="0" cellspacing="5">
       <tr>
           <td><input type="checkbox"
                name="bold">Bold</td>
           <td><input type="checkbox"
                name="italic" checked>Italic</td>
           <td><input type="checkbox"  
                name="underline">Underline</td>
       </tr>
   </table>
   ..........
</form>

세 개의 체크박스는 bold, italic, underline Boolean 속성들에 연결되어 있다.
public class PBean implements java.io.Serializable {

   ..........

   private boolean bold;

   public boolean isBold() {
       return bold;
   }

   public void setBold(boolean bold) {
       this.bold = bold;
   }
   private boolean italic;

   public boolean isItalic() {
       return italic;
   }

   public void setItalic(boolean italic) {
       this.italic = italic;
   }
   private boolean underline;

   public boolean isUnderline() {
       return underline;
   }

   public void setUnderline(boolean underline) {
       this.underline = underline;
   }

   ..........

}

HTML 폼이 생성될 때 자바 빈즈와 연결된 속성 값이 ture이면(참이면), JSF는 checked HTML 속성을 체크박스에 적용한다. 검증을 통해 에러가 없었다면 JSF는 사용자 입력을 받을 때 자바 빈즈를 갱신 한다.

예제에서 체크박스는 분리되어 생성된다. JSF는 체크박스 그룹을 생성할 수 있는 <h:selectmany_checkboxlist> 태그를 제공한다. 이외에도 JSF는 테이블을 생성할 수 있는 <h:panel_list>, <h:panel_data> 두 개의 태그를 갖고있다.

명령 버튼

faces-config.xml 파일은 네비게이션 규칙을 정의한다. 규칙이란 사용자가 페이지 버튼 중 하나를 클릭했을 때 <from-tree-id> 태그에 설정된 경로를 JSF에게 알려주는 것이다. <navigation-case> 요소 안에는 두 개의 네비게이션 케이스가 있다.
..........
<faces-config>
   <navigation-rule>
       <from-tree-id>/edit.jsp</from-tree-id>
       <navigation-case>
           <from-outcome>editOutcome</from-outcome>
           <to-tree-id>/edit.jsp</to-tree-id>
       </navigation-case>
       <navigation-case>
           <from-outcome>viewOutcome</from-outcome>
           <to-tree-id>/view.jsp</to-tree-id>
       </navigation-case>
   </navigation-rule>
   ..........
</faces-config>

/edit.jsp 페이지는 <h:command_button> 태그에 의해 생성되는 두 개의 버튼을 가지고 있다. 버튼 각각은 ID, 라벨, JSF에 의해 사용되는 명령이름, action, actionRef 속성을 가지고 있다.
<f:use_faces>
   <h:form formName="pform">
       ..........
       <p>
       <h:command_button id="view" label="View"
           commandName="viewCmd" action="viewOutcome"/>
       <h:command_button id="boldUpperCase"
           label="Bold Upper Case / View"
           commandName="boldUpperCaseCmd"
           actionRef="pbean.boldUpperCaseAction"/>
   </h:form>
</f:use_faces>

상단의 JSP 코드는 다음의 HTML 코드를 만든다.
<form method="post" action="/usingjsf/faces/edit.jsp">
   ..........
   <p>
   <input type="submit" name="view" value="View">
   <input type="submit" name="boldUpperCase"
       value="Bold Upper Case / View">
</form>

JSF는 매번 사용자 입력이 브라우저로부터 제출될 때 폼 데이터를 검증한다. 이상이 없고 데이터 형 변환 에러가 없다면 JSF는 네비게이션 규칙을 고려한다. 첫번째 버튼의 경우 JSF는 두 번째 이동 케이스의 <from-outcome> 요소 값과 같은 action 속성을 얻는다. 그러므로 JSF는 HTTP 요청을 <to-tree-id> 요소 값인 view.jsp 페이지로 포워드 한다.

사용자가 두 번째 버튼을 눌렀을 때 JSF는 PBean 객체의 getBoldUpperCaseAction() 메소드를 호출한다. 이 메소드는 PBean의 내부 클래스 BoldUpperCaseAction 인스턴스를 반환한다. 그러면 JSF는 HTML에 하드 코딩되어있을 때가 아니라 런타임에서 출력을 반환하는 invoke() 메소드를 호출한다.
public class PBean implements java.io.Serializable {

   ..........

   public BoldUpperCaseAction getBoldUpperCaseAction() {
       return new BoldUpperCaseAction();
   }

   public class BoldUpperCaseAction
           extends javax.faces.application.Action {
       public String invoke() {
           String ucText = getText().toUpperCase();
           if (isBold() && getText().equals(ucText))
               return "viewOutcome";
           else {
               setBold(true);
               setText(ucText);
               return "editOutcome";
           }
       }
   }

}

bold 속성이 true(참)이고 text의 값이 같으면 JSF는 두 번째 이동 케이스를 따라 HTTP 요청을 view.jsp 페이지로 포워딩한다. 그렇지 않으면 invoke() 메소드는 bold 속성을 true(참)으로 만들고 모든 텍스트 속성의 문자를 대문자로 변환한 다음 editOutcome을 반환한다. JSF는 현재 페이지 /edit.jsp를 유지하는 첫번째 네비게이션 케이스를 따른다.

폼 데이터 처리

Pbuilder 클래스는 Pbean 인스턴스를 파라미터로 받아 빈즈의 속성을 가지고 HTML 문단을 만들어내는 static 메소드를 포함하고 있다.
package com.devsphere.articles.usingjsf;

public class PBuilder {

   public static String toHTML(PBean pbean) {
       StringBuffer buf = new StringBuffer();
       buf.append("<p align=\"");
       buf.append(pbean.getAlign());
       buf.append("\">");
       buf.append("<font size=\"");
       buf.append(pbean.getSize());
       buf.append("\" color=\"");
       buf.append(pbean.getColor());
       buf.append("\"");
       Object font[] = pbean.getFont();
       if (font != null && font.length > 0) {
           buf.append(" face=\"");
           for (int j = 0; j < font.length; j++) {
               if (j > 0)
                   buf.append(',');
               buf.append(font[j]);
           }
           buf.append("\"");
       }
       buf.append(">");
       if (pbean.isBold())
           buf.append("<b>");
       if (pbean.isItalic())
           buf.append("<i>");
       if (pbean.isUnderline())
           buf.append("<u>");
       String s = pbean.getText();
       int n = s.length();
       for (int i = 0; i < n; i++) {
           char ch = s.charAt(i);
           switch (ch) {
               case '<':
                   buf.append("<");
                   break;
               case '>':
                   buf.append(">");
                   break;
               case '&':
                   buf.append("&");
                   break;
               case '"':
                   buf.append(""");
                   break;
               default:
                   buf.append(ch);
           }
       }
       if (pbean.isUnderline())
           buf.append("</u>");
       if (pbean.isItalic())
           buf.append("</i>");
       if (pbean.isBold())
           buf.append("</b>");
       buf.append("</font>");
       buf.append("</p>");
       return buf.toString();
   }

}

view.jsp 페이지는 JSF에 의해 관리되는 자바빈즈 인스턴스를 얻기위해 <jsp:useBean>를 사용하고 PBuildertoHTML() 메소드를 호출하여, 결과적으로 HTML 문단을 출력한다. JSF의 <h:command_hyperlink> 태그는 edit.jsp를 가리키는 링크를 제공한다.
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>

<html>
<head>
<title>View</title>
</head>
<body>

<jsp:useBean id="pbean" scope="session"
   class="com.devsphere.articles.usingjsf.PBean"/>

<%= com.devsphere.articles.usingjsf.PBuilder.toHTML(pbean) %>

<f:use_faces>
   <h:command_hyperlink label="Back to Editing" href="edit.jsp"/>
</f:use_faces>

</body>
</html>

[그림 3] view.jsp에 의해 나타나는 텍스트
애플리케이션 설정

JSF 프레임워크는 JSP 페이지로 향하는 요청을 가로채는 FacesServlet 제어 서블릿을 가지고있다. 서블릿은 web.xml 파일 안에 설정되고 /faces/* URL 패턴에 매핑된다. 서블릿을 활성화시키기 위해 JSP 페이지는 반드시 "faces"로 시작해야 한다. 애플리케이션의 index.jsp 홈페이지는 브라우저 요청을 faces/edit.jsp 페이지로 보내기 위해 response.sendRedirect()를 사용한다.
<% response.sendRedirect("faces/edit.jsp"); %>
faces-config.xml 파일의 위치는 web.xml의 context 파라미터 값에 의해 결정된다. web.xml 파일은 리스너 등록 설정과 JSF 실행에 관련된 파라미터 값을 가지고 있다. 다음은 web.xml 파일의 내용이다.
<?xml version="1.0"?>

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

   <context-param>
       <param-name>avax.faces.application.CONFIG_FILES</param-name>
       <param-value>/WEB-INF/faces-config.xml</param-value>
   </context-param>

   <context-param>
       <param-name>com.sun.faces.saveStateInClient</param-name>
       <param-value>false</param-value>
   </context-param>

   <context-param>
       <param-name>com.sun.faces.validateXml</param-name>
       <param-value>true</param-value>
   </context-param>

   <listener>
       <listener-class>com.sun.faces.config.ConfigListener</listener-class>
   </listener>

   <servlet>
       <servlet-name>FacesServlet</servlet-name>
       <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
       <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
       <servlet-name>FacesServlet</servlet-name>
       <url-pattern>/faces/*</url-pattern>
   </servlet-mapping>

</web-app>

처음 폼이 생성될 때 JSF는 컴포넌트 트리, UI 컴포넌트에 관한 정보를 가진 객체, 객체에 등록된 검증자를 만든다. 사용자가 폼 데이터를 제출하면 JSF는 컴포넌트 트리로부터 정보를 얻어 사용자 입력을 검증한다. 기본적으로 JSF는 session 범위에 컴포넌트 트리를 저장한다. 이 작업은 애플리케이션이 끝날 때 한번 일어난다. 개발기간 동안 UI 컴포넌트를 추가하거나 제거하여 JSF 폼을 변경 하면 JSF는 JSP 페이지가 수정될 때 컴포넌트 트리 값을 버리지 않기 때문에 예외를 던진다. web.xml 파일에 선언된 saveStateInClient 플래그가 true(참)으로 바뀌면 JSF는 session 속성으로 저장하지 않고 컴포넌트 트리를 HTML hidden 필드로 직렬화시킨다.

요약

본 기사에서는 JSF 태그로 폼 작성하는 방법을 학습하면서 프레임워크의 기본적인 모습을 살펴보았다. 여타의 EA 패키지처럼 JSF EA4도 아직 배포단계는 아니지만 대부분의 기능을 사용할 수 있을 것이다. 자바 개발자에게 웹 사용자 인터페이스 작성을 위한 표준 태그 라이브러리와 커스텀 웹 컴포넌트 작성을 위한 표준 API가 절실했기 때문에 JCP에서 2년의 시간을 보낸 JSF는 현재 환영 받고 있다.

참고자료

본 기사의 저자 안드레이 키오뢰아누(Andrei Cioroianu)는 Devsphere의 설립자이며, ONJava, JavaWorld, Java Developer's Journal 등에 다양한 자바관련 기사를 쓰고 있다.

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...