進軍社會軟體是為應用程序增值的好方法。使用社會網路可以更輕鬆地獲得並聚合數據,從而創建富有革新精神的新 Web 應用程序。但是,仍然必須處理創建可伸縮 Web 應用程序的所有常見問題。現在,使用 Google App Engine (GAE) 也可以簡化工作。使用 GAE,可以不必考慮管理應用伺服器池的所有事務。您不必擔心存儲大量靜態內容和動態數據。相反,您可以將精力集中在創建優秀的 mashup 上。本文是共分三部分的系列文章 “使用 Eclipse 在 Google App Engine 上創建 mashup” 的第一部分,將了解如何開始開發 GAE 應用程序,以及如何使用 Eclipse 簡化 GAE 開發。
關於本系列
在本系列中,將了解如何開始使用 Google App Engine (GAE)。在第 1 部分中,將了解如何設置開發環境,以便可以開始創建運行在 GAE 上的應用程序。了解如何使用 Eclipse 簡化應用程序的開發和調試。在第 2 部分中,將使用 Eclipse 構建一個 Ajax mashup 並將其部署到 GAE 中。最後,在第 3 部分中,通過為應用程序創建 RESTful Web 服務返回到生態系統,這樣其他人就可以使用它創建自己的 mashup。
GAE 是創建 Web 應用程序的平台。使用它的最重要的先決條件是具備 Python 知識,因為要在 GAE 中使用 Python 作為編程語言(目前為 Python V2.5.2)。對於本系列,具備一些典型的 Web 開發技能將會有幫助(例如,HTML、JavaScript 和 CSS 知識)。要針對 GAE 進行開發,需要下載三個軟體包。
下面詳細討論了后兩個軟體包的安裝。如果您剛開始使用 Eclipse,請參閱 參考資料 獲得入門。
![]() ![]() |
設置 GAE
如果曾經花大量時間開發過 Web 應用程序,則很可能在想要開始使用新應用程序堆棧時習慣下載庫、Web 伺服器和資料庫。有時,可以將所有這些包綁定到優秀的安裝程序中,從而可以更輕鬆地使用所有活動部分。一切就緒后,通常需要進行更多的設置,才能正常使用所喜愛的開發環境。幸運的是,使用 GAE 時不會遇到這種情況。讓我們看看如何設置它以及如何將它和 Eclipse 結合起來。
設置 GAE 首先需要做的是下載 SDK,可用於 Microsoft® Windows®、Mac OS X 和 Linux®。對於 Windows 和 Mac OS X,SDK 是以安裝程序出現的,不但要在系統中安裝 SDK,而且要在路徑中放置幾個關鍵的可執行腳本以便使用。圖 1 顯示了 SDK 的目錄結構圖。
在根目錄中,您應當會看到兩個 Python 腳本:appcfg.py 和 dev_appserver.py。dev_appserver.py 腳本用於啟動開發應用伺服器。沒有獨立安裝,也不需要為開發和測試應用程序進行部署。當您準備好將應用程序部署到 GAE 中時,將使用 appcfg.py 腳本。
您可以在 Google 目錄中查找構成 GAE 平台基礎的所有 API。您將不可避免地使用和擴展該目錄中的類。因此,如果需要運行 GAE 應用程序代碼,則需要知道該目錄,因為需要了解應用程序代碼所使用的 API。作為示例,讓我們看一看如何設置用於開發 GAE 代碼的 Eclipse。
![]() ![]() |
設置 Eclipse
Eclipse 被稱為開發 Java™ 編程語言應用程序的首要 IDE。但是,它不但適用於 Java 開發人員,而且還可以用於許多其他語言,包括 C++、PHP、Ruby 和 Python。實際上,有多個 Eclipse 插件可用於將 Eclipse 轉換為 Python IDE。這些插件中最常見的是 PyDev。可以使用更新站點 http://pydev.sourceforge.net/updates/ 從 Eclipse 中安裝該插件。
安裝 PyDev 之後,需要配置它。打開 Eclipse 並轉到 Preferences > PyDev。
您需要把 Python 安裝位置告訴 PyDev。轉到 Interpreter > Python 並單擊 New,如上所示。只需瀏覽到 Python V2.5+ 安裝,然後 Eclipse 應當會執行剩餘操作。單擊 OK,然後您將準備好從 Eclipse 中開發 Python。
![]() ![]() |
創建應用程序
首先在 Eclipse 中創建一個新 PyDev。通過選擇 Windows > Open Perspective > Other 並從可用透視圖列表中選擇 PyDev 切換到 PyDev 透視圖。
現在應當能夠通過選擇 File > New > PyDev Project 創建新應用程序。在本例中,我們將為源代碼創建一個單獨的 src 文件夾,但這是可選的並且主要取決於個人習慣。到目前為止,所做的一切都是在 Eclipse 上進行的一般的 Python 開發。現在將開始執行一些特定於 GAE 的操作。
![]() ![]() |
GAE 模板項目
GAE 項目的布局十分簡單;只有一個沒有子目錄的目錄。一定有三個文件:app.yaml、index.yaml 和 main.py。下面顯示了第一個文件 app.yaml。
application: aggrogator version: 1 runtime: python api_version: 1 handlers: - url: .* script: main.py |
這是 GAE 應用程序的主要配置文件。該文件中的大部分內容只需要設置一次,例如應用程序名稱、版本和構建該應用程序所使用的 GAE API 的版本。需要更多處理的部分是 handlers 部分。這是 HTTP 請求 URL 和項目中的 Python 腳本之間的映射。在以上情況下,我們將把所有內容都映射到同一個 main.py 腳本中。該文件隨後可以執行額外的路徑以將 URL 與方法匹配在一起。
另一個 YAML 文件 index.yaml 用於幫助 GAE 高效地獲取數據。實際上,即使沒有這樣一個文件也沒有關係,因為如果遺漏了該文件,GAE 也會為您生成一個。現在無需對該文件進行任何操作,清單 2 顯示了一個空的 index.yaml。
indexes: # AUTOGENERATED # This index.yaml is automatically updated whenever the dev_appserver # detects that a new type of query is run. if you want to manage the # index.yaml file manually, remove the above marker line (the line # saying "# AUTOGENERATED"). If you want to manage some indexes # manually, move them above the marker line. The index.yaml file is # automatically uploaded to the admin console when you next deploy # your application using appcfg.py. |
最後,我們將接觸到應用程序的核心:main.py 腳本。實際上您可以給該腳本任意命名,只要它是與 app.yaml 同步的。通常都使用 main.py 名稱,因此我們在這裡也使用這個名稱。在查看該文件之前,讓我們先描述一下編寫的應用程序的類型。
![]() ![]() |
aggroGator
我們的應用程序名為 aggroGator。它將允許用戶關聯已經使用的各項 Web 服務。然後將從這些服務中獲取數據提要並按時間順序聚集這些數據提要。對於我們的應用程序,將使用常見的 FeedParser 庫來解析提要。還將通過 Google 使用 GAE 的內置身份管理,因此無需編寫自己的註冊/登錄/退出特性。用戶將只使用 Google 身份進行登錄。記住這一切之後,讓我們看一看 main.py。
def main(): application = webapp.WSGIApplication( [('/', MainPage), ('/add', AddService)], debug=True) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main() |
因此這實際上只是腳本的主要方法。該方法所做的是設置更多路徑。在這種情況下,它將把 “/” 的請求發送到名為 MainPage 的類中,並把 “/add” 的請求發送到名為 AddService 的類中。現在讓我們看一看 MainPage 類。
class MainPage(webapp.RequestHandler): def get(self): user = users.get_current_user() if users.get_current_user(): url = users.create_logout_url(self.request.uri) url_linktext = 'Logout' else: url = users.create_login_url(self.request.uri) url_linktext = 'Login' updates = [] account = None if user: account_query = Account.all() account_query.filter('user = ', users.get_current_user()) result_set = account_query.fetch(1) if len(result_set) > 0: account = account_query.fetch(1)[0] if account: updates = [] for service in account.dynamic_properties(): url = getattr(account, service) feed = GenericFeed(url, service) updates.extend(feed.entries()) else: account = Account() account.user = user account.put() updates.sort(key=attrgetter('timestamp'), reverse=True) template_values = { 'account': account, 'updates': updates, 'url': url, 'url_linktext': url_linktext, } path = os.path.join(os.path.dirname(__file__), 'index.html') self.response.out.write(template.render(path, template_values)) |
該類執行了很多操作,因為它是應用程序的主要控制器。首先需要注意的是它只有 get 方法。那意味著它只支持 HTTP GET 請求。對 “/” 執行 POST 將導致錯誤。接下來,它將檢查身份。users 類是來自 GAE SDK 的 API。它將利用 Google 的身份管理。我們將使用它檢查用戶是否已登錄。如果用戶已登錄,就會知道用戶的身份(其 Google ID)。然後創建登錄鏈接或者退出鏈接,這取決於他是否已登錄。如果沒有登錄,則只顯示登錄鏈接;否則,繼續查找帳戶。下面是已經編寫的另一個類:
class Account(db.Expando): user = db.UserProperty() |
該類將利用 Google 的數據存儲 API(Google 的著名 Bigtable 資料庫)。Account 實體擁有 User 屬性並且是 Expando Model。這將允許我們創建動態屬性 — 用於每項服務的 URL。對於每項服務,將使用 GenericFeed 類檢索條目列表,如下所示:
class GenericFeed: def __init__(self, url, name): self.url = url self.name = name def entries(self): result = urlfetch.fetch(self.url) updates = [] if result.status_code == 200: feed = feedparser.parse(result.content) for entry in feed['entries']: x = Entry() x.service = self.name x.title = entry['title'] x.link = entry['link'] if entry.summary: x.content = entry.summary else: x.content = entry['title'] x.timestamp = entry.updated_parsed updates.append(x) return updates |
這是使用 FeedParser 庫的類。在使用該庫之前,我們將使用另外一個 GAE API:urlfetch 類。該類將允許 HTTP 請求,但只是 80 埠和 443 埠(用於安全請求)。只使用它對存儲的 URL 執行 HTTP GET,然後將結果傳遞給 FeedParser 庫。接著創建 Entry 類的實例,如下所示:
class Entry: def __init__(self=None, title=None, link=None, timestamp=None, content=None, service=None): self.title = title self.link = link self.content = content self.service = service self.timestamp = timestamp def printTime(self): return strftime('%B %d,%Y at %I:%M:%S %p',self.timestamp) |
該類幾乎只是一個簡單的數據結構。它惟一的邏輯是擁有一個輸出時間戳的方法。GenericFeed 類將返回與該用戶相關的每項服務的 Entry 實例列表。然後按降序根據時間戳排序 Entries(第一個是最新的 Entry)。返回到 MainPage,然後將若干個對象、用戶的 Account、排序后的 Entries 列表及登錄/退出鏈接傳遞給模板。GAE 使用的模板系統類似於常見的 Python 框架 Django 所使用的模板系統。在本例中,將把數據傳遞給名為 index.html 的模板。
<html> <body> <a href="{{ url }}">{{ url_linktext }}</a> <ol> {% for update in updates %} <li> From {{update.service}}: <a href="{{update.link}}">{{update.content}}</a> posted at: {{update.printTime}} </li> {% endfor %} </ol> {% if account %} <form action="/add" method="post"> <label for="service">Service: </label> <select name="service"> <option>twitter</option> <option>del.icio.us</option> <option>last.fm</option> <option>YouTube</option> </select><br/> <label for="username">Username: </label> <input type="text" name="username"/> <input type="submit" value="Add"/> </form> {% endif %} </body> </html> |
這是一個簡單的模板。它大部分只是 HTML,其中帶有幾個動態部分。首先,它將創建相應的登錄/退出鏈接。接下來,它將遍歷條目列表以將其顯示給用戶。最後,如果用戶已登錄,則創建允許用戶添加服務的表單。該表單將對 /add URL 執行 HTTP POST。如清單 3 所示,該請求將被發送到 AddService 控制器類中。
class AddService(webapp.RequestHandler): def post(self): # check if user already exists account_query = Account.all() account_query.filter('user = ', users.get_current_user()) result_set = account_query.fetch(1) if len(result_set) > 0: account = account_query.fetch(1)[0] else : account = Account() account.user = users.get_current_user() service = self.request.get('service') username = self.request.get('username') if service == 'twitter': service = 'http://twitter.com/statuses/user_timeline/'+username+'.rss' account.twitter = service if service =='del.icio.us': service = 'http://del.icio.us/rss/' + username account.del_icio_us = service if service == 'last.fm': service = 'http://ws.audioscrobbler.com/1.0/user/'+username+ '/recenttracks.rss' account.last_fm = service if service == 'YouTube': service = 'http://www.youtube.com/rss/user/'+username+'/videos.rss' account.you_tube = service account.put() self.redirect('/') |
該類將查找用戶的帳戶。然後根據使用的服務創建相應的 URL。使用 Expando 屬性把該 URL 添加到帳戶的服務中,並且把所有內容保存回 Bigtable 中。最後,重定向到 MainPage。
現在已經看過應用程序的所有代碼,並且已經準備好運行。但是如何運行?Eclipse 將再次幫您輕鬆運行。
![]() ![]() |
在本地進行測試
GAE SDK 將提供在本地運行項目的命令行工具。但是,我們希望利用 Eclipse,因此需要從 Eclipse 中運行所有內容。這將允許我們調試應用程序,稍後我們將看到。運行應用程序的第一步是編輯項目的 PYTHONPATH。完成此操作的最簡單方法是在項目上右鍵單擊並選擇 Properties。這將打開項目屬性。
正如您所見,需要在左側菜單中選擇 PyDev - PYTHONPATH。然後需要選擇 Add source folder 並瀏覽到 GAE SDK 的安裝位置。該位置將根據 OS 的不同而有所變化,並且可以自定義。對於 Windows,默認值(由安裝程序設定)為 C:\Program Files\Google\AppEngine,而對於 OS X,默認值為 /usr/local/google_appengine。如果位於 Linux 中或者下載了 ZIP 而不是特定於 OS 的安裝程序,請選擇放置 SDK 的位置。可以是任意位置,但是需要讓 Eclipse 知道該位置。該位置將稱為 $APP_ENGINE_HOME。
現在,運行項目還需要做最後一件事:需要為它創建一個 Run 配置文件。為此,選擇 Run > Open Run 對話框。
該 Run 配置文件被稱為 aggroGator。在 Main Module 下,瀏覽到 $APP_ENGINE_HOME 並選擇 dev_appserver.py 腳本。這是模擬 GAE 生產環境的 Python 應用伺服器。接下來,轉到 Arguments 選項卡,如圖 6 所示。
在 Program arguments 框中,輸入 ${project_loc}/src。Eclipse 變數 ${project_loc} 僅指向當前項目的物理位置。需要將應用程序目錄傳遞給 dev_appserver.py 腳本,因而傳遞給 /src。如果不把代碼放到 src 目錄中,則需要相應地調整實參。
現在已經準備好運行應用程序。如果單擊 Run,則應當會在 Eclipse 控制台中看到清單 10 中的輸出。
INFO 2008-06-08 05:00:29,236 appcfg.py] Server: appengine.google.com INFO 2008-06-08 05:00:29,283 appcfg.py] Checking for updates to the SDK. WARNING 2008-06-08 05:00:29,581 datastore_file_stub.py] Could not read datastore data from /var/folders/oo/ooKE4ln2HqC9exSMWxwprk+++TI/-Tmp-/dev_appserver.datastore WARNING 2008-06-08 05:00:29,582 datastore_file_stub.py] Could not read datastore data from /var/folders/oo/ooKE4ln2HqC9exSMWxwprk+++TI/-Tmp-/dev_appserver.datastore.history INFO 2008-06-08 05:00:29,606 dev_appserver_main.py] Running application aggrogator on port 8080: http://localhost:8080 |
注意,這段代碼說明應用程序運行在 http://localhost:8080。在瀏覽器中轉到該 URL 並嘗試一下,如下所示:
單擊 Login 將顯示圖 8。
很明顯,這是模擬的登錄屏幕。您可以使用任意一個電子郵件地址,因為這不會實際訪問 Google 身份驗證服務。實際上,[email protected] 可以正常工作。登錄后即可以開始添加服務。
現在可以通過添加服務開始玩轉應用程序。如果返回到清單 8 的 AddService 控制器,各項服務提要的 URL 都是被硬編碼到該類中。當然,這一切可以在將來改變,並且可能得到錯誤。這時有調試器會方便得多。讓我們看一看如何將 Eclipse 調試器與 GAE 項目結合使用。
![]() ![]() |
調試
使用諸如 Eclipse 之類的 IDE 的主要優點是更易於調試應用程序,甚至複雜的 Web 應用程序。首先需要為 GAE 項目做的是創建 Debug 配置文件。該配置文件類似於 Run 配置文件,因此只需選擇項目並單擊 Run > Open Debug 對話框。
Eclipse 將智能地把默認值設為先前創建的 Run 運行設置。無需修改,並且只需單擊 Debug。查看 Eclipse 控制台,並且應當會看到類似於清單 11 的一些輸出。
pydev debugger: warning: psyco not available for debugger speedups pydev debugger: starting INFO 2008-06-08 05:18:37,704 appcfg.py] Server: appengine.google.com INFO 2008-06-08 05:18:37,755 appcfg.py] Checking for updates to the SDK. INFO 2008-06-08 05:18:38,196 dev_appserver_main.py] Running application aggrogator on port 8080: http://localhost:8080 |
前兩行顯示 pydev 調試器的輸出。現在可以在項目中設置斷點並且開始調試。在圖 11 中,我們將調試 AddService 控制器。
現在可以開始逐步調試代碼並檢查變數。如果任何一項服務發生更改,或者需要添加新服務,這將使您可以輕鬆地找到並修復錯誤。
![]() ![]() |
結束語
在本文中,很快就實現了一個完整的應用程序。Google App Engine SDK 已經安裝並且與 Eclipse 連接在一起。這將允許我們快速編寫、測試和調試代碼。我們了解了 GAE 項目中的許多關鍵概念,包括 URL 路由、通過 URL 獲取與外部站點進行交互、使用演示模板以及使用 Bigtable。我們的應用程序已經準備好部署到 GAE 中,將在第 2 部分中了解這些內容。(責任編輯:A6)
[火星人 ] 使用 Eclipse 在 Google App Engine 上創建 mashup,第 1 部分: 創建應用程序已經有707次圍觀