Làm chủ việc phát triển ứng dụng Facebook bằng PHP, IBM Rational Application Developer, IBM WebSphere Application Server và DB2, Phần 3: Hoàn thành ứng dụng trình diễn môi giới chứng khoán Facebook

Đây là phần cuối cùng trong loạt bài hướng dẫn ba phần về phát triển một ứng dụng Facebook đầy đủ chức năng trong các ngôn ngữ PHP và Java™ để cung cấp một giao diện Facebook cho một ứng dụng buôn bán môi giới cổ phiếu hiện có. Trong hướng dẫn này bạn sử dụng tất cả các công cụ mà bạn đã cài đặt và các thành phần bạn đã phát triển trong hai phần đầu của loạt bài này để thực hiện các chi tiết của ứng dụng Facebook.

Jake Miles, Tác giả tự do, 软通动力信息技术有限公司

Author photoJake Miles là người liên lạc kỹ thuật cao cấp tại Twistage, Inc, hiện đang làm việc với các ứng dụng Facebook, Myspace và OpenSocial, bằng cách sử dụng Java, PHP, Adobe Flex và JavaScript. Ông đã làm việc như một nhà phát triển chuyên nghiệp trong suốt 10 năm qua và đã từng là một học sinh khát khao hiểu biết và yêu thích máy móc kể từ khi 10 tuổi. Ông cũng giảng dạy trên cơ sở tình nguyện.



11 09 2009

Trước khi bạn bắt đầu

Hướng dẫn này dành cho các nhà phát triển có trình độ kinh nghiệm khác nhau trong Java, PHP hoặc cả hai, những người muốn gia nhập vào thế giới đang lên của sự phát triển ứng dụng Facebook. Nó cũng dành cho các nhà phát triển nào muốn tìm hiểu cách tích hợp PHP và Java vào chung một ứng dụng.

Về loạt bài này

Loạt bài này sẽ cho phép bạn phát triển các ứng dụng Facebook của chính mình và làm như vậy bên trên đỉnh của một ứng dụng Java doanh nghiệp hiện có.

  • Trong Phần 1 bạn đã có một cái nhìn khái quát về Facebook và sau đó cài đặt các công cụ cần thiết gồm cả môi trường Rational của IBM (Rational® Application Developer environment), Zend Core for IBM® với các bản cài đặt kèm theo của Apache 2 và cơ sở dữ liệu DB2® Express-C và WebSphere® Application Server của IBM. Sau đó bạn khảo sát chi tiết các điểm tích hợp của Facebook -- các cơ chế mà Facebook cung cấp để tích hợp ứng dụng vào mạng xã hội -- và bắt đầu một số phát triển khung sườn.
  • Trong Phần 2 bạn đã tạo ra một dự án ứng dụng web Java™ trong Rational Application Developer của IBM, sau đó tích hợp khung Spring để áp đặt một cấu trúc MVC trên mã lệnh và cung cấp việc tiêm vào thuộc tính/bean, và bạn đã triển khai ứng dụng vào WebSphere.
  • Phần 3 đảm nhiệm các chi tiết triển khai thực hiện một ứng dụng Facebook đầy đủ chức năng bằng cách sử dụng Ngôn ngữ Đánh dấu Facebook (FBML), Facebook JAVASCRIPT (FBJS), và Facebook API trong cả Java và PHP.

Về hướng dẫn này

Trong hướng dẫn này, bạn sẽ sử dụng tất cả các công cụ bạn đã cài đặt và các thành phần mà bạn đã phát triển để thực hiện chi tiết ứng dụng Facebook. Ứng dụng này sẽ bao gồm trang vải nền (canvas) chính hiển thị danh mục đầu tư cổ phiếu của người sử dụng (và các cổ phiếu có sẵn khác), một hộp lược tả hiển thị tin điện báo giá thị trường chứng khoán (stock ticker) trong danh mục đầu tư đó, khả năng mua và bán số lượng cổ phiếu từ trang vải nền, và khả năng giới thiệu cổ phiếu cho bạn bè trên Facebook. Bạn sẽ sử dụng cả thư viện trình khách Facebook Java và PHP để giao tiếp với Facebook thông qua giao diện REST của nó từ bên trong các trình điều khiển PHP và Java của bạn, bằng cách sử dụng phiên bản mã nguồn mở của thư viện trình khách Java được chứa trên kho mã Google, gồm cả Tiện ích Bạn bè (Companion Utility) mới để tạo kết nối với Facebook dễ dàng như trong PHP. Sau đó bạn sẽ dùng FBML để tạo ra nội dung Facebook, và FBJS và giao diện AJAX của Facebook để cập nhật giá cổ phiếu trong danh mục đầu tư và tổng giá trị của danh mục đầu tư trong thời gian thực, mỗi giây một lần.

Các đều kiện tiên quyết

Bạn cần đọc Làm chủ việc phát triển ứng dụng Facebook, Phần 1 (Mastering Facebook application development, Part 1) và Sử dụng song song các ngôn ngữ Java và PHP, Phần 2 (Using Java and PHP languages in parallel, Part 2) trước khi tiếp tục với Phần 3.

Yêu cầu về hệ thống

Để hoàn thành các bước trong hướng dẫn này, bạn cần các công cụ sau:


Tạo một nguồn cấp JSON giá cổ phiếu trong Java

Trang vải nền của ứng dụng của bạn sẽ hiển thị danh mục đầu tư chứng khoán của người sử dụng và các chứng khoán có sẵn khác, và sẽ cập nhật giá cả của những cổ phiếu đó mỗi giây một lần bằng cách sử dụng AJAX. Vì vậy bước đầu tiên trong phần này sẽ là cung cấp dữ liệu JSON này. Cần giả thiết rằng chức năng giá cổ phiếu đã có sẵn trong ứng dụng môi giới cổ phiếu rồi (viết bằng Java), do đó bạn sẽ cung cấp nguồn cấp JSON này từ một trình điều khiển chạy trong IBM WebSphere.

Sử dụng StockListController.java để cung cấp giá cổ phiếu

Để bắt đầu trước tiên bạn phải sửa đổi phương thức handleRequests() trong StockListController.java, như Liệt kê 1, như vậy bạn sẽ được cung cấp một số giá cổ phiếu.

Liệt kê 1. Sửa đổi lớp StockListController (Java) để cung cấp giá cổ phiếu
public ModelAndView handleRequest(HttpServletRequest request,
                      HttpServletResponse response) throws Exception { 
    List<Stock> stocks = getDao().fetchAllStocks();
    for (Stock stock : stocks) {
        stock.setPrice (getStockPriceSource().getPriceInCents(stock.getId()));
    }
    
    return new ModelAndView (getSuccessView(), "stocks", stocks);
    }

Sử dụng một lớp StockPriceSource để mô phỏng sự biến động của giá cổ phiếu

Thay vì chỉ cung cấp các chứng khoán cho khung nhìn khi được tìm nạp từ DAO, StockListController bây giờ gọi một đối tượng StockPriceSource để lấy giá cả của từng cổ phiếu, vì giá cả này thay đổi theo thời gian thực, đối lập với được cho theo cơ sở dữ liệu. Một cuộc môi giới chứng khoán thực sự sẽ triển khai thực hiện lớp StockPriceSource để lấy ra giá chứng khoán từ một nguồn dữ liệu ở đâu đó, có độ an toàn cao và theo đặc thù của ngành công nghiệp. Tuy nhiên ứng dụng này sẽ mô phỏng biến động giá cổ phiếu bằng một lớp StockPriceSource chứa một ánh xạ “tin điện báo cổ phiếu với mức giá” (stock ticker to price), và mọi yêu cầu về giá của một cổ phiếu sẽ cập nhật giá đó trong ánh xạ này, thay đổi nó lên xuống một cách ngẫu nhiên trong biên độ thay đổi lập sẵn (xem mã kèm theo trong phần Tải về để biết thêm chi tiết).

Để cung cấp StockPriceSource cho StockListController, sửa đổi các định nghĩa bean của StockListController trong spring-servlet.xml và cung cấp một định nghĩa bean mới cho đối tượng StockPriceSource, như Liệt kê 2.

Liệt kê 2. Cung cấp cho StockListController một StockPriceSource trong spring-servlet.xml
<bean id="stockPriceSource" class="com.jm.fbstockdemo.StockPriceSource">
    <property name="volatility" value="50"/>
    <property name="startPrice" value="5000"/>
    <property name="minPrice" value="500"/>
    <property name="maxPrice" value="10000"/>
</bean>

    <bean id="stockListController" class="com.jm.fbstockdemo.StockListController">
    <property name="dao" ref="stocksDao"/>     
    <property name="stockPriceSource" ref="stockPriceSource"/>
    <property name="successView">
      <value>stockList.jsp</value>
    </property>
</bean>

