Article Category

분류 전체보기 (202)
사는 이야기 (15)
Programming (174)
Photo (5)
게임 (2)
프로젝트 (0)

Recent Comment

Recent Trackback

Calendar

«   2019/08   »
        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

Archive

  • Total96,717
  • Today3
  • Yesterday4
  1. 2008.08.06
    Working XML: RSS 기능 확장하기 (1)
  2. 2008.08.06
    자바 개발자를 위한 Ajax: Ajax와 Direct Web Remoting
Working XML: RSS 기능 확장하기 (한글)

네임스페이스를 통해 핵심 표준 강화하기

 





난이도 : 중급

Benoit Marchal, Consultant, Pineapplesoft

2006 년 10 월 17 일

RSS의 대중성에도 불구하고, RSS 표준은 매우 단순하고 제한적입니다. RSS는 많은 것들을 수행하지는 않지만, RSS 모듈을 통해 확장이 가능합니다. 이 글에서 세 개의 대표적인 RSS 확장을 소개하고, RSS 확장을 디자인 하는 방법을 설명합니다.

RSS는 단순하지만 한계가 없다

RSS라는 단어는 많은 뜻으로 풀이될 수 있다: Really Simple Syndication, Rich Site Summary, RDF Site Summary 말고도 더 많은 뜻으로 풀이될 수 있다. 실제로, RSS는 developerWorks를 비롯하여 점점 더 많은 사이트에서 찾아볼 수 있다.

RSS 피드를 통해서 사이트에 등록하고 업데이트 공지를 받을 수 있다. 이메일과는 구별되는 RSS의 두 가지 중요한 특성이 있다:

  • RSS는 특별한 클라이언트, RSS 리더(reader)를 필요로 하고, 이는 웹 브라우저에 점차적으로 추가되고 있다.
  • 이메일과는 달리, RSS는 어떤 개인적인 정보도 사이트와 교환되지 않기 때문에 사용자의 프라이버시를 지켜준다.

RSS 101

RSS 파일을 코딩 하기는 쉽다. 기본적인(root) RSS 엘리먼트를 rss라고 한다. 바로 뒤에는 channel 엘리먼트가 뒤따른다.

channel 뉴스피드의 디스크립션으로 시작한다. 적어도 피드 타이틀(title) 웹 사이트로의 링크(link), 피드의 디스크립션(description)이 포함되어야 한다.

다른 엘리먼트들은 선택적이다. 가장 일반적으로 사용되는 옵션들은 피드 언어(language), 전개일(pubDate), 카테고리 구분(category) 채널이 캐싱될 수 있는 시간(분)인 활성화 시간(ttl) 등이 있다.

docs 엘리먼트 역시 종종 포함된다. 그리고 특별하다. docs 엘리먼트는 RSS 문서를 가리켜서 모든 RSS 문서에 같은 값을 갖도록 한다.

채널 디스크립션이 item 엘리먼트의 리스트가 된 후에, 이 곳에서 각 아이템은 뉴스가 될 만한 이벤트를 나타낸다.

뉴스가 될 만한 것이란 무엇인가? 이는 사이트와 애플리케이션에 의존한다. 일반 웹 사이트의 경우 아이템은 중요한 업데이트를 나타낸다. Podcast의 경우, 새로운 에피소드를 나타낸다. 네트워크 모니터링 애플리케이션의 경우에는 네트워크 경고가 될 것이고, 포럼의 경우에는 새로운 게시물이 될 것이다.

item의 콘텐트는 채널처럼 시작한다: title, link, description. 날짜, 멀티미디어 콘텐트로의 링크(enclosure), 소스, 코멘트 등으로 보다 구체적이 된다.

디스크립션에 HTML 태그를 포함하려면 이들에서 벗어나야 한다. (주로 CDATA 섹션을 통한다.)

주목해야 할 것은, guid 엘리먼트이다. 이것은 유일 식별자이다. 이것이 있을 경우, RSS 리더는 여기에 의존하여 새로운 아이템을 구분한다. GUID를 사용할 수 없다면 리더는 아이템 타이틀과 콘텐트를 비교하여 새로운 아이템을 찾는다.

Listing 1은 RSS 피드 샘플이다:


Listing 1. RSS 피드
				

<rss version="2.0">

  <channel>

    <title>Marchal.com</title>

    <link>http://www.marchal.com/</link>

    <description>Marchal's site.</description>

    <docs>http://blogs.law.harvard.edu/tech/rss</docs>

    <language>en</language>

    <copyright>Copyright 2006, Benoit Marchal.</copyright>

    <pubDate>Fri, 30 Jun 2006 00:35:40 +0200</pubDate>

    <item>

      <title>Online photos</title>

      <link>http://www.marchal.com/en/photos</link>

      <description><![CDATA[<p>In 2002 I added a digital camera to my

         writer toolbox. I have used it to illustrate my articles and web

         sites.</p>

         <p>While I had some experience with film-based photos, I was

         new to digital images. Most of the things I knew were

         still valid, others I had to re-learn. There was

         a lot of new material as well. These pages summarize

         my findings.</p>]]></description>

      <pubDate>Fri, 30 Jun 2006 00:35:40 +0200</pubDate>

      <category>photo</category>

      <category>2002</category>

      <guid isPermaLink="false">photos</guid>

    </item>

  </channel>

</rss>


피드에 등록하려면 방문자는 RSS 리더가 필요하다. 리더는 일정 간격으로 RSS 파일을 다운로드 하고 새로운 아이템이 발견되면 사용자에게 공지해야 한다.

RSS 리더는 메인 브라우저로 빌트인 된다: Firefox 1.5, Internet Explorer 7, Safari에는 이미 RSS 리더가 포함되어 있다. NewsGator에서 독립 리더기 역시 사용할 수 있다. 새로운 소프트웨어를 설치하고 싶지 않은 경우, Google Reader나 NetVibes 같은 Aggregator 사이트를 통해 피드를 읽을 수 있다. Zookoda 같은 이메일을 보내는 RSS도 있다.

섹션에서 다룬 것 이상의 더 많은 엘리먼트들이 RSS에서 정의된다. 참고자료를 참조하라.

RSS 힘

간단히 말해서, 정보를 공유하거나 사용자에게 공지를 해야 하는 애플리케이션이나 웹 사이트들은 RSS 피드의 효과를 보고 있다. 실제로, RSS 사용이 산불처럼 확산되고 있다.

