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 2: Sử dụng đồng thời Java và PHP

Phần 2 của loạt hướng dẫn này bao gồm các chi tiết liên quan đến việc phát triển ứng dụng Facebook mà bạn đã bắt đầu trong Phần 1. Xây dựng một giao diện Facebook cho một công ty môi giới chứng khoán đang hoạt động, cho phép quản lý trực tuyến danh mục đầu tư. Tìm hiểu một cách tiếp cận để phân chia chức năng của một ứng dụng giữa các thành phần PHP và Java, và sử dụng khung công tác Spring để áp dụng một kiến trúc MVC tiêu chuẩn đối với mã Java ™. Loạt bài hướng dẫn này dẫn dẫn dắt bạn đi qua quy trình phát triển một ứng dụng Facebook đầy đủ chức năng bằng cách sử dụng WebSphere® Application Server (Máy chủ ứng dụng WebSpher), Rational® Application Developer (Bộ Phát triển ứng dụng Rational), Zend Core cho IBM, PHP 5 và DB2®.

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

Về loạt bài này

Loạt bài hướng dẫn này dẫn dắt bạn đi qua quy trình phát triển một ứng dụng Facebook đầy đủ chức năng bằng cách sử dụng WebSphere Application Server, Rational Application Developer, Zend Core for IBM, PHP 5 và DB2. Bạn sẽ xây dựng một phần của ứng dụng bằng cách sử dụng mã Java và một phần bằng PHP 5. Làm đại diện cho một công ty môi giới chứng khoán đang hoạt động, bạn sẽ thêm một giao diện Facebook vào hệ thống quản lý trực tuyến danh mục đầu tư của họ.

  • Trong Phần 1 bạn đã có một cái nhìn khái quát về phát triển ứng dụng Facebook, và đã bắt đầu bằng một ứng dụng khung sườn.
  • Trong Phần 2 bạn sẽ thực hiện công việc khởi đầu để tạo ra phía Java của ứng dụng -- một dự án Rational Application Developer và ứng dụng web bằng cách sử dụng khung công tác Spring nổi tiếng.
  • Phần 3 sẽ giải quyết các công việc đặc thù cho việc thực hiện một ứng dụng Facebook đầy đủ các 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ả hai ngôn ngữ Java và PHP.

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

Môi trường Rational Application Developer của IBM, Zend Core cho IBM với các bản cài đặt Apache 2 và cơ sở dữ liệu DB2 Express-C của IBM kèm theo và WebSphere Application Server của IBM. Sau đó bạn đã khảo sát chi tiết một vòng 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. Bạn đã tạo ra và lập cấu hình ứng dụng trên Facebook, đã tạo ra một tệp index.php thử nghiệm đối với URL Callback, và sau đó thiết lập cơ sở dữ liệu DB2, tạo ra một số bảng cơ sở và điền vào các dữ liệu mẫu để bắt đầu.

Trong hướng dẫn này, Phần 2 của loạt bài, bạn sẽ lập ra một dự án Rational Application Developer để tạo điều kiện phát triển Java, tạo cấu hình một nguồn dữ liệu DB2 đã đăng ký kết nối JNDI trong IBM WebSphere Application Server, và sử dụng khung công tác Spring để áp dụng một cấu trúc MVC cho mã Java để áp đặt một cấu trúc truy cập JDBC. Sau đó bạn sẽ viết ra một số lớp PHP đa dụng, cho phép bạn áp dụng cùng cấu trúc MVC ấy với mã PHP và cho phép bạn thêm các thuộc tính vào các cá thể lớp giống như bạn làm trong Spring. Bạn sẽ viết ra một lớp PHP Db2DataSource đa dụng để kết nối với DB2, và sử dụng mod_rewite và mod_proxy để cho PHP và Java cùng tồn tại một cách trong suốt tại cùng một URL. Hướng dẫn này sẽ cấu trúc nên thế giới Java và PHP giống nhau nhất đến mức có thể, vì một trong những rào cản để tích hợp hai thế giới đó là ở chỗ các nhà phát triển PHP và Java thường đến từ các nền tảng khác nhau, và nhìn các thế giới này theo các cách khác nhau. Hai ngôn ngữ này có thể cùng tồn tại trong cùng một ứng dụng (và cùng một nhóm phát triển) rất thành công, và với một mức độ trừu tượng cao và cấu trúc sạch một cách toàn diện.

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

Hướng dẫn này dành cho các nhà phát triển Java và PHP có mức kinh nghiệm khác nhau, những người muốn bắt đầu viết các ứng dụng Facebook trong Java, PHP hoặc tích hợp cả hai như là những bộ phận của một ứng dụng lớn hơn. Nó dành cho các nhà phát triển PHP, những người muốn tìm hiểu công việc xây dựng một ứng dụng J2EE bằng cách sử dụng khuôn mẫu Spring và cách áp dụng một cấu trúc hướng đối tượng vào các ứng dụng PHP của họ, và dành cho những người phát triển Java muốn bắt đầu sử dụng PHP, có thể vì mục đích thêm PHP vào ứng dụng Java doanh nghiệp hiện hành.

Bạn nên đọc Mastering Facebook application development, Part 1 (Làm chủ ứng dụng Facebook, Phần 1) trước khi tiếp tục Phần 2.

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 phần mềm sau. Nếu bạn chưa cài đặt các sản phẩm này, hoặc không có phiên bản mới nhất, bạn có thể tải về các phiên bản dùng thử miễn phí:

  • Tải về một phiên bản dùng thử miễn phí Spring Framework -- Tôi sử dụng phiên bản 2.5.3, bản phát hành mới nhất.
  • Tải về một phiên bản dùng thử miễn phí Rational Application Developer. Bạn sẽ sử dụng Rational Application Developer như là một bản IDE đầy đủ tính năng dựa trên Eclipse để phát triển ứng dụng Web Java của bạn.
  • Tải về một phiên bản dùng thử miễn phí IBM WebSphere Application Server V6.1.
  • Tải về Zend Core For IBM (gồm có IBM DB2® Express-C)
  • Zend Studio là một công cụ tuyệt vời để viết mã PHP, mặc dù có thể dùng trình soạn thảo văn bản nào cũng được.

Bổ sung Java cùng với PHP

Trong Phần 1 bạn đã nhận được bên PHP của ứng dụng đang chạy. Bây giờ bạn sẽ thực hiện việc khởi tạo ban đầu để tạo ra bên Java của ứng dụng -- một dự án Rational Application Developer và ứng dụng web bằng cách sử dụng khung công tác Spring nổi tiếng. Sau đó bạn sẽ viết ra các lớp PHP cho phép bạn áp đặt cùng một mẫu MVC lên mã PHP như trong Java, và tạo một proxy đảo ngược từ Apache đến IBM WebSphere bằng cách sử dụng mod_rewrite và mod_proxy, do đó bạn có thể sử dụng cùng một URL Facebook Callback đối với các máy chủ PHP và Java. Sau đó bạn sẽ sử dụng tập tin .htaccess để gửi các yêu cầu đến PHP hoặc Java tùy thuộc vào URI yêu cầu. Một cấu trúc chung giữa các máy chủ Java và PHP của bạn sẽ làm cho sự tích hợp của chúng dễ dàng hơn và cho phép bạn (hoặc nhóm của bạn) sử dụng bất cứ công nghệ nào thích hợp hơn cho mỗi mảnh của ứng dụng Facebook, và việc sử dụng proxy và .htaccess sẽ tách rời mặt trước với việc sử dụng hai công nghệ của bạn ở mặt sau.

Thiết lập dự án Rational Application Developer

Làm theo các bước sau để thiết lập một dự án trong Rational Application Developer:

  1. Mở Rational Application Developer từ trình đơn Start: Start > All Programs > IBM Software Development Platform > IBM Rational Application Developer > IBM Rational Application Developer.
  2. Tạo một dự án Java mới (File > New > Project), chọn Dynamic Web Project làm kiểu dự án và WebSphere Application Server v6.1 làm môi trường chạy đích.
    Phải chắc chắn đã đánh dấu chọn các khía cạnh (facet) của dự án Dynamic Web Module, Java, JSTL, và khía cạnh WebSphere web.
  3. Đặt gốc ngữ cảnh ở facebook-stock-demo, thư mục nội dung vào mặc định của WebContent, và thư mục nguồn Java vào src. Rational Application Developer sau đó sẽ tạo ra cấu trúc dự án ứng dụng web tiêu chuẩn cho bạn và bạn chỉ cần điền nó vào.