Thuộc tính của bean stockPriceSource cấu hình hành vi của nó: tất cả các cổ phiếu bắt đầu với giá 5000 cent ($50), có thể thay đổi đến 50 cent mỗi tích tắc (thuộc tính volatility ), và không được phép rớt giá xuống dưới $5 hoặc lên trên $100 trong dải biến thiên ngẫu nhiên của chúng theo thời gian. Thuộc tính stockPriceSource trên bean stockListController cung cấp cho stockListController một cá thể stockPriceSource có phạm vi trên toàn ứng dụng. Vì StockPriceSource là một bean, cùng một cá thể như vậy sẽ vẫn nằm trong bộ nhớ cho đến khi ứng dụng web hoặc IBM WebSphere được khởi động lại, và như vậy biến thiên giá cổ phiếu sẽ vẫn ổn định trong trang vải nền Facebook cho đến khi ứng dụng còn đang chạy.

Sử dụng thư viện thẻ JSP JSON để tạo ra nguồn cấp JSON

Bây giờ bạn đã có một nguồn cổ phiếu và giá cả của chúng được mô phỏng theo thời gian thực, hãy cung cấp thông tin này như là dữ liệu JSON cho các lần gọi Javascript AJAX mà sẽ chạy trong trang vải nền. JSON (ký pháp đối tượng JavaScript), đặc tả của nó hiện có tại http://www.json.org/, là một định dạng thay thế cho XML để chuyển dữ liệu đối tượng, và đang trở thành được ưa thích đối với dữ liệu AJAX. Nó cô đọng hơn (do đó truyền tải nhanh hơn), cung cấp một ký pháp dễ hiểu cho các thuộc tính của một đối tượng (trái ngược với sự pha trộn của các thuộc tính và các thẻ con của XML), và không như XML cung cấp một cấu tạo rõ ràng để biểu thị một danh sách các mục. Các tính năng này làm cho nó nhanh hơn, đơn giản, và không nhập nhằng khi chuyển dữ liệu JSON thành các đối tượng trong một ngôn ngữ như Javascript mà hỗ trợ các đối tượng và mảng.

Tuy nhiên, các khung nhìn của ứng dụng là JSPs, và các JSP gồm cả XML, nên sử dụng một thư viện thẻ JSP cho phép bạn dựng nên các đối tượng bằng cách sử dụng XML, trong khi các thẻ biểu hiện dữ liệu đối tượng ở định dạng JSON. Để làm điều đó, hãy sử dụng thư viện thẻ JSON JSP sẵn có tại http://json-taglib.sourceforge.net/index.html. Tải về json-taglib JAR vào thư mục WEB-INF/lib của bạn. Sau đó sửa đổi stockList.jsp -- khung nhìn được StockListController biểu hiện -- để cung cấp dữ liệu dưới dạng JSON, như Liệt kê 3.

Liệt kê 3. Sử dụng thư viện thẻ JSON JSP để biểu hiện nguồn cấp giá cổ phiếu JSON
<%@ page contentType="text" %>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="json" uri="http://www.atg.com/taglibs/json" %>
<json:object>
    <json:array name="stocks">
        <c:forEach items="${stocks}" var="stock"> 
            <json:object>
                <json:property name="id"><c:out 
value="${stock.id}"/></json:property>
                <json:property name="ticker"><c:out 
value="${stock.ticker}"/></json:property>
                <json:property name="price"><c:out 
value="${stock.price}"/></json:property>
            </json:object>
        </c:forEach>
    </json:array>
</json:object>

Một đối tượng JSON gồm có các cặp tên/giá trị, trong đó một giá trị có thể là giá trị kiểu nguyên thủy như một chuỗi ký tự, một đối tượng JSON khác, hoặc một mảng JSON. Trong stockList.jsp, thẻ <json:object> tạo ra một đối tượng JSON như là vỏ bọc bậc cao nhất của nó. Nhãn <json:array> tạo ra một thuộc tính của đối tượng bậc cao nhất gọi là stocks là một mảng của các đối tượng JSON, trong trường hợp này là cổ phiếu. JSP lặp qua các cổ phiếu do StockListController cung cấp để xây dựng nên mảng JSON, tạo ra một đối tượng JSON cho mỗi cổ phiếu, mỗi cái với một mã nhận dạng (id), tin điện báo (ticker) và thuộc tính giá cả (price).

Chú ý rằng contentType ở đây là text (văn bản) nên bạn có thể xem các kết quả trong một trình duyệt và gỡ lỗi Javascript dễ dàng hơn, nhưng một cách khác nó có thể là “text/json”. Cũng lưu ý rằng bạn không thể bao gồm các chú thích <!-- xml comments --> trong JSP này, vì mặc dù chúng sẽ bị bỏ qua nếu đầu ra là XML, nhưng chúng sẽ được diễn giải như là dữ liệu hỏng khi kết quả được diễn giải như là JSON.

Để kiểm tra nguồn cấp JSON của giá cả cổ phiếu, hãy triển khai lại ứng dụng Web lên WebSphere (như trong Phần 2 của hướng dẫn này), di chuyển đến http://localhost/fb_stock_demo/stockList trong trình duyệt của bạn, và bạn sẽ thấy các cổ phiếu và giá cả của chúng ở định dạng JSON. Tải lại trình duyệt và giá cả cổ phiếu trong dữ liệu JSON sẽ thay đổi, vì StockPriceSource sẽ thay đổi giá cả của chúng với mỗi yêu cầu.

Xem nguồn cấp JSON này đang hoạt động khi bạn thực hiện việc gọi ra AJAX trong FBJS của trang vải nền (Facebook JavaScript). Tuy nhiên, trước khi bạn đến đó bạn cần phải nhận ra người sử dụng Facebook đang xem trang danh mục đầu tư (portfolio page), do đó hãy chuyển sự chú ý của bạn trở lại phía bên PHP của ứng dụng để kết nối với Facebook và nhận dạng người sử dụng Facebook trong cơ sở dữ liệu DB2 của bạn.


Kết nối với ứng dụng và với Facebook trong PHP

Bây giờ hãy thực hiện trang vải nền của ứng dụng, gồm cả việc kết nối với Facebook và nối kết người sử dụng Facebook với mã nhận dạng của họ trong cơ sở dữ liệu DB2 IBM, và thực hiện trang danh mục đầu tư chính của người sử dụng, dùng nguồn cấp JSON.

Sửa đổi URL gọi lại để sử dụng tập tin .htaccess

Trong Phần 1 của hướng dẫn này bạn đã sử dụng một tệp index.php đơn giản để kiểm tra cấu hình ứng dụng Facebook. Do bạn đã bổ sung hoàn thiện cơ sở hạ tầng và đang sử dụng tập tin .htaccess để gửi đi các yêu cầu, bạn cần phải thay đổi URL gọi lại của ứng dụng trong thiết lập của ứng dụng. Trong Facebook, nhấn vào ứng dụng Applications ngay bên dưới hộp tìm kiếm (Search box). Trong ứng dụng Applications bạn có thể nhìn thấy toàn bộ các ứng dụng được cài đặt của bạn. Nhấn vào ứng dụng Developer nó chứa một danh sách các ứng dụng mà bạn là nhà phát triển, hiển thị dưới dạng một danh sách nằm ở phía bên phải (xem Hình 1).

Hình 1. Danh sách ứng dụng của bạn trong ứng dụng Developer
Danh sách ứng dụng của bạn trong ứng dụng Developer

Nhấn vào tên ứng dụng của bạn để xem trang thiết lập của nó, nhấn Edit Settings, và đổi Callback URL thành http://SERVER/fb_stock_demo/, thay SERVER bằng URL của máy chủ web Apache 2 ở xa của ứng dụng của bạn. Nếu bạn đặt Callback URL như trong Phần 1, việc này chỉ đòi hỏi loại bỏ tên tệp index.php khỏi phần cuối của URL.

Sửa đổi .htaccess để hỗ trợ ứng dụng đầy đủ

Do trang vải nền của bạn trỏ đến thư mục fb_stock_demo, được điều quản bởi RewriteRules, của tập tin .htaccess, hãy sửa đổi .htaccess như trong Liệt kê 4 để cung cấp tất cả các quy tắc cần thiết để hoàn tất ứng dụng.

Liệt kê 4. Tập tin .htaccess đầy đủ
RewriteEngine on

# php dispatcher request
RewriteCond %{QUERY_STRING} (.*)
RewriteRule ^php/(.*) index.php?controller=$1&%1  [last]

# index
RewriteRule ^$ php/defaultCanvas [next]

# php actions
RewriteRule ^login$ php/login [next]
RewriteRule ^portfolio$ php/portfolio [next]
RewriteRule ^recommendStockToFriends$ php/recommendStockToFriends [next]

# java actions
RewriteRule ^tradeStock$ java/tradeStock [next]
RewriteRule ^stockList$ java/stockList [next]