많이 사용되는 만큼, 골칫거리도 있다. 많은 개발자들은 아이템에 개념을 맞춰야 하고 너무 제한적이라는 것에 불만을 쏟아내고 있다. 이러한 한계를 해결하기 위해, RSS 2.0은 확장 가능한 언어로 설계된다. 원리는 간단하다. RSS 엘리먼트는 네임스페이스에 포함되는 것뿐만 아니라(RSS 0.92와 백워드 호환), 개발자들은 자신의 네임 스페이스에 엘리먼트를 추가하는 것으로 RSS를 자유롭게 확장할 수 있다.

태그에 네임스페이스가 있을 때 RSS 리더는 이 네임스페이스에서 확장을 인식해야 한다. 이것이 성공하면 엘리먼트를 처리할 수 있다. 그렇지 못할 경우 그 엘리먼트를 무시한다.

따라서 RSS는 보다 강력한 애플리케이션을 구현할 수 있는 중추가 된다. 이 메커니즘의 힘은 확장이 리더에 선택적이기 때문에 확장을 처리하지 못한 리더도 핵심 RSS 스팩으로 민감한 작업을 수행할 수 있다.

네임스페이스

여기에서 잠깐, 네임스페이스에 대한 몇 가지 미신들을 짚고 넘어가겠다. 놀랍게도, W3C에서 네임스페이스 권고안이 발표된 후 7년이 지났는데, 여전히 상당한 오해가 생겨나고 있고, 몇몇 RSS 리더에 표준이 잘못 구현되고 있다.

네임스페이스는 RSS 같이 핵심 엘리먼트 세트에 대한 확장을 필요로 하는 어휘에 대해 설계된다. 특별히, 네임스페이스는 두 개의 다른 확장이 다른 의미를 지닌 채 같은 XML 엘리먼트를 사용할 때 네임 충돌을 방지한다.

확장은 독립적으로 개발되기 때문에, 공통 이름이 재사용되기 전 시간의 문제이다. 예를 들어 “key”라는 단어를 생각해 보자. 이것은 데이터베이스 키로 사용되거나 암호 키로 사용될 수 있다.

이러한 모호함을 없애기 위해, 네임스페이스는 엘리먼트 이름을 로컬 이름과 네임스페이스 Uniform Resource Identifier (URI)로 나눈다. 네임스페이스 URI는 확장의 고유 식별자이다. 로컬 이름은 독자성을 보장할 수 없지만 로컬 이름과 네임스페이스 URI를 결합하면 고유성이 보장된다.

독자 여러분들은 이러한 네임스페이스 문법을 알고 있으리라 생각한다. xmlns 애트리뷰트는 접두사를 선언하고 이것을 네임스페이스 URI로 제휴시킨다. 접두사는 네임스페이스 URI를 로컬 이름과 연결한다. 로컬 이름과 접두사를 구분할 때는 콜론을 사용한다. Listing 2는 예제이다.


Listing 2. 네임스페이스 선언
				

<dc:contributor xmlns:dc="http://purl.org/dc/elements/1.1/">

Marchal</dc:contributor>


실제로, 네임스페이스의 두 가지 부분이 혼돈스럽다:

  • 식별자는 URI와 대부분의 경우 URL이다.
  • 접두사와 로컬 이름의 결합으로 독자성을 보장하지 못한다. 독자성을 위해서 네임스페이스 URI를 사용해야 한다.

두 가지 실수에 대해 설명하겠다.

우선, 네임스페이스 URI부터 설명하겠다. 네임스페이스 정황에서, URI는 어휘의 정의가 아닌 식별자이다. 따라서 URI가 가리키는 리소스는 관련이 없다. 많은 경우, 리소스는 존재하지도 않는다.

개발자와 사용자는 정의를 좋아하지만, 이들은 주어진 네임스페이스에서 엘리먼트를 처리하기 전에 파일 다운로드에 애플리케이션 실행이 허용되지 않는 것으로 간주한다.

많은 애플리케이션들은 영구적인 인터넷 연결 없이도 실행된다. 인터넷 연결이 된 상태에서는, 파일 다운로드는 느려진다. 웹 사이트를 (임시적으로) 사용할 수 없을 때 어떤 일이 발생하겠는가?

더욱이, 네임스페이스 정황 속에서, 식별자만 필요하다.

접두사는 어떤가? URI를 모든 태그에 붙이면 문서의 길이가 길어진다. 따라서, 접두사는 URI를 짧게 할 수단으로 사용되었다. 하지만 접두사로는 독자성을 보장할 수 없으므로(로컬 이름을 독자적으로 만들 수 없다면 접두사에 독자성을 기대할 수는 없다. 게다가 접두사는 대게 짧기 마련이다.) URI를 참조해야 한다.

따라서 특별한 문자로 URI를 만들게 된다. 대부분의 URI는 URL이고, URL에는 도메인 이름이 포함되어 있기 때문에 유일 식별자이다. 여러분이 가진 도메인 이름을 사용하여 네임스페이스를 정의하는 한, 다른 조직이 같은 도메인으로 등록할 수 없기 때문에 고유성이 보장된다.

세 가지 확장

실제로 확장이 어떻게 작동하는지 잘 이해할 수 있도록 RSS의 세 가지 확장에 대해 살펴보기로 하자:

  • 메타데이터용 Dublin Core
  • Podcasting용 iTunes
  • 확장을 확장하는 Syndicated Photography

Dublin Core

Dublin Core는 RFC2413에 정의된 메타데이터 엘리먼트이다. Dublin Core는 리소스를 검색하는 최소 메타데이터 세트이다. (META 엘리먼트) HTML과 다양한 XML 어휘로 사용되었다.

Dublin Core의 몇몇 엘리먼트는 RSS 엘리먼트(예, language)를 중복하는데, 이는 RSS 이전에 개발되었기 때문에 어쩔 수 없었다. Dublin Core 확장을 channel이나 item에 붙일 수 있기 때문에 중복 역시 유용하다. 예를 들어, RSS copyright 엘리먼트는 channel 레벨에만 나타나는 반면, Dublin Core rights를 개별 아이템들에 붙일 수 있다.

Dublin Core 네임스페이스는 http://purl.org/dc/elements/1.1/이다.

Listing 3은 RSS의 Dublin Core 예제이다:


Listing 3. Dublin Core
				

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> 

<channel>

   <title>Marchal</title>

   <link>http://www.marchal.com/</link>

   <description>Personal site.</description>

   <language>en</language>

   <item>>

      <title>Introduction</title>

      <link>http://www.marchal.com/en/</link>

      <description>Introduction to the site.</description>

      <dc:creator>Marchal</dc:creator>

      <dc:rights>Copyright 2001-2004 Marchal</dc:rights>

   </item>

</channel>

</rss>


