본 시리즈의 이전 기술자료에서는 LAMP 계열 런타임과 Eclipse IDE로 구성된 개발 환경을 설정했다. 그리고, 데이터베이스, 미드-티어(mid-tier) PHP 로직, 간단한 XHTML을 생성하여 스타일링과 XML HTTP Request (XHR) 유틸리티 함수들로 싱글 페이지 기반 브라우저를 제공했다. 세 번째이자 마지막 시리즈에서는, JavaScript로 Ajax 클라이언트 로직을 구현할 것이다. PHP로 Representational State Transfer (REST) 요청 디스패처를 구현하여 deposit, debit, stock portfolio 값 같은 고객의 뱅킹 태스크를 수행할 것이다. 또한 SOAP (Simple Object Access Protocol) 웹 서비스 클라이언트(PHP)를 개발하여 실제 서드 파티(무료) 웹 서비스로 액세스 할 것이다. 이 코든 컴포넌트들(XHTML, CSS, JavaScript, PHP, Web services client, MySQL)을 통합하는 방법도 배울 것이다. 마지막으로, 개발된 시나리오를 LAMP 계열 런타임에서 전개, 테스트, 디버깅하는 방법을 설명한다. 이 때에는 Ajax 클라이언트, Apache-PHP-MySQL 런타임, 제휴 Eclipse 기반 IDE를 설명하는 엔드투엔드 시나리오 예제도 구현해볼 것이다.
시작하기 전에, Bank DB, Bank Logic, Bank Portal용 Bank 시나리오 생성물들(Part 2에서 개발됨)이 Eclipse IDE에 그대로 있는지 확인한다. SQL 스크립트는 데이터베이스를 생성 및 채운다. PHP 코드는 데이터베이스 액세스를 제공한다. XHTML, CSS, XHR은 싱글 페이지 브라우저 애플리케이션의 필요를 다룬다. 이러한 생성물들에 작성된 코드는 그림 1의 Bank 시나리오에 나타난 기능들의 일부만을 제공한다. 이러한 미리 개발된 생성물들을 잇는데 필요한 컴포넌트들은 아직 없다. XHTML 파일을 미리 본다면, 단일 브라우저 창에 다른 애플리케이션 스팩의 UI 스크린들을 디스플레이 할 것이다. 여러분은 올바른 클라이언트 측 JavaScript 로직을 작성하여 그러한 다양한 UI 스크린들을 통합하여 싱글 페이지 브라우저 애플리케이션의 효과를 주어야 한다. 같은 클라이언트 측 코드로, 적절한 XHR 비동기식 통신 로직이 추가되어야 한다. 클라이언트 측 JavaScript 코드가 없다면, Bank Teller 함수들은 수행될 수 없다.
그림 1. Bank 시나리오
특정 Bank Teller 함수들을 제공하는 모든 HTML 폼들은 사용자 데이터를 REST 기반의 미드 티어 서비스로 게시하도록 설정된다. deposit, debit, stock portfolio 값 액션들을 위한 Bank Teller의 브라우저 요청을 받을 또 다른 PHP 모듈로서 이러한 서비스를 개발해야 한다. 이 PHP 모듈은 Bank Teller의 특정 트랜잭션 요청을 파싱하고 요청을 처리 할 Bank Logic 함수를 호출하는 뱅크 요청 디스패처로서 작동할 것이다. 여러분은 또한 이와 같은 REST 기반 서비스를 PHP로 수행하는 것이 얼마나 쉬운지도 알게 될 것이다.
REST 요청 디스패칭용 PHP 서비스를 개발한 후에, 우리의 초점은 인터넷에서 사용할 수 있는 .NET 기반 웹 서비스로 옮겨간다. 웹 서비스는 현재 주식 티커 심볼을 무료로 가져올 수 있다. PHP 미드 티어에서 웹 서비스 클라이언트를 개발하여 PHP 기반 뱅크 액션 요청 디스패처에서 원격으로 이 웹 서비스에 액세스 하여 주식 시세를 알 수 있다. 그리고 나서, 뱅크 액션 요청 디스패처는 현재 주식 가격으로 Bank Logic PHP 모듈을 호출하여 계정 보유자를 위해 현재 포트폴리오 값을 계산한다. SOAP을 사용하는 웹 서비스 액세스 기술을 배우고, XML과 JavaScript Object Notation (JSON)이라는 데이터 교환 포맷에 대해서도 배울 것이다.
우리의 싱글 페이지 브라우저 기반 애플리케이션에서, Ajax 스타일 사용자 인터페이스와 데이터 교환을 위한 미드 티어 서비스와의 인터랙션을 핸들하는 클라이언트 측 로직이 필요하다. 본 시리즈 Part 2에서 설명된 것처럼, 많은 Ajax 프레임웍과 라이브러리들 중 하나를 사용할 수 있다. 하지만, 매우 선택적인 Ajax 기능에 집중하기 위해서, 미가공 JavaScript로 클라이언트 측 로직을 작성할 것이다. 이렇게 하면 다음과 같이 Ajax 관련 목표에 집중할 수 있다.
- 싱글 페이지 브라우저 애플리케이션
- 브라우저 DOM 조작
- 애플리케이션 정황에서 XHR 사용하기
- 애플리케이션 데이터 교환 시 JSON의 역할
- Ajax 코드의 클라이언트 측 디버깅
뱅크 시나리오에서 평범한 JavaScript 코드를 이해하면, 특별한 Ajax 프레임웍을 사용하여 같은 클라이언트 측 로직을 만들 수 있다. 각각의 방식에서, Eclipse 기반 Aptana Web IDE는 클라이언트 측 코드 개발을 수행하기에 이상적이다.
JavaScript가 강력한 언어 기능을 제공한다는 것은 다 알려진 사실이다. 브라우저 환경에서, JavaScript는 이벤트 핸들링 메소드를 제공하여 사용자 액션과, 타이머와 네트워크 이벤트 같은 시스템 액션을 포착한다. 우리의 뱅크 시나리오에서는 마우스 액션(mouseover, mouseout, mouseclick 등)과 XML HTTP Request (XHR) 객체를 사용한 서버 응답 비동기식 콜백에 이벤트 핸들러를 사용할 것이다.
싱글 페이지 브라우저 애플리케이션은 모든 사용자 인터페이스 관련 코드 생성물들(XHTML, CSS, JavaScript)이 애플리케이션 URL이 브라우저에 입력될 때 서버에서 단 한번에 다운로드 되어야 한다. 클라이언트 측 로직은 뱅크 시나리오의 클라이언트 측 요구 사항을 핸들하는데 필요한 모든 것을 갖고 있어야 한다는 의미이다. 스크린 레이아웃과 제휴 스타일링은 XHTML과 CSS 파일을 통해 전달된다. 기타 클라이언트 측 로직은 JavaScript로 작성된 코드를 통해 전달된다. 수 많은 로직은 다른 애플리케이션 스크린들을 나누고 이들을 하나의 스크린에 적절히 디스플레이 한다. 본 시리즈의 Part 2에서는 다른 스크린들을 배열할 때 <DIV>, <SPAN>, <TABLE> HTML 엘리먼트를 사용하여 전체 웹 애플리케이션을 위한 단일 XHTML 페이지를 만드는 방법을 설명했다. JavaScript를 사용하면, <DIV> 엘리먼트에 저장된 다른 사용자 인터페이스 콘트롤을 숨기고 보여주는 브라우저 DOM을 조작하는 것을 배울 수 있다. 게다가, CSS 규칙들의 동적인 할당을 통해 다른 사용자 인터페이스 컨트롤을 스타일링 하는 것에 대해 배울 수 있다. 이러한 애플리케이션(일반적으로 Bank Teller)의 사용자가 계정 관련 태스크(deposit, debit, stock portfolio 값 업데이트)를 수행할 때마다, 클라이언트 측 JavaScript 로직은 REST 스타일로 미드 티어 PHP 서비스와 통신한다. 이러한 인터랙션의 결과로, 애플리케이션 스팩의 데이터는 브라우저 클라이언트와 미드 티어 PHP 서비스 간 교환된다. 이 모든 것은 본 시리즈 Part 2에 설명된 것처럼 XHR 객체를 사용하여 수행된다. JavaScript 클라이언트 로직은 XHR 객체를 사용하여 애플리케이션 중심의 데이터를 서버와 주고 받는다. 비동기식 모드에서 서버 응답을 받는 Ajax 방법도 소개할 것이다.
Ajax(Asynchronous JavaScript + XML)의 컴포넌트에 이어서, 비동기성(asynchronous)과 JavaScript 컴포넌트를 설명했다. 이제는 Ajax 개발의 또 다른 중요한 구현 블록들을 다루어야 할 차례이다. 바로 데이터 표현이다. Ajax라는 단어에서는 XML이 주요 요소로 자리잡고 있지만, XML은 웹 애플리케이션에서 사용할 수 있는 유일한 데이터 교환 메커니즘은 아니다. XML은 소프트웨어 개발 커뮤니티에 잘 알려져 있기 때문에, 이 글에서는 여러분도 이미 잘 알고 있는 것을 반복할 필요가 없다. 대신, JSON이라고 하는 차세대 웹 데이터 포맷을 소개하겠다. XML과 마찬가지로, JSON은 텍스트 기반이며, 인간과 머신 모두 읽을 수 있다. 머신 가독성에 관한 한, JSON은 브라우저 애플리케이션에서 파싱하고 사용하기가 훨씬 더 쉽다. JavaScript 객체의 신택스와 어레이 데이터 구조를 따르기 때문이다. 브라우저 애플리케이션에서 JSON을 사용하는 것은 전체 데이터 구조를 일급 JavaScript 객체로서 취급한다는 의미이다. 이는 많은 개발자들에게는 좋은 소식이다. 추가 파싱 작업을 완벽히 줄여주기 때문이다. JSON 포맷은 자바, PHP, Ruby, C++ 같은 프로그래밍 언어들에서 인정을 받고 있다. 다음 섹션에서는 JSON의 구성 요소를 자세히 설명하도록 하겠다. 참고자료 섹션에서 JSON에 관한 자세한 내용을 참조할 수 있다. 기존 XML 데이터를 JSON 포맷으로 변환하려는 노력도 있다. 참고자료 섹션에 소개된 IBM® developerWorks 기술자료를 통해 이러한 기술들을 배울 수 있다. 우리의 뱅크 시나리오용 클라이언트 측 로직은 브라우저와 미드 티어 PHP 서비스 간 데이터 교환 포맷으로 JSON을 사용한다. 다음 섹션에서는, JavaScript와 PHP에서 JSON 프로세싱에 대해 설명한다.
JSON은 두 개의 구조를 기반으로 구현된다:
- 이름/값 쌍의 컬렉션.
- 다양한 언어들에서, 다음 중 하나로서 구현된다.
- Object
- Record
- Struct
- Hash table
- Associative array
- 값의 번호가 있는 리스트(ordered list)
- 대부분의 언어에서, 어레이로서 구현된다.
이것은 보편적인 데이터 구조이다.
- 모든 현대적인 프로그래밍 언어들은 이를 지원한다.
- 프로그래밍 언어들과 교환할 수 있는 구조들로 이루어진 데이터 포맷(JSON)은 이치에 맞는다.
이러한 구현 블록과 본 시리즈의 Part 1과 Part 2에서 배웠던 지식과 경험과 함께, 이제 Ajax 개발의 개념을 알게 되었다. Ajax를 구성하고 있는 많은 기술들이 존재했지만, 이러한 기술들을 혼합함으로써 애플리케이션을 개발하는 Ajax 방식은 최근 유행한 것이다. 기술들의 혼합은 웹 애플리케이션의 디버깅을 매우 중요하게 만든다. 뱅크 시나리오의 정황에서 디버깅 방식에 대해 알아보자.
이전 섹션에서 언급했듯이, JSON은 우리의 뱅크 시나리오에서 선택한 데이터 교환 포맷이다. JSON은 JavaScript eval 문을 사용하여 브라우저 애플리케이션에서 직접 소비될 수 있다. 하지만, 임의의 JSON 코드를 직접 계산하는 것은 보안상의 문제를 가져온다. 이러한 보안상의 문제를 줄이기 위해, JSON의 창시자인 Douglas Crockford는 JavaScript 객체로 변환될 수 있기 전에 JSON 포맷의 텍스트의 안전 검사를 수행하는 간단한 JavaScript 라이브러리를 만들었다. 우리는 JSON 데이터를 처리할 때 이러한 라이브러리 함수들을 사용한다.
먼저, JavaScript로 클라이언트 측 로직을 만든다:
- 브라우저를 열고 URL로 간다: http://www.json.org/json.js:
- File Download 다이얼로그 박스에서, Save를 클릭한다.
- c:\eclipse\workspace\BankTeller 디렉토리에 json.js 파일을 저장하고 브라우저를 닫는다.
- 아직 하지 않았다면, Eclipse에서 Aptana 퍼스펙티브로 변경한다: Window->Open Perspective->Other->Aptana를 클릭하고 OK를 클릭한다.
- Aptana 퍼스펙티브에서, 왼쪽 하단 프레임에서, Project라는 탭 뷰를 선택한다.
- BankTeller 프로젝트를 오른쪽 클릭하고, Refresh를 클릭한다. 이제, BankTeller 프로젝트의 일부로서 json.js 파일을 보게 된다.
- BankTeller 프로젝트를 오른쪽 클릭하고 New->JavaScript File을 선택한다.
- File name 필드에서, BankTeller.js를 입력하고 Finish를 클릭한다.
- Listing 1의 소스 코드에 파일 콘텐트를 붙이고 파일을 저장한다. 이러한 파일들의 코멘트를 검토하여 코드를 이해하거나 다음 섹션을 참조하면, 코드 로직을 잘 파악할 수 있다.
BankTeller.js 파일의 클라이언트 측 로직은 싱글 페이지 브라우저 애플리케이션을 만들고, 비동기식 방식으로 미드 티어 서비스와 통신하고, 서비스 액세스와 데이터 교환에 REST/JSON을 사용하는데 중요한 Ajax 개념을 담고 있다. 이 모든 것은 대부분 사용자 인터랙션과 XHR 객체용 JavaScript 이벤트 핸들러를 통해 수행된다. 이 파일의 함수들은 두 개의 다른 JavaScript 파일들(xhr.js와 json.js)의 다른 유틸리티 함수들도 필요로 한다. 이 파일의 코드는 애플리케이션 스팩의 변수와 상수들을 정의한다. 그리고 나서, JavaScript 함수들은 어떤 특정한 순서를 따르지 않는다. 다음 10개의 함수들은 Bank Teller 애플리케이션에서 사용자 인터랙션과 관련된 것들이다.
- initOnPageLoad
- showFooterOptions
- changeOptionsLinkStyleForSelection
- changeOptionsLinkStyleToDefault
- processTellerOperation
- hideShowAndInsertAsTopElement
- populateDropDownListWithAccountOwnersData
- setElementFocusAndTextAndCursorPosition
- processFooterOperation
- updateTellerActionResultTextArea
다음 9개의 함수들은 미드 티어 서비스에서 애플리케이션 스팩의 데이터를 교환하는 것과 관련이 있다.
- getAllAccountsInformation_Async
- http_response_async_callback_for_get_all_acounts_info
- depositAmountAction_Async
- http_response_async_callback_for_deposit_to_account
- debitAmountAction_Async
- http_response_async_callback_for_debit_from_account
- portfolioAction_Async
- http_response_async_callback_for_get_stock_portfolio_value
- getHostnameFromThisURL
이 파일은 이러한 Ajax 브라우저 애플리케이션의 내부 작동을 이해하는데 도움이 되도록 충분한 주석이 달려있다. 다음 디스크립션은 클라이언트 측 JavaScript 함수들에 대한 고급 정보를 제공한다. 자세한 내용은 BankTeller.js 파일의 코멘트를 읽어보라. 사용자의 브라우저가 이 애플리케이션의 URL을 가리키면, 이 애플리케이션의 유일한 XHTML 페이지가 서버에서 파견되고 브라우저에 로딩된다. 초기 페이지 로딩 동안, initOnPageLoad 함수가 실행된다. 앞서 언급했듯이, 이 애플리케이션의 사용자 인터페이스에는 HTML <DIV> 엘리먼트를 사용하여 다른 섹션들로 나뉘는 하나의 XHTML 페이지가 포함되어 있다. "mainPage"라고 하는 메인 <DIV> 엘리먼트가 있는데, 이것은 브라우저 DOM 트리 구조의 탑 레벨에 있다. 다른 모든 <DIV> 엘리먼트들은 메인 <DIV> 엘리먼트의 자식들이다. 이 함수에서, 이 애플리케이션에 있는 모든 <DIV> 엘리먼트들은 글로벌 변수에 저장된다. 메인 페이지와 텔러 메뉴 옵션을 제외한 모든 <DIV> 엘리먼트는 이들을 숨기는데 CSS 규칙이 적용된다. 이 모든 <DIV> 엘리먼트들은 나중에 사용하기 위해 글로벌 변수에 저장되기 때문에, 숨은 <DIV> 엘리먼트들 역시 부모 <DIV> 엘리먼트에서 제거되어 브라우저에서 수직적 스크롤 바를 피한다. Ajax XHR 호출은 뱅크 계정 정보를 비동기식으로 가져온다.
showFooterOption 함수는 애플리케이션의 <DIV> 섹션에서 페이지 풋터를 보여주거나 숨긴다. 이 페이지 풋터는 현재의 텔러 이름과 이 애플리케이션의 다른 스크린에서 메인 메뉴로 돌아가는 또 다른 옵션을 디스플레이 한다. 이것은 "visible" 또는 "hidden" 같은 CSS 빌트인 스타일을 사용하여 페이지 풋터를 보여주거나 숨긴다.
이 애플리케이션은 메뉴를 사용하여 수행될 Bank Teller 옵션을 선택한다. 이 애플리케이션의 메인 스크린은 메뉴를 디스플레이 한다. 메뉴 구조는 <SPAN> 엘리먼트에 삽입된 정식 HTML 텍스트를 사용하여 XHTML 파일로 코딩된다. 이러한 <SPAN> 엘리먼트들에는 mouseover, mouseout, onclick 마우스 이벤트 핸들러가 할당된다. mouseover와 mouseout 이벤트가 발생할 때마다, 각각의 이벤트 핸들러 함수들(changeOptionsLinkStyleForSelection, changeOptionsLinkStyleToDefault)이 호출된다. 이러한 함수 안에서, 이러한 <SPAN> 엘리먼트들의 스타일이 배경색을 가진 CSS 클래스 규칙 또는 배경색이 없는 CSS 규칙을 사용하여 토글링 된다. 이는 메뉴 옵션의 하이라이팅 효과를 만들어 낸다.
processTellerOperation 함수는 사용자가 <SPAN> 엘리먼트의 menuitem 텍스트를 클릭할 때 실행되는 onclick 이벤트용 이벤트 핸들러이다. 이 함수는 매개변수로 전달되어 어떤 메뉴 옵션을 사용자가 선택했는지를 가리킨다. 이 함수 안에, 현재 선택된 메뉴 옵션은 글로벌 변수에 저장되어 텔러에 의해 수행되는 현재 Bank Teller 옵션의 기록을 저장한다. 메뉴 옵션 <DIV> 엘리먼트는 숨겨지고, 선택된 Bank Teller용 UI 컨트롤을 숨기고 있는 또 다른 <DIV> 엘리먼트가 나타난다. 새롭게 보여지는 스크린(deposit, debit, portfolio value)에서, 리스트는 모든 계정 보유자 이름들로 채워진다. 이 리스트에서, 텔러는 계정 보유자를 선택하고, 필요한 Bank Teller 연산을 수행한다.
hideShowAndInsertAsTopElement 함수는 숨겨질 엘리먼트, 보여질 엘리먼트, 특정 엘리먼트 아이디, 인풋 필드에 설정될 선택적 커서 위치, 페이지 풋터를 보여주거나 숨기는 옵션 같은 여러 인풋 매개변수들을 가진 유틸리티 함수이다. 인풋 매개변수에 기반하여, 상응하는 엘리먼트를 보여주고 숨긴다. 가끔, 다른 인풋 매개변수들을 통해 명령을 받은 일들을 수행한다.
populateDropDownListWithAccountOwnersData 함수는 리스트 박스에 모든 계정 보유자 이름들을 삽입한다. 이렇게 되면 Bank Teller는 특정 고객 이름을 선택하여 필요한 텔러 기능을 수행하기 쉽다. 이 함수는 계정 보유자 이름을 정렬하면서, 이들을 리스트 박스로 삽입한다.
updateTellerActionResultTextArea 함수는 텍스트 영역에서, Bank Teller 액션의 결과를 업데이트 한다. processFooterOperation이라고 하는 또 다른 함수는 페이지 풋터에서 사용할 수 있는 옵션을 처리한다.
이제, XHR 관련 함수를 살펴보자. 우리 애플리케이션은 진정한 싱글 페이지 Ajax 애플리케이션이기 때문에, 프리젠테이션 콘텐트는 애플리케이션 시작 시에만 다운로드 된다. 따라서, 브라우저 클라이언트는 애플리케이션 스팩의 데이터 교환의 경우에만 서버로 간다. 데이터 교환은 XHR 객체를 사용하여 비동기식 방식으로 수행된다. REST(Representational State Transfer) 스타일로 미드 티어 서비스로 액세스 한다. REST는 PUT, GET, POST, DELETE 같은 HTTP 동사들을 사용하면서, 데이터를 교환함으로써 원격 서버 리소스를 다루는 방법을 나타내고 있다. (참고자료.)
많은 Ajax 애플리케이션에서, XHR은 REST 스타일의 액세스 메커니즘과 잘 작동한다. 이전 섹션에서 설명했듯이, JSON 포맷은 애플리케이션 데이터를 인코딩 하는데 사용된다. 이 애플리케이션에서, 브라우저와 미드 티어 서비스 간 네 개의 다른 데이터 교환이 있다. 이러한 네 개의 데이터 교환에 개입된 절차는 매우 비슷하다. 따라서, Deposit Bank Teller 함수용 데이터 교환만 이 글에서 설명하겠다. 각각의 데이터 교환은 두 개의 다른 JavaScript 함수를 통해 수행된다. 하나는 요청을 미드 티어 서비스로 보내는 것이고, 하나는 서버 응답 데이터를 비동기식으로 받는 것이다. Bank Teller가 Deposit 함수를 수행하면, 예금액을 입력하고 Deposit 버튼을 누르기 전에 계정 소유자 이름을 선택한다. 이 버튼용 onclick 이벤트는 depositAmountAction_Async라는 이벤트 핸들러로 설정된다. 이 함수 내에서, 예금액은 인풋 필드에서 읽히고 유효성 검사가 된다. 그리고 나서, 계정 소유자 이름이 드롭다운 리스트에서 선택되고, 호스트 이름은 완전한 문서 URL에서 획득된다. 이때, JSON 객체는 두 개의 객체 프로퍼티(계정 소유자 이름과 예금액)를 사용하여 생성된다. 이는 REST와 POST HTTP 동사를 사용하여 미드 티어 서비스로 보내지는 데이터이다.
JSON 객체를 JSON 포맷 스트링으로 변환하려면, json.js 파일에서 유틸리티 함수를 사용한다. (Douglas Crockford 개발). HTTP POST 쿼리 스트링은 두 세트의 키-값 쌍으로 생성된다. 첫 번째의 키-값 쌍은 미드 티어 서비스에게 어떤 리소스나 명령어가 수행되어야 하는지를 명령한다. 이 경우, Deposit 명령어이다. 두 번째 키-값 쌍은 미드 티어 서비스에게 브라우저에서 보내진 요청 데이터에 대해 말해준다. 이 경우, 이것은 계정 소유자 이름과 예금액으로 구성된 JSON 포맷 데이터이다. 그리고 나서, 미드 티어 서비스 URL이 할당된다. 이 후에, 새로운 XHR 객체가 생성되고, 가장 중요한 콜백 함수 http_response_async_callback_for_deposit_to_account가 설정된다. xhr.js의 유틸리티 함수 sendHttpRequest는 인풋 매개변수로서 XHR 객체, 콜백 함수, 미드 티어 서비스 URL, 포스트 데이터로 호출된다. 이것은 Deposit 함수용 데이터-교환 요청을 미드 티어 서비스로 보낸다.
이제, 콜백 함수에 대해 알아보자. 콜백 함수는 모든 HTTP 상태 변화를 위해 호출된다. 콜백 함수 내에서 검사되는 HTTP 상태들은 HTTP_READYSTATE_LOADED와 HTTP_STATUS_OK 등이 있다. 이러한 두 개의 상태들은 서버 응답 데이터를 완전히 받았는지, HTTP 내부 상태 코드가 200인지를 가리킨다. 이러한 두 가지 조건이 부합되면, 서버 응답 데이터가 XHR 객체의 내부 프로퍼티(responseText)로부터 읽힌다. JSON 포맷 스트링 데이터는 json.js에서 유틸리티 함수 parseJSON을 사용하여 안전하게 변환된다. 이러한 변환의 결과는 네이티브 JavaScript 객체이다. 이 객체 안에서, 애플리케이션 스팩의 상태는 Deposit 함수가 성공적이었는지 여부를 알기 위해 검사된다. 성공 시, 리턴된 계정 정보 객체가 글로벌 변수 tellerActionResultInfo에 저장된다. 마지막으로, 현재 Deposit 연산 스크린이 숨겨지고, Bank Teller 함수 결과 디스플레이 스크린이 보이게 되고, 결과 데이터가 텔러가 볼 수 있도록 업데이트 된다.
지금까지 클라이언트 측 JavaScript 코드의 내부 로직에 대해 알아보았다. 클라이언트 측 로직은 실제 상황에서 벌어질 수 있는 많은 런타임 에러들을 다루지 않는다. Listing 1의 코드에 있는 주석을 꼼꼼히 체크하기 바란다.
다음 섹션에서는 미드 티어 서비스에 초점을 맞추고, 뱅크 시나리오 구현으로 끝을 맺도록 하겠다.
웹 서비스는 XML과 JSON 같은 표준화 된 메시지 포맷을 통해 네트워크로 접근하는 연산들의 컬렉션을 기술하는 인터페이스이다. 웹 서비스는 프로그램 대 프로그램 인터랙션을 수행하는데 주로 사용된다. 웹 서비스는 애플리케이션들이 보다 신속하고, 쉽고, 저렴하게 통합될 수 있도록 한다. 통합은 비즈니스 서비스 시맨틱을 중심으로 한 메시지를 기반으로 메시지 스택의 고급 레벨에서 발생한다. 엔터프라이즈 내외에서 공통 방식을 사용하여 비즈니스 함수들의 유연한 통합을 실행한다.
일반적인 웹 서비스 모델에 도달하는 열쇠는 표준이다. 중요한 표준으로는 HTTP, SOAP, REST, XML, JSON, WSDL (Web Services Description Language) 등이 있다.
그림 2는 웹 서비스 모델의 중요한 역할과 인터랙션을 묘사하고 있다. 다음은 웹 서비스 아키텍처 모델에 개입된 세 가지 일반적인 역할이다.
- 서비스 공급자(Service provider)
- 서비스 레지스트리(Service registry)
- 서비스 요청자(Service requester)
다음은 웹 서비스 아키텍처 모델에 속한 세 가지 인터랙션이다.
- Publish
- Find
- Bind
그림 2. 웹 서비스 역할과 인터랙션
서비스 공급자(service provider)는 서비스의 소유자 또는 플랫폼이다. 서비스 요청자(service requester) 또는 서비스 소비자(service consumer)는 서비스와의 인터랙션을 호출하거나 초기화 하는 애플리케이션이다. 서비스 소비자 역할은 사용자 인터페이스(PHP, 자바, Ruby, 서블릿, EJB) 없이 사람 또는 프로그램에 의해 구동되는 브라우저 애플리케이션에 의해 작동될 수 있다. 서비스 레지스트리(service registry)는 서비스 디스크립션의 검색 가능한 디렉토리로서, 서비스 공급자는 자신들의 서비스 디스크립션을 공개한다. 서비스 소비자는 레지스트리를 사용하여 서비스를 찾고 서비스와 관련한 정보를 획득한다.
Publish 인터랙션은 서비스 공급자가 서비스 디스크립션을 공개하여 서비스 소비자가 서비스를 찾을 수 있도록 한다. Find 인터랙션은 서비스 소비자가 서비스 디스크립션을 직접 찾을 수 있도록 한다. Bind 인터랙션은 서비스 소비자가 런타임 시 서비스 디스크립션에 지정된 바인딩 상세를 사용하여 서비스와의 인터랙션을 호출하거나 초기화 할 수 있도록 한다.
서비스 디스크립션은 웹 서비스 모델의 중요한 측면이다. WSDL은 서비스 공급자가 머신과 인간이 읽을 수 있는 포맷으로 서비스를 기술할 수 있도록 하는 표준이다. 그림 3은 WSDL 문서의 구조이다. WSDL 표준은 두 부분, 서비스 인터페이스와 서비스 구현을 갖고 있다. 서비스 인터페이스(service interface)는 다중 서비스 구현들에 의해 참조될 수 있는 추상적이거나 재사용 가능한 서비스 정의이다. 서비스 구현(service implementation)은 특정 서비스가 주어진 서비스 공급자에 의해 구현되는 방식을 기술한다.
WSDL 서비스 인터페이스에서, 유형들은 서비스 소비자와 서비스 공급자 간 인터랙션에 사용될 커스텀 XML 데이터 유형들을 정의한다. 메시지는 어떤 XML 데이터 유형들이 서비스 소비자와 서비스 공급자 간 전달되는 페이로드의 다양한 부분들을 구성하는지를 지정한다. 연산은 웹 서비스의 인풋과 아웃풋에 어떤 메시지가 나타날 수 있는지를 정의한다. PortTypes는 허용된 웹 서비스 연산들을 정의한다. 마지막으로 바인딩은 프로토콜과 데이터 포맷을 기술한다.
WSDL 서비스 구현에서, 포트(port) 엘리먼트는 엔드포인트(네트워크 주소 위치 또는 URL)와 서비스 인터페이스의 바인딩 엘리먼트를 연결한다. 서비스 엘리먼트는 포트 엘리먼트의 컬렉션을 포함하고 있다.
그림 3. WSDL의 구조
텔러가 수행하는 뱅크 액션들 중 하나는 해당 계정 소유자의 현재 수식 포트폴리오 값을 가져오는 것이다. Bank Teller가 웹 페이지에서 이 옵션을 선택하면, HTTP 요청은 미드 티어 PHP 서비스로 보내진다. Bank Logic PHP 모듈이 호출되어 주식 포트폴리오의 가치를 계산하기 전에, 매개변수로서 현재 주식 시세를 보내야 한다. 계정 소유자의 포트폴리오에 저장된 단일 주식의 현재 가격을 가져오려면, 인터넷에 호스팅 된 원격 웹 서비스에 액세스 해야 한다.
원격 웹 서비스로 액세스 하려면, WSDL을 사용하여 웹 서비스 클라이언트 프록시를 생성해야 한다. PHP에서, 단 몇 줄의 코드로 이를 수행할 수 있다. PHP SOAP Client 라이브러리로는 웹 서비스 클라이언트가 서비스 공급자에 의해 제공된 WSDL에서 동적으로 생성될 수 있다. 이 경우, WebserviceX.net 에 의해 인터넷에서 무료로 제공되는 .NET 기반 주식 시세 서비스를 사용하게 될 것이다. 시간을 내어 참고자료 섹션의 WebServiceX.net 링크에 방문하여 원격 주식 시세 서비스용 WSDL 파일을 이해하기 바란다.
WebserviceX.net에 공개된 주식 시세 서비스 WSDL을 사용하여 PHP에서 웹 서비스 클라이언트를 생성하는 단계는 다음과 같다.
- Eclipse PHP 퍼스펙티브로 전환한다. Window->Open Perspective->Other->PHP를 클릭하고 OK를 클릭한다.
- PHP Explorer 뷰(좌측 상단 프레임)에서, BankTeller 프로젝트를 오른쪽 클릭하고 New->PHP File을 선택한다.
- 파일 이름에
GetStockPrice.php를 입력한다. - Finish를 클릭한다.
- Listing 2의 소스 코드를 입력하거나 붙여서 이 파일의 콘텐트를 바꾸고 파일을 저장한다. 파일의 주석들을 검토하여 코드를 이해하거나, 다음 섹션에서 고급 코드 로직을 파악하라.
Listing 2. GetStockPrice.php 파일의 콘텐트
<?php
/*
============================================================
Project: End-to-End-Ajax application development
Purpose: This is an example scenario to be used in
an IBM developerWorks article.
Last modified: May/17/2007.
This PHP module provides the logic to access a remote
Web service hosted on the Internet. This Web service
will return the complete and current stock details about a
given stock ticker symbol.
This module shows how easy it is to consume a remote
Web Service (running on a .NET platform) using PHP
dynamically by pointing to a remote WSDL file for that
Web service.
It uses PHP SOAP Client library to accomplish that.
============================================================
*/
// Get the required Bank Logic PHP module.
require_once("BankLogic.php");
/*
============================================================
Function: getStockPortfolioValue
Last modified: May/17/2007.
This function accepts an account holder name as input.
In this scenario, all the account holders have a single stock
in their respective portfolio. The code here obtains the
ticker symbol of the stock held by the given account holder.
Then it uses PHP SOAP client to remotely invoke the
.NET based stock quote Web service and obtains the
XML-based response returned by that service. It parses the
XML-based stock details response and gets the current
stock price of that stock. It then calls another function
inside of the Bank Logic PHP module to update the database
with the new portfolio value.
============================================================
*/
function getStockPortfolioValue($accountHolderName) {
// From the Bank Logic module, obtain all the account
// information stored in the database.
// [If someone wants to optimize it, a new function
// could be written directly to return the account
// information for the given account holder, instead of
// retrieving all the account information.]
$finalResult = getAllAccountInformation();
// Ensure that all the account information was read from the DB.
if ($finalResult["ResultCode"] != 0) {
// Some error occurred. Return now.
return($finalResult);
} // End of if ($finalResult["ResultCode"] != 0)
// Get the account info of the customer whom we are dealing with now.
$accountInfoArray = $finalResult["AccountInfo"];
$tickerSymbol = null;
// Loop through all the available account information and filter
// the account information for the account holder's name that was
// passed as a parameter to the function we are in now.
foreach ($accountInfoArray as $accountInfo) {
// Is it the account for the person of interest?
if (strcasecmp($accountInfo["AccountHolderName"], $accountHolderName) == 0) {
// Get the stock ticker symbol of the only stock held in this portfolio.
$tickerSymbol = $accountInfo["StockName"];
// We got it. Skip out of the loop now.
break;
} // End of if (strcasecmp($accountInfo["AccountHolderName"] ...
} // End of foreach ($accountInfoArray as $accountInfo)
// If there was an error in getting the ticker symbol, return now.
if ($tickerSymbol == null) {
$finalResult["ResultCode"] = 1;
$finalResult["ResultMsg"] =
"Unable to get ticker symbol from the account of $accountHolderName.";
return($finalResult);
} // End of if ($tickerSymbol == null)
// This is the WSDL published by the service provider.
$wsdl = "http://www.webservicex.net/stockquote.asmx?WSDL";
// The magic happens here in the next four lines to execute
// a fairly complex function remotely over the Internet.
// It is really cool. Why can't the other middleware runtimes follow
// the simplicity of PHP to do such things.
// Instantiate the PHP SOAP client library by pointing directly to
// remote WSDL URL.
$proxy = new SoapClient($wsdl, array("trace"=>1,"exceptions"=>0));
// Set the required input parameter for the remote service.
// In our case, it is just the ticker symbol.
$param['symbol'] = $tickerSymbol;
// Execute the remote logic. It is that simple.
$result = $proxy->GetQuote($param);
// You have the XML-based response string now.
$quoteResult = $result->GetQuoteResult;
// Convert the XML formatted string into a DOM object.
// PHP also does XML processing so elegantly and simply.
$xml = simplexml_load_string($quoteResult);
$stockPrice = 0.0;
// The XML-based stock quote response is somewhat elaborative.
// It contains information about different aspects of the given stock.
// We are interested only in the current market price of that stock.
// That information is available as:
// <Stock>...<Last>56.34</Last>...</Stock>
// All we have to do is just parse the value of the <Last> XML element.
// See for yourself how easy it is to do this in PHP.
if (property_exists($xml, "Stock") == true) {
// We have the <Stock> element in the Web service response.
$stockInfo = $xml->Stock;
// Now, check if the <Stock> element contains a child named <Last>.
if (property_exists($stockInfo, "Last")) {
// Just retrieve the last market price of this stock.
$stockPrice = $stockInfo->Last;
} else {
$finalResult["ResultCode"] = 1;
$finalResult["ResultMsg"] =
"Unable to get current stock price of " .
"$accountHolderName's stock $tickerSymbol.";
return($finalResult);
} // End of if (property_exists($stockInfo, "Last"))
} else {
$finalResult["ResultCode"] = 1;
$finalResult["ResultMsg"] =
"Unable to get current stock price of " .
"$accountHolderName's stock $tickerSymbol.";
return($finalResult);
} // End of if (property_exists($xml, "Stock") == true)
// Now that we have the current stock price, compute the
// portfolio value and update it in the DB.
// Return the result to the caller of this function.
$finalResult = portfolioValue($accountHolderName, $stockPrice);
return($finalResult);
} // End of function getStockPortfolioValue
?>
|
이전 섹션에서 웹 서비스 클라이언트를 생성하기 위해 여러분이 따라갔던 절차는 PHP SOAP 클라이언트 라이브러리에서 사용할 수 있는 가장 간단한 방법 중 하나이다. GetStockPrice.php의 로직은 주식 시세 서비스에 대한 웹 서비스 클라이언트가 http://www.webserviceX.net URL에 호스팅 되도록 한다. PHP SOAP 클라이언트 라이브러리는 서비스 공급자에 의해 공개된 WSDL URL을 직접 가리키고, WSDL로 인코딩 된 서비스 디스크립션 정보를 사용하여 서비스용 내부 인-메모리 프록시를 동적으로 생성한다. 그리고 나서, 프록시 코드는 주식 시세 함수가 머신에서 로컬로 사용하는 것처럼 원격 호출을 한다. 이 경우, 클라이언트 프록시는 SOAP 액세스 프로토콜을 사용하여 원격 주식 시세 서비스와 인터랙션 한다. 인풋으로서 주식 티커 심볼을 보내고, 주식 시세 서비스에서 온 아웃풋으로서 XML 문서를 받는다.
GetStockPrice.php의 로직은 간단하다. 단 한 개의 함수만 포함되어 있기 때문이다: getStockPortfolioValue PHP 모듈의 경우 BankLogic.php 모듈이 데이터베이스 액세스 함수를 사용해야 한다. getStockPortfolioValue 함수는 주식 포트폴리오 값이 계산 및 업데이트 되어야 하는 계정 소유자 이름의 매개변수를 취한다. 데이터베이스에 저장된 모든 계정 정보를 가져다가 해당 계정 소유자에 속한 것을 필터링 한다. 모든 계정을 위한 정보를 내보내는 대신, 이 코드를 수정하여 특정 계정 소유자에 대한 계정 정보만 얻는다. (이 부분은 나중에 직접 수행할 것이다.) 필터링 된 계정 정보에서, 주식 포트폴리오에 저장된 단 한 개에 대한 티커 심볼을 얻을 수 있다. 그리고 나서, PHP SoapClient 객체는 주식 시세 WSDL URL을 매개변수로서 클래스 구조체로 전달함으로써 초기화 된다. 주식 티커 심볼은 웹 서비스용 인풋 매개변수로서 추가된다. 프록시 상의 GetQuote 메소드가 호출되는데, 이는 원격 웹 서비스의 SOAP 호출을 수행한다. 성공 시, 웹 서비스 응답을 XML 포맷 스트링으로서 받을 수 있다. PHP는 XML 포맷 스트링을 XML DOM 객체 구조로 변환하는 가장 간단한 방법을 제공한다. XML 트리에서, <Last>라고 하는 엘리먼트에는 해당 주식의 현재 시장 가격이 들어 있다. <Last>의 값이 파싱된다. 마지막으로, Bank Logic PHP 모듈의 portfolioValue 함수가 계정 소유자 이름과 현재 주식 가격과 함께 호출된다. 이 함수는 새로운 포트폴리오 값을 현재 주식 시세를 사용하여 계산하고, 데이터베이스를 업데이트 하고, 이전 및 현재 포트폴리오 값을 포함하고 있는 제휴 어레이(associative array)를 리턴한다. 제휴 어레이는 getStockPortfolio 함수의 콜러에게 리턴된다.
원격 주식 시세 서비스의 결과는 문제의 주식 티커 심볼에 대한 많은 정보를 갖고 있는 XML 문서이다. Listing 3은 주식 티커 심볼 IBM에 관한 주식 시세 서비스 아웃풋이다. 아웃풋 XML에는 보고된 주식 가격의 날짜와 시간, 시작 가격과 마감 가격, 가격의 백분율 변화, 최고가와 최저가, 거래량, 실제 가격폭, 주식 당 수익, 주식의 P/E 비율 같은 많은 정보들을 포함하고 있다. 이 모든 정보들 중에서, 우리가 관심이 있는 것은 해당 주식 티커 심볼의 마감 가격이다. 이는 <Last> XML 엘리먼트에 있는 것이다. getStockPrice 메소드의 나머지 코드들은 DOM 파서를 사용하여 웹 서비스에서 전체 XML 결과를 파싱하는 것에 관한 것이다.
Listing 3. 원격 주식 시세 웹 서비스에서 온 XML 응답 예제
<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="http://www.webserviceX.NET/">
<StockQuotes>
<Stock>
<Symbol>IBM</Symbol>
<Last>101.17</Last>
<Date>4/27/2007</Date>
<Time>4:01pm</Time>
<Change>+0.27</Change>
<Open>100.30</Open>
<High>101.17</High>
<Low>100.06</Low>
<Volume>6141359<Volume>
<MktCap>152.3B</MktCap>
<PreviousClose>100.90</PreviousClose>
<PercentageChange>+0.27%</PercentageChange>
<AnnRange>72.73 - 101.17</AnnRange>
<Earns>6.262</Earns>
<P-E>16.11</P-E>
<Name>INTL BUSINESS MAC</Name>
</Stock>
</StockQuotes>
</string>
|
필수 생성물들을 파악하고 구현해 보았다. 이제 마지막으로, 모든 세 개의 티어들에 대한 코드를 이어주는 REST 요청 디스패처에 대해 알아보자. PHP는 REST 서비스 호출(이 경우, HTTP POST)을 간단히 받고, 이들을 해당 서비스 함수들로 보내고, 결과를 브라우저 클라이언트로 리턴한다. 브라우저 클라이언트와 PHP 모듈 간 데이터 교환은 JSON 포맷을 사용하여 수행되고, PHP로 된 JSON 파서가 필요하다. 우리는 오픈 소스 JSON 파서를 사용할 것이다. (PEAR.net) 이 섹션에서는 구현 상세와 REST 요청 디스패처 PHP 모듈의 디스크립션을 제공한다.
이 단계들을 사용하여 REST 요청 디스패처 PHP 모듈을 구현한다:
- Eclipse PHP 퍼스펙티브로 전환한다: Window->Open Perspective->Other->PHP를 선택하고 OK를 클릭한다.
- PHP Explorer 뷰(좌측 상단 프레임)에서, BankTeller 프로젝트를 오른쪽 클릭하고 New->PHP File을 선택한다:
- 파일 이름에
JSON.php를 입력한다. - Finish를 클릭한다.
- 브라우저를 열고 다음 URL로 간다: http://mike.teczno.com/JSON/JSON.phps:
- 브라우저에 디스플레이 된 모든 콘텐트를 클립보드에 복사하고 브라우저를 닫는다.
- 클립보드에서 콘텐트를 붙임으로써 Eclipse 에디터에 있는 JSON.php 파일의 모든 콘텐트를 바꾼다.
- File->Save를 클릭한다.
- 파일을 닫는다.
- PHP Explorer 뷰(좌측 상단 프레임)에서, BankTeller 프로젝트를 오른쪽 클릭하고 New->PHP File을 선택한다:
- 파일 이름에
BankActions_REST_Service.php를 입력한다. - Finish를 클릭한다.
- Listing 4의 소스 코드를 입력하거나 붙여서 이 파일의 콘텐트를 대체하고, File->Save를 클릭하여 파일을 저장한다.
BankActions_REST_Service.php의 간단한 코드 로직은 브라우저 클라이언트 요청을 보내서 Bank Teller 함수가 수행되도록 한다. 이 PHP 모듈은 세 개의 다른 PHP 모듈에 의존한다. 이 중 두 개는 이 프로젝트의 일부이고(BankLogic.php와 GetStockPrice.php), 다른 하나는 PHP로 된 외부 오픈 소스 JSON 파서이다. 우리는 이미 이 두 PHP 모듈에서 사용할 수 있는 모든 함수들을 다루었다. JSON.php 라이브러리는 사용하기가 매우 쉽다. PHP 프로그래밍 환경과 흡사하다. JSON.php는 JSON 파서에 다음과 같은 함수들을 제공한다:
-
decode()는 JSON 데이터를 PHP 객체로 변환한다. -
encode()는 PHP 제휴 어레이를 JSON 데이터 구조로 변환한다.
브라우저 클라이언트가 뱅크 시나리오 미드 티어 서비스로 RESTful (HTTP POST) 서비스 호출을 할 때, BankActions_REST_Service.php의 코드는 브라우저 클라이언트에 의해 게시된 서비스 인풋을 모은다. 브라우저 클라이언트에 의해 게시된 인풋 데이터는 PHP 서버의 수퍼글로벌 $_REQUEST 제휴 어레이의 키-값 쌍으로서 사용할 수 있다. 브라우저 클라이언트에 의해 보내진 인풋 데이터에는 두 개의 키-값 쌍이 있다. 이 중 하나에는 수행되어야 할 Bank Teller 명령어가 포함되어 있다. 대부분 deposit, debit, 또는 get/update portfolio 값이다. 다른 데이터 아이템에는 Bank Teller 명령어를 수행하는데 필요한 애플리케이션 스팩의 데이터가 포함되어 있다. 이 데이터는 JSON을 사용하여 인코딩 된다. Bank Teller 명령어와 서비스 인풋 데이터를 파싱한 후에, 이 로직은 JSON 파서를 사용하여 JSON 포맷 텍스트를 PHP 객체로 변환한다. 일단 이것이 수행되면, switch 문은 다른 PHP 모듈의 알맞은 Bank Teller 함수로 컨트롤을 분기한다. 이러한 함수들을 호출하면서, JSON 텍스트에서 파싱된 필수 매개변수들이 여기로 전달된다. Bank Teller 함수들이 리턴할 때, PHP 제휴 어레이로 최종 결과를 제공한다. (성공 또는 실패). 최종 결과 데이터는 JSON 포맷 텍스트로 변환되고 브라우저 클라이언트로 리턴된다.
이제 end-to-end 뱅크 시나리오의 세 개의 모든 티어들에 필요한 모든 코드 생성물들을 구현했다. 축하한다!
Listing 4. BankActions_REST_Service.php 파일의 콘텐트
<?php
/*
============================================================
Project: End-to-End-Ajax application development
Purpose: This is an example scenario to be used in
an IBM developerWorks article.
Last modified: May/17/2007.
This module is the REST service request handler for the
server-side of the bank scenario. It receives the
REST (HTTP POST) requests from the single-page based
bank teller browser clients. It dispatches different
request requests to different bank logic functions.
It also sends and receives application-specific data
in a previously agreed JSON format.
============================================================
*/
// Get the other required PHP modules.
// JSON.php is an open source JSON parser in PHP.
// It can be obtained from: : http://mike.teczno.com/JSON/JSON.phps
require_once("JSON.php");
// Bank Logic module has all the core bank teller server-side functions.
require_once("BankLogic.php");
// GetStockPrice is a Web service proxy client to a remote Web service.
require_once("GetStockPrice.php");
// Define all the constants that will be used here.
define ("BANK_TELLER_COMMAND_KEY", "Bank_Teller_Command");
define ("BANK_TELLER_POST_DATA_KEY", "Post_Data");
define ("GET_ALL_ACCOUNTS_INFO", "Get_All_Accounts_Info");
define ("DEPOSIT_TO_ACCOUNT", "Deposit_To_Account");
define ("DEBIT_FROM_ACCOUNT", "Debit_From_Account");
define ("GET_STOCK_PORTFOLIO_VALUE", "Get_Stock_Portfolio_Value");
// XHTML form data from the bank teller Ajax browser client will be
// available in one of the PHP superglobals
// i.e. $_REQUEST associative array.
// Each REST request from the client will have two key-value pairs.
// First one is the bank teller command that tells if the client
// wants to perform deposit, debit, portfolio value etc.
// The second key-value pair is the application specific data sent as
// JSON-formatted string.
$bankTellerCommand = $_REQUEST[BANK_TELLER_COMMAND_KEY];
$bankTellerPostData = $_REQUEST[BANK_TELLER_POST_DATA_KEY];
// Using JSON in PHP is as easy as it can get.
// Instantiate the JSON parser (available through JSON.php)
$json = new Services_JSON();
// In one statement, convert the JSON formatted text to
// an equivalent PHP class structure. That is it.
$bankTellerInput = $json->decode($bankTellerPostData);
$responseToBeSent = "";
$bankActionResult = null;
// Switch through the bank teller command issued by the browser client.
switch($bankTellerCommand) {
case GET_ALL_ACCOUNTS_INFO:
// Go and get all the account information stored in the database.
$bankActionResult = getAllAccountInformation();
break;
case DEPOSIT_TO_ACCOUNT:
// Perform the deposit account transaction.
// Pass the account holder name and the deposit amount as
// sent by the browser client. Third parameter of 1 indicates DEPOSIT.
// This function is available in BankLogic.php
$bankActionResult =
accountTransaction(
$bankTellerInput->accountHolderName,
$bankTellerInput->amount, 1);
break;
case DEBIT_FROM_ACCOUNT:
// Perform the debit account transaction.
// Pass the account holder name and the debit amount as
// sent by the browser client. Third parameter of 2 indicates DEBIT.
// This function is available in BankLogic.php
$bankActionResult =
accountTransaction(
$bankTellerInput->accountHolderName,
$bankTellerInput->amount, 2);
break;
case GET_STOCK_PORTFOLIO_VALUE:
// Perform the "Update Stock Portfolio Value" transaction.
// This will require going out on the Internet to a remote Web service.
// This function is available in GetStockPrice.php
$bankActionResult =
getStockPortfolioValue($bankTellerInput->accountHolderName);
break;
default:
// Invalid Bank teller command.
$bankActionResult["ResultCode"] = 1;
$bankActionResult["ResultMsg"] = "Invalid Teller Command";
} // End of switch($bankTellerCommand)
// We completed everything that the client asked us to do.
// Let us return the final results in JSON formatted text.
// It takes one line of code in PHP to convert a
// PHP associative array data structure into JSON formatted text.
$responseToBeSent = $json->encode($bankActionResult);
// Set the HTTP header to indicate that we are sending JSON plain text data.
// There are also efforts underway at this time (MAY/2007) to define a
// new content type called text/json.
header("Content-Type: text/plain");
// That is it. Return the JSON formatted response in
// RESTful way back to the browser now.
echo($responseToBeSent);
?>
|
이 부분에서, 뱅크 시나리오에 필요한 Ajax 클라이언트, PHP 미드 티어 서비스, MySQL 데이터베이스 컴포넌트를 개발했다. 다음과 같다:
- BankDB (MySQL에 기반한 Bank 데이터베이스)
- BankLogic (PHP 모듈에 있는 Bank Teller 함수의 핵심 로직)
- BankPortal (Ajax 기술을 사용하는 Bank Teller 웹 클라이언트)
- BankActions (PHP로 된 Bank Teller 액션 REST 서비스)
- Stock Quote Web service client (PHP SOAP Client를 사용하는 SOAP 프록시)
이러한 컴포넌트들은 우리의 뱅크 시나리오에서 특정 태스크를 핸들한다. 세 파트의 시리즈에서 관찰했겠지만, 각 컴포넌트는 다른 컴포넌트에 의존하여 뱅크 시나리오의 엔드투엔드 그림을 연결한다. 전형적인 3-티어 웹 애플리케이션에서, .NET 같은 기반 프레임웍들은 다양한 애플리케이션 컴포넌트들을 통합하기 위해 상세한 의존성 설정을 요한다. 이러한 시나리오를 구현하기 위해 선택된 기술들은 이 같은 복잡한 통합 요구 사항을 요구하지 않는 것으로 스스로를 차별화 한다. 모든 필요한 의존성들은 이러한 컴포넌트들을 구현하는 동안 이미 다루어졌다. Ajax(XHTML, CSS, JavaScript, REST, JSON), PHP, MySQL에 필요한 애플리케이션 스팩의 런타임 통합이 없기 때문에 엔드투엔드 애플리케이션에서 많은 오버헤드와 복잡성을 줄일 수 있다.
지금까지 뱅크 시나리오 컴포넌트의 개발과 통합을 마쳤으니, 이제는 Zend Core PHP 서버에 이들을 전개할 차례이다. Zend Core는 Apache 웹 서버에서 구동된다.
- Eclipse PHP 퍼스펙티브가 활성화 되어 있는지를 확인한다: Window->Open Perspective->Other->PHP를 클릭하고 OK를 클릭한다.
- Window->Web Browser->Internal Web Browser 옵션이 선택되었는지를 확인한다.
- PHP Explorer 뷰에서(좌측 상단 프레임), BankTeller 프로젝트를 오른쪽 클릭하고, Run As->Run을 선택한다:
- Run 다이얼로그 박스의 좌측 프레임에서, 옆에 있는 + 부호를 클릭하여 "PHP Web Page" 옵션을 확장한다.
- "PHP Web Page" 옵션 밑에 New_configuration 항목이 있는지를 확인한다.
- New_Configuration 항목이 보이지 않으면, PHP Web Page를 오른쪽 클릭하고, New를 선택하여 항목을 만든다.
- New_Configuration 항목을 클릭한다.
- 같은 다이얼로그의 오른쪽 패널에서, New_Configuation에 대한 다양한 설정 매개변수를 볼 수 있다. Server 필드가 Default PHP Web Server인지를 확인하라.
- File/Project 필드에서, Browse 버튼을 클릭하고, BankTeller를 선택하고 OK를 클릭한다.
- Publish files to Server 체크 박스가 선택되었는지를 확인한다.
- Publish To: 필드에서, BankTeller 텍스트를 붙여서 이 설정 매개변수가 reads C:\Program Files\Zend\Apache2\htdocs\BankTeller를 읽도록 한다.
- Auto Generate 체크 박스가 선택되었는지를 확인한다.
- Run을 클릭한다.
이 단계를 거쳐 파일을 Zend Core에 전개하고, Eclipse 내부 브라우저를 시작한다. 지금 Eclipse 내부 브라우저를 닫는다.
Bank Teller 애플리케이션 메인 메뉴가 Eclipse 브라우저 스크린에 나타났다는 것이 확인되면, 모든 것이 잘 진행된 것이다. 그렇지 않다면, 몇 단계를 지나치지 않았는지를 확인해 본다. 지금까지 엔드투엔드 Ajax 애플리케이션을 전개 및 실행해 보았다.
마지막으로, 지금까지의 모든 작업들의 열매를 맛 볼 차례가 되었다. 이 뱅크 시나리오는 테스트 단계에 와있다. 다음 단계를 따라서 Bank Teller 액션들을 테스트 하고, 여러분이 개발하고 전개했던 세 개의 모든 티어에서 코드를 실행해 본다:
- Eclipse 툴바에서, Eclipse 내부 웹 브라우저(지구 모양) 아이콘을 클릭한다.
- Eclipse 내부 브라우저가 시작했는지 확인한다.
- 브라우저의 URL 주소 필드에, 로컬 머신에서 실행되는 뱅크 시나리오용 URL인
http://localhost/BankTeller를 입력하고 Enter를 누른다. - Figure 4와 같이 Bank Teller 애플리케이션의 메인 스크린으로 간다. 이 글에서 설명했듯이, 이것은 Bank Teller 애플리케이션의 유일한 웹 페이지이다. 애플리케이션을 테스트 하면서 URL을 계속적으로 모니터링 한다. 이것은 전체 애플리케이션에 대한 유일한 URL이다. 이 하나의 페이지의 모든 부분인 애플리케이션용 여러 섹션들과 스크린이 있다. 지금은, 이러한 스크린에 대한 모든 사용자 인터페이스 컨트롤이 숨겨지고, 오직 메인 스크린만 보인다. 이러한 Ajax 기능의 요점은 브라우저 세션 동안 이러한 애플리케이션을 위해 서버로부터 오는 더 이상의 페이지 리프레시가 없다는 점이다.
- 메뉴 옵션에서 마우스를 갖다 대거나 이동할 수 있다. 메뉴 아이템 하이라이트도 보게 된다. 이것은 mouseover와 mouseout 이벤트 동안, 메뉴 텍스트를 갖고 있는 <SPAN> 엘리먼트의 CSS 클래스 스타일을 변경함으로써 수행되는 간단한 Ajax 기능이다.
- "Deposit to an account" 메뉴 옵션을 클릭하면, Ajax 방식으로 Deposit 스크린이 나타난다. (페이지를 얻는데 개입된 어떤 서버 도움도 필요 없다.) 현재의 계정 보유자들을 가진 리스트 박스가 보인다. 이 계정 데이터는 Ajax 비동기식 XHR 기능을 사용하여 백그라운드에 있는 미드 티어 서버로부터 획득되었다. 가짜 Bank Teller 이름을 디스플레이 하는 페이지 풋터를 볼 수 이고, 메인 메뉴로 돌아가는 옵션도 제공한다.
- 계정 소유자인 Merry를 선택하고 예금액
125.00을 입력한다. (그림 5). - Deposit을 클릭한다. 트랜잭션 상세가 있는 결과 페이지를 보게 된다. (그림 6).
- 페이지 풋터에 Back to main menu 링크를 클릭한다.
- 두 번째 메뉴 옵션 Debit from an account를 클릭한다. 이 옵션은 지체 없이 debit 스크린을 연다.
- 계정 소유자를 선택하고, 금액을 입력하고 Debit을 클릭한다.
- 서버에서 리턴된 결과 데이터를 검사한다.
- 페이지 풋터에 있는 Back to main menu 링크를 클릭한다.
- 세 번째 메뉴 옵션 Current portfolio value를 클릭한다. 포트폴리오 값 스크린이 즉시 열린다.
- 리스트 박스에서, 계정 소유자 Gandalf를 선택한다. (그림 7).
- Get Stock Portfolio Value를 클릭한다. 업데이트 된 주식 포트폴리오 값을 가진 결과 스크린이 보인다. (그림 8) 이 Bank Teller 액션은 REST 요청을 미드 티어 PHP 서비스로 보내는데, 이렇게 되면, 원격 주식 시세 서비스를 위한 동적인 웹 서비스 클라이언트가 만들어 지고, 그 서비스를 호출한다. 새로운 주식 가격이 데이터베이스에서 업데이트 되었고, 새로운 포트폴리오 값이 계산되어 브라우저 클라이언트로 리턴된다.
- 페이지 풋터에서 Back to main menu 링크를 클릭한다.
- Eclipse 내부 웹 브라우저를 닫는다.
이러한 테스팅 절차를 통해 이러한 단일 페이지 웹 애플리케이션이 미드 티어와 데이터 티어의 애플리케이션 생성물들과 인터랙팅 함으로써 중요한 태스크를 수행하는지를 볼 수 있다.
그림 4. Bank Teller 메인 스크린
그림 5. Bank Teller deposit 스크린
그림 6. Bank Teller deposit 결과 스크린
그림 7. Bank Teller portfolio value 스크린
그림 8. Bank Teller portfolio value 결과 스크린
모든 소프트웨어 개발 환경에서, 디버깅 툴은 프로젝트 실행의 속도와 품질에 있어서 중요한 기여를 하고 있다. 우리의 뱅크 시나리오 같은 멀티 티어 웹 애플리케이션에서, 디버거는 개발자의 툴 세트의 필수적인 부분이다. 바람직한 기능은 하나의 IDE 내에 웹 애플리케이션의 모든 티어들을 디버깅 하는 것인데 아직 실현되지 않았다. 하지만, PHP Development Tool (PDT)과 Aptana Web IDE 같은 최신 Eclipse 기반 오픈 소스 노력이 매우 전망이 밝다. 이 둘은 모두 같은 Eclipse 플랫폼으로 연결되기 때문에, 개발자들이 JavaScript 함수에 중단점을 설정하고, PHP 함수에 또 다른 중단점을 설정하게 함으로써 엔드투엔드 디버깅 기능을 제공할 전망이다. 이로써, 브라우저와 Zend Core 서버에서 단일 엔드투엔드 트랜잭션을 디버깅 하게 될 것이다.
PDT와 Aptana는 각각 PHP와 JavaScript를 위한 뛰어난 디버깅 기능을 갖고 있다. Aptana는 Firefox, Internet Explorer, Safari, Opera 같은 대중적인 브라우저들과 통합되어 JavaScript 디버깅을 수행한다. 마찬가지로, Firebug (Firefox 애드온)는 JavaScript에 뛰어난 디버깅 기능을 제공한다. 하지만, 이 글을 쓰고 있는 현재, 이러한 디버깅 툴들은 브라우저 코드부터 서버 코드까지 엔드투엔드 디버깅 기능을 제공하기에는 미흡하다.
현재로서는 엔드투엔드 디버거가 없기 때문에 이 글에서는 다음과 같이 디버깅 절차를 설명하겠다. 다음과 같은 두 개의 방식들은 잘 작용하며, 서버와 브라우저에서 개별적으로 엔드투엔드 시나리오를 디버깅 하는 방식을 제공한다.
- PDT 디버거를 사용하여 Zend Core 서버에서 PHP 코드를 디버깅 한다.
- Firebug 디버거를 사용하여 Firefox 브라우저에서 클라이언트 측 JavaScript 코드를 디버깅 한다.
다음 단계를 따라 PDT 디버거를 사용하여 미드 티어 PHP 서버 로직을 디버깅 한다. 여러분이 뱅크 시나리오 애플리케이션을 전개하고, 이전 두 섹션에서 지시한 대로 정상적인 테스트를 수행한 것으로 간주한다.
- Eclipse PHP 퍼스펙티브가 활성화 되어 있는지를 확인한다: Window->Open Perspective->Other->PHP를 클릭하고 OK를 클릭한다.
- Window->Web Browser->Internal Web Browser 옵션이 선택되었는지 확인한다.
- 이 글을 쓰고 있는 현재, PDT와 Zend 디버거는 애플리케이션의 초기 페이지가 PHP 파일일 경우에만 작동한다. 따라서, index.html 파일을 index.php로 바꿔야 한다. 이것은 단순히 파일 확장자를 바꾸는 것이고 애플리케이션 작동에는 전혀 영향을 주지 않는다:
- PHP 프로젝트 익스플로러 뷰에서, BankTeller 프로젝트 밑에, index.html을 클릭하고 Refactor->Rename을 선택한다.
- 파일 이름을
index.php로 바꾼다. - Eclipse PHP 프로젝트 익스플로러 뷰에서, BankTeller 프로젝트를 오른쪽 클릭하고, Debug As->Debug를 선택한다:
- 결과 Debug 다이얼로그 박스의 왼쪽 페인에서, PHP Web Page->New_configuration을 선택한다. 다이얼로그 박스 아래에 Debug 버튼이 있는 오른쪽 페인이 나타난다.
- Debug를 클릭한다.
- PHP Debug 퍼스펙티브를 연다는 프롬프트가 뜨면, Yes를 클릭한다. index.php 파일과 Eclipse 내부 브라우저가 열린 상태에서 PHP Debug 퍼스펙티브로 간다. 이 디버거는 index.php 파일의 위에서 멈춘다. (여기에는 PHP 코드가 아닌 HTML 스크립트만 있다.)
- 빠르게, Debug 뷰(스크린의 좌측 상단)에서 Resume 아이콘(노란색 바가 있는 녹색 화살표)을 클릭한다. 이를 수행하는데 60초 이상 걸린다면, 내부 브라우저가 종료되고, 디버깅 단계를 처음부터 시작해야 한다.
- 초기 페이지 로딩 시, Ajax XHR을 사용하여 서버에서 모든 계정 정보를 가져온다. XHR 요청이 Zend Core 서버로 갈 때, 디버거는 REST Request 디스패처 PHP 파일의 첫 줄에서 멈춘다. (디버거는 실행 중인 PHP 파일의 첫 줄에 멈추도록 설정된다. 이것은 여러분도 설정할 수 있는 중단점이다.)
- 이제 Debug 뷰의 위에 있는 아이콘을 사용하여 step into a function 또는 step over a function 같은 디버그 기능을 사용할 수 있다.
- step into와 step over 기능을 사용하면서, PHP 코드의 애플리케이션 변수들의 값을 확인할 수 있다. 이는 Debug 퍼스펙티브의 Variables 뷰 안에서 수행된다.
- 브라우저 타임아웃을 피하려면, 60초 이내에 빠르게 트레이싱을 수행하고, Debug 뷰에서 Resume 아이콘(노란색 바가 있는 녹색 화살표)을 클릭한다.
- PHP 코드가 실행될 때마다 첫 번째 줄에 멈추는 대신, PHP 코드의 특정 중단점에 멈추는 기능을 검사해 보자:
- PHP 퍼스펙티브로 전환한다.
- BankTeller 프로젝트에서, BankActions_REST_Service.php 파일을 연다.
- 이 파일에서 PHP 문을 배치한다:
$json = new Services_JSON(). - 이 문장의 라인 넘버를 더블 클릭한다. (에디터의 맨 왼쪽). 문장에 중단점 아이콘이 삽입된다.
- 같은 파일의 끝으로 가서, 마지막 라인에 또 다른 중단점을 설정한다:
echo($responseToBeSent). - Eclipse PHP Debug 퍼스펙티브로 전환한다.
- Eclipse 내부 브라우저가 열리면, 이를 닫는다.
- Eclipse 메뉴 바에서, Run->Debug 메뉴 아이템을 선택한다. Debug 다이얼로그 박스가 열린다.
- 다이얼로그의 오른쪽 페인에서, Advanced 탭을 클릭한다.
- Breakpoint 섹션에서, Override project/workspace Break at First Line을 말하고 있는 체크 박스를 선택한다. Break at First Line 체크 박스를 해제한다.
- Debug를 클릭한다. 내부 브라우저가 시작되고, JSON 문에 설정된 첫 번째 중단점으로 직접 이동한다. 초기 페이지 로딩 동안 모든 계정 정보를 실행하는 XHR 요청 때문에 여기에서 중단한다.
- Debug 뷰에서 Resume 아이콘을 클릭한다. 이 파일의 끝에서 두 번째 중단점에 프로그램이 진행하다가 멈춘다. Resume 아이콘을 다시 클릭하여 실행을 계속한다.
- 내부 브라우저로 전환하고 Bank Teller 연산을 수행한다.
- PHP Debug 퍼스펙티브에서, Breakpoints 뷰를 클릭한다.
- 중단점들 중 하나를 오른쪽 클릭하고 Remove All을 선택한다.
- 확인 다이얼로그가 생기면, Yes를 클릭하여 이들을 제거한다.
주: 여러분은 다음과 같은 작은 PDT 디버깅 문제를 주의해야 한다. PHP 디버그 세션 동안, PHP 스크립트의 디버깅을 완료할 때 Debug 뷰에서 다음과 같은 메시지를 보게 될 것이다: <terminated> New_configuration [PHP Web Page]. 전체 애플리케이션의 디버깅을 끝마칠 때 까지는 이들을 제거하지 말라. 이러한 메시지들을 제거한다면, 후속 애플리케이션 함수들이 같은 Debug 세션에서 디버깅 될 수 없고, 여러분은 새로운 Debug 세션을 시작해야 한다. 이러한 문제와 내부 브라우저 타임아웃 문제는 PDT가 릴리스 후보(RC3)에서 공식 릴리스 버전이 될 때 픽스될 것이다.
다음 단계를 사용하여 본 시리즈 Part 1에서 설치했던 Firebug 디버거를 사용하여 클라이언트 측 JavaScript 로직을 디버깅한다. 여러분이 뱅크 시나리오 애플리케이션을 전개했고, 이전 섹션에 설명된 대로 정상적인 테스팅을 수행한 것으로 간주한다.
- 머신에서 Firefox 브라우저를 시작한다.
- URL을 입력한다:
http://localhost/BankTeller. - Bank Teller 애플리케이션 메인 메뉴가 브라우저 스크린에 전개되는지를 확인한다.
- Firefox 메뉴 바에서, Tools->Firebug->Open Firebug를 클릭한다. Firefox 브라우저 창의 아래 부분에 Firebug 창이 열린다.
- Firebug 창의 HTML 탭을 클릭한다:
- HTML의 <body> 섹션을 확장한다.
- 디스플레이 된 HTML 텍스트에서, <div id="mainPage"로 마우스를 움직인다. mainPage <DIV> 엘리먼트에 포함된 애플리케이션 스크린의 부분들이 하이라이트 된다.
- <h1 title=... 텍스트에 마우스를 움직이고, 이 애플리케이션 타이틀이 하이라이트 되는지를 확인한다.
- tellerOptions와 pageFooter <DIV> 엘리먼트에도 같은지를 확인한다.
- pageFooter가 스크린에서 숨겨진다는 것을 알 수 있다; Firebug는 이것을 보여줄 수 있다.
- Firebug 창의 CSS 탭을 클릭한다. 이 애플리케이션의 전체 CSS 파일을 볼 수 있다.
- Firebug 창의 Script 탭을 클릭한다. 이 애플리케이션에 사용된 모든 JavaScript 파일들을 볼 수 있다.
- Firebug 창 위에서, JavaScript 파일의 이름 옆에 디스플레이 된 작은 아래 방향 화살표를 클릭한다. 여기에 리스팅 된 JavaScript 파일을 선택하고 코드를 볼 수 있다.
- Firebug 창의 DOM 탭을 클릭한다. Bank Teller 브라우저 애플리케이션의 전체 DOM 구조를 디스플레이 한다.
- Firebug 창의 Net 탭을 클릭한다:
- 지금까지 Bank Teller 애플리케이션에 발생했던 모든 네트워크 액티비티를 볼 수 있다.
- HTML, CSS, JavaScript, Images를 선택하고, HTTP Headers, Post data, Response 데이터를 볼 수 있다.
- 선택된 콘텐트 유형을 보내는데 걸렸던 시간을 그래픽으로 디스플레이 한다.
- Firebug 창 위에서, XHR을 클릭한다. Bank Teller 애플리케이션에서 발생했던 XHR 액티비티를 디스플레이 한다. 지금까지, XHR을 사용하여 수행되었던 데이터 교환은 단 한 개이다. 서버에 액세스 되었던 REST 리소스가 보인다.
- BankActions_REST_Service.php 항목을 확장한다.
- Post와 Response 탭을 클릭하여 미드 티어 서비스에서 교환된 JSON 요청과 응답 데이터를 본다.
- 많은 Firebug 백그라운드를 사용하여, JavaScript 코드를 디버깅 해보자:
- Firebug 창의 Script 탭을 클릭한다.
- Firebug 창의 위에서 작은 아래쪽 화살표를 사용하여, BankTeller.js를 선택한다.
- BankTeller.js 파일 콘텐트의 끝으로 스크롤 한다. 여기에서 이 파일의 마지막 함수가 정의된다.
- 마지막 함수에서,
var textResult = teller_request.responseText;를 읽는 소스 라인의 번호를 클릭한다. - 이것은 이 라인에 대한 중단점을 설정한다. (또 다른 마우스 클릭은 중단점을 토글링 한다. 이 경우, 이 라인을 위해 중단점을 활성화 한다.)
- 이전 함수
portfolioAction_Async()로 스크롤을 올린다. - 이 함수의 첫 번째 소스 문에 중단점을 설정한다.
- Bank Teller 애플리케이션 메뉴에서(브라우저 창의 상단 중앙), 현재 포트폴리오 값에 3 옵션을 선택한다. 곧 포트폴리오 값 스크린으로 가게 된다.
- 계정 소유자를 선택하고 Get Stock Portfolio Value를 클릭한다. JavaScript 실행은 portfolioAction_Async() 함수 내의 중단점에서 중지한다.
- Firebug 창의 우측 하단에서, continue, step over, step into, step out debugger 옵션에 대한 아이콘을 볼 수 있다.
- step over 아이콘을 클릭한다. (또는 F10 키를 누른다.) 이는 다음 라인으로 실행을 진행한다.
- 몇 라인을 건너뛰고 Firebug 창의 우측에서 변수 값을 볼 수 있다.
- 몇 줄 더 건너뛰고 JSON 객체가 생성되고 JSON 포맷 스트링으로 변환되는 방법을 볼 수 있다.
- Continue 아이콘을 클릭한다. (또는 F8 키를 누른다.)
- 현재 함수의 실행이 끝난다. -- 요청을 미드 티어 서버로 보내서 포트폴리오 값을 가져온다.
- 머신이 인터넷에 연결되어 있다면, 미드 티어 PHP 서비스는 원격 주식 시세 웹 서비스를 호출하고, 결과를 서버로 리턴한다. 이는 JavaScript 코드가 XHR 콜백 함수에서 설정된 다른 중단점에 멈추게 한다.
- 이 함수의 모든 문장에서 계속적으로 F10 (step over)를 누른다. 서버에서 받은 JSON 응답에 주목하고, 이것이 parseJSON (Douglas Crockford)을 사용하여 어떻게 안전하게 파싱 되는 지를 보라. 이 함수의 끝에서, 미드 티어 서버에서 페이지 리프레시를 수행하지 않고 한 개의 애플리케이션 스크린을 숨기고(get portfolio) 또 다른 애플리케이션 스크린(teller operation results)을 보여주는 방법을 보게 될 것이다.
- Bank Teller 애플리케이션의 페이지 풋터에서 Back to main menu 링크를 클릭한다.
- Firebug 창을 닫는다.
- Firefox 브라우저를 닫는다.
Firebug를 사용하여 Ajax 애플리케이션을 디버깅 해 보았다. Firefox 브라우저에 사용하기 쉬운 많은 기능들이 통합되었다. 필자 생각으로는, Firebug는 확실히 벤치마크로 자리잡았고, 앞으로의 디버거 제품들도 더 나아질 것이라 믿는다.
세 편의 기술자료에서,에서, end-to-end Ajax 애플리케이션을 개발하는 다양한 단계들을 배웠다. Ajax 스타일 웹 애플리케이션들이 얼마나 많이 향상되었는지를 알 수 있었다. 향상된 부분들 일부는 다음 섹션에서 소개한다. 이들을 우리의 end-to-end Ajax 애플리케이션을 통해 볼 수 있다면, 이 글의 목표는 달성한 것이다.
- Ajax 애플리케이션에서, 클릭하고 페이지 리프레시를 기다렸는가? 절대로 그렇게 하지 말라.
- 모든 클라이언트 로직을 싱글 브라우저 애플리케이션으로 로컬화 함으로써 빠른 응답 시간을 달성한다.
- Deposit, Debit, Get Stock Portfolio Value을 클릭하면, 이 애플리케이션은 PHP 미드 티어 서버와 통신하여 적은 데이터를 교환한다. (이는 네트워크 대역폭 사용을 매우 향상시킨다.)
- 이 애플리케이션을 사용하면서 다른 페이지를 검색하는 것처럼 보인다. 실제로, 이 효과는 하나의 HTML 페이지에 모두 놓인 다른 <DIV> 엘리먼트들을 숨기고 보여줌으로써 만들어졌다.
- Ajax 스타일로 웹 애플리케이션을 디자인 하면, 풍부한 사용자 인터랙션 패턴이 브라우저에 생긴다. 사용자 만족도가 더 높아진다.
- 이러한 방식으로 웹 애플리케이션을 구축하면 미드 티어 서버에 부담이 줄어든다. 이 서버는 불필요한 HTML 페이지 리프레시를 위해 더 이상 연결되지 않아도 되기 때문이다. 대신, 서버는 데이터 교환이 필요할 때만 연결된다.
- 이 애플리케이션으로 작업하면서, 브라우저 URL 변화가 있었는가? 이것은 결코 변하지 않고, 전체 애플리케이션을 위해 단 하나의 URL로 설정된다. 바로 이것이 싱글 페이지 브라우저 애플리케이션이다. 프리젠테이션 콘텐트(HTML, CSS, JavaScript)는 처음에 단 한번 웹 서버에서 다운로드 된다.
세 개의 모든 티어들(클라이언트, 중간, 데이터 티어)에 걸쳐 확장되는 Ajax 애플리케이션을 개발해 보았다. 여러 오픈 소스 기술들을 미들웨어 스택으로서 사용하여 애플리케이션을 구현 및 전개했다. 이 프로세스에서, Zend Core와 Eclipse IDE 툴을 사용했다. MySQL, PHP, Ajax (XHTML, CSS, JavaScript, XHR), REST, JSON, XML, 웹 서비스 클라이언트에 대해서도 배웠다. Eclipse IDE에서, PHP와 Aptana 퍼스펙티브에서 작업했다. 또한, Zend Core/Apache 서버에서 전개 및 테스팅 하는 방법을 배웠다. JavaScript 클라이언트 측 로직용 코드 생성물, PHP 웹 서비스 클라이언트, PHP REST 요청 디스패처, 주식 시세 WSDL은 다운로드 가능한 파일에 포함되어 있다. (다운로드).
우리의 중요한 뱅크 시나리오는 Ajax, PHP, MySQL의 기초를 다루었다. 세 편의 기술자료에서 배운 기초적인 지식을 강력한 오픈 소스 오퍼링을 사용하여 웹 애플리케이션 개발의 고급 영역까지 확장할 수 있다.
요약하면, 본 기술자료 시리즈에서는 Zend Core와 Eclipse(PDT와 Aptana) 개발 환경의 힘을 증명하려고 했다. 이 두 가지 모두 오픈 소스 미들웨어 스택을 모색하거나 .NET 환경에서 오픈 소스 스택으로 마이그레이션을 고려 중인 중소 비즈니스를 위한 믿을 수 있는 선택이다. 이러한 런타임과 Eclipse 기반 툴은 여러 벤더들의 제품과 서비스들의 미션 수행에 중요한 상용 오퍼링으로 자연스럽게 확장된다. Zend Core, Eclipse PDT, Aptana 웹 IDE를 통해서 웹 개발의 새로운 시대가 열린 것이다.
| 이름 | 크기 | 다운로드 방식 |
|---|---|---|
| wa-aj-end2end3.zip | 28KB | HTTP |
교육
- 본 기술자료 "End-to-end Ajax 애플리케이션 개발" 시리즈.
- 이 기술자료의 기초가 된 기술자료: "Ajax: A New
Approach to Web Applications" - Jesse James Garrett.
-
IBM developerWorks Ajax 리소스 센터에서 Ajax 기술자료와 튜토리얼 보기
-
IBM developerWorks PHP 리소스 센터에서 PHP 기술자료와 튜토리얼 보기.
- PHP API 문서: PHP 매뉴얼 웹사이트 (한글).
-
Eclipse PDT 프로젝트.
-
Aptana Web IDE.
-
Zend Core.
- XMLHttpRequest용 W3C Working Draft
-
PHP MySQLi API 문서.
-
CSS Zen Garden 데모를 통해 CSS의 힘 경험하기.
-
JSON에 관한 모든 것.
- "XML을 PHP의 JSON으로 변환하기" (Senthil Nathan, Edward J Pring, and John Morar, developerWorks, 2007년 1월)
- Roy Fielding의 보고서: REST.
- 원격 주식 시세 웹 서비스용 WSDL 파일: WebserviceX.net.
- 오픈 소스 PHP 라이브러리 검색: PEAR.
제품 및 기술 얻기
- 모질라 파이어폭스 브라우저 다운로드: 모질라 다운로드 웹사이트 (한글).
- MySQL database server 다운로드: MySQL 다운로드 웹사이트.
- Zend Core 다운로드: Zend 다운로드 웹사이트.
- Eclipse PDT (PHP 개발 툴) 다운로드: Zend PDT 다운로드 웹사이트.
- MySQL PHP connector 다운로드: MySQL connector 다운로드 웹사이트.
- JavaScript용 JSON 파서 다운로드(Douglas Crockford): JSON 웹사이트.
-
PHP용 JSON parser 다운로드.