RewriteRule đầu tiên định tuyến tất cả các yêu cầu có tiền tố “php/” đến index.php như trong Phần 2 của hướng dẫn này. Quy tắc tiếp theo tiến hành so khớp Callback URL nhưng không có phần đường dẫn tiếp theo được xác định, và nó uỷ quyền cho yêu cầu PHP defaultCanvas. Các hành động PHP khác hoạt động tương tự, và các hành động Java hiện nay bao gồm cả một yêu cầu tradeStock mà bạn sẽ triển khai thực hiện sau trong hướng dẫn này.

Sửa đổi app.properties

Trong Phần 2 bạn đã phát triển lớp ActionDispatcher nó định tuyến các yêu cầu đến các lớp của trình điều khiển bằng cách sử dụng các tệp thuộc tính trong lớp Injectable. Để cung cấp cho trình điều khiển các ánh xạ định nghĩa trong tập tin .htaccess mới, hãy sửa đổi app.properties (trong thư mục conf, dưới thư mục fb_stock_demo, là nơi chứa tệp .htaccess) như Liệt kê 5.

Liệt kê 5. Tập tin app.properties đầy đủ
ActionDispatcher/defaultCanvas=DefaultCanvasController
ActionDispatcher/login=LoginController
ActionDispatcher/portfolio=PortfolioController
ActionDispatcher/recommendStockToFriends=RecommendStockToFriendsController

AbstractStockDemoFacebookController/facebook_api_key=[YOUR FACEBOOK API_KEY]
AbstractStockDemoFacebookController/facebook_secret=[YOUR FACEBOOK SECRET]
AbstractStockDemoFacebookController/facebookAppUrl=http://apps.facebook.com/
[YOUR CANVAS PAGE URL] AbstractStockDemoFacebookController/siteUrl=
http://[YOUR SERVER URL]/fb_stock_demo

DefaultCanvasController/loggedInForward=portfolio
DefaultCanvasController/loginView=loginView.php

LoginController/alreadyHasUserForward=portfolio
LoginController/validUserForward=portfolio
LoginController/invalidUserView=loginView.php

Vào thời điểm này, dòng đầu tiên là hệ trọng nhất, bởi vì nó sẽ ánh xạ khoá của trình điều khiển defaultCanvas (được cung cấp bởi quy tắc viết lại trong .htaccess) đến lớp DefaultCanvasController sao cho lớp ActionDispatcher sẽ tạo ra một cá thể DefaultCanvasController và cho chạy nó khi có người truy cập trang vải nền của ứng dụng của bạn. Các thuộc tính khác sẽ trở nên hữu ích khi bạn thực hiện phần còn lại của ứng dụng.

DefaultCanvasController

DefaultCanvasController xử lý các yêu cầu được gửi tới trang vải nền của ứng dụng Facebook (mà không có URI phụ), và cần để xử lý hai khả năng. Một khả năng là, nếu đây là lần đầu tiên người sử dụng truy cập trang vải nền của ứng dụng này, có nghĩa là bây giờ họ chỉ vừa mới thêm ứng dụng vào. Khi họ truy cập lần đầu tiên, bạn có được mã nhận dạng người sử dụng Facebook vì Facebook gửi nó trong yêu cầu, nhưng bạn còn chưa biết người sử dụng facebook này là ai về mặt môi giới chứng khoán, nghĩa là tên người sử dụng là gì theo hệ thống hiện hành, vì vậy bạn cần đến chúng để đăng nhập và thiết lập liên kết đó. Khả năng thứ hai là trường hợp người sử dụng đã đăng nhập vào hệ thống, trong trường hợp này họ có thể bỏ qua màn hình đăng nhập tuỳ chỉnh của bạn và xem danh mục đầu tư của họ. Trong trường hợp đầu, DefaultCanvasController biểu hiện khung nhìn đăng nhập tùy chỉnh của ứng dụng, và trong trường hợp thứ hai, nó chuyển điều khiển đến PortfolioController (mà bạn sẽ thực hiện sau đây), như Liệt kê 6.

Liệt kê 6. Lớp DefaultCanvasController
class DefaultCanvasController extends AbstractStockDemoFacebookController {

  public function __construct() {
    parent::__construct(false);
  }

  protected function executeFacebookRequest() {    
    return $this->user 
      ? new ControllerForward ($this->loggedInForward)
      : new ModelAndView ($this->loginView);
  }
}

DefaultCanvasController Chuyển giao kết quả là false đến hàm tạo của lớp cha, chỉ rõ rằng không yêu cầu người sử dụng đã được đăng nhập vào hệ thống môi giới chứng khoán. Thuộc tính loginView được thêm vào từ app.properties và tương ứng với loginView.jsp. loggedInForward cũng được thiết lập trong app.properties, và nó xác định rõ khoá của trình điều khiển “portfolio”, ánh xạ đến lớp PortfolioController (tham khảo liệt kê mã lệnh của app.properties để biết các giá trị khoá khác nhau được ánh xạ vào).

Trong trường hợp đầu, khi mà người sử dụng lần đầu tiên thêm ứng dụng Facebook và cần đăng nhập vào môi giới chứng khoán, loginView.jsp là một trang đăng nhập đơn giản (xem Liệt kê 7) mà sau đó được hiển thị như trang vải nền của ứng dụng của bạn (xem Mã nguồn để có toàn bộ tập tin).

Liệt kê 7. Thẻ form trong loginView.php
<form method="post" action="login">
<p>
   <span class="label">Username:</span><input 
name="username"/><br/>
   <span class="label">Password:</span><input 
name="password" type="password"/><br/>
</p>
<input type="submit" value="Submit"/>
</form>

Đây thực sự là FBML, mặc dù nó không sử dụng bất kỳ thẻ FBML đặc trưng Facebook nào. Chú ý rằng hành động (action) của biểu mẫu liên quan đến Callback URL của ứng dụng; Facebook uỷ nhiệm yêu cầu post tới máy chủ của bạn. Lớp LoginController xử lý yêu cầu post (gửi dữ liệu) đăng nhập (xem Mã nguồn để biết thêm chi tiết), bằng cách chèn thêm vào một hàng trong bảng facebook_user, liên kết mã nhận dạng người sử dụng facebook của người sử dụng với ID nhà kinh doanh môi giới chứng khoán của họ.

Thực hiện một trình điều khiển cơ sở chung

Do tất cả các trình điều khiển, ngoại trừ LoginController đều yêu cầu rằng người sử dụng Facebook được nhận biết trong hệ thống môi giới chứng khoán, và do tất cả các trình điều khiển này sẽ yêu cầu một kết nối với trình khách Facebook, sẽ hữu ích nếu sử dụng một lớp cơ sở chung, kết nối với Facebook và tìm kiếm người sử dụng trong cơ sở dữ liệu trước khi thực hiện các chi tiết của yêu cầu đó. Để làm điều này, hãy thực hiện lớp điều khiển cơ sở AbstractStockDemoFacebookController, như Liệt kê 8.

Liệt kê 8. Lớp AbstractStockDemoFacebookController (PHP)
abstract class AbstractStockDemoFacebookController extends AbstractStockDemoController {

  protected $facebook = null;
  private $requiresUser;
  protected $user = null;

  public function __construct($requiresUser = true) {
    parent::__construct();
    $this->addPrefix('AbstractStockDemoFacebookController');
    $this->requiresUser = $requiresUser;
  }

  public function executeSpecific() {

    $this->facebook = new StockDemoFacebookClient ($this->facebook_api_key, 
$this->facebook_secret);

    $this->user = $this->dao->fetchUserByFacebookId
($this->getFacebookUserId());

    if ($this->user == null && $this->requiresUser) {
      throw new Exception ("AbstractStockDemoFacebookController -- 
no matching user found in stocks database.");
    }    

    return $this->executeFacebookRequest();
  }

  protected function getFacebookUserId() {
    return $this->facebook->user;
  }

  protected function getUser() {
    return $this->user;
  }

  protected abstract function executeFacebookRequest();
}

Hãy nhớ lại rằng ActionDispatcher sẽ tạo ra một cá thể của trình điều khiển thích hợp, thiết lập đối tượng Properties của nó từ tệp tin thuộc tính, và gọi ra phương thức execute() của nó. Lớp AbstractStockDemoFacebookController mở rộng lớp AbstractStockDemoController, mà phương thức execute() của lớp này sẽ kết nối với cơ sở dữ liệu IBM DB2, đưa ra một thông báo lỗi nếu không kết nối được, và gọi phương thức trừu tượng executeSpecific(). Mã triển khai thực hiện phương thức executeSpecific() của lớp AbstractStockDemoFacebookController tạo ra một cá thể StockDemoFacebookClient (mà bạn sẽ thực hiện tiếp theo) để kết nối với Facebook và xác nhận rằng người sử dụng đã đăng nhập vào ứng dụng Facebook. Sau đó nó tìm kiếm người sử dụng Facebook trong cơ sở dữ liệu thông qua StocksDAO, nhận được đối tượng User liên kết mã nhận dạng Facebook của họ với ID người sử dụng nhà kinh doanh cổ phiếu của họ. Nếu người sử dụng Facebook không tương ứng với một người sử dụng trong cơ sở dữ liệu, lớp này huỷ bỏ bằng một lỗi ngoại lệ (Exception), trừ phi hàm tạo của lớp con chuyển tới kết quả là false dành cho cờ báo $requiresUser -- chỉ có DefaultCanvasController làm việc này vì nó cần có khả năng điều phối LoginController dành cho đăng nhập ban đầu.

Tạo một lớp bọc xung quanh trình khách Facebook PHP

Để bao kín các lần gọi ban đầu đến Facebook và cung cấp các phương thức đặc thù cho ứng dụng mà chính nó cũng bao gói các lần gọi đến trình khách Facebook, hãy tạo lớp StockDemoFacebookClient như trong Liệt kê 9.

Liệt kê 9. Lớp StockDemoFacebookClient (PHP)
class StockDemoFacebookClient extends Facebook {
  