Dublin Core 확장은 RSS와 비슷한 엘리먼트 조차도 더 많은 옵션들을 제공함으로서 값을 추가할 수 있다는 것을 보여준다.

iTunes Music Store

iTunes는 iTunes Music Store를 통해 Podcast로 직접 액세스 할 수 있다. 스토어에 Podcast를 통합하기 위해, iTunes는 http://www.itunes.com/dtds/podcast-1.0.dtd 네임스페이스로 확장을 정의했다.

iTunes 확장은 다음과 같은 이유로 인해 주목할 만 하다:

  • 정의가 다를 때 RSS와 비슷한 엘리먼트를 재 정의 한다. (itunes:image iTunes는 300/300 픽셀의 이미지가 필요한데, RSS는 최대 넓이를 144로 정의한다.)
  • 새로운 엘리먼트를 정의하여 사용자 접근성을 강화한다. (예를 들어, itunes:duration은 Podcast 기간을 제공하는 반면, RSS는 파일 길이만 제공한다.)

Listing 4는 iTunes 확장이 된 RSS 예제이다:


Listing 4. iTunes 확장의 RSS 피드
				

<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"

    version="2.0">

  <channel>

    <title>Declencheur</title>

    <link>http://www.declencheur.com/</link>

    <description>Le podcast qui parle photos</description>

    <docs>http://blogs.law.harvard.edu/tech/rss</docs>

    <language>fr</language>

    <copyright>© 2006, Benoit Marchal. Tous droits reserves.</copyright>

    <pubDate>Wed, 24 May 2006 16:19:39 +0200</pubDate>

    <itunes:author>Benoit Marchal</itunes:author>

    <itunes:image href="http://www.declencheur.com/clic/medias/2006/dsc_7478.jpg"/>

    <itunes:category text="Arts & Entertainment">

      <itunes:category text="Photography"/>

    </itunes:category>

    <itunes:category text="International">

      <itunes:category text="French"/>

      <itunes:category text="Belgian"/>

    </itunes:category>

    <item>

      <title>Histogramme</title>

      <link>http://www.declencheur.com/clic/archives/2006/05/histogramme-visuel</link>

      <description><![CDATA[<p><img alt="L'histogramme" height="225"

      width="150" align="right" class="photo illustrationright" 

       src="http://www.declencheur.com/clic/medias/2006/_dsc1808.jpg" />A mes yeux,

       l'histogramme est un des progres les plus remarquables de la photographie sur

       les dix dernieres annees. Un progres dans la precision de l'exposition au moins

       aussi important que la mesure matricielle en son temps.</p>

       <p>Les trois segments de l'episode sont (entre parentheses, le debut du

       segment concerne) :</p>

       <ol><li>(01:34) Elinchrom D-Lite, je suis particulierement enthousiaste

       par l'arrivee de ces flashes electroniques de studio. Mes premieres

       impressions.</li>

       <li>(07:40) Histogramme, le theme principal de l'episode. Un

       <a href="http://www.declencheur.com/clic/medias/2006/decl-2006-05-13.pdf"

       target="_blank">complement visuel</a> est disponible.</li>

       <li>(27:03) Vos commentaires, mes reactions : conseils pour la sauvegarde

       et precisions sur l'impression jet d'encre. Merci de votre

       soutien !</li></ol>

       <p>Les liens presentes dans l'episode :</p>

       <ul><li><a href="http://www.elinchrom.com"

       target="_blank">Elinchrom</a></li>

       <li><a href="http://www.foto-mueller.at" target="_blank">Foto

       Mueller</a><br clear="right" /></li></ul>]]></description>

      <pubDate>Mon, 15 May 2006 00:21:13 +0200</pubDate>

      <category>numerique</category>

      <category>technique</category>

      <enclosure length="34722926" type="audio/mpeg"

      url="http://www.declencheur.com/clic/medias/2006/decl-2006-05-14.mp3" />

      <guid isPermaLink="false">histogramme</guid>

      <itunes:duration>36:08</itunes:duration>

    </item>

  </channel>

</rss>


Syndicated Photography

Photocasting은 RSS 피드를 통해 사진을 배포하는 것이다. Podcast와 원리가 비슷하지만 소리 대신 이미지가 사용된다. 언뜻 보기에, RSS 피드에 사진을 배포하는 것처럼 보이지만 enclosure 엘리먼트면 충분하다.

좋은 포토 뷰어는 먼저 썸네일을 다운로드 하고 사용자 요청 시 사진을 다운로드 한다. 이는 enclosure 작동이 아니므로 Pheed는 두 개의 태그로만 확장을 정의해야 한다: photo:thumbnail (빠르게 다운로드 되는 작은 이미지)과 photo:imgsrc (완벽한 해상도의 이미지). Pheed는 사진 같은 멀티미디어 문서를 지원하는 RSS Aggregator이다.

사진 역시 메타데이터가 필요하고 Pheed는 Dublin Core를 선택했다. 따라서 사진 확장은 또 다른 확장으로 구현된다. 중복 노력을 줄일 수 있다.

Listing 5는 사진 피드의 예제이다. 두 개의 네임스페이스가 선언된다:


Listing 5. 포토 피드 확장을 갖춘 RSS 피드
				<?xml version="1.0" encoding="iso-8859-1"?>

<rss version="2.0" xmlns:photo="http://www.pheed.com/pheed/"

                   xmlns:dc="http://purl.org/dc/elements/1.1/"> 

<channel>

   <title>Fun with photos</title>

   <link>http://www.marchal.com/en/photos/</link>

   <description>Photo humor.</description>

   <language>en</language> 

   <item>

      <title>Journalist</title>

      <link>http://www.marchal.com/en/photos/humour</link>

      <description>He needs to fly</description>

      <dc:creator>Marchal</dc:creator>

      <dc:rights>Copyright 2004 Marchal</dc:rights>

      <dc:format>digital</dc:format>

      <dc:subject>Lego humor</dc:subject>

      <photo:imgsrc>

         http://www.marchal.com/en/photos/humour/phbd0001.jpg

      </photo:imgsrc>

      <photo:thumbnail>

         http://www.marchal.com/images/shared/thbd0001.jpg

      </photo:thumbnail>

   </item>

</channel>

</rss>


확장 정의하기

RSS에 한 개 이상의 기능을 추가하려면 어떻게 해야 할까?

  1. 필요한 확장이 이미 존재하고 있는지의 여부를 확인한다. 바퀴를 다시 만들 필요는 없기 때문이다. RSS 리더에 이만한 악몽은 없다.
  2. 새로운 확장이 여전히 필요하다면 네임스페이스 생성에 대한 정확한 규칙을 적용하라.
  3. 정확히 맞는다면 기존 엘리먼트를 과감하게 재 정의하라. (예를 들어, itunes:image는 비슷하지만 RSS의 고유 image와는 다르다.) 엘리먼트의 과용은 혼란만 가져올 뿐이다.