Hợp nhất khung công tác Spring

Thêm khung công tác Spring đa năng vào ứng dụng.

  1. Tải về phiên bản khung công tác Spring với tất cả các phần phụ thuộc (xem Prerequisites để có một đường liên kết).
  2. Giải nén nó vào vị trí có ích nào đó, thí dụ c:\ (việc giải nén các tập tin có thể mất một thời gian), và từ thư mục dist sao chép tệp spring.jar và tất cả các tệp JAR dưới thư mục dist/modules vào thư mục WEB-INF/lib của dự án. Bạn có thể tìm thấy thư mục WEB-INF/lib của dự án của bạn bằng cách chuyển đến Project > Properties và xem ô Info. Thí dụ, tôi đã sao chép chúng vào C:\Documents and Settings\jmiles\IBM\rationalsdp7.0\workspace\facebook-stock-demo\WebContent\WEB-INF\lib.
  3. Bổ sung thêm commons-logging.jar vào đường dẫn lớp (classpath) của dự án của bạn, từ thư mục lib/jakarta-commons của khung công tác Spring, thông qua Project > Properties > Java Build Path > Add External JARs (xem Hình 1). Không được sao chép JAR này vào thư mục lib của bạn; nó sẽ gây ra một lỗi khi triển khai WebSphere.
    Hình 1. Thêm các JAR bên ngoài vào dự án Rational Application Developer của IBM
    Thêm các JAR bên ngoài vào dự án Rational Application Developer của IBM
  4. Làm mới vùng làm việc (nhấn chuột phải vào tên dự án và chọn Refresh), và khung nhìn Project Explorer sẽ cập nhật tất cả các JAR được thêm vào.

Lập cấu hình Spring

Giờ thì bạn đã cài đặt Spring, và bạn cần phải lập cấu hình ứng dụng Web để sử dụng nó. Nhấn chuột phải vào web.xml trong Project Explorer (xem Hình 2) và chọn Open with > Text Editor.

Hình 2. Mở web.xml bằng một trình soạn thảo văn bản trong Rational Application Developer
Mở web.xml bằng một trình soạn thảo văn bản trong Rational Application Developer

Thay nội dung bằng nội dung của Liệt kê 1.