  public function __construct($apiKey, $secret) {

    parent::__construct ($apiKey, $secret);

    $this->require_frame();
    $this->require_install();
    $this->require_login();
  }
}

Đây cũng là mã mà bạn trông thấy trong Phần 1 của hướng dẫn, trong tệp index.php khung sườn bạn đã sử dụng để kiểm tra kết nối giữa Zend Core for IBM với các máy chủ của Facebook. Khi AbstractStockDemoFacebookClient tạo ra một cá thể của đối tượng khách này nó sẽ kết nối với Facebook và yêu cầu rằng người sử dụng phải có ứng dụng đã cài đặt và đã đăng nhập vào nó (theo Facebook, chứ không phải là đăng nhập vào môi giới chứng khoán). Các lời gọi require_install()require_login() chuyển hướng đến các trang tương ứng trên Facebook nếu người sử dụng hoặc chưa thêm vào ứng dụng này hoặc chưa được đăng nhập vào nó trên Facebook. Lớp Facebook sử dụng các tham số yêu cầu gửi trong yêu cầu từ Facebook để xác định người sử dụng. Ngoài ra, sau này bạn sẽ thêm các lời gọi trình khách đặc thù của ứng dụng vào đây.


Kết nối với Facebook và thực hiện giao dịch mua bán phía Java

Do bạn đã được kết nối với Facebook và đã đồng bộ hoá người sử dụng với cơ sở dữ liệu cổ phiếu bên phía PHP, theo đó hoàn tất mã giao dịch mặt sau (backend transaction code) ở đó, sẽ hữu ích khi viết mã tương tự như thế ở phía Java, để bạn có một mặt sau hoàn chỉnh sẵn sàng khi bạn thực hiện trang vải nền chính để hiển thị thông tin kết quả từ các hoạt động mặt sau khác nhau.

Sử dụng một lớp cơ sở để kết nối với Facebook phía Java

Giống như bạn đã làm cho bên PHP của ứng dụng, trong Rational Application Developer của IBM hãy tạo ra lớp AbstractStockDemoFacebookController như Liệt kê 10.

Liệt kê 10. Lớp AbstractStockDemoFacebookController (Java)
public abstract class AbstractStockDemoFacebookController extends 
  AbstractStockDemoController {
    
    private FacebookKeys facebookKeys;
    private User user;
    private StockDemoFacebookClient facebookClient;    
    
    public ModelAndView handleRequest(HttpServletRequest request,
                      HttpServletResponse response) throws Exception {
    
    this.facebookClient =
        new StockDemoFacebookClient (request, response, getFacebookKeys());

    this.user = getDao().fetchUserByFacebookId(getFacebookClient().getUser());
    
    if (this.user == null) {
        throw new RuntimeException("AbstractStockDemoFacebookController -- 
no user in database matching facebook id");
    }

    return handleFacebookRequest (request, response);
    }
    
    protected abstract ModelAndView handleFacebookRequest 
    (HttpServletRequest request, HttpServletResponse response);
    
    public void setFacebookKeys(FacebookKeys facebookKeys) {
    this.facebookKeys = facebookKeys;
    }
    
    protected FacebookKeys getFacebookKeys() {
    return facebookKeys;
    }
    
    protected StockDemoFacebookClient getFacebookClient() {
    return this.facebookClient;
    }    
    
    protected User getUser() {
    return this.user;
    }
}

Mã này trông hầu như giống hệt lớp PHP tương ứng -- handleRequest() kết nối với Facebook bằng cách sử dụng một lớp StockDemoFacebookClient (mà bạn sẽ viết ngay bây giờ), tìm kiếm người sử dụng Facebook trong cơ sở dữ liệu cổ phiếu, đưa ra một lỗi RuntimeException nếu không tìm thấy người sử dụng nào như vậy, và gọi phương thức trừu tương handleFacebookRequest() Tiếp theo, sử dụng thư viện phía khách Java để kết nối với Facebook như bạn đã làm trong PHP.

Kết nối với Facebook trong Java

Vấn đề đầu tiên của bạn khi kết nối với Facebook từ Java là ở chỗ Facebook gần đây đã đình chỉ thư viện khách Java của nó, không tiếp tục duy trì việc cập nhật nữa. May mắn là, một dự án có tên facebookjava-api (xem Các điều kiện tiên quyết), được chứa trên máy chủ Google Code, đã tự đặt ra sứ mệnh của mình là để “cung cấp một phiên bản chất lượng cao, cập nhật hơn của API Facebook phía khách cho các nhà phát triển Java, và cho phép nó được bảo trì đều đặn thường kỳ sau này để duy trì các hỗ trợ khi các API nền Facebook thay đổi và tiến hoá lên.” Với việc đình chỉ thư viện khách chính thức, dường như đã coi nó là một chuẩn thực tế (de facto standard), và nó chính là thư viện mà bạn sẽ sử dụng trong ứng dụng này.

May mắn là dự án facebook-java-api cũng đã cung cấp Tiện ích Bạn bè (Companion), trong đó chủ yếu cung cấp cùng một lớp Facebook mà bạn đã sử dụng bên phía PHP. Nó bao bọc lớp khách REST Facebook thực tế, và cung cấp các phương thức thuận tiện như requireLogin() làm cho việc kết nối một ứng dụng PHP với Facebook một cách đúng đắn trở thành rất dễ dàng. Thư viện khách Java ban đầu không bao gồm lớp này, đòi hỏi bạn phải tự xử lý một số bước xác thực và mang lại một rào chắn quan trọng để bước vào phát triển ứng dụng Facebook.

Vì vậy trước tiên tải về tất cả các JAR đã đề cập trên địa chỉ trang ấy, trừ activation.jar, vì hầu hết các máy chủ ứng dụng đã bao gồm nó trong biến đường dẫn lớp dùng chung (shared classpath). Ở đây gồm có năm tệp JAR được liệt kê dưới Quick Start và hai tệp JAR dưới Companion Utility. Hãy đặt các JAR này vào thư mục WEB-INF/lib trong dự án ứng dụng web của bạn.

Để sử dụng thư viện khách, hãy thực hiện lớp StockDemoFacebookClient như thấy trong Liệt kê 11.

Liệt kê 11. Lớp StockDemoFacebookClient (Java)
public class StockDemoFacebookClient extends Facebook {    

    public StockDemoFacebookClient(HttpServletRequest request, 
HttpServletResponse response, FacebookKeys keys) {

    // connect to facebook
    super(request, response, keys.getApiKey(), keys.getSecret());
    
    // will redirect if we're not logged in already        
    String next = request.getServletPath().substring(1); 
    if (requireLogin(next)) {
        throw new RuntimeException ("User not logged into facebook!");
    }
    }
}

Giống như trong phiên bản PHP, trình khách Facebook đặc thù riêng cho ứng dụng của bạn là lớp con của trình khách thật. Còn lớp Facebook, để cách ly bạn khỏi các chi tiết của các tham số yêu cầu liên quan gửi đến từ Facebook (giống như phiên bản PHP đã làm), sẽ lấy các đối tượng HttpServletRequest và HttpServletResponse để xử lý việc nhận biết người sử dụng đang gọi Facebook và khả năng chuyển hướng đến trang đăng nhập ứng dụng Facebook khi cần thiết. StockDemoFacebookClient cũng lấy một đối tượng FacebookKeys, một lớp đơn giản chứa API KeySecret của ứng dụng Facebook.

Thực hiện giao dịch mua bán phía Java

Do việc môi giới chứng khoán có lẽ đã cho phép buôn bán cổ phiếu trước khi ứng dụng Facebook xuất hiện, hãy triển khai mã lệnh giao dịch cổ phiếu phía Java. Để làm điều đó, tạo ra một bean Spring tradeStockController như Liệt kê 12.

Liệt kê 12. bean Spring tradeStockController
<bean id="tradeStockController" class="com.jm.fbstockdemo.TradeStockController">
      <property name="dao" ref="stocksDao"/>
      <property name="facebookKeys" ref="facebookKeys"/>
      <property name="stockPriceSource" ref="stockPriceSource"/>
      <property name="postToNewsFeed" value="false"/>
      <property name="successView">
        <value>http://apps.facebook.com/devworksstockdemo/</value>
      </property> 
</bean>

Mã lệnh này cung cấp cho trình điều khiển bean Dao (StocksDao), bean stockPriceSource một cờ báo cho nó biết có gửi lên nguồn cung cấp tin tức Facebook hay không (để không quấy nhiễu bạn bè của nhà phát triển trong khi gỡ lỗi), một thuộc tính successView chứa URL của ứng dụng Facebook mà trình điều khiển này sẽ chuyển hướng đến khi hoàn thành, và một bean facebookKeys. Bean facebookKeys chứa API Facebook KeySecret, như Liệt kê 13.

Liệt kê 13. Bean spring facebookKeys
<bean id="facebookKeys" class="com.jm.fbstockdemo.FacebookKeys">
    <constructor-arg value="b7d42ca56cd47fc94274ecb8428f9d8d"/>
    <constructor-arg value="a42ce25076de43546f886aa2fec77321"/>
</bean>

Đưa các giá trị này vào một bean Spring cho phép bạn giữ các giá trị đó tách khỏi mã và cho phép bạn dễ dàng thêm chúng vào bất kỳ trình điều khiển nào cần kết nối với Facebook.

Để làm công việc buôn bán, hãy tạo lớp StockTradeController như Liệt kê 14.

Liệt kê 14. Lớp TradeStockController (Java)
public class TradeStockController extends AbstractStockDemoFacebookController {

    private boolean postToNewsFeed = false;

    @Override
    protected ModelAndView handleFacebookRequest(HttpServletRequest request,
                         HttpServletResponse response) {
        
    int stockId = Integer.parseInt(request.getParameter("stockId"));
    int shares = Integer.parseInt(request.getParameter("shares"));           

    long stockPriceInCents = getStockPriceSource().getPriceInCents(stockId);

    long previousSum = getDao().fetchTradeSum(getUser().getTraderId(), stockId);

    // effect the trade 
    Trade trade = getDao().createTrade (getUser().getTraderId(), 
                        stockId, shares, stockPriceInCents);

    long newSum = getDao().fetchTradeSum(getUser().getTraderId(), stockId);

    long net = newSum - previousSum;

    trade.setNetInCents (net);
    
    // notify the user
    getFacebookClient().sendNotificationToUser 
        (createTradeNotificationText (trade));
    
    // if a profit, post to mini/news feeds
    if (trade.getNetInCents() > 0 && this.postToNewsFeed) {            
        getFacebookClient().postToNewsAndMiniFeeds 
        (createTradeNewsItemText (trade, getFacebookClient().getAddUrl("")));
    }        
    
    // redirect to portfolio page with result of trade
    try {
        response.sendRedirect(getSuccessView() + 
                  "?tradeResult=" + trade.getNetInCents() + 
                  "&tradeResultStockId=" + trade.getStock().getId());
    } catch (IOException e) {
        throw new RuntimeException (e);
    }
    return null;
    }

    public void setPostToNewsFeed (boolean b) {
    this.postToNewsFeed = b;
    }
}

TradeStockController lấy các tham số yêu cầu stockIdshares xác định mã chứng khoán và số lượng cổ phiếu để mua hoặc bán (một giá trị số cổ phiếu âm = một cuộc bán), xúc tiến việc mua bán và ghi lại nó trong cơ sở dữ liệu, và sau đó thực hiện hai lời gọi Facebook thông qua trình khách Facebook. Trước nhất, nó gửi một thông báo cho người sử dụng xác nhận việc mua bán. Và thứ hai là, nếu người sử dụng đã mua các cổ phần của mã chứng khoán, vì ứng dụng Facebook này cũng là một trò chơi xã hội, trình khách gửi một hành động đến nguồn cấp tin mini (Mini Feed) của người sử dụng, mà có thể sẽ được lan truyền đến các Nguồn cung cấp tin tức (News Feeds) của bạn bè họ. Sau đó nó gửi một chuyển hướng HTTP đến trang vải nền danh mục đầu tư chính (xác định trang ứng dụng Facebook, không phải là URL của trang theo máy chủ ở xa), cung cấp các tham số yêu cầu tradeResulttradeResultStockId để hiển thị ở đó.

Gửi lên các thông báo Facebook và các hành động Nguồn cấp tin mini / Nguồn cung cấp tin tức từ Java

Để thêm chức năng thông báo và gửi hành động, hãy thêm các phương thức sendNotificationToUser()postToNewsAndMiniFeeds() vào StockDemoFacebookClient, như trong Liệt kê 15.

Liệt kê 15. StockDemoFacebookClient.sendNotificationToUser() StockDemoFacebookClient.postToNewsAndMiniFeeds()
public void sendNotificationToUser(String fbml) {
    try {
        getFacebookRestClient().notifications_send (fbml);
    } catch (FacebookException e) {
        throw new RuntimeException (e);
    } catch (IOException e) {
        throw new RuntimeException (e);
    }
 }
    
 public void postToNewsAndMiniFeeds(String fbml) {
    try {
        getFacebookRestClient().feed_publishTemplatizedAction (fbml);
    } catch (FacebookException e) {
        throw new RuntimeException (e);
    } catch (IOException e) {
        throw new RuntimeException (e);
    }
 }

Đối tượng Facebook tự nó là một vỏ bọc bao quanh đối tượng trình khách hiện thời, thu được qua getFacebookRestClient(). Các phương thức phía khách (trong cả hai thư viện khách Java và PHP) sử dụng một quy ước đặt tên bắt chước tên của các lời gọi hàm API REST thực tế, danh sách những API này bạn có thể xem tại http://wiki.developers.facebook.com/index.php/API. Chú ý rằng khi sử dụng thư viện khách Java, tất cả các lời gọi phương thức phải xử lý các lỗi ngoại lệ được kiểm tra là FacebookExceptionIOException -- một lý do để sử dụng lớp StockDemoFacebookClient.

Để tạo ra lời văn của thông báo, thêm createTradeNotificationText() vào lớp TradeStockController, như Liệt kê 16.

Liệt kê 16. TradeStockController.createTradeNotificationText()
    private String createTradeNotificationText (Trade trade) {
    return "Trade confirmation: " + trade.getShares() + " @ " 
+ trade.getStock().getPriceFormatted();
    }

Mã lệnh này sẽ được xử lý như FBML khi gửi đến Facebook, nhưng thông báo cụ thể này không sử dụng thẻ FBML nào.

Để tạo ra hành động Nguồn cấp tin mini/Nguồn cung cấp tin tức, hãy thêm createTradeNewsItemText() vào lớp TradeStockController như trong Liệt kê 17.

Liệt kê 17. TradeStockConroller.createTradeNewsItemText()
    private String createTradeNewsItemText (Trade trade, String addUrl) {
    return "{actor} is buying " + trade.getStock().getTicker() + 
        "using the <a href=\"" + addUrl + "\">" + 
        "DeveloperWorks Stock Demo Application!" + "</a>";
    }
}

Chú ý rằng StockDemoFacebookClient gọi phương thức feed_publishTemplatizedAction() của trình khách Facebook với FBML đã cung cấp. Hành động được đưa vào khuôn mẫu cho phép bạn đặt tên của người sử dụng vào lời văn của thông báo bằng cách sử dụng thẻ bài {actor}, thẻ bài này sẽ được thay thế bằng tên của người sử dụng khi gửi đi hành động này.

Do mặt sau đã xong xuôi, bạn sẽ thực hiện trang vải nền danh mục đầu tư chính, nơi ghép mọi thứ ở trên cùng với nhau.


Thực hiện trang vải nền danh mục đầu tư cổ phiếu

Trang vải nền chính sẽ hiển thị tất cả các mã chứng khoán sẵn có trong hệ thống, và số cổ phiếu của người sử dụng của bất cứ mã chứng khoán nào mà họ sở hữu. Nó sẽ cũng cung cấp các điều khiển để buôn bán cổ phiếu và đề xuất một cổ phiếu đến bạn bè trên Facebook. Hãy thực hiện trang danh mục đầu tư trong PHP, bằng cách sử dụng FBML và FBJS.

Tạo tệp PortfolioController.php

Đầu tiên hãy tạo tệp PortfolioController.php, trong đó sẽ tạo ra mô hình cho khung nhìn, như trong Liệt kê 18.

Liệt kê 18. Lớp PortfolioController (PHP)
class PortfolioController extends AbstractStockDemoFacebookController {