RSS는 유연한 포맷이지만, 이 보다 더 중요한 사실은 방송이 필요한 애플리케이션의 좋은 출발점이다. 확장 메커니즘 덕택에 가능성은 무궁무진 하다.

기사의 원문보기



참고자료



필자소개

Benoît Marchal은 벨기에에서 컨설턴트 및 저술가로 활동하고 있다. XML by Example, Applied XML Solutions, XML and the Enterprise 등을 집필했다. Declencheur podcast도 만들고 있다.


Trackback 0 and Comment 1

자바 개발자를 위한 Ajax: Ajax와 Direct Web Remoting

데이터 직렬화

 

 

 


 



난이도 : 중급

Philip McCarthy, Software development consultant, Independent

2006 년 10 월 17 일
2006 년 10 월 17 일 수정

Ajax 기능을 애플리케이션에 추가하기란 간단한 일이 아닙니다. 자바™ 개발자를 위한 Ajax 시리즈 세 번째 기사에서는 Direct Web Remoting (DWR)을 사용하여 JavaBeans 메소드를 JavaScript 코드에 직접 노출하고 Ajax를 자동화 하는 방법을 설명합니다.

Ajax 프로그래밍의 기초 (한글) 이해하는 것은 필수적인 일이지만, 복잡한 Ajax UI를 구현한다면, 고급 추상화 레벨에서 작업할 수 있어야 한다. Ajax for Java developers 시리즈 세 번째 글에서는 지난 달 소개했던 Ajax용 데이터 직렬화 기술 (한글)을 바탕으로, 자바 객체들을 직렬화 하는 문제를 단순화 하는 방법을 설명하겠다.

이전 글에서, JavaScript Object Notation (JSON)을 사용하여 클라이언트 상에서 JavaScript 객체로 쉽게 변환되는 포맷으로 데이터를 직렬화 하는 방법을 설명했다. 이 설정을 통해, JavaScript 코드를 사용하여 원격 서비스 호출을 호출하고, 원격 프로시저 호출과는 달리, 그에 대한 응답으로 JavaScript 객체 그래프를 받을 수 있다. 이번에는, 한 단계 더 나아가서 JavaScript 클라이언트 코드로부터, 서버 측 자바 객체에 대한 원격 프로시저 호출을 하는 기능을 규정하는 프레임웍을 사용해 보겠다.

DWR은 오픈 소스이며, 서버 측 자바 라이브러리, DWR 서블릿, JavaScript 라이브러리로 구성된 Apache 라이센스 솔루션이다. DWR이 자바 플랫폼에 사용할 수 있는 유일한 Ajax-RPC 툴킷은 아니지만, 가장 성숙하고, 많은 유용한 기능들을 제공하고 있다. 참고자료 섹션에서 DWR을 다운로드 하기 바란다.

DWR이란 무엇인가?

간단히 말해서, DWR은 서버 측 자바 객체의 메소드를 JavaScript 코드로 노출하는 엔진이다. DWR을 사용하여 애플리케이션 코드에서 Ajax 요청-응답 사이클 절차를 줄일 수 있다. 다시 말해서, 클라이언트 측 코드가 XMLHttpRequest 객체를 직접 다루거나 서버의 응답을 직접 다룰 필요가 없다는 것을 의미한다. 객체 직렬화 코드를 작성하거나 서드 파티 툴을 사용하여 객체를 XML로 전환할 필요가 없다. 서블릿 코드를 작성하여 Ajax 요청들을 자바 도메인 객체에 대한 호출로 중재할 필요도 없다.

DWR은 웹 애플리케이션에 서블릿으로서 전개된다. 블랙 박스처럼 보이는 이 서블릿은 두 가지 중요한 역할을 한다. 하나는, 각각 노출된 클래스에 대해, DWR은 JavaScript를 동적으로 생성하여 웹 페이지에 포함시킨다. 생성된 JavaScript에는 자바 클래스에 상응하는 메소드를 나타내는 스텁 함수가 포함되어 있고 막후에서 XMLHttpRequest도 수행한다. 이러한 요청들은 DWR 서블릿으로 보내지고, 요청들을 서버 측 자바 객체에 대한 메소드 호출로 변환하고, JavaScript로 인코딩 하여 메소드의 리턴 값을 다시 클라이언트로 보낸다. 이것이 두 번째 역할이다. DWR은 일반적인 UI 태스크를 수행하는 것을 돕는 JavaScript 유틸리티 함수도 제공한다.




위로


예제

DWR을 보다 자세히 설명하기 전에, 간단한 예제 시나리오를 소개하겠다. 이전 글에서와 마찬가지로, 온라인 스토어에 기반한 최소한의 모델을 사용하겠다. 이번에는 기본적인 제품 표현으로 구성된, 제품 아이템들을 포함시킬 수 있는 사용자의 쇼핑 카트와, 데이터 액세스 객체(DAO)를 사용하여 데이터 스토어에서 제품 상세를 검색한다. Item 클래스는 이전 글에서 사용했던 클래스이지만, 더 이상 수동 직렬화 메소드는 구현하지 않겠다. 그림 1은 설정 방법을 묘사한 것이다.


그림 1. Cart, CatalogDAO, Item 클래스를 나타내는 클래스 다이어그램

이 시나리오에서 두 개의 매우 간단한 유스 케이스를 설명하겠다. 첫 번째는 사용자가 카탈로그에서 텍스트 검색을 수행하고 매칭 아이템을 찾는 것이다. 두 번째는, 사용자가 아이템을 쇼핑 카트에 추가하고 카트에 있는 아이템들의 총 비용을 보는 것이다.




위로


카탈로그 구현하기

DWR 애플리케이션의 시작점은 서버 측 객체 모델을 작성하는 것이다. 이 경우, DAO를 작성하여 제품 카탈로그 데이터스토어에 검색 기능을 제공한다. CatalogDAO.java는 단순한 스테이트리스 클래스로서 인자 구조체가 없다. Listing 1은 Ajax 클라이언트로 노출 할 자바 메소드이다:


Listing 1. DWR을 통해 노출 할 CatalogDAO 메소드
				
/**
 * Returns a list of items in the catalog that have 
 *  names or descriptions matching the search expression
 * @param expression Text to search for in item names 
 *  and descriptions 
 * @return list of all matching items
 */