Liệt kê 1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    <display-name>facebook-stock-demo</display-name>
    
    <servlet>
      <servlet-name>spring</servlet-name>
          <servlet-class>
               org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

      <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/action/*</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    
</web-app>

Việc này sẽ định tuyến tất cả các yêu cầu mà các URI của chúng bắt đầu bằng facebook-stock-demo/action (ở đây facebook-stock-demo là bối cảnh mà bạn sẽ chỉ định trong WebSphere của IBM) thông qua DispatcherServlet của Spring, điểm nhập vào khung công tác MVC Spring.

Tiếp theo bạn cần có một tập tin Spring-servlet.xml để lập cấu hình cho các bean Spring. Spring theo mặc định sẽ nối thêm đuôi “-servlet.xml” vào phần tử <servlet-name> trong web.xml làm tên của tập tin cấu hình, do đó trong khung nhìn Project Explorer, hãy tạo một tập tin văn bản mới trong thư mục WEB-INF có tên là spring-servlet.xml. Bạn có thể phải đóng tập tin và nhấn chuột phải vào nó để mở ra bằng một trình soạn thảo văn bản nếu Rational Application Developer mở nó ra theo mặc định trong một trình soạn thảo XML. Dán nội dung của Liệt kê 2 vào spring-servlet.xml.

Liệt kê 2. Spring-servlet.xml ban đầu
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  
    <bean id="viewResolver" 
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass">
            <value>org.springframework.web.servlet.view.JstlView</value>
        </property>    
        <property name="prefix">
            <value>/WEB-INF/jsp/</value>
        </property>
    </bean>  
  
     <bean id="urlMapping" class="org.springframework.web.servlet.
handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
            <entry key="/stockList">
                     <ref bean="stockListController"/>
            </entry>
            </map>     
        </property> 
    </bean>    

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

Bean đầu tiên quy định cách thức mà các tên khung nhìn được ánh xạ vào URL. Bất cứ khi nào một trình điều khiển trả lại một tên khung nhìn, trình phân giải khung nhìn (view resolver) sẽ nối thêm phần đầu /WEB-INF/jsp/ vào nó, tạo ra chẳng hạn tệp /WEB-INF/jsp/stocks.jsp để đáp ứng lại tên khung nhìn stocks.jsp. Bean thứ hai ánh xạ các URL vào các trình điều khiển spring, trong trường hợp này nó ánh xạ một url đơn lẻ, /stockList, vào bean điều khiển bằng id stockListController, mà được định nghĩa như là bean thứ ba trong tập tin này. Định nghĩa bean stockListController nội xạ một thuộc tính successView với đối tượng StockListController để giữ các tên của các khung nhìn nằm bên ngoài mã Java.

Thêm vào một lớp trình điều khiển Spring và khung nhìn tương ứng

Để thêm vào một lớp trình điều khiển Spring và khung nhìn tương ứng, hãy làm như sau:

  1. Tạo một gói dưới thư mục src bằng cách nhấn chuột phải vào Java Resources: src trong khung nhìn Project Explorer và chọn New > Package. Tôi gọi gói của tôi là com.jm.fbstockdemo.
  2. Nhấn chuột phải vào gói mới này và tạo một lớp StockPriceController có thực hiện org.springframework.web.servlet.mvc.Controller. Bạn có thể chỉ cần gõ Controller sau khi nhấn vào Add và Rational Application Developer sẽ thu hẹp danh sách các tùy chọn tương ứng khi bạn gõ nhập.
  3. Điền vào nó một triển khai thực hiện cơ bản nhất có thể, đơn giản chỉ thực hiện trả lại một tên khung nhìn để biểu hiện (xem Liệt kê 3).
    Liệt kê 3. Một lớp StockListController ban đầu (Java)
    public class StockListController implements Controller {
    
        public ModelAndView handleRequest(HttpServletRequest request,
                HttpServletResponse response) throws Exception {    
            
            return new ModelAndView (getSuccessView());        
        }
    
    }
  4. Tiếp theo nhấn chuột phải vào WEB-INF và tạo một thư mục jsp.
  5. Trong thư mục jsp tạo tệp stockList.jsp ban đầu, có chứa xml để kiểm thử như Liệt kê/như trong Liệt kê 4.
    Liệt kê 4. Một stockList.jsp ban đầu
    <%@ page contentType="text/xml" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <stockList>
        <stock>
            <id>1</id>
            <ticker>JAKE</ticker>
                <price>3000</ticker>
        </stock>
    </stockList>

Triển khai vào WebSphere Application Server

Với ứng dụng Spring Java khung sườn đã viết, giờ đây bạn có thể triển khai nó vào WebSphere Application Server (Máy chủ ứng dụng WebSphere).

  1. Tạo tập tin WAR bằng cách nhấn chuột phải vào dự án trong Rational Application Developer, và chọn Export > WAR file.
  2. Trong cửa sổ Save As, di chuyển đến thư mục của dự án (như bạn đã làm trên đây) và tạo một thư mục mới có tên dist bên cạnh các thư mục src và WebContent. Thí dụ, tôi đã ghi lưu tệp WAR là c:\Documents và Settings\jmiles\IBM\rationalsdp7.0\workspace\facebook-stock-demo\dist\facebook-stock-demo.war.
  3. Nhấn Finish. Rational Application Developer sẽ bao bọc ứng dụng một cách thành thục thành facebook-stock-demo.war.
  4. Để triển khai tập tin WAR, khởi động một cá thể máy chủ ứng dụng WebSphere qua Start>All Programs>IBM WebSphere > Application Server v6.1 > Profiles > [your profile name] > Start the server (xem Hình 3). Đợi nó khởi động (một cửa sổ nhắc lệnh sẽ xuất hiện, hiển thị thông tin khởi động, sau đó biến mất), và sau đó di chuyển đến bàn điều khiển (Administrative Console) qua cùng đường dẫn của trình đơn Start. Thao tác này sẽ mở ra bàn điều khiển của cá thể WebSphere của bạn trong trình duyệt Web.
    Hình 3. Khởi động Máy chủ Ứng dụng WebSphere từ trình đơn khởi động Windows
    Khởi động Máy chủ Ứng dụng WebSphere từ trình đơn khởi động Windows
  5. Đăng nhập vào bàn điều khiển admin, mở phiếu Applications và chọn Install New Application.
  6. Chọn Local file system, di chuyển đến tệp tin WAR của bạn và chọn nó.
  7. Chỉ rõ /facebook-stock-demo làm bối cảnh gốc, và nhấn Next. Giữ nguyên tất cả các giá trị mặc định trên màn hình các tùy chọn cài đặt và nhấn Next.
  8. Trên màn hình “Map modules to servers” chọn ứng dụng web của bạn để thêm nó vào server1.
  9. Nhấn vào Finish trên màn hình summary, và WebSphere sẽ cài đặt ứng dụng web. Hãy chắc chắn nhấn vào Save dưới đáy màn hình đầu ra khi cài đặt hoàn tất.
  10. Nhấn vào Enterprise Applications ở bên trái, và bạn sẽ thấy ứng dụng của bạn nằm trong danh mục các ứng dụng đã cài đặt. Chọn cái đó và nhấn Start để khởi động.
  11. Để xác nhận cổng mà ứng dụng của bạn đang chạy trên đó, hãy mở phần Servers ở bên trái, nhấn Application servers, chọn server1, và trong phần Communications của cấu hình server1 nhấn Ports ((xem Hình 4). WC_defaulthost chỉ rõ cổng mà qua đó bạn có thể truy cập ứng dụng web của bạn. Trong cài đặt của tôi cổng này là 9083; thay thế giá trị ấy vào chỗ của WC_defaulthost trong tất cả các URL được chỉ ra sau đây.
    Hình 4. Tìm cổng HTTP của máy chủ của bạn trong Máy chủ ứng dụng WebSphere
    Tìm cổng HTTP của máy chủ của bạn trong Máy chủ ứng dụng WebSphere
  12. Cuối cùng, để xác nhận rằng tất cả hoạt động tốt, hãy mở một cửa sổ trình duyệt nữa, vào http://localhost:9083/facebook-stock-demo/action/stockList, và bạn sẽ thấy xml của stockList.jsp.

Ứng dụng web MVC Spring bây giờ đã được cài đặt và làm việc dưới IBM WebSphere cung cấp một cấu trúc MVC tiêu chuẩn để phát triển mã ứng dụng Facebook của bạn trong đó.


Cơ cấu một ứng dụng PHP tương tự như một ứng dụng Java Spring

Cấu trúc của một ứng dụng Web Java và DispatcherServlet của Spring cung cấp một mô hình tuyệt vời cho nửa PHP của ứng dụng. Không ném qua cửa sổ những kết quả trừu tượng hóa hướng đối tượng đẹp đẽ như vậy, bạn sẽ nhanh chóng trực tiếp làm ra một số các lớp có thể giúp cho việc mô phỏng chức năng thêm thuộc tính của Spring và chức năng điều phối của MVC. Bạn sẽ viết ra một lớp Properties đọc các tệp tin thuộc tính, một lớp Injectable cho phép bạn thêm các thuộc tính từ các tệp tin đó vào các cá thể lớp, và một lớp ActionDispatcher sẽ điều phối một biến yêu cầu đến đúng lớp điều khiển để xử lý yêu cầu.

Để viết mã PHP, bất kỳ trình soạn thảo văn bản nào cũng làm được, nhưng Zend Studio là tuyệt vời (xem Tài nguyên).

Đọc các giá trị từ các tệp tin thuộc tính

Để giữ cho những phần không thay đổi của ứng dụng nằm bên ngoài mã, bạn sẽ sử dụng một tập hợp các tệp tin thuộc tính và một lớp Properties đọc được chúng, lắp ráp một mảng kết hợp các thuộc tính mà phần còn lại của ứng dụng có thể sử dụng được, như trong liệt kê 5 (đặt Properties.php trong một thư mục con lib dưới thư mục fb_stock_demo).

Liệt kê 5. Properties.php
<?php

class Properties {

  private $props;

  public function __construct ($propertiesFilePaths) {

    $this->props = array();

    foreach ($propertiesFilePaths as $path) {
      $this->loadProperties($path);
    }
  }

  private function loadProperties($propertiesFilePath) {

    $lines = file($propertiesFilePath);    

    foreach ($lines as $line) {

      $trimmed = trim($line);
      if (strlen($trimmed) > 0 && strchr($trimmed, 0, 1) != "#") {
        $split = split("=", trim($line));      
        $key = $split[0];
        $value = $split[1];    
        $this->props[$key] = $value;
      }
    }
  }

  public function get($key) {

    if (! isset($this->props[$key])) {
      throw new Exception ("Properties: unknown key $key");
    }

    return $this->props[$key];
  }
}

Bạn cung cấp cho hàm tạo (constructor) một mảng các đường dẫn đến tệp tin thuộc tính, nó đọc lần lượt từng cái một, lắp ráp mảng kết hợp trong loadProperties(). Bằng cách nhận cả một mảng các đường dẫn tệp tin thuộc tính chứ không phải chỉ là một đường dẫn, bạn tách rời các thuộc tính phụ thuộc vào môi trường như các giá trị kết nối cơ sở dữ liệu. Điều này làm cho việc sao chép mã dễ dàng hơn từ một môi trường này đến môi trường khác (ví dụ từ phát triển đến sản xuất) không phải viết đè lên các giá trị đó; bạn chỉ cần không sao chép các tập tin đặc trưng cho môi trường hoặc thiết lập cấp quyền truy cập chúng sao cho bạn không thể viết đè lên chúng được trong khi sao chép. Thí dụ, ứng dụng này sẽ sử dụng hai tập tin thuộc tính, app.properties và db.properties, ở đây app.properties chứa các hằng số như khoá mã và bí mật API Facebook (Facebook API Key and Secret), còn db.properties chứa thông tin đăng nhập cơ sở dữ liệu.

Sử dụng các phương thức thần kỳ PHP 5 để cung cấp phép thêm vào thuộc tính kiểu như Spring

Bây giờ ta xem xét một số phép thần kỳ PHP 5. Để cung cấp thêm một chút gì hơn kiểu như Spring, bạn có thể thêm các thuộc tính vào một đối tượng từ một tệp tin cấu hình mà sẽ xem xét và đối xử chính xác như các biến cá thể trong đối tượng đích. Tất cả các lớp cần có các thuộc tính được thêm vào như vậy cần phải là lớp con của lớp Injectable (xem Liệt kê 6).

Liệt kê 6. Lớp Injectable (PHP)
class Injectable {

  protected $properties;
  private $prefix;

  public function Injectable($properties=null, $propPrefix=null) {
    $this->prefix = $propPrefix == null ? get_class($this) . '/' : $propPrefix;
    $this->setProperties ($properties);
  }
  
  public function setProperties($properties) {
    $this->properties = $properties;
  }  

  public function __get($property) {
    return $this->getProperty($property);
  }

  public function getProperty($property) {
    return $this->properties->get($this->prefix . $property);
  }
}

Then chốt của lớp Injectable là phương thức __get() đó là một phương thức thần kỳ của PHP 5. Các phương thức thần kỳ là phương thức đặc biệt có sẵn trên tất cả các đối tượng PHP 5, mà PHP sử dụng để cung cấp cho các đối tượng các hành vi lõi đặc biệt; bất kỳ biến PHP và bất kỳ phương thức nào có tên bắt đầu bằng __ (hai gạch dưới) sẽ được coi là phương thức thần kỳ. Bất cứ khi nào bạn truy cập một biến cá thể của một đối tượng, nếu biến đó không được tìm thấy trên đối tượng, PHP sẽ gọi phương thức __get() của đối tượng để tìm ra giá trị của nó, chỉ cần cung cấp tên của biến được yêu cầu dưới dạng chuỗi ký tự. Phương thức __get() của lớp Injectable tìm kiếm thuộc tính đó trên đối tượng Properties, đặt thêm vào trước tên thuộc tính một tiền tố duy nhất của nó, mà mặc định là tên lớp của đối tượng Injectable theo sau bởi một dấu gạch chéo (Ghi chú: sử dụng dấu chấm (dot) sẽ gây ra các vấn đề cho trình phân tích PHP). Điều này làm cho việc thêm các thuộc tính từ bên ngoài vào trong một cái gì đó, ví dụ như một lớp kết nối cơ sở dữ liệu trở thành một việc tầm thường, và bạn sẽ làm ngay sau đây. Các thuộc tính được thêm vào có thể được tham chiếu đến đối tượng đích như các biến cá thể bình thường, cứ như là chúng đã được đặt trong mã rồi.

Do đó bây giờ bạn có thể thêm bất kỳ thuộc tính nào mà bạn cần vào một đối tượng bằng cách chỉ rõ giá trị thuộc tính trong một tập tin thuộc tính bên ngoài, tương tự như hành vi Spring-servlet.xml của Spring. Điều này rõ ràng là một nhóm phụ rất nhỏ các chức năng của Spring, nhưng lại khá hữu ích trong việc giữ cho mã Java và mã PHP có cấu trúc tương tự và sạch sẽ.

Viết ActionDispatcher

Để duy trì một sự đối xứng với khung MVC của Spring, bạn sẽ sử dụng các lớp điều khiển như bạn đã làm trong Spring, mỗi lớp dành cho một yêu cầu, và sử dụng cùng một phép trừu tượng hóa ánh xạ các khoá URI với các tên lớp điều khiển, sao cho URI có thể chỉ cần chỉ định rõ một khoá cho yêu cầu đó, và ActionDispatcher sẽ tạo ra và gọi đúng đối tượng điều khiển để đáp ứng lại yêu cầu, như trong Liệt kê 7 (đặt ActionDispatcher.php vào trong thư mục con lib).

Liệt kê 7. Lớp ActionDispatcher (PHP)
class ActionDispatcher extends Injectable {  

  public function __construct($properties) {
    parent::__construct($properties);
  }

  public function dispatchKey($controllerKey) {
    try {

      $controllerName = $this->getProperty($controllerKey);

      if (! $controllerName) {
    throw new Exception ("ActionDispatcher.createController 
-- unknown controller key: $controllerKey");
      }

      // load the controller class
      require_once("$controllerName.php");

      // create an instance of the action's controller 
      $controller = eval("return new $controllerName();");      
      
      // give it the application-wide properties file
      $controller->setProperties($this->properties);

      // let the response call back into this dispatcher to respond
      $response = $controller->execute();      
      $response->respond($this);

    } catch (Exception $e) {
      echo $e; 
      exit;
    }
  }
}

ActionDispatcher làm lớp con của lớp Injectable như vậy bạn có thể tiêm vào các thuộc tính (các khóa yêu cầu, sẽ trình bày sau). dispatchKey() tìm kiếm khoá đã cho trong đối tượng Properties (tường minh, không qua phương thức thần kỳ __get() vì vào lúc này bạn đã có tên của thuộc tính dưới dạng là một chuỗi ký tự rồi), lấy được tên của lớp điều khiển để thi hành. Nó sử dụng eval() để tạo ra một cá thể của điều khiển đó (bạn cũng có thể sử dụng các lớp phản chiếu Zend 2 để làm việc này), đặt đối tượng Properties lên điều khiển đó, và gọi ra phương thức execute() của trình điều khiển đó, nhận được một đối tượng đáp ứng. Sau đó nó gọi phương thức respond() của đối tượng đáp ứng, chuyển tham số là chính nó trong trường hợp đối tượng đáp ứng cần đến. Dãy lời gọi phương thức có chút tiến rồi lại lui này cho phép bạn thêm vào các kiểu đáp ứng khi cần thiết mà không bao giờ phải thay đổi execute() của trình điều khiển đó, nhận được một đối tượng đáp ứng. Sau đó nó gọi phương thức respond() của đối tượng đáp ứng, chuyển tham số là chính nó trong trường hợp đối tượng đáp ứng cần đến. Dãy lời gọi phương thức có chút tiến rồi lại lui này cho phép bạn thêm vào các kiểu đáp ứng khi cần thiết mà không bao giờ phải thay đổi ActionDispatcher -- đấy là tinh thần lập trình hướng đối tượng.

Các đối tượng đáp ứng xác định thực chất phải làm gì để biểu hiện đáp lại: nó tạo ra một lớp cho mỗi kiểu đáp ứng để biểu hiện trong ActionDispatcher.php, như trong Liệt kê 8.

Liệt kê 8. Các lớp đáp ứng của ActionDispatcher
class ModelAndView {

  public function __construct($viewURI, $model=null) {
    $this->viewURI = $viewURI;
    $this->model = $model;
  }

  public function respond($dispatcher) {
    $model = $this->model;
    include($this->viewURI);    
  }
}

class ControllerForward {

  public function __construct($controllerKey) {
    $this->controllerKey = $controllerKey;
  }

  public function respond($dispatcher) {
    $dispatcher->dispatchKey($this->controllerKey);
  }
}

Lớp ModelAndView cung cấp cùng một hành vi như ModelAndView của Spring. Phương thức execute của điều khiển của bạn trả lại một đối tượng ModelAndView chứa đường dẫn tập tin của khung nhìn (view) để biểu hiện và một đối tượng mô hình nếu có, và khi ActionDispatcher gọi phương thức respond() của nó, respond() chỉ làm một việc tầm thường là gửi đi tệp tin khung nhìn tới cho trình xử lý PHP, bằng cách sử dụng phương thức include(). Khung nhìn được gửi có quyền truy cập vào các biến trong phạm vi của mã gọi ra, do đó bạn tạo ra một biến có tên $model chứa đối tượng mô hình được cung cấp, đây là cái mà tất cả các khung nhìn mong đợi có thể tìm thấy (thậm chí nếu nó là rỗng).

Lớp ControllerForward là để dành cho một trình điều khiển làm một điều gì đó nhưng sau đó lại muốn chuyển điều khiển đến một trình điều khiển ActionDispatcher khác. Phương thức respond() của nó chỉ gọi lại ActionDispatcher với khoá của trình điều khiển mới, khởi động một lần nữa toàn bộ quá trình đối với trình điều khiển đó (nhưng không phải đọc lại tệp tin các thuộc tính).

Do tất cả các trình điều khiển phải cung cấp một phương thức execute() và để làm cho dễ dàng thêm các thuộc tính vào chúng, tất cả chúng sẽ đều là lớp con của lớp AbstractController (xem Liệt kê 9).

Liệt kê 9. AbstractController (PHP)
abstract class AbstractController extends Injectable {
  public abstract function execute();
}

Bây giờ bạn có một khung công tác MVC và thêm thuộc tính đơn giản, cho phép bạn cấu trúc mã của bạn tương tự như mã Java Spring của bạn, loại bỏ việc cần phải dẫn hướng di chuyển trong hai cấu trúc mã hoàn toàn khác nhau khi bạn di chuyển qua lại giữa hai ngôn ngữ.

Sử dụng index.php để khởi động việc điều phối yêu cầu

Khi ActionDispatcher sẵn sàng xử lý các yêu cầu, nó cần phải được gọi ra. Hãy tạo một tệp index.php tối thiểu, hành động như là điểm vào của hệ thống điều phối (xem Liệt kê 10).

Liệt kê 10. index.php
<?php

ini_set('include_path', '.;.\client;.\lib;.\app');

require_once('ActionDispatcher.php');
require_once('Properties.php');

$dispatcher = 
  new ActionDispatcher (new Properties (array('conf\app.properties',
                                    'conf\db.properties')));

$dispatcher->dispatchKey($_REQUEST['controller']);

?>

Lời gọi ini_set thiết lập đường dẫn để bao gồm thêm (include) (chú ý việc sử dụng ';' đối với một đường dẫn bao gồm thêm trong Windows; nó phải là một ':' trên các hệ thống Linux), sao cho các tệp tin PHP khác không cần phải biết chúng được yêu cầu lẫn nhau ở đâu. Kịch bản lệnh sau đó tạo ra đối tượng Properties chuyển giao vào nó toàn bộ các đường dẫn tệp tin thuộc tính được sử dụng trong ứng dụng, và tạo ra một đối tượng ActionDispatcher với nó. Sau đó nó gọi ra phương thức dispatchKey() của ActionDispatcher, chuyển giao tham số là giá trị của một biến yêu cầu trình điều khiển (controller), chứa khoá của điều khiển để tạo và gọi ra.

index.php đóng một vai trò tương tự như web.xml trong ứng dụng Web Java, chuyển toàn bộ kiểm soát đến một trình điều phối yêu cầu đơn lẻ cấu hình được; DispatcherServlet của Spring về phía Java, ActionDispatcher trong PHP.

Tạo ra một proxy đảo ngược từ Apache đến máy chủ ứng dụng

Để ngăn cách thế giới bên ngoài khỏi việc sử dụng hai máy chủ, hãy sửa đổi httpd.conf và sử dụng một tệp tin .htaccess cho proxy từ Apache đến máy chủ ứng dụng WebSphere đối với các yêu cầu mà bạn đã thực hiện trong java. Trước tiên, trong httpd.conf (C:\Program Files\Zend\Apache2\conf\httpd.conf), thực hiện hai thay đổi:

  1. Đảm bảo rằng các dòng trong Liệt kê 11 đã được bỏ dấu chú thích (nghĩa là, phải chắc chắn rằng chúng không bắt đầu bằng một #).
    Liệt kê 11.Kích hoạt mod_rewrite và mod_proxy trong httpd.conf
    LoadModule rewrite_module modules/mod_rewrite.so 
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
  2. Thêm nội dung của Liệt kê 12 vào bất cứ nơi nào trong httpd.conf (nhưng không phải bên trong một thẻ khác).
    Liệt kê 12. Thêm thư mục và uỷ nhiệm (proxying) cho ứng dụng vào httpd.conf
    <Directory "C:/Program Files/Zend/Apache2/htdocs/fb_stock_demo">
        Options FollowSymLinks
        AllowOverride All    
    </Directory>
    
    <Proxy *>
        Order deny,allow  
        Allow from all  
    </Proxy>
    
    ProxyPass /fb_stock_demo/java http://localhost:9083/facebook-stock-demo/action
    ProxyPassReverse /fb_stock_demo/java http://localhost:9083/facebook-stock-demo/action

Việc này tạo ra một định nghĩa cho thư mục fb_stock_demo cho phép bạn sử dụng .htaccess để kiểm soát nó bằng cách sử dụng lệnh AllowOverride All và tạo ra một proxy đảo ngược bằng cách sử dụng mod_proxy, sao cho bất kỳ yêu cầu nào bắt đầu bằng /fb_stock_demo/java sẽ được chuyển hướng đến DispatcherServlet của Spring (ánh xạ đến URI hành động trong web.xml) chạy trong máy chủ ứng dụng WebSphere.

Để làm cho các thay đổi này có hiệu lực, khởi động lại Apache bằng cách mở một dấu nhắc lệnh, vào thư mục bin của Apache2 (C:\Program Files\Zend\Apache2\bin), và ra các lệnh httpd.exe -k stophttpd.exe -k start. Không sử dụng lệnh khởi động lại; trên Windows nó sẽ chết một cách thầm lặng nếu nó không tắt được Apache. Nếu Zend Core đã cài đặt nó như một dịch vụ Windows, bạn có thể phải ngừng nó lại thông qua trình quản lý dịch vụ Windows để có thể ngừng và khởi động nó từ dấu nhắc lệnh, hoặc tắt qua trình quản lý Task Manager.

Sử dụng .htaccess để điều phối các yêu cầu tới PHP hoặc tới Java

Do bạn đã có một cơ chế trung tâm để định tuyến các yêu cầu đến ứng dụng Java, bạn cần một cách để ánh xạ các yêu cầu cụ thể đến đúng các trình điều khiển PHP hoặc Java. Khi apache khởi động lại, tạo ra một tập tin .htaccess trong c:\Program Files\Zend\Apache2\htdocs\fb _stock_demo có chứa nội dung của Liệt kê 13.

Liệt kê 13. .htaccess
RewriteEngine on

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

RewriteRule ^phpDbTest$ php/dbTest [next]

RewriteRule ^stockList$ java/stockList [next]

Dòng đầu tiên bật cho phép việc viết lại URL cho thư mục này. Cặp RewriteCond/RewriteRule tạo ra một giao thức để gọi ra index.php; tất cả các yêu cầu dưới thư mục fb_stock_demo bắt đầu bằng php/được chuyển đến index.php, thiết lập một biến yêu cầu trình điều khiển thành tất cả các ký tự tìm thấy sau php/, và nối thêm bất kỳ biến yêu cầu nào khác sau đó. Thí dụ, http://localhost/fb_stock_demo/php/myController?var=3 sẽ được viết lại thành http://localhost/fb_stock_demo/index.php?controller=myController&var=3.

Sau đó bạn có thể tạo ra RewriteRules riêng để định tuyến các yêu cầu cụ thể tới các trình điều khiển cụ thể chạy trong Zend Core hoặc IBM WebSphere. RewriteRule thứ hai định tuyến URL “phpDbTest”, ví dụ, http://localhost/fb_stock_demo/phpDbTest đến http://localhost/fb_stock_demo/php/phpDbTest, rồi lại được viết lại một lần nữa bởi quy tắc đầu tiên trở thành http://localhost/fb_stock_demo/index.php?controller=dbTest. RewriteRule thứ ba viết lại URI “stockList”, ví dụ thế, http://localhost/fb_stock_demo/stockList, thành http://localhost/fb_stock_demo/java/stockList, sau đó được định nghĩa proxy đảo ngược trong httpd.conf viết lại thành http://localhost:9083/facebook-stock-demo/action/stockList, rồi trình điều phối Spring định tuyến đến StockListController. Xem tài liệu về mod_rewrite để biết thêm thông tin về mô đun Apache rất hữu ích này trong Tài nguyên.

Để kiểm thử proxy đảo ngược và trình đơn điều phối PHP/Java mà bạn đã tạo ra trong .htaccess, trong trình duyệt của bạn hãy vào http://localhost/fb_stock_demo/stockList, và một lần nữa bạn sẽ thấy danh mục chứng khoán dưới dạng XML, được chuyển từ trình điều khiển Java. Giờ thì bạn đã có một cơ chế gọn gàng để gọi ra ứng dụng từ thế giới bên ngoài (tức Facebook) trong khi tách rời thế giới bên ngoài khỏi việc sử dụng hai công nghệ máy chủ của bạn.

Hình 5 minh hoạ chuỗi điều phối của một yêu cầu từ trình duyệt của người sử dụng đến một trình điều khiển PHP hay Java.

Hình 5. Đường đi của một yêu cầu
Đường đi của một yêu cầu

Kết nối với cơ sở dữ liệu trong Java

Do bạn đã có một mẫu MVC giống nhau được lập ra trong cả bên Java lẫn bên PHP của các ứng dụng, bạn sẽ kết nối vào cơ sở dữ liệu phía Java. Bạn sẽ sử dụng nó để xử lý các khía cạnh an toàn hơn của ứng dụng Facebook của bạn – nguồn cung cấp giá cổ phiếu và các việc kinh doanh cổ phiếu thật.

Thiết lập kết nối cơ sở dữ liệu Java

Để thiết lập kết nối cơ sở dữ liệu Java, hãy tạo ra một nguồn dữ liệu bằng pool kết nối DB2 trong IBM WebSphere với vai trò một nguồn dữ liệu JNDI, và sau đó tham chiếu nguồn dữ liệu từ trong ứng dụng Spring. Sau đó, tạo ra một trình điều khiển Spring và khung nhìn tương ứng, sử dụng nguồn dữ liệu này để biểu hiện cơ sở dữ liệu về chứng khoán dưới dạng XML. Hình 6 đưa ra cái nhìn khái quát về tất cả các mảnh dính đến nguồn dữ liệu Java.

Hình 6. Các thành phần của một nguồn dữ liệu DB2 JNDI được sử dụng trong một ứng dụng Spring chạy trong máy chủ ứng dụng WebSphere của IBM
Các thành phần của một nguồn dữ liệu DB2 JNDI được sử dụng trong một ứng dụng Spring chạy trong máy chủ ứng dụng WebSphere của IBM

Tạo một nguồn dữ liệu với pool kết nối trong Máy chủ ứng dụng WebSphere

Trước khi bạn tạo ra bản thân nguồn dữ liệu, bạn cần phải tạo một biệt danh xác thực để đăng nhập cơ sở dữ liệu, vì WebSphere Application Server quản lý tập trung toàn bộ dữ liệu xác thực:

  1. Mở rộng phần Security phía bên trái.
  2. Nhấn vào Secure administration, applications, and infrastructure.
  3. Dưới phần Authentication, mở rộng Java Authentication and Authorization Service.
  4. Nhấn J2C Authentication data.
  5. Thêm một xác thực mới với biệt danh StocksDB2Login. Do DB2 sử dụng hệ điều hành để xác thực người dùng, gõ nhập tên người dùng và mật khẩu đăng nhập vào hệ điều hành của bạn.
  6. Nhấn OK và lưu các thay đổi của bạn vào cấu hình chính.
  7. Để tạo (Data Source) nguồn dữ liệu, trong bàn điều khiển Administrative Console dưới Resources chọn JDBC > Data sources.
  8. Chọn máy chủ của bạn (server1) trong trình đơn thả xuống Scope và nhấn New.
  9. Chỉ rõ jdbc/StocksDataSource là tên nguồn dữ liệu và cũng là tên JNDI.
  10. Chọn biệt danh xác thực DB2 của bạn (StocksDB2Login) trong trình đơn thả xuống, và nhấn Next.
  11. Tạo một bộ cung cấp JDBC mới với các giá trị sau:
    • Kiểu cơ sở dữ liệu: DB2.
    • Kiểu bộ cung cấp: DB2 Universal JDBC Driver Provider (Bộ cung cấp điều khiển JDBC tổng hợp DB2).
    • Kiểu thực hiện: Connection pool data source (Nguồn dữ liệu với pool kết nối).
    • Tên: DB2 Universal JDBC Driver Provider.
  12. Trên màn hình thông tin đường dẫn của lớp, gõ nhập đường dẫn chứa db2jcc.jar, C:\Program Files\IBM\SQLLIB\java, và nhấn Next.
  13. Trên màn hình thuộc tính riêng cho cơ sở dữ liệu, gõ nhập các giá trị sau:
    • Tên cơ sở dữ liệu: stocks (là tên của cơ sở dữ liệu DB2 mà bạn đã tạo ra trong Phần 1 của hướng dẫn này).
    • Kiểu điều khiển: 4
    • Tên máy chủ: localhost
    • Số cổng: 50000. Bạn có thể xác minh điều này bằng cách mở bàn điều khiển DB2 (Start > All Programs > IBM DB2 > DB2COPY1 (default) > General Administration Tools > Control Center), tìm cá thể DB2 dưới All Systems, nhấn “Configure Parameters”, và nhấn nút Properties cạnh TCP/IP.
  14. Nhấn Finish và lưu vào cấu hình chính trên màn hình tiếp theo.
  15. Chọn nguồn dữ liệu mới của bạn trong danh sách và nhấn Test connection.

Máy chủ WebSphere Application Server bây giờ sẽ báo cáo rằng việc kết nối đã thành công.

Thêm nguồn dữ liệu vào ứng dụng web của bạn

Để ứng dụng web của bạn có thể truy cập vào nguồn dữ liệu JNDI mà bạn đã tạo ra trong thùng chứa (container), hãy thêm một phần tử <resource-ref> vào web.xml (xem Liệt kê 14).

Liệt kê 14. Bộc lộ nguồn dữ liệu JNDI cho ứng dụng web
<resource-ref>
<description>DB2 Database Connection</description>
      <res-ref-name>jdbc/StocksDataSource</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
</resource-ref>

Để sau đó cung cấp cho Spring khả năng truy cập nguồn dữ liệu, bạn thêm một bean cho nó vào spring-servlet.xml, và sửa đổi định nghĩa bean điều khiển để thêm nguồn dữ liệu vào StockListController (xem Liệt kê 15).

Liệt kê 15. Cung cấp nguồn dữ liệu JNDI như là một bean Spring
<bean id="dataSource"
          class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
          <value>java:comp/env/jdbc/StocksDataSource</value>
      </property>
</bean>

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

Sử dụng bean DataSource trong các trình điều khiển của bạn

Không trộn lẫn SQL vào logic điều khiển của bạn, hãy đặt tất cả các truy vấn SQL của bạn vào một lớp StocksDao mà bạn cũng có thể làm thành một bean Spring, rồi thêm nó vào bất kỳ điều khiển nào cần đến nó (xem Liệt kê 16).

Liệt kê 16. Thêm một bean StocksDao của Spring
<bean id="stocksDao" class="com.jm.fbstockdemo.StocksDao">
    <constructor-arg ref="dataSource"/>
</bean>

StocksDao có thể chỉ cần tập trung vào việc thực hiện các truy vấn SQL, khi biết dữ liệu của nó sẽ ở đó khi nó được Spring tạo ra và kết nối (xem Liệt kê 17).

Liệt kê 17. StocksDao (lớp Java)
public class StocksDao {

    private SimpleJdbcTemplate jdbcTemplate;

    public StocksDao(DataSource dataSource) {
        super();
        this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

    public List<Stock> fetchAllStocks() {
        return jdbcTemplate.query("select * from stock", 
            new ParameterizedRowMapper<Stock> () {
                public Stock mapRow(ResultSet rs, int row) throws SQLException {
                    return new Stock(rs.getInt("id"),
                                     rs.getString("ticker"));
                    }
          });
    }

Spring sẽ gọi hàm tạo của DAO của bạn bằng bean dataSource khi tạo ra và kết nối các bean lúc khởi động, và hàm tạo này tạo ra một cá thể của lớp SimpleJdbcTemplate của Spring với nó. fetchAllStocks() sử dụng SimpleJdbcTemplate để sắp xếp hợp lý truy vấn SQL; nó tìm nạp tất cả các hàng trong bảng “stocks” và ánh xạ chúng vào các đối tượng Stock bằng cách sử dụng lớp trong vô danh ParameterizedRowMapper. SimpleJdbcTemplateParameterizedRowMapper sử dụng Java chung thông thường (như với Java 1.5) để mapRow() trả lại một đối tượng Stock thực sự (xem mã kèm theo) chứ không phải là một đối tượng mà nó ép kiểu thành một Stock. Mã được tạo ra sẽ thực sự làm việc ép kiểu này, nhưng các lớp được tham số hóa lại buộc phải tuân theo sự an toàn về kiểu vào lúc biên dịch.

Do tất cả các trình điều khiển của bạn cần phải truy vấn cơ sở dữ liệu, sẽ có một khung nhìn mà chúng chuyển tiếp đến khi thành công, và cũng sẽ cần truy cập vào giá cổ phiếu, hãy tạo ra một lớp cơ sở trừu tượng, AbstractStockDemoController, nằm bên trên một StocksDao, một giá trị successView và một đối tượng StockPriceSource được Spring thêm vào (xem Liệt kê 18).

Liệt kê 18. Tạo một lớp cơ sở trừu tượng
public abstract class AbstractStockDemoController implements Controller {

    private StocksDao dao;
    private String successView;

    public void setDao(StocksDao dao) {
        this.dao = dao;
    }

    protected StocksDao getDao() {
        return dao;
    }
    
    protected String getSuccessView() {
        return successView;
    }

    public void setSuccessView(String successView) {
        this.successView = successView;
    }
}

Sau đó sửa đổi StocksListController để nó mở rộng lớp cơ sở này và sử dụng StocksDao để cung cấp dữ liệu cho khung nhìn (xem Liệt kê 19).

Liệt kê 19. StockListController cung cấp dữ liệu mô hình cho khung nhìn
public class StockListController extends AbstractStockDemoController {
    
    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
List<Stock> stocks = getDao().fetchAllStocks();
        
        return new ModelAndView (getSuccessView(), "stocks", stocks);        }
}

StockListController bây giờ tìm nạp các cổ phiếu từ StocksDao và cung cấp các cổ phiếu như là mô hình, dưới tên bean JSP “stocks”, trả lại giá trị successView được Spring thêm vào như là khung nhìn đáp ứng để biểu hiện.

Để kiểm tra việc kết nối cơ sở dữ liệu, hãy thay stockList.jsp bằng nội dung của Liệt kê 19, cung cấp các cổ phiếu như là một nguồn cấp XML.

Liệt kê 19. stockList.jsp cung cấp dữ liệu từ DB2
<%@ page contentType="text/xml" %>  
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<stocks>    
    <c:forEach items="${stocks}" var="stock"> 
        <stock>
            <id><c:out value="${stock.id}"/></id>
            <ticker><c:out value="${stock.ticker}"/></ticker>
        </stock>
    </c:forEach>
</stocks>

Cập nhật ứng dụng web trong máy chủ ứng dụng WebSphere

Cuối cùng, để xem thành quả lao động của bạn, tái xuất WAR và cập nhật ứng dụng web trong máy chủ ứng dụng WebSphere qua bàn điều khiển Administrative Console.

  1. Mở rộng phần ứng dụng, nhấn Enterprise Applications, chọn ứng dụng web của bạn trong danh sách và nhấn Update.
  2. Nhấn nút Browse dưới Specify the path to the replacement ear file (việc này cũng áp dụng với một tệp tin WAR), chọn tệp tin WAR của bạn như trước đây, và phải bảo đảm chắc chắn chỉ rõ lại gốc bối cảnh (/facebook-stock-demo) trước khi nhấn Next.
  3. Nhấn Next một lần nữa trên màn hình tùy chọn tiếp theo, phải chắc chắn chọn ứng dụng web của bạn trên màn hình Map modules to servers (ánh xạ các mô-đun tới các máy chủ) trước khi nhấn vào Next ở đó. Vì bạn lần đầu tiên thêm một nguồn dữ liệu vào ứng dụng web, màn hình tiếp theo lúc này là một màn hình Map resource references to resources (Ánh xạ các tham chiếu nguồn tài nguyên đến các tài nguyên).
  4. Chọn Use default method đối với phương thức xác thực, chọn biệt danh xác thực StocksDB2Login.
  5. Chọn ứng dụng web của bạn trong bảng, Nhấn Browse dưới Target JNDI Name, chọn tên jdbc/StocksDataSource JNDI, nhấn Apply, nhấn Next và nhấn Finish.
  6. Đợi máy chủ ứng dụng WebSphere bố trí lại ứng dụng, và nhấn vào Save dưới đáy màn hình kết quả để lưu các thay đổi của bạn.

Như trước đây, trong trình duyệt Web vào http://localhost/fb_stock_demo/stockList, và giờ bạn sẽ nhìn thấy các cổ phiếu thực sự từ cơ sở dữ liệu dưới dạng XML.


Kết nối cơ sở dữ liệu trong PHP

Bây giờ bạn sẽ kết nối vào cùng một cơ sở dữ liệu DB2 từ PHP chạy trong Zend Core for IBM, và tạo ra một trình điều khiển và khung nhìn để kiểm tra kết nối đó. Để duy trì một sự trừu tượng hóa tương tự như sự trừu tượng hóa DataSource bên phía Java, bạn sẽ tạo ra một lớp Db2DataSource chịu trách nhiệm về duy trì kết nối với DB2 và về các giao dịch đối với kết nối đó, và sẽ sử dụng đối tượng Properties đối với các giá trị kết nối/đăng nhập của nó. Bạn cũng sử dụng một lớp StocksDao như bạn đã làm trong Java, lớp này sử dụng một Db2DataSource để truy cập vào các bảng của ứng dụng. Sử dụng một cấu trúc chung trong các nửa Java và PHP của ứng dụng sẽ cho phép bạn di chuyển giữa chúng dễ dàng hơn, cho phép bạn thực hiện các đặc tính của ứng dụng Facebook của bạn trong bất kỳ công nghệ nào thích hợp hơn mà không cần lo lắng đến việc sửa đổi các mã đó.

Giao tiếp với DB2

Trước tiên hãy viết Db2DataSource để đóng gói việc truy cập DB2. Trong thư mục con lib, tạo tệp Db2Database.php như trong Liệt kê 20.

Liệt kê 20. Lớp Db2DataSource (PHP)
class Db2DataSource extends Injectable {

  private $connection;

  public function __construct($properties, $persist=true) {
    parent::__construct($properties);
    $this->connect ($persist);
  }

  private function connect ($persist=true) {

    $connectionString = 
      "DRIVER={IBM DB2 ODBC DRIVER};" .
      "DATABASE=$this->database;" .
      "HOSTNAME=$this->hostname;" . 
      "PORT=$this->port;" . 
      "PROTOCOL=TCPIP;" . 
      "UID=$this->username;" . 
      "PWD=$this->password;";

    if ($persist) {
      $this->connection = db2_pconnect($connectionString, '', '');
    } else {
      $this->connection = db2_connect($connectionString, '', '');    
    }
    
    if (! $this->connection) {
      throw new Exception ("Db2DataSource -- couldn't connect to DB2: " . 
               db2_conn_errormsg());
    } 
  }

  public function close() {
    if ($this->connection) {
      db2_close($this->connection);
    }
  }
}

Hàm tạo này nhận một đối tượng Properties vì nó là một đối tượng Injectable, và một cờ báo $persist xác định xem liệu có tạo ra một kết nối cơ sở dữ liệu tồn tại lâu dài phục vụ nhiều yêu cầu hay là một kết nối được tạo mới mỗi lần. connect() tạo ra xâu ký tự kết nối DB2 tiêu chuẩn có chứa trình điều khiển, giao thức, và thông tin kết nối cho riêng cơ sở dữ liệu này. Phương thức close() đóng lại kết nối nếu có một kết nối hợp lệ tồn tại. Lưu ý rằng connect() tham chiếu đến các giá trị ấy như là các biến cá thể, mặc dù chúng thực sự được xác định trong một tệp tin thuộc tính (trình bày dưới đây); lớp con Injectable ngăn cách Db2DataSource khỏi chi tiết này chứ không phải cần chấp nhận một đối tượng Properties trong hàm tạo của nó.

Bây giờ bạn có thể kết nối với DB2, bạn có thể truy vấn nó và viết dữ liệu lên nó.

Bắt đầu với một phương thức executeQuery() chung, nó gói lời gọi db2_exec() và đưa ra một lỗi ngoại lệ báo cáo lại bất kỳ thông báo lỗi nào nó nhận được qua db2_stmt_errormsg() nếu việc truy vấn thất bại (xem Liệt kê 21).

Liệt kê 21. Db2DataSource.executeQuery()
public function executeQuery($query) {
    $result = db2_exec($this->connection, $query);
    if ($result == null) {
      throw new Exception("Db2DataSource.executeQuery failed on query [$query], 
DB2 error is " . db2_stmt_errormsg());
    }
    return $result;
  }

Sau đó thêm một phương thức fetchObjects() sử dụng executeQuery(), trả lại một mảng các đối tượng PHP để đáp ứng một truy vấn SQL (xem Liệt kê 22). Lưu ý rằng db2_fetch_object() đặt các tên trường lên các đối tượng được trả về toàn bộ viết hoa (ALL CAPS), ví dụ, $stock->TICKER, chứ không phải là $stock->ticker.

Liệt kê 22. Db2Database.fetchObjects()
public function fetchObjects($query) {
    $result = $this->executeQuery($query);
    $objects = array();
    while ($rowObject = db2_fetch_object($result)) {
      $objects[] = $rowObject;
    }
    return $objects;
}

Do bạn đã có một lớp chung để kết nối với DB2 và thi hành các truy vấn DB2, như bạn đã làm trên mã phía Java, bạn sẽ tạo ra một lớp StocksDao có chứa các truy vấn riêng cho ứng dụng này.

Lớp StocksDao

StocksDao sẽ chứa toàn bộ các truy vấn SQL thực tế, cũng giống như nó làm trong mã phía Java. Trước tiên, chúng ta hãy thêm vào một phương thức để thu thập tất cả các cổ phiếu đang có sẵn (xem Liệt kê 23).

Liệt kê 23. StocksDao.php
<?php

class StocksDao {

  private $db;

  public function StocksDao($db) {
    $this->db = $db;
  }
  
  public function fetchAllStocks() {
    return $this->db->fetchObjects('select * from stock');
  }
}

?>

Lưu ý rằng StocksDao dựa trên một đối tượng $db (một Db2DataSource) mà nó sử dụng cho toàn bộ các truy cập cơ sở dữ liệu, và do đó StocksDao sẽ hầu như không chứa mã lệnh nào khác trừ các truy vấn SQL riêng cho ứng dụng mà bạn cần.

Hình 7 cung cấp một bản đồ của các thành phần truy cập dữ liệu PHP để so sánh với sơ đồ tương tự về phía mã Java trong Hình 6. Nguồn dữ liệu Java liên quan đến nhiều thành phần chi tiết hơn và yêu cầu công việc cấu hình nhiều hơn, nhưng bù lại cung cấp sự an toàn, khả năng mở rộng nhiều hơn và một tiêu chuẩn công nghiệp.

Hình 7. Truy cập dữ liệu trong PHP
Truy cập dữ liệu trong PHP

Sử dụng một lớp cơ sở điều khiển trừu tượng trong PHP

Hãy nhớ lại rằng ActionDispatcher sẽ tạo ra một trình điều khiển PHP, cung cấp cho nó một đối tượng Properties và gọi một phương thức execute() của nó, trông đợi nhận lại một đối tượng ModelAndView để biểu hiện khung nhìn, chính xác như ở bên mã Java. Vì bạn sẽ cần một kết nối cơ sở dữ liệu trong tất cả các trình điều khiển của mình, hãy cho tất cả chúng trở thành lớp con của lớp AbstractStockDemoController mà chính lớp này lại là lớp con của AbstractController (xem Liệt kê 24). Toàn bộ mã PHP chỉ riêng cho ứng dụng của bạn phải đặt trong thư mục con app của fb_stock_demo.

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

  protected $db;
  protected $dao;

  public function __construct() {
    
  }

  public function execute() {
    
    try {
     
      $this->db = new Db2DataSource($this->properties, 'db');    
      
      $this->dao = new StocksDao ($this->db);

      $response = $this->executeSpecific();

      $this->db->close();

      return $response;

    } catch (Exception $e) {     
      $this->db->close();
      throw $e;
    }
  }

  protected abstract function executeSpecific();
}

AbstractStockDemoController triển khai thực hiện phương thức execute() được ActionDispatcher gọi ra, kết nối vào cơ sở dữ liệu bằng cách sử dụng tệp tin thuộc tính được thêm vào, quy định db làm tiền tố để sử dụng khi tìm kiếm các thuộc tính kết nối cơ sở dữ liệu, tạo ra một StocksDao từ nó để các lớp con sử dụng, và gọi ra phương thức executeSpecific() trừu tượng. Lớp con triển khai executeSpecific() xử lý các chi tiết cụ thể của yêu cầu. Execute() cũng đảm bảo đóng kết nối cơ sở dữ liệu. Chú ý rằng vì PHP không cung cấp một cấu kiện finally như trong mã Java, bạn cần phải làm điều này cả trong khối try và khối catch. Bạn cung cấp phương thức rỗng __construct() sao cho lớp con có thể gọi parent::__construct() (nó không cần biết rằng nó không phải làm việc đó đối với lớp cơ sở riêng này).

Kiểm tra nguồn dữ liệu PHP bằng một trình điều khiển và khung nhìn

Với lớp trình điều khiển trừu tượng đã sẵn sàng, bạn có thể tạo ra một lớp con, DbTestController, để thử nghiệm kết nối cơ sở dữ liệu, như trong Liệt kê 25. Đặt tệp DbTestController.php trong thư mục con app dưới fb_stock_demo.

Liệt kê 25. Lớp PHP DbTestController
class DbTestController extends AbstractStockDemoController {
  public function executeSpecific() {
    return new ModelAndView ("dbTestView.php",
                       $this->dao->fetchAllStocks());
  }
}

Lớp này trông rất quen thuộc. Phương thức executeSpecific(), do phương thức execute() của lớp cơ sở gọi ra, tìm nạp các các cổ phiếu và trả lại khung nhìn (dbTestView.php) và mô hình (mảng các đối tượng Stock), đúng như trình điều khiển đã làm bên mã Java, và ActionDispatcher sẽ biểu hiện dbTestView.php bằng cách sử dụng mô hình các cổ phiếu đã được cung cấp (xem Liệt kê 26). Đặt tệp dbTestView.php trong thư mục con app cùng với trình điều khiển.

Liệt kê 26. dbTestView.php
The result of calling DbTestController was:
<br/><br/>

<?
foreach ($model as $stock):
?>

Stock <?= $stock->ID ?>: <?= $stock->TICKER ?> <br/>

<?
endforeach;
?>

Chú ý rằng bạn phải truy cập vào các trường của các đối tượng trả lại bằng cách sử dụng ALL CAPS, vì đây là cách mà db2_fetch_object() đã tạo ra các đối tượng hàng.

Bạn đã tạo nên một mục cho trình điều khiển này trong .htaccess dưới khoá yêu cầu phpDbTest để gửi đến phía PHP của ứng dụng; bây giờ bạn cần cung cấp một khóa cho ActionDispatcher. Do khoá này được thêm vào, hãy tạo một app.properties có chứa một mục cho trình điều khiển mới (xem Liệt kê 27), trong một thư mục con conf dưới fb_stock_demo.

Liệt kê 27. app.properties
ActionDispatcher/dbTest=DbTestController

Cuối cùng, để cung cấp thông tin kết nối cơ sở dữ liệu, hãy tạo tệp tin db.properties bên cạnh app.properties, có chứa nội dung của Liệt kê 28.

Liệt kê 28. db.properties
Db2DataSource/database=stocks
Db2DataSource/hostname=localhost
Db2DataSource/port=50000
Db2DataSource/username=[your operating system username]
Db2DataSource/password=[your operating system password]

Bạn có thể thêm bất cứ thuộc tính nào khác vào bất kỳ lớp nào mà bạn muốn bằng cách tạo ra các mục tương tự như vậy trong app.properties (hoặc một tập tin khác, miễn là index.php bao gồm cả nó khi tạo ra đối tượng Properties).

Để xác nhận rằng khung công tác MVC hạng nhẹ của bạn và kết nối DB2 đang làm việc bên phía PHP, truy cập http://localhost/fb_stock_demo/phpDbTest trong trình duyệt, và bạn sẽ thấy khung nhìn của bạn được điền đầy bằng các cổ phiếu từ cơ sở dữ liệu.


Tóm tắt

Kết hợp các ngôn ngữ Java và PHP vào chỉ một ứng dụng có thể cảm thấy như kết hợp táo với cam. Do bản chất, ngôn ngữ lập trình Java áp đặt rất nhiều cấu trúc lên mã lệnh, và giới ngôn ngữ Java có xu hướng hội tụ nhanh chóng đến các mẫu và khung công tác phổ biến, trong khi giới PHP có cấu trúc ít hơn nhiều và được chuẩn hóa ít hơn nhiều, đôi khi làm cho các ứng dụng PHP trở thành một tập hợp các kịch bản lệnh liên quan nhau không rõ nét, mỗi kịch bản có cách tiếp cận sự vật riêng của nó. Nhưng với một số quan tâm thiết kế hai thế giới này có thể trở thành ngày càng giống nhau hơn. Trong hướng dẫn này, bạn đã khám phá ra một cách tiếp cận để tích hợp hai công nghệ này trong khi vẫn duy trì một số mã lệnh đối xứng giữa hai thế giới. Với những nền móng đã xây dựng, Phần 3 sẽ đảm nhận các chi tiết cụ thể của việc thực hiện một ứng dụng Facebook đầy đủ chức năng bằng cách sử dụng FBML, FBJS, Facebook API trong cả hai ngôn ngữ Java và PHP, và các mẫu MVC và truy cập dữ liệu tương đối đối xứng mà bạn đã thiết lập sẵn sàng ở đây để tạo ra một ứng dụng quản lý danh mục đầu tư cổ phiếu với các tính năng mạng xã hội, biến nó thành một trò chơi có tính cạnh tranh.


Tải về

Mô tảTênKích thước
Part 2 source codefacebook-tutorial-src.tar180KB

Tài nguyên

Học tập

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

Thảo luận

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, Information Management
ArticleID=427408
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 2: Sử dụng đồng thời Java và PHP
publish-date=09112009