  public function executeFacebookRequest() {
    
    $stocks = $this->dao->fetchStocksAndPortfolio($this->user->TRADER_ID);

    $tradeResult = isset($_REQUEST['tradeResult']) ? $_REQUEST['tradeResult'] : null;
    $tradeResultStockId = $tradeResult ? $_REQUEST['tradeResultStockId'] : null;
    
    $this->facebook->updateProfile ($this->createProfileBoxFBML($stocks));

    return new ModelAndView 
      ('portfolio.php', 
       array ('facebookId' => $this->getFacebookUserId(),
          'tradeResult' => $tradeResult,
          'tradeResultStockId' => $tradeResultStockId,
          'stocks' => $stocks,
          'appUrl' => $this->siteUrl));
  }
}

Sau khi lớp cơ sở đã kết nối với Facebook, xác nhận rằng người sử dụng đã đăng nhập vào ứng dụng Facebook và môi giới chứng khoán, executeFacebookRequest() tìm kiếm tất cả các mã chứng khoán và tất cả các số cổ phiếu của người sử dụng của những mã chứng khoán đó qua DAO (xem mã nguồn để biết thêm chi tiết). Vì chính là trình điều khiển xử lý yêu cầu chuyển hướng từ kết quả của việc buôn bán (được chuyển hướng từ TradeStockController đang chạy trong WebSphere IBM), nó cũng sẽ tìm kiếm các tham số yêu cầu tradeResulttradeResultStockId đặt chúng vào mô hình của khung nhìn.

PortfolioController thực hiện một việc khác: nó cập nhật Hộp lược tả của người sử dụng bằng cách gọi StockDemoFacebookClient.updateProfile(). Hãy thêm phương thức này vào StockDemoFacebookClient như Liệt kê 19.

Liệt kê 19. StockDemoFacebookClient.updateProfile()
public function updateProfile($profileBox) {
    $this->facebook->api_client->profile_setFBML($profileBox);
  }

Về phía Java, đối tượng Facebook là một bao gói cho trình khách API REST của Facebook hiện tại, mà các phương thức của nó lặp lại đúng tên của tất cả các API REST giống như trong trình khách Java.

Để tạo văn bản cho hộp lược thảo, hãy thêm createProfileBoxFBML() vào PortfolioController như trong Liệt kê 20.

Liệt kê 20. PortfolioController.createProfileBoxFBML()
  private function createProfileBoxFBML($stocks) {
    
    $tickers = join(", ", $this->collectStockTickers($stocks));

    $facebookId = $this->getFacebookUserId();
    
    return 
<<<FBML

      <fb:name uid="$facebookId" useyou="false" possessive="true" 
firstnameonly="true" linked="false"/>

      portfolio:

       <br/> $tickers <br/>

       <a href="http://apps.facebook.com/devworksstockdemo">
          Join the stock game!
       </a>

FBML;
  }

Phương thức này trước tiên tìm nạp toàn bộ các mã chứng khoán của người sử dụng, và sử dụng một đoạn Heredoc PHP (PHP Heredoc segment) để xây dựng dễ dàng hơn nội dung của FBML. Thẻ <fb:name> cung cấp nhiều chức năng để hiển thị tên của một người sử dụng hoặc một số từ khác để trỏ đến người sử dụng. Ví dụ, theo mặc định khi Facebook biểu hiện nhãn này, nếu người sử dụng đang xem lược thảo là người sử dụng mà thuộc tính uid chỉ ra, nó sẽ biểu hiện từ bạn (you) chứ không phải tên của người sử dụng. Useyou="false" ngăn chặn hành vi này. Tương tự như vậy, firstnameonly="true" quy định chỉ hiển thị tên riêng của người sử dụng, linked="false" nói rằng không được tạo một liên kết từ tên này đến lược thảo của người sử dụng (do người xem đã có trên lược thảo của người sử dụng rồi), và possessive="true" chuyển tên người sang dạng sở hữu cách, ví dụ, “Jake's” (của Jake). Phần còn lại của hộp lược thảo liệt kê các chứng khoán mà người sử dụng này sở hữu và cung cấp một liên kết đến ứng dụng. Nếu người sử dụng nhấn vào nó và chưa cài đặt sẵn ứng dụng nào, họ sẽ được nhắc nhở để cài đặt nó trước đã.

Khung nhìn danh mục đầu tư

Do PortfolioController đã nạp vào mô hình, bây giờ là lúc để biểu hiện khung nhìn. Trong thư mục app, tạo tệp portfolio.php, trong đó bạn sẽ xây dựng lên dần từng mảnh, cái đầu tiên trong số đó được hiển thị trong Liệt kê 21.

Liệt kê 20. portfolio.php
<link rel="stylesheet" type="text/css" media="screen" href="<?= $model['appUrl'] 
   ?>/app/stylesheet/portfolio.css?v=1.0" />

<script>
  var STOCK_PRICE_AJAX_URL = '<?= $model['appUrl'] ?>/stockList';
</script>

<script src="<?= $model['appUrl'] ?>/app/javascript/
portfolio.js"></script>

Mã lệnh này chỉ thiết lập phần còn lại của trang với một phiểu định kiểu từ bên ngoài (Facebook gần đây đã thêm hỗ trợ cho các phiếu định kiểu từ bên ngoài) và tệp FBJS (Javascript). Nó cũng tạo ra một biến FBJS là STOCK_PRICE_AJAX_URL, cho phép PortfolioController cung cấp URL của lời gọi AJAX đến FBJS.

Tiếp theo thêm nội dung của Liệt kê 22 để chào người sử dụng.

Liệt kê 22. portfolio.php: Chào người sử dụng
<div id="content">

<h2>Hi 

<!-- first name-->
<fb:name firstnameonly="true" useyou="false" 
   uid="<?= $model['facebookId'] ?>"/>.

Welcome to Stocks R Us

</h2>

Ở đây một lần nữa bạn sử dụng thẻ <fb:name> để chèn thêm tên riêng của người sử dụng. Cũng chú ý rằng trang vải nền được gói trong một thẻ div với ID là “content” để cung cấp thông tin tạo kiểu dáng trên toàn bộ trang vải nền (ví dụ, các lề).

Tiếp theo thêm phần thịt của trang, bảng chứng khoán, như Liệt kê 23.

Liệt kê 23. portfolio.php - bảng cổ phiếu
<table>
   <tr>
     <th>Ticker</th>
     <th>Price</th>
     <th>Shares</th>
     <th>Total</th>
    <th colwidth="2">(negative shares = sell)</th>
   </tr>
   