public List<Item> findItems(String expression);

/**
 * Returns the Item corresponding to a given Item ID
 * @param id The ID code of the item
 * @return the matching Item
 */
public Item getItem(String id);

다음에는, DWR을 설정하여, Ajax 클라이언트가 CatalogDAO를 구현하고 이러한 메소드를 호출하도록 할 것이다. Listing 2의 dwr.xml config 파일을 사용했다.


Listing 2. CatalogDAO 메소드를 노출하는 설정
				
<!DOCTYPE dwr PUBLIC
  "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
  "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
  <allow>
    <create creator="new" javascript="catalog">
      <param name="class" 
        value="developerworks.ajax.store.CatalogDAO"/>
      <include method="getItem"/> 
      <include method="findItems"/> 
    </create> 
    <convert converter="bean" 
      match="developerworks.ajax.store.Item">
      <param name="include" 
        value="id,name,description,formattedPrice"/>
    </convert>
  </allow>
</dwr>

dwr.xml 문서의 루트 엘리먼트는 dwr이다. 이 엘리먼트 안에는 allow 엘리먼트가 있는데, 이것은 DWR이 원격 조정할 클래스들을 지정한다. allow의 두 개의 자식 엘리먼트들은 createconvert이다.

Creat 엘리먼트

Create 엘리먼트는 DWR에게 서버 측 클래스가 Ajax 요청으로 노출되도록 명령하고, DWR이 그 클래스의 인스턴스를 얻는 방법을 정의한다. creator 애트리뷰트에는 new 값이 설정되고, 이는 DWR이 클래스의 디폴트 컨스트럭터를 호출하여 인스턴스를 얻어야 한다는 것을 의미한다. 다른 기능들은 Bean Scripting Framework (BSF)를 사용하여 스크립트 조각을 통해 인스턴스를 만들거나, IOC 컨테이너인 Spring과의 통합을 통해 인스턴스를 얻는 것이다. 기본적으로, DWR에 대한 Ajax 요청이 creator를 호출하면, 인스턴스화 된 객체가 페이지 범위에 놓이고, 요청이 완료된 후에는 더 이상 사용할 수 없다. 스테이트리스 CatalogDAO의 경우, 이것은 괜찮다.

Createjavascript 애트리뷰트는 JavaScript 코드에서 액세스 될 객체 이름을 지정한다. create 엘리먼트 내에 중첩된 param 엘리먼트는 creator가 만들 자바 클래스를 지정한다. 마지막으로, include 엘리먼트는 노출되어야 하는 메소드의 이름을 지정한다. 노출될 메소드를 명확히 드러내는 것은 잠재적으로 발생할 수 있는 위험들을 피하기에 좋다. 엘리먼트가 생략된다면 모든 클래스의 메소드들은 원격 호출에 노출될 것이다. exclude 엘리먼트를 사용하여 접근을 방지하고 싶은 메소드만 지정할 수 있다.

Convert 엘리먼트

creator가 클래스를 노출하는 것과, 웹 리모팅 방식과 연관이 있는 반면, convertor는 그러한 메소드의 매개변수와 리턴 유형과 연관이 있다. convert 엘리먼트의 역할은 서버 측 자바 객체 구현과 직렬화된 JavaScript 구현 사이에서 데이터 유형을 변환하는 방법을 DWR에게 명령하는 것이다.

DWR은 자바와 JavaScript 구현들 간 데이터 유형들을 자동으로 중재한다. 이 유형에는 자바 프리머티브와 각각의 클래스 구현, String과 Date, 어레이, 컬렉션 유형들이 포함된다. DWR은 또한 JavaBeans를 JavaScript 구현으로 변환하고, 보안 때문에, 명확한 설정이 필요하다.

Listing 2convert 엘리먼트는 DWR에게 리플렉션 기반 빈 convertor를 CatalogDAO의 노출된 메소드에 의해 리턴된 Item에 사용하고 직렬화에 포함될 Item의 멤버를 지정한다. 멤버들은 JavaBean 네이밍 규약을 사용하여 지정되어, DWR은 상응하는 get 메소드를 호출할 것이다. 이 경우, 숫자 price 필드를 생략하고, 대신 통화로 포맷된 formattedPrice 필드를 포함시켰다.

이 시점에서, dwr.xml을 나의 웹 애플리케이션의 WEB-INF 디렉토리에 전개할 준비가 되고, 이 곳에서 DWR 서블릿이 집어낸다. 진행하기 전에, 모든 것이 생각한 대로 잘 작동하는지를 확인해보는 것이 좋다.




위로


전개 테스팅

DWRServletweb.xml 정의에서 init-param debugtrue로 설정했다면 DWR의 가장 유용한 테스트 모드가 실행된 것이다. /{your-web-app}/dwr/을 검색하면 DWR이 설정했던 클래스 리스트가 나타날 것이다. 해당 클래스에 대해 상태 스크린을 클릭한다. CatalogDAO용 DWR 테스트 페이지는 그림 2에 나타나 있다. script 태그를 웹 페이지에 붙일 뿐만 아니라, 클래스용으로 생성된 DWR의 JavaScript를 가리키면서, 이 스크린 역시 클래스의 메소드 리스트를 제공한다. 이 리스트에는 클래스의 상위 유형에서 상속된 메소드가 포함되어 있고, dwr.xml에서 원격용으로 명확하게 지정한 메소드도 액세스 가능한 것으로 표시된다.


그림 2. CatalogDAO용 DWR 테스트 페이지
The diagnostic and test page generated by DWR for CatalogDAO

매개변수 값을 액세스 가능한 메소드 옆 텍스트 박스에 입력하고 Execute 버튼을 눌러 이들을 호출할 수 있다. 단순한 값이 아니라면, 서버의 응답은 경고 박스에 JSON 공지를 사용하여 디스플레이 될 것이다. 이 경우 메소드를 따라서 한 줄로 디스플레이 된다. 이러한 테스트 페이지들은 매우 유용하다. 어떤 클래스와 메소드가 원격으로 노출되어있는지 쉽게 검사할 수 있고 각 메소드가 기대한 대로 작동하는지를 테스트 할 수 있다.

일단 원격 메소드가 올바르게 실행되었다면 DWR의 JavaScript 스텁을 사용하여 클라이언트 측 코드에서 서버 측 객체들을 호출할 수 있다.




위로


원격 객체 호출하기

원격 자바 객체 메소드와 이에 상응하는 JavaScript 스텁 함수들간 매핑은 간단하다. 일반적인 폼은 JavaScriptName.methodName(methodParams ..., callBack)인데, 여기에서 JavaScriptNamecreatorjavascript 애트리뷰트로 지정된 이름이고, methodParams는 자바 메소드의 n 매개변수이며, callback은 자바 메소드의 리턴 값과 함께 호출 될 JavaScript 함수이다. Ajax를 잘 알고 있다면 이 콜백 메커니즘이 XMLHttpRequest의 비동기화에 유용한 접근 방식이라는 것을 알 수 있을 것이다.

예제 시나리오에서, Listing 3의 JavaScript 함수를 사용하여 검색 결과로 UI를 검색 및 업데이트 한다. 이 리스팅은 DWR의 util.js에서 편리한 함수를 사용한다. $()라는 JavaScript 함수에 주목하라. 이것은 document.getElementById()의 다른 버전이라고 생각하면 된다. 타이핑 하기 쉽다. 프로토타입 JavaScript 라이브러리를 사용했다면, 이 함수가 익숙할 것이다.


Listing 3. 클라이언트에서 원격 findItems() 메소드 호출하기
				
/*
 * Handles submission of the search form
 */
function searchFormSubmitHandler() {

  // Obtain the search expression from the search field
  var searchexp = $("searchbox").value;

  // Call remoted DAO method, and specify callback function
  catalog.findItems(searchexp, displayItems);

  // Return false to suppress form submission
  return false;
}
       
/*
 * Displays a list of catalog items
 */
function displayItems(items) {

  // Remove the currently displayed search results
  DWRUtil.removeAllRows("items");

  if (items.length == 0) {
    alert("No matching products found");
    $("catalog").style.visibility = "hidden";
  } else {

    DWRUtil.addRows("items",items,cellFunctions);
    $("catalog").style.visibility = "visible";
  }
}

searchFormSubmitHandler() 함수에서, 재미있는 코드는 무엇보다도 catalog.findItems(searchexp, displayItems);이다. 이 한 줄의 코드는 네트워크를 통해 XMLHttpRequest를 DWR 서블릿으로 보내고 원격 객체의 응답과 함께 displayItems() 함수를 호출할 때 필요하다.

displayItems() 콜백 그 자체는 Item의 어레이와 함께 호출된다. 이 어레이는 DWRUtil.addRows() 함수로 전달되고, 전개할 테이블의 아이디와 함수의 어레이가 함께 전달된다. 각 테이블 행(row)에는 셀들이 있기 때문에 이 어레이에는 많은 함수들이 있다. 각 함수는 어레이에서 Item과 함께 호출되고 상응하는 셀에 전개될 콘텐트를 리턴해야 한다.

이 경우, 이 아이템 테이블의 각 행이 아이템의 이름, 디스크립션, 가격은 물론, 마지막 칼럼에는 아이템용 Add to Cart 버튼을 디스플레이 하도록 해야 한다. Listing 4는 이를 수행하는 셀 함수 어레이 모습이다.


Listing 4. 아이템 테이블을 전개하는 셀 함수 어레이
				
/*
 * Array of functions to populate a row of the items table
 * using DWRUtil's addRows function
 */
var cellFunctions = [
  function(item) { return item.name; },
  function(item) { return item.description; },
  function(item) { return item.formattedPrice; },
  function(item) {
    var btn = document.createElement("button");
    btn.innerHTML = "Add to cart";
    btn.itemId = item.id;
    btn.onclick = addToCartButtonHandler;
    return btn;
  }
];

처음 세 개의 함수들은 dwr.xml의 Itemconvertor에 포함된 필드의 콘텐트를 리턴한다. 마지막 함수는 버튼을 만들고, Item의 아이디를 여기에 붙이고, addToCartButtonHandler 함수가 버튼이 클릭될 때 호출되도록 지정한다. 이 함수는 두 번째 유스 케이스에 대한 엔트리 포인트이다. Item을 쇼핑 카트에 추가한다.




위로


쇼핑 카트 구현하기

DWR의 보안

DWR은 보안도 염두 해 두었다. dwr.xml을 사용하여 원격화 할 클래스와 메소드만 리스팅하면 악용될 수 있는 기능의 노출을 피할 수 있다. 게다가, 디버그 Test Mode를 사용하면 웹에 노출된 모든 클래스와 메소드를 검사할 수 있다.

DWR은 또한 역할 기반 보안을 지원한다. creator 설정을 통해 특정 빈에 액세스 하기 위해 사용자가 갖춰야 하는 J2EE 역할을 지정할 수 있다. URL 보안이 된 DWRServlet 인스턴스와 dwr.xml config 파일을 전개하여 다양한 사용자들에게 다양한 원격 기능들을 제공할 수 있다.

사용자 쇼핑 카트의 자바 구현은 Map에 기반하고 있다. Item이 카트에 추가될 때, Item은 키로서 Map으로 삽입된다. 그 Map에서 상응하는 값은 카트에 있는 Item의 양을 나타내는 Integer이다. 따라서 Cart.javaMap<Item,Integer>로 선언된 contents라는 필드를 갖고 있다.

해시(hash) 키로서 복합 유형을 사용하면 DWR에 문제가 생긴다. JavaScript에서, 어레이 키는 리터럴이어야 한다. 결과적으로, contents Map은 DWR에 의해 그 자체로 변환될 수 없다. 하지만, 쇼핑 카트 UI의 목적 상, 모든 사용자는 카트에 있는 각 아이템의 이름과 양을 봐야 한다. 따라서 getSimpleContents() 메소드를 Cart에 추가하여, contents Map을 취해 단순화된 Map<String,Integer>를 구현하여, 각 Item의 이름과 양만 나타내도록 하였다. 이러한 스트링 키 map 구현은 DWR의 빌트인 컨버터에 의해서 JavaScript로 변환될 수 있다.

클라이언트가 관심을 갖고 있는 Cart의 다른 필드는 totalPrice이다. 이것은 쇼핑 카트에 있는 모든 것의 총합을 나타낸다. Item과 마찬가지로, 숫자로 된 총합을 사전 포맷 된 String으로 나타낸 formattedTotalPrice을 제공했다.

카트 변환하기

콘텐트를 얻기 위해서 그리고 최종 가격을 알기 위해, 클라이언트 코드가 Cart로 두 번의 호출을 하도록 하는 대신, 이 모든 데이터를 클라이언트로 한번에 보낸다. 이를 위해서, 이상하게 보이는 메소드를 추가했다. (Listing 5):


Listing 5. Cart.getCart() 메소드
				
/**
 * Returns the cart itself - for DWR
 * @return the cart
 */ 
public Cart getCart() {
  return this;
}