   <? foreach ($model['stocks'] as $stock): ?>
   <tr>
     <td><?= $stock->TICKER ?></td>
     <td id="stock-price-<?= $stock->ID ?>"></td>
    
    <td id="stock-shares-<?= $stock->ID ?>">
       <?= $stock->SHARES ?>
     </td>

    <? if ($stock->SHARES): ?>
      <script> 
          portfolioShares[<?= $stock->ID ?>] = <?= $stock->SHARES ?>;
      </script>
    <? endif; ?>
 
     <td id="stock-total-<?= $stock->ID ?>"></td>
     <td class="row-controls">
       <div>

         <!-- buy/sell form for this stock -->
         <form action="<?= $model['appUrl'] ?>/tradeStock">
           <input type="submit" value="Buy/Sell" class="trade-button"/>
           <input type="hidden" name="stockId" value="<?= 
$stock->ID ?>"/>
           <input type="text" name="shares" class="shares"/>           
           shares.
         </form>

         <!-- recommend this stock to your friends -->
         <a href="<?= $model['appUrl'] ?>/recommendStockToFriends?ticker=<?=
$stock->TICKER ?>"
            class="recommend-control">
           Recommend to your friends!
         </a>

       </div>

       <? if ($model['tradeResult'] && $model['tradeResultStockId'] 
== $stock->ID): ?>                              
         Change: <span id="trade-result"></span>         

     <!-- leave the formatting to the javascript -->
         <script>            
        tradeResult = <?= $model['tradeResult'] ?>;
         </script>

       <? endif; ?>