이 메소드는 정상적인 자바 코드에서는 과잉이지만(메소드를 호출하면 Cart에 대한 참조가 이미 존재한다.) DWR 클라이언트가 Cart가 스스로를 JavaScript로 직렬화 시킬 수 있도록 한다.

getCart() 외에, 원격화 될 다른 메소드는 addItemToCart()이다. 이 메소드는 카탈로그 아이템의 아이디의 String 구현을 취해서, 이 아이템을 Cart에 추가하고, 총 합을 업데이트 한다. 이 메소드는 또한 Cart를 리턴하여, 클라이언트 코드가 Cart 콘텐트를 업데이트 하고 하나의 연산으로 새로운 상태를 받을 수 있다.

Listing 6은 확장된 dwr.xml config 파일로서, Cart 클래스를 원격화 하는데 필요한 여분의 config 정보가 포함되어 있다:


Listing 6. Cart 클래스를 통합하는 변경된 dwr.xml
				
<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
    "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
  <allow>
    <create creator="new" javascript="catalog">
      <param name="class" 
        value="developerworks.ajax.store.CatalogDAO"/>
      <include method="getItem"/>
      <include method="findItems"/>
    </create>
    <convert converter="bean" 
      match="developerworks.ajax.store.Item">
      <param name="include" 
        value="id,name,description,formattedPrice"/>
    </convert>
    <create creator="new" scope="session" javascript="Cart">
      <param name="class" 
        value="developerworks.ajax.store.Cart"/>
      <include method="addItemToCart"/>
      <include method="getCart"/>
    </create>
    <convert converter="bean" 
      match="developerworks.ajax.store.Cart">
      <param name="include" 
        value="simpleContents,formattedTotalPrice"/>
    </convert>
  </allow>
</dwr>

이 버전의 dwr.xml에서, Cartcreatorconvertor를 추가했다. create 엘리먼트는 addItemToCart()getCart() 메소드가 원격화 되고, 생성된 Cart 인스턴트가 사용자 세션에 놓이도록 지정한다. 결과적으로, 카트의 콘텐트는 사용자 요청 사이에 되풀이 된다.

Cartconvert 엘리먼트는 원격 Cart 메소드가 Cart 자체를 리턴하기 때문에 필요하다. 직렬화 된 JavaScript에 나타나야 하는 Cart의 멤버는 simpleContents 맵과 formattedTotalPrice 스트링이다.

약간 혼란스럽다면, create 엘리먼트는 DWR 클라이언트에 의해 호출될 수 있는 Cart에 대한 서버 측 메소드를 지정하고, convert 엘리먼트는 Cart의 JavaScript 직렬화에 포함될 멤버를 지정한다는 것을 기억하면 된다.

이제, 원격 Cart 메소드를 호출하는 클라이언트 측 코드를 구현할 수 있다.




위로


원격 Cart 메소드 호출하기

무엇보다도, 스토어 웹 페이지가 처음 로딩되면, 세션에 저장된 Cart의 상태를 검사하고 싶다. 사용자가 아이템들을 Cart에 추가하고 페이지를 리프레쉬 하거나 다시 검색할 수 있기 때문에 이는 필요하다. 이러한 상황에서, 재 로딩된 페이지는 세션에서 Cart 데이터와 연결되어야 한다. 나는 이 페이지의 함수에 수행된 호출을 사용했다: Cart.getCart(displayCart). displayCart()는 서버에서 Cart 응답 데이터와 함께 호출된 콜백 함수이다.

Cart가 이미 세션에 있다면 creator는 이를 가져오고 이것의 getCart() 메소드를 호출할 것이다. 어떤 Cart도 세션에 없다면 creator는 새로운 것을 인스턴스화 하여, 이것을 세션에 두고, getCart() 메소드를 호출한다.

Listing 7은 아이템의 Add to Cart 버튼이 클릭될 때 호출되는 addToCartButtonHandler() 함수의 구현 모습이다:


Listing 7. addToCartButtonHandler() 구현
				
/*
 * Handles a click on an Item's "Add to Cart" button
 */
function addToCartButtonHandler() {

  // 'this' is the button that was clicked.
  // Obtain the item ID that was set on it, and
  // add to the cart.
  Cart.addItemToCart(this.itemId,displayCart);
}

모든 통신을 책임지고 있는 DWR을 사용하여 클라이언트에서의 카트에 추가하기 작동은 문자 그대로 한 줄의 함수이다. Listing 8은 최종 가격이다. Cart의 상태로 UI를 업데이트 하는 displayCart() 콜백의 구현이다:


Listing 8. displayCart() 구현
				
/*
 * Displays the contents of the user's shopping cart
 */
function displayCart(cart) {

  // Clear existing content of cart UI
  var contentsUL = $("contents");
  contentsUL.innerHTML="";

  // Loop over cart items
  for (var item in cart.simpleContents) {

    // Add a list element with the name and quantity of item
    var li = document.createElement("li");
    li.appendChild(document.createTextNode(
                    cart.simpleContents[item] + " x " + item
                  ));
    contentsUL.appendChild(li);
  }

  // Update cart total
  var totalSpan = $("totalprice");
  totalSpan.innerHTML = cart.formattedTotalPrice;
}

simpleContentsString을 숫자로 매핑하는 JavaScript 어레이라는 것을 기억하라. 각 스트링은 아이템의 이름이고, 연관 어레이의 상응하는 숫자는 카트에 있는 아이템의 수량이다. 따라서 cart.simpleContents[item] + " x " + item 식은 "2 x Oolong 128MB CF Card"로 계산된다.

DWR Store 애플리케이션

그림 3은 DWR 기반의 Ajax 애플리케이션 실행 모습이다. 오른쪽에 사용자 쇼핑 카트와 검색된 아이템들을 디스플레이 하고 있다:


그림 3. DWR 기반의 Ajax 스토어 애플리케이션 실행 모습
Screenshot of example scenario, with search results and shopping cart



위로


DWR의 장단점

함수의 일괄처리

DWR에서, 여러 원격 호출이 하나의 HTTP 요청과 함께 서버로 보내질 수 있다. DWREngine.beginBatch()를 호출하면 DWR에게 후속 원격 호출들을 바로 보내지 말라고 명령하는 것이다. 이들을 하나의 일괄 요청으로 묶지 않는다. DWREngine.endBatch()을 호출하면, 일괄 요청이 서버로 보내진다. 원격 호출은 서버 측에서 순서대로 실행되고, 각 JavaScript 콜백이 실행된다.