     </td>
   </tr>
   <? endforeach; ?>
   <tr class="footer">
     <td>Total:</td>
     <td id="total"></td>
     <td></td>
     <td></td>
   </tr>
</table>

<a id="toggle-refresh" onclick="toggleRefresh()">Start refresh</a>

</div>

<script>
init();
</script>

Bảng này là một bảng HTML tiêu chuẩn, chứa một chứng khoán trên mỗi hàng, mỗi hàng cũng gồm một mẫu biểu cho phép người sử dụng Mua/Bán các cổ phiếu chứng khoán đó. Chú ý rằng hành động của mẫu biểu này là URL của ứng dụng trên máy chủ ở xa (nghĩa là http://www.YOURSERVER.com/fb_stock_demo/tradeStock). Hành động đó cũng có thể là tương đối như trong loginView. Nếu người sử dụng sở hữu các cổ phiếu của chứng khoán trên hàng đó, PHP này đưa vào thêm một mẩu nhỏ mã lệnh FBJS để cập nhật mảng portfolioShares (được định nghĩa trong portfolio.js, sẽ xuất hiện bên dưới). Đây là một mảng kết hợp toàn cục của các “tin điện báo cổ phiếu” mà người sử dụng sở hữu, được dùng trong tệp tin FBJS đã bao gồm vào. Mỗi hàng cũng chứa một liên kết cho phép người sử dụng đề xuất chứng khoán của hàng này với bạn bè Facebook của họ, và nếu portfolio.php đang biểu hiện kết quả của một giao dịch buôn bán, nó đưa thêm vào một biến FBJS là tradeResult chứa kết quả của việc buôn bán này.

Do trang này sẽ được làm mới lại các giá cổ phiếu một lần trong một giây bằng cách sử dụng AJAX, phần dưới đáy của trang bao gồm một đường liên kết “Pause refresh” (Tạm dừng làm mới), hữu ích chủ yếu trong việc gỡ lỗi, và nó cũng gọi hàm FBJS init() ở phần đáy dưới cùng của trang để khởi động việc làm mới AJAX khi trang vải nền được nạp lần đầu.


Thêm FBJS và danh mục đầu tư bước vào hoạt động

Bây giờ bạn đã có một khung nhìn trang vải nền đã sẵn sàng, cần phải hiển thị một số giá chứng khoán. Trong phần này hãy thêm vào mã FBJS để thực hiện việc đó, và sau đó chạy ứng dụng môi giới chứng khoán và xem nó trông như thế nào trên Facebook.

Bắt đầu với tệp tin FBJS

Tạo một thư mục Javascript dưới thư mục “fb_stock_demo/app” và một tệp tin portfolio.js, như trong Liệt kê 24.

Liệt kê 24. portfolio.js
var refreshTimer;
var REFRESH_DELAY = 1000;
var portfolioShares = [];
var tradeResult = null;

function init() {
    updateTradeResult();
    toggleRefresh();
}

Trước tiên nó tạo ra một số biến được sử dụng trong phần còn lại của kịch bản và trang - một đối tượng refreshTimer, nắm giữ đối tượng Timer (đồng hồ) dùng để kích hoạt các lời gọi AJAX, portfolioShares, mảng kết hợp các “tin điện báo cố phiếu” được tham khảo trong portfolio.php trên đây, và tradeResult, mà giá trị của nó cũng được thiết đặt trong portfolio.php trên đây để thông báo cho FBJS về kết quả của một cuộc mua bán. init() là hàm được gọi tại phần dưới cùng của porfolio.php, khi trang vải nền hoàn tất việc tải về.

Cập nhật kết quả buôn bán trong trang

Việc đầu tiên mà init() làm là cập nhật kết quả của việc buôn bán trên trang này, như Liệt kê 25.

Liệt kê 25. portfolio.js: updateTradeResult()
function updateTradeResult() {
    if (tradeResult) {
      var resultElement = getTradeResultElement();
      resultElement.toggleClassName (tradeResult > 0 ? 'increase' : 'decrease');
      resultElement.setTextValue (formatMoney(tradeResult));
    }
}

function getTradeResultElement() {
  return document.getElementById('trade-result');
}

Nếu biến tradeResult không rỗng (null) (nghĩa là được portfolio.php thiết đặt giá trị), updateTradeResult() tìm kiếm phần tử 'trade-result' (kết quả buôn bán) do portfolio.php đưa vào để đáp ứng lại việc buôn bán đó. Sau đó nó sử dụng hai phương thức DOM FBJS đặc biệt, toggleClassName()setTextValue(). FBJS sửa đổi DOM và cung cấp các phương thức DOM đặc biệt để truy cập các phần tử như phần tử này. Bạn có thể dễ dàng thêm vào hoặc loại bỏ một tên lớp, hoặc thiết lập tên lớp của phần tử đó bằng cách sử dụng toggleClassName(). Phương thức SetTextValue() là một phương thức đặc biệt nữa cho phép bạn thiết lập giá trị thuần văn bản của một phần tử DOM. Thay cho innerHTML, mà Facebook không hỗ trợ, bạn có thể thực hiện điều tương tự bằng cách sử dụng setTextValue() để thiết lập văn bản thuần, hoặc setInnerFBML() để thiết lập FBML bên trong của một phần tử. Chú ý rằng FBJS không cung cấp một phương thức getInnerFBML() để nhận được nội dung của một phần tử, cho nên nó không mang lại một sự thay thế hoàn toàn cho innerHTML. Đây là một lý do cho việc sử dụng một mảng FBJS portfolioShares toàn cục, ngược với việc cho FBJS kiểm tra innerHTML của phần tử share (hoặc tương đương) để thu được các cổ phiếu của chứng khoán trên hàng đó của người sử dụng. Cũng có phương cách có thể là tốt hơn để giữ thông tin này trong mã FBJS, nhưng là một sự biểu diễn một cách giải quyết khả dĩ khác.

Cũng lưu ý rằng getTradeResultElement() gọi ra document.getElementById() với ID mà bạn đã sử dụng trong portfolio.php. Nếu bạn xem mã nguồn trang của trang vải nền trong trình duyệt, bạn sẽ thấy rằng Facebook nối thêm một mã vào phần đầu của toàn bộ các ID của phần tử và các lớp CSS của bạn. Nó cũng nối mã này làm phần đầu vào toàn bộ các tên hàm FBJS và các tên biến của bạn. Nó làm việc này để gói gọn ứng dụng của bạn trong vùng tên trình duyệt riêng của chính mình, nên bạn có thể viết mã cứ như là bạn đang ở trong một hệ thống khép kín trái ngược với việc phải lo lắng về các xung đột với trang Facebook xung quanh.

Làm mới trang về giá chứng khoán mỗi giây một lần

Để khởi động việc làm mới định kỳ giá chứng khoán, thêm vào phương thức toggleRefresh() như trong Liệt kê 26.

Liệt kê 26. portfolio.js: toggleRefresh()
function toggleRefresh() {

    var button = document.getElementById('toggle-refresh');

    if (refreshTimer) {
      clearInterval(refreshTimer);
      refreshTimer = null;
      button.setTextValue('Start refresh');
    } else {
      refreshTimer = setInterval(refreshPrices, REFRESH_DELAY);    
      button.setTextValue('Pause refresh');
    }      
}

Đồng hồ (timer) và đồng hồ đếm giờ (interval timer) của FBJS làm việc cũng giống như các đồng nhiệm của chúng trong Javascript, trừ setInterval()setTimer() nhận đầu vào là một đối tượng Function nghĩa là setInterval(refreshPrices), không phải là một đoạn Javascript để thi hành như trong setInterval('refreshPrices()'). ClearInterval() nhận đầu vào là đối tượng đồng hồ đếm giờ lặp lại Timer và ngừng nó lại.

Thực hiện lời gọi AJAX để gọi nguồn cấp JSON các giá chứng khoán

Do bạn đã có một đồng hồ đếm giờ lặp lại, hãy thêm vào hàm refreshPrices() thực hiện lời gọi AJAX để lấy giá chứng khoán, như Liệt kê 27.

Liệt kê 27. portfolio.js: refreshPrices()
function refreshPrices() {

    var ajax = new Ajax();
    ajax.responseType = Ajax.JSON;

    ajax.ondone = function (data) {
      updateStockPrices (data.stocks);
    }

    ajax.onerror = onStockListError; 

    ajax.requireLogin = 1;
    ajax.post (STOCK_PRICE_AJAX_URL);
}

Việc này sử dụng đối tượng Ajax dễ dùng của FBJS. Bạn quy định kiểu đáp ứng (Ajax.JSON, Ajax.XML hoặc Ajax.RAW), cung cấp một đối tượng hàm ondone, được gọi cùng với dữ liệu trả về, và một đối tượng hàm onerror, được gọi nếu một lỗi đã xảy ra trong khi thực hiện lời gọi Ajax. Bạn cũng có thể quy định rõ người sử dụng có buộc phải đăng nhập vào ứng dụng hay không để thực hiện lời gọi Ajax (trường hợp của chúng ta là phải đăng nhập vào). Sau đó bạn gọi phương thức post() của nó với URL cần gọi, và nó sẽ gọi ra hoặc hàm ondone hoặc hàm onerror của bạn khi yêu cầu hoàn tất. Vì cá thể này sử dụng responseType, JSON, nó sẽ gọi hàm ondone với dữ liệu JSON được dịch sang thành một hệ phân cấp các đối tượng Javascript thực tế tương ứng với các đối tượng JSON mà bạn đã chỉ rõ trong stockList.jsp.

UpdateStockPrices() tự nó chạy qua mảng các đối tượng chứng khoán, tìm kiếm mỗi hàng của từng mã chứng khoán trong bảng chứng khoán và cập nhật giá cổ phiếu của nó (và tổng tiền bằng đồng đô la nếu người sử dụng sở hữu các cổ phiếu của mã chứng khoán này), bằng cách sử dụng setTextValue() giống như là với kết quả buôn bán. Xem Tải về để biết thêm chi tiết.

Trang danh mục đầu tư đang hoạt động

Vào lúc này bạn có thể xem ứng dụng đang hoạt động. Vào trang vải nền của bạn, đăng nhập vào hệ thống môi giới chứng khoán (qua LoginController), và trang môi giới chứng khoán sẽ xuất hiện. Nó sẽ tạm ngừng một giây, sau đó bắt đầu cập nhật giá cả và tính tổng số lên xuống của danh mục đầu tư trang này như Hình 2.

Hình 2. Trang danh mục đầu tư đang hoạt động
Trang danh mục đầu tư đang hoạt động

Nhập vào một số cổ phiếu của một mã chứng khoán để mua, nhấn Buy/Sell, và quan sát cuộc mua bán trên được phản ánh trên hàng đó như trong Hình 3.

Hình 3. Trang danh mục đầu tư sau một cuộc mua bán
Trang danh mục đầu tư sau một cuộc mua bán

Cuộc mua bán cũng gửi cho bạn một thông báo Facebook, như bạn có thể thấy trong trang Các thông báo của bạn (xem Hình 4).

Hình 4. Các thông báo mua bán
Các thông báo mua bán

Và cuộc mua bán cũng gửi đi một hành động đến Nguồn cấp nhỏ của bạn (xem Hình 5) và có thể là đến các Nguồn cung cấp tin tức của bạn bè của bạn (tùy thuộc vào một thuật toán chưa biết).

Hình 5. Hành động Nguồn cấp tin mini các giao dịch mua bán
Hành động Nguồn cấp tin mini các giao dịch mua bán

Đoạn cuối cùng của ứng dụng này là một liên kết trên mỗi hàng trong bảng chứng khoán cho phép người sử dụng giới thiệu mã chứng khoán cho bạn bè trên Facebook, bằng cách sử dụng một yêu cầu Facebook. Việc này đòi hỏi một trình điều khiển PHP khác, đó là, RecommendStockToFriendsController (xem Mã nguồn), nó đặt ID người sử dụng Facebook của người sử dụng, URL của ứng dụng, và biểu tượng của tin điện báo giá thị trường chứng khoán (stock's ticker) vào mô hình và biểu hiện khung nhìn recommendStockToFriendsView.php, như Liệt kê 28.

Liệt kê 28. recommendStockToFriendsView.php
<? 

$content = <<<FBML 

   <fb:name uid="$model['userId'] firstnameonly="true"</fb:name>
    requests that you check out the hot stock " 
   <a href="$model['appUrl']">$model['ticker']</a>.

FBML;
?>

<fb:request-form 
   action="<?= $model['appUrl'] ?>" 
   method="post" 
   invite="true" 
   type="Hot Stock" 
   content="<?= htmlentities($content) ?>">

   <fb:multi-friend-selector 
       showborder="false" 
       actiontext="Invite your friends to check out <?= $model['ticker'] ?>"/> 

</fb:request-form>

Thẻ <fb:request-form> tạo ra một mẫu biểu yêu cầu Facebook, mà khi được đệ trình lên sẽ gửi một yêu cầu đến cho người sử dụng đã chỉ ra. Thuộc tính action (hành động) chỉ rõ sẽ lấy người sử dụng từ đâu sau khi họ đệ trình yêu cầu hoặc nhấn vào nút Skip (Bỏ qua). Thuộc tính phương thức sẽ chỉ rõ POST/GET như thường lệ, và thuộc tính kiểu sẽ chỉ rõ tên của yêu cầu, sử dụng trên nút được biểu hiện như nút đệ trình (submit button) của mẫu biểu <fb:request-form>. Thuộc tính mời (invite) thay đổi một số lời văn sử dụng trên yêu cầu và nhãn của nút đệ trình. Thuộc tính nội dung chứa nội dung để biểu hiện trong yêu cầu. Do nội dung là một thuộc tính của một thẻ FBML tất cả các thực thể HTML phải được kèm dấu thoát, giống như với htmlentities() ở đây. Nội dung của yêu cầu này chỉ cung cấp một liên kết đến trang vải nền của ứng dụng, nhưng có thể làm bất cứ điều gì mà ứng dụng của bạn có thể làm.

Có các loại thẻ cho phép người sử dụng chọn ra bạn bè để gửi yêu cầu đến họ -- một trong số thẻ bạn dùng ở đây là thẻ <fb:multi-friend-selector>, sẽ xuất hiện ra như là một danh sách cuộn của tất cả bạn bè của người sử dụng với một hộp tìm kiếm gõ ký tự trước (typeahead) tiện dụng, như thấy trong Hình 6.

Hình 6. Mẫu biểu yêu cầu Giới thiệu Cho Bạn bè
Mẫu biểu yêu cầu Giới thiệu Cho Bạn bè

Nhấn vào Skip sẽ đưa bạn trở lại trang danh mục đầu tư (như thuộc tính hành động của <fb:request> đã xác định). Chọn một hay nhiều bạn bè và nhấn vào 'Send Hot Stock Invitation' sẽ hiện ra một màn hình xác nhận yêu cầu (xem Hình 7).

Hình 7. Màn hình xác nhận yêu cầu
Màn hình xác nhận yêu cầu

Nhấn Send sẽ gửi đi yêu cầu, và bạn bè của bạn sẽ trông thấy yêu cầu đó trên trang Các yêu cầu của họ như thấy trong Hình 8.

Hình 8. Yêu cầu mà bạn bè sẽ nhìn thấy
Yêu cầu mà bạn bè sẽ nhìn thấy

Nội dung của yêu cầu này là nội dung được xác định trong phần Heredoc của recommendStockToFriendsView.php.

Đưa vào cuộc sống

Bước cuối cùng là phát hành ứng dụng của bạn vào nơi chưa được khai phá. Vào trang thiết đặt của ứng dụng của bạn, chuyển chế độ Dev sang off để những người không phải là các nhà phát triển có thể thêm vào ứng dụng. Bạn sẽ cũng muốn tạo ra một trang About tĩnh cho Danh mục Sản phẩm (Product Directory) (và làm sạch một số chi tiết trong ứng dụng; ví dụ, hạn chế truy cập vào các tập tin và thư mục khác nhau trong tập tin .htaccess), và sau đó nhấn vào liên kết Submit (xem Hình 9).

Hình 9. Nộp ứng dụng vào Product Directory
Nộp ứng dụng vào Product Directory

Sẽ có một vài trường để điền vào (và ứng dụng của bạn sẽ cần ít nhất 5 người sử dụng trước khi nó có thể được gửi đến Danh mục Sản phẩm), nhưng sau đó ứng dụng của bạn sẽ sẵn sàng để sử dụng công cộng.


Tóm tắt

Bạn đã đề cập đến nhiều nền móng cơ sở trong loạt bài hướng dẫn này, khi xây dựng một ứng dụng Facebook đầy đủ từ nền đất trống bằng cả Java và PHP, nửa Java chạy trong Máy chủ ứng dụng WebSphere của IBM và được phát triển bằng cách sử dụng Rational Application Developer của IBM, nửa PHP chạy dưới Zend Core for IBM; hai nửa này dùng chung một cơ sở dữ liệu IBM DB2. Bạn đã khám phá các điểm tích hợp của Facebook và cách truy cập chúng từ cả PHP và Java bằng cách sử dụng các thư viện khách, FBML và FBJS. Bây giờ bạn có thể phát triển các ứng dụng Facebook của riêng bạn bằng cách sử dụng tất cả các công nghệ này. Hãy chắc chắn theo kịp với blog và wiki của nhà phát triển Facebook vì Facebook thay đổi API và chức năng được hỗ trợ trên đây khá thường xuyên. Hãy tận hưởng các kỹ năng mới của bạn và hãy viết một ứng dụng nổi bật.


Tải về

Mô tảTênKích thước
Part 3 source codefacebook.part3.src.zip82KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Rational, Nguồn mở, Information Management
ArticleID=427418
ArticleTitle=Làm chủ việc phát triển ứng dụng Facebook bằng PHP, IBM Rational Application Developer, IBM WebSphere Application Server và DB2, Phần 3: Hoàn thành ứng dụng trình diễn môi giới chứng khoán Facebook
publish-date=09112009