일괄 작업은 두 가지 방식으로 레이턴시를 줄일 수 있다. 우선, XMLHttpRequest 객체를 만들고, 각 호출에 대해 HTTP 연결을 만드는 오버헤드를 피할 수 있다. 또한, 실행 환경에서, 웹 서버는 많은 동시 HTTP 요청들을 다룰 필요가 없기 때문에 응답 시간이 빨라진다.

DWR을 사용하여 Ajax 애플리케이션을 구현하기가 얼마나 쉬운지를 배웠다. 이 샘플 시나리오는 단순하고 유스 케이스를 구현하는데 매우 단순한 접근 방식을 취했지만, DWR의 역할을 과소 평가해서는 안된다. 이전 글에서, Ajax 요청과 응답을 직접 설정하고 자바 객체 그래프를 JSON으로 변환하는 과정을 설명했지만, 여기에서는 DWR이 이 모든 작업을 수행했다. 나는 50줄 미만의 JavaScript를 작성하여 클라이언트를 구현했고, 서버 측에서도 내가 했던 일은, 나의 JavaBean에 두 개의 추가 메소드만 추가했을 뿐이다.

물론, 모든 기술에는 단점도 있기 마련이다. RPC 메커니즘과 마찬가지로, DWR에서도 원격 객체로 하는 호출이 로컬 함수 호출보다 훨씬 더 비싸다는 것을 쉽게 잊는다. DWR은 Ajax를 숨기는 일은 잘 하지만, 네트워크는 투명하지 않다는 것을 기억해야 한다. DWR 호출에는 레이턴시가 있고, 애플리케이션은 대단위 원격 메소드가 되도록 설계되어야 한다. 이러한 이유로 addItemToCart()Cart 자체를 리턴한다. addItemToCart()를 유효 메소드로 만드는 것이 더 자연스럽지만, 각 DWR 호출 다음에는 getCart()가 호출되어 변경된 Cart 상태를 검색한다.

DWR은 호출 일괄처리 시 레이턴시 문제에 대한 자체 해결책을 갖고 있다. (함수 일괄처리 사이드 바 참조) 애플리케이션에 맞는 대단위 Ajax 인터페이스를 줄 수 없다면 호출 일괄처리를 사용하여 여러 원격 호출들을 하나의 HTTP 요청으로 묶는다.

영역의 분리

본질상, DWR은 클라이언트 측과 서버 측 코드간 강결합을 만든다. 우선, 원격 메소드의 API 변경은 DWR 스텁을 호출하는 JavaScript로 반영되어야 한다. 두 번째(더 중요한 것은), 이 커플링이 클라이언트 측 영역이 서버 측 코드로 누수 되어야 한다. 예를 들어, 모든 자바 유형들이 JavaScript로 변환될 수 있는 것은 아니기 때문에 자바 객체에 추가 메소드를 추가하여 보다 쉽게 원격화 될 수 있도록 한다. 예제 시나리오에서, CartgetSimpleContents() 메소드를 추가하여 이 문제를 해결했다. 또한 getCart() 메소드를 추가했는데, 이것은 DWR 시나리오에서는 유용하지만 완전한 과잉이다. 원격 객체에 대한 대단위 API가 필요하고, 특정 자바 유형을 JavaScript로 변환하는 문제 때문에, 원격화된 JavaBean이 Ajax 클라이언트에만 유용한 메소드로 인해 어떻게 오염되는지를 볼 수 있다.

이를 해결하기 위해, 래퍼 클래스를 사용하여 여분의 DWR 스팩의 메소드를 JavaBean에 추가한다. JavaBean 클래스의 자바 클라이언트는 원격화와 관련된 과잉이 더 이상 없고, 원격화된 메소드에 보다 친숙한 이름을 줄 수 있다. 예를 들어, getFormattedPrice() 대신 getPrice()로 한다. 그림 4는 Cart를 래핑하여 여분의 DWR 기능을 추가하는 RemoteCart 클래스 모습이다:


그림 4. 원격 기능을 위해 Cart를 래핑하는 RemoteCart
Class diagram of RemoteCart wrapper class

마지막으로, DWR Ajax 호출은 비동기식이고, 이들이 파견된 순서대로 리턴 되리라고 기대해서는 안된다. 예제 코드에서 작은 문제를 무시했지만, 이 시리즈의 첫 번째 글에서는 순서 없이 도착하는 데이터에 대한 방어책으로서 응답에 타임스탬프를 실행하는 방법을 설명했다.




위로


맺음말

DWR은 많은 기능을 한다. 서버 측 도메인 객체에 대한 인터페이스를 빠르고 간단하게 만든다. 서블릿 코드, 객체 직렬화 코드, 클라이언트-측 XMLHttpRequest 코드를 작성할 필요가 없다. DWR을 사용하면 웹 애플리케이션으로의 전개도 매우 간단하고, DWR의 보안 기능은 J2EE 역할 기반 인증 시스템과 통합될 수 있다. DWR이 모든 애플리케이션 아키텍처에 적용되는 것은 아니지만 도메인 객체의 API 디자인에 고려해볼 만한 가치가 있다.

Ajax와 DWR의 장단점에 대해 보다 자세히 알고 싶다면 직접 다운로드 하여 시험해 보기 바란다. 여기에서 미처 다루지 못한 DWR의 많은 기능들이 있지만, 이 글에 소개된 소스 코드는 DWR을 시작할 수 있는 좋은 출발점이 된다. 참고자료 섹션에는 Ajax, DWR, 관련 기술들이 보다 자세하게 설명되어 있다.

가장 중요한 포인트는 Ajax 애플리케이션에는 정해진 하나의 솔루션이 없다는 것이다. Ajax는 새로운 기술들을 사용하는 개발 분야이다. 이 시리즈를 통해서 Ajax 애플리케이션의 웹 티어에서 자바 기술을 활용하는 방법에 초점을 맞췄다. XMLHttpRequest-기반 방식에 객체 직렬화 프레임웍을 선택하든, 아니면 DWR의 고급 추상화를 사용했든 상관은 없다. 다음 달, Ajax for Java developers 시리즈를 기대해주기 바란다.

기사의 원문보기





위로


다운로드 하십시오

설명 이름 크기 다운로드 방식
DWR source code j-ajax3dwr.zip 301 KB  FTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론


필자소개

Philip McCarthy는 자바와 웹 기술 전문 소프트웨어 개발 컨설턴트이다. 현재는 Hewlett Packard 연구소와 Orange에서 디지털 미디어 및 텔레콤 프로젝트에 참여하고 있으며, City of London에서 금융 소프트웨어 관련 작업을 하고 있다. philmccarthy@gmail.com

Trackback 0 and Comment 0