Phát triển ứng dụng di động máy khách, máy chủ mashup với IBM Worklight

Bài này trình bày quá trình phát triển của ứng dụng di động lai (hybrid) – là sự kết hợp của dữ liệu, trình diễn (presentation) và chức năng từ các nguồn ở cả phía máy khách (client) và máy chủ (server). Đặc điểm chính của ứng dụng mashup là sự kết hợp, trực quan và tổ hợp của những nguồn khác nhau. Các nguồn web đã xuất bản được tận dụng, cũng như dữ liệu từ cơ sở dữ liệu quan hệ có thể được nắm giữ bởi doanh nghiệp. Bạn sẽ thấy rằng IBM® Worklight V6 là một nền tảng tốt cho việc xây dựng các ứng dụng lai dựa trên mashup cho các thiết bị di động khác nhau. Nội dung này nằm trong loạt bài về IBM WebSphere Developer Technical Journal.

Walter M. Jenny, Kiến trúc sư, IBM

Ảnh của Walter JennyWalter Jenny là một kiến trúc sư trong nhóm Software của IBM. Ông có trên 20 năm kinh nghiệm trong lĩnh vực phát triển ứng dụng và quản lý quy trình nghiệp vụ (BPM). Walter có một bằng Thạc sỹ Khoa học máy tính, một bằng Thạc sỹ và Tiến sỹ về quản trị doanh nghiệp.



14 11 2013

Giới thiệu

Tải về Worklight

Tải về phiên bản IBM Worklight Developer Edition 6.0 miễn phí và không giới hạn thời gian sử dụng!

IBM Worklight V6 cung cấp một nền tảng ứng dụng di động mở, toàn diện và tiên tiến, có thể giúp phát triển hiệu quả, chạy và quản lý các ứng dụng HTML5, ứng dụng gốc và ứng dụng lai.

Bằng cách sử dụng các công cụ và công nghệ chuẩn, các cơ chế bảo mật, khả năng phân tích và quản lý, Worklight đơn giản hóa vòng đời phát triển phần mềm thông qua nhiều nền tảng di động bao gồm iOS, Android, BlackBerry, Window® Phone. Như môi trường phát triển Eclipse, Worklight giúp bạn nâng cao sự phát triển, kiểm thử và phân phối các ứng dụng di động bằng cách sử dụng các công nghệ mở như HTML5, Apavhe Cordova, JavaScript™, và các khung công tác (framework) Javascript phổ biến như Dojo, jQuery, và Sencha Touch.

Để nắm rõ các công nghệ sử dụng khi phát triển ứng dụng di động, bạn cần hiểu bản chất của các phương thức phát triển di động khác nhau: ứng dụng web di động, ứng dụng lai (hybrid), ứng dụng gốc (native):

  • Ứng dụng web di động có thể chạy trên bất kỳ thiết bị nào, khi chúng không cần bất kỳ tính năng bên dưới của thiết bị (như lưu trữ tập tin cục bộ, đưa ra các thông báo, v.v…). Những ứng dụng này thường dựa trên HTML5 cùng với CSS và JavaScript. Bằng cách sử dụng các công nghệ này có thể giúp giảm chi phí phát triển bởi bạn có thể tái sử dụng các kỹ năng và không yêu cầu các nhà phát triển hiểu biết về nền tảng gốc của thiết bị. Vòng đời triển khai, kiểm thử, bảo trì cũng ít phức tạp hơn. Thêm vào đó, bạn không cần lo lắng về việc chạy ứng dụng trên các kho ứng dụng độc quyền, làm giảm lợi nhuận của bạn và làm quá trình bảo trì ứng dụng trở nên phức tạp.
  • Ứng dụng lai là kết hợp của HTML5, CSS và JavaScrip với việc truy cập các tính năng bên dưới của thiết bị di động. Loại ứng dụng này có được ưu điểm của ứng dụng web di động là khả năng chạy trên nhiều nền tảng, và thêm các tính năng bên dưới thiết bị. Cách tiếp cận này thông thường thúc đẩy khung công tác hiện thực hóa khả năng của thiết bị, tối ưu kinh nghiệm người dùng và cung cấp khả năng linh động, mềm dẻo cao nhất để phát triển ứng dụng trên nhiều thiết bị. Sự khác nhau giữa hình thức và khả năng của thiết bị có thể được giải quyết thông qua giao diện (skin).
  • Ứng dụng gốc có ích khi bạn muốn tận dụng các tính năng bên dưới của thiết bị, cùng với cái nhìn và cảm nhận trên thiết bị. Các ứng dụng này được khuyến khích khi cần các tính năng phức tạp, xử lý về bộ nhớ. Tuy nhiên, nhược điểm là chi phí cao và ít mềm dẻo bởi vì mã gốc cho các thiết bị khác nhau cần được phát triển, bảo trì và kiểm thử.

Các ứng dụng lai tận dụng điểm mạnh của Worklight và ứng dụng web được viết bởi HTML5, CSS, JavaScript, nhưng cũng có thể truy cập đầy đủ khả năng thiết bị thông qua Cordova như một phần của môi trường chạy trên ứng dụng máy khách. Cordova là một khung công tác cho phép bạn tận dụng điểm mạnh tầng native của tất cả điện thoại thông minh với mã nguồn duy nhất dựa trên WebView, Webkit được nhúng trên thiết bị.

Trong bài này, bạn sẽ khám phá các tính năng của Worklight để tạo một ứng dụng lai dùng để pha trộn dữ liệu, trình diễn, và các tính năng từ nhiều nguồn ở phía máy khách, cũng như ở phía máy chủ. Bạn cũng có thể chạy thử mã nguồn mẫu trong bài này.


Kiến trúc Worklight

Ngữ cảnh được trình bày trong bài này sử dụng một vài thành phần Worklight (Hình 1):

  • IBM Worklight Studio là một IDE dựa trên Eclipse cho phép thực thi tất cả mã nguồn và các nhiệm vụ tích hợp được yêu cầu để phát triển ứng dụng.
  • IBM Worklight Server là cổng gateway dựa trên Java giữa các ứng dụng, các dịch vụ ngoài và cơ sở hạ tầng cuối của doanh nghiệp. Worklight server chứa các tính năng bảo mật cho phép kết nối, trích xuất dữ liệu nhiều nguồn và thao tác, xác thực, cập nhật trực tiếp web và ứng dụng lai, và các tính năng quản lý, phân tích. Worklight server có thể chạy như máy chủ ứng dụng Java EE, WebSphere. Với mục đích của bài này, chúng ta sẽ sử dụng máy chủ nhỏ gọn Jetty HTTP cùng với Workligh Studio.
  • IBM Worklight Device Runtime Components cung cấp SDK và môi trường chạy ứng dụng di động phía máy khách cho các môi trường đích khác nhau. Nó nhúng phần máy khách của tính năng tích hợp máy chủ.
  • IBM Worklight Console là giao diện dựa trên web cho việc quản lý, theo dõi máy chủ Worklight và các ứng dụng phát triển, các adapter và đưa ra các thông báo.
Hình 1. Các thành phần chính của Worklight
Hình 1. Các thành phần chính của Worklight

Với kịch bản này, tưởng tượng bạn cần hiển thị thông tin từ một số nguồn, tất cả liên quan tới vị trí cụ thể. Đây có thể là thông tin bán hàng từ lĩnh vực văn phòng hoặc vùng lãnh thổ địa lý, tất cả được cung cấp theo các dạng khác nhau. Để đơn giản, chúng ta chỉ tận dụng nguồn Internet công cộng.

Tất cả mã nguồn (HTML, CSS, JavaScript) sẽ được phát triển trong Worklight Studio và sau được triển khai tới Worklight server. Worklight cung cấp một khung công tác của các adapter mà kết nối tới các hệ thống cuối, phân phối dữ liệu tới và từ các ứng dụng di động và thực thi bất kỳ logic nào trên dữ liệu phía máy chủ. Worklight Console sẽ hữu ích cho việc điều khiển ứng dụng, cũng như là một điểm tập trung cho việc chạy ứng dụng.

Luồng điều khiển cơ bản của ứng dụng mẫu được hiển thị trong Hình 2.

Hình 2. Luồng điều khiển
Hình 2. Dòng điều khiển
  1. Ứng dụng web di động được tải từ máy chủ Worklight.
  2. Như một phần của tệp HTML ban đầu, một widget được tạo cho việc gọi Google Maps API để đưa ra bản đồ, với vị trí hiện tại của người dùng thông qua chức năng geolocation của HTML5.
  3. Ứng dụng gọi adapter bên phía máy chủ để cung cấp danh sách các vị trí.
  4. LocationAdapter ở máy chủ nhận một mảng các vị trí thông qua JDBC từ cơ sở dữ liệu DB2® và gửi nó trở lại ứng dụng trên máy khách di động.
  5. Bất kỳ khi nào người dùng chọn một vị trí mới, vị trí trên bản đồ được cập nhật và thông tin được nhận thông qua NewsAdapter.
  6. Đầu tiên, NewsAdapter chọn dữ liệu từ Google News Feed.
  7. Sau đó, NewsAdapter gọi StockAdapter để nhận những thông tin chứng khoán từ Yahoo! Finance và gia tăng hai phần thông tin này.

Hãy nhìn vào hai phần chính mà bạn cần xây dựng trong ứng dụng này – phần máy khách và phần máy chủ – và sau đó chạy chúng trên một trình mô phỏng thiết bị di động.


Phần máy khách (client)

Hãy bắt đầu với phần máy khách.

  1. Trong Worklight Studio, tạo một dự án Worklight bằng cách chọn File > New > Worklight Project hoặc nhấn vào Create Worklight Artifacts (Hình 3).
    Hình 3. Tạo dự án Worklight
    Hình 3. Tạo dự án Worklight
  2. Đặt tên dự án là Project Mashup, chọn một khuôn mẫu Hybrid Application, sau đó nhấn Next (Hình 4).
    Hình 4. Chọn một Hybrid Application
    Hình 4. Chọn một ứng dụng lai Hybrid
  3. Đặt tên ứng dụng của bạn là Mashup. Chọn Add Dojo Toolkit, cho phép ứng dụng của bạn tận dụng các khả năng của thư viện Dojo Javascript, sau đó chọn Finish (Hình 5).
    Hình 5. Tạo ứng dụng Worklight
    Hình 5. Tạo ứng dụng Worklight

Đến đây sẽ tạo ra cho bạn một cấu trúc dự án Worklight cơ bản (Hình 6). (Xem bài IBM Worklight user documentationLàm việc với Worklight, Phần 1: Bắt đầu với ứng dụng Worklight đầu tiên của bạn để tìm hiểu chi tiết các thành phần chính này.)

Hình 6. Cấu trúc dự án Worklight cơ bản
Hình 6. Cấu trúc dự án Worklight cơ bản

Các bước tiếp theo là tạo logic để hiển thị bản đồ với thông tin vị trí địa lý. Bạn có thể làm bước này bằng cách viết đoạn mã JavaScript trực tiếp trong Mashup.js bằng cách sử dụng bộ công cụ Dojo cùng với khung công tác Dijit, một tập widget toàn diện và mạnh mẽ. Tuy nhiên, nếu bạn muốn xây dựng một widget tùy biến, bạn có thể tái sử dụng bởi những người trong đội phát triển của bạn, widget tùy biến là một hướng tiếp cận tốt.

Tạo một widget Dijit tùy biến

Trong kịch bản này, bạn cần một widget tùy biến mà hiển thị dữ liệu trong bản đồ với một vị trí cụ thể. Phần đầu là hiển thị vị trí hiện tại và đưa ra trong bản đồ Google chuẩn. Một widget tùy biến được phát triển để đóng gói các thành phần UI có thể tái sử dụng, cùng với phần đặc tả của chức năng bổ sung. Các bước để tạo widget Dojo tùy biến bao gồm:

  1. Tạo cấu trúc tệp cho widget tùy biến của bạn

    Nó được xem xét là cách thực hành tốt để có một cấu trúc tệp phù hợp cho công việc Dijit tùy chọn và Worklight Studio hỗ trợ bạn. Bạn sẽ tạo một thư mục với tên tùy ý, đại diện cho namesapce của bạn. (Bạn có thể sử dụng bất kỳ tên nào bạn thích, nhưng nên có ý nghĩa, như tên của ứng dụng hoặc tên của tổ chức.)

    Worklight Studio tạo bước này dễ dàng:

    1. Nhấn chuột phải vào thư mục /Mashup/apps/Mashup/common trong Explorer và chọn New > Dojo Widget. Một cửa sổ Dojo Widget mới xuất hiện. Ở mục Module Name, bạn nhập vào custom; ở mục Widget Name, nhập vào LocationViewer. Mục HTML template và style sheet của widget được sinh tự động (Hình 7).
      Hình 7. Cửa sổ Dojo Widget mới
      Hình 7. Dojo Widget mới
    2. Nhấn Finish. Ba tệp được tạo trong thư mục common (Hình 8).
      Hình 8. Cửa sổ Dojo Widget mới
      Hình 8. Dojo Widget mới
  2. Tạo lớp widget sử dụng đặc tả

    Worklight Studio tự động mở tệp nguồn LocationViewer JavaScript trong trình soạn thảo, chứa đoạn Dojo được sinh ra (Liệt kê 1, các comment đã được xóa).

    Liệt kê 1. Tạo mã JavaScript widget tùy ý
    define("custom/LocationViewer", [ "dojo", "dijit", "dijit/_Widget",
    		"dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
    		"dojo/text!custom/templates/LocationViewer.html" ], function(dojo,
    		dijit, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin) {
    	return dojo.declare("custom.LocationViewer", [ dijit._Widget,
    			dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin ],
    {
    templateString : dojo.cache("custom",	"templates/LocationViewer.html"),
    constructor : function() {
    		},
    	postMixInProperties : function() {
    		},
    	postCreate : function() {
    		}
    	});
    });

    Định dạng module AMD thay thế dojo.provide và dojo.require trong định nghĩa khi tạo các module tùy chọn. Những định nghĩa này là duy nhất để yêu cầu lời gọi, ngoại trừ callback trả lại một giá trị mà được lưu trữ và được sử dụng như giá trị được giải quyết của module. Worklight Studio định nghĩa widget LocationViewer tùy biến của bạn bằng cách sử dụng dijit/_WidgetBase và dijit/_TemplatedMixin làm cơ sở.

    Chú ý: nếu bạn muốn lấy mẫu giống nhau đã được tạo mà không cần sử dụng wizard (ví dụ, khi làm việc với một tệp JS đã tồn tại), bạn cũng có thể sử dụng công cụ tự tạo mã build-in bằng cách gõ decl và nhấn Ctrl+Space (Hình 9).

    Hình 9. Định nghĩa Dijit widget không sử dụng wizard
    Hình 9. Định nghĩa Dijit widget không cần trình trợ giúp

    Tiếp theo, bạn cần xác định một số thuộc tính, để widget là phù hợp với các dạng thuộc tính mà nó sẽ nhận (Liệt kê 2).

    Liệt kê 2. Thiết lập các thuộc tính
    zoom			: 10,
    address		: "",
    // Define reasonable defaults for mobile devices
    containerWidth	: "320px",
    containerHeight	: "460px",

    Hàm postMixlnProperties được gọi khi tất cả biến được kế thừa từ các lớp cha là “mixed in”. Các phương thức chung cho postMixlnProperties được hiệu chỉnh hoặc gán các giá trị cho các biến thuộc tính của widget được định nghĩa trong tệp HTML. Tất cả những gì bạn cần làm ở đây là gọi phương thức của lớp cha (Liệt kê 3).

    Liệt kê 3. Thiết lập các thuộc tính ‘mixed in’
    postMixInProperties : function() {
    	this.inherited('postMixInProperties', arguments);
    },

    Phương thức postCreat được gọi mỗi khi cấu trúc DOM của widget sẵn sàng, nhưng trước khi nó được thêm vào trang. Đây thường là vị trí tốt nhất để đặt mã khởi tạo. Lúc này, bạn sẽ gọi hàm refreshMap, tạo Google map, với địa chỉ rỗng và không có thông tin. Để giữ các hàm khởi tạo, gọi phương thức của lớp cha (Liệt kê 4).

    Liệt kê 4. Khởi tạo widget tùy ý
    postCreate : function()
    {
    this.refreshMap(this.address, "");
    	this.inherited('postCreate', arguments);
    },

    Các tính năng thực tế được thực hiện trong refreshMap. Khi được gọi với địa chỉ rỗng và không có thông tin , bạn sử dụng tính năng định vị trí HTML5 để lấy vị trị hiện tại. Ngược lại, bạn cố gắng tìm địa chỉ xác định trên bản đồ bằng cách sử dụng Google Geocoder. Nội dung của InfoWindow được truyền như một tham số (Liệt kê 5).

    Liệt kê 5. Vẽ bản đồ
    refreshMap : function(address, information)
    {
      var localZoom = this.zoom;
      var mapOptions = {
                zoom : localZoom,
                mapTypeId : google.maps.MapTypeId.ROADMAP
      };
      var map = new google.maps.Map(this.mapNode, mapOptions);
      if (address == null || address == "")
      {
        if(navigator.geolocation) // Try HTML5 geolocation
        {
          navigator.geolocation.getCurrentPosition(function(position)
          {
            var pos = new google.maps.LatLng(position.coords.latitude,
                                             position.coords.longitude);
            var infoWindow = new google.maps.InfoWindow({map : map,
                                             position :        pos,
                                             content : 'This your current location<br>' +
    		Found using <a href="http://dev.w3.org/geo/api/spec-source.html">HTML5 
    		Geolocation</a>'
          });
          map.setCenter(pos);
          infoWindow.open(map);
        }, function() {
          handleNoGeolocation(true);
          });
        }
        else // Browser doesn't support Geolocation
        {
          handleNoGeolocation(false);
        }
        return;
      }
      var geocoder = new google.maps.Geocoder();
      geocoder.geocode({'address' : address
      }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK)
        {
          map.setCenter(results[0].geometry.location);
          var infoWindow = new google.maps.InfoWindow({ content  : information,
    maxWidth : 230
          });
          var marker = new google.maps.Marker({ map      : map,
                                                position : results[0].geometry.location
          });
          infoWindow.open(map, marker);
          }
          else
          {
            alert("Error: " + status);
          }
        });
      },
      handleNoGeolocation : function (errorFlag)
      {
        …
      }

AMD là gì?

AMD (Asynchronous Module Definition) định dạng module mới cho Dojo bản 1.7 trở đi, thay thế dojo.provide, dojo.require, dojo.requireIf, dojo.requireAfterIf, dojo.platformRequire, và dojo.requireLocalization. Nó cung cấp nhiều cải tiến so với Dojo kiểu module, bao gồm cả hoạt động không đồng bộ, tính đóng gói di động, quản lý độc lập tốt hơn, và cải tiến hỗ trợ việc gỡ lỗi. AMD cũng là chuẩn hướng cộng đồng, có nghĩa là các module được viết theo đặc tả AMD có thể được dùng bởi bất kỳ bộ tải AMD tương thích hay các thư viện khác. Xem bài Định nghĩa các module để biết thêm thông tin.

  1. Tạo mã HTML cho widget tùy chỉnh

    Các khuôn mẫu nên có một cha, một thành phần đóng gói chứa tất cả các thành phần khác. Điều này có thể là thành phần nào đó bạn muốn, nhưng quan trọng là có một thành phần gốc. Với widget cơ bản này, thì sử dụng div như thành phần đóng gói.

    Trong Explorer, nhấp đúp vào templates/LocationViewer.html để mở khuôn mẫu HTML cho widget và hoàn thành mã của bạn như Liệt kê 6.

    Liệt kê 6. Mã HTML cho widget tùy chỉnh
    <div>
    	<div dojoAttachPoint="mapNode"
                 style="width:${containerWidth}; height:${containerHeight}">
    	</div>
    </div>

    Bằng cách sử dụng dijit/_TemplatedMixin, bạn có thể dùng cú pháp ${attribute} để chèn trực tiếp một số giá trị, như containerWidth. Các nút nên được xác định một điểm đính kèm, nghĩa là trong mã widget của bạn, bạn có thể sử dụng tên để tham chiếu nút trực tiếp. Tương tự như bạn gọi getElementById và thiết lập tham chiếu trong advance.

  2. Kiểu phù hợp

    Trong trường hợp bạn cần lệnh CSS đặc biệt, bạn có thể tùy biến tệp themes/LocationViewer.css.

  3. Sử dụng widget tùy biến trong ứng dụng của bạn

    Widget tùy biến có giá trị trong các widget Dojo khác của Worklight Studio (Hình 10). Để sử dụng widget này trong dự án, Rich Page Editor của Worklight Studio cung cấp một giải pháp tuyệt vời.

    Hình 10. Widget tùy biến trong khuôn mẫu Worklight Studio
    Hình 10. Widget tùy chỉnh trong khuôn mẫu Worklight Studio

    Trong Explorer, nhấn đúp vào common/Mashup.html để mở khuôn mẫu HTML. Xóa dòng chữ "Mashup". Kéo dojox.mobile.View từ bảng "Dojo Mobile Widgets" tới Mashup.html và bỏ gần dòng ghi chú <!-- application UI goes here -->. Kéo biểu tượng locationViewer vào Mashup.html và thả vào thẻ div dojox.mobile.View. Thêm tham chiếu tới Google map API (dòng dậm trong Liệt kê 7), và thêm một id cho LocationViewer trong mã hoặc trong thẻ Properties.

    Tùy thuộc vào tham chiếu cá nhân của bạn, bạn có thể viết mã này thủ công hoặc sử dụng các lợi ích của Design Mode trong Rich Page Editor để thay thế mã khi bạn kéo một widget vào container widget. Bộ gợi ý sẽ làm sáng vị trí có thể bỏ xuống và gợi ý pop-up chỉ cho phép hiệu chính các hàm cho widget đã chọn. Ví dụ, khi bạn kéo LocationViewer từ Pallete vào View, bạn lấy gợi ý thực tế cho vị trí muốn đặt. Rich Page Editor sử dụng các trình duyệt nhúng để tạo ra sự hiển thị trực quan cho trang web trong Design View. (Xem chi tiết về Module 03.5 - Rich Page Editor.)

    Hình 11. Design mode của Rich Page Editor
    Hình 11. Chế độ thiết kế của Rich Page Editor

    Worklight Studio sẽ chèn tất cả mã được yêu cầu (Liệt kê 7).

    Liệt kê 7. Widget tùy chỉnh trong tệp HTML chính
    <!DOCTYPE html>		
    <html>
    	<head>
    		<meta charset="utf-8" />
    <meta name="viewport"
    	content="width=device-width, initial-scale=1, maximum-scale=1, 
    	user-scalable=no" />
    <title>Mashup</title>
    		<link rel="shortcut icon" href="images/favicon.png" />
    		<link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
    		<link rel="stylesheet" href="css/reset.css" />
    		<link rel="stylesheet" href="css/Mashup.css" />
    <script type="text/javascript"
    	data-dojo-config="isDebug: false, async: true, parseOnLoad: true"
    	src="dojo/dojo.js"></script>
    <script type="text/javascript" src="dojo/core-web-layer.js"></script>
    <script type="text/javascript" src="dojo/mobile-ui-layer.js"></script>
    <script type="text/javascript" src="dojo/mobile-compat-layer.js"></script>
    <!--  add this line -->
    <script
    src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
    require(
    // Set of module identifiers
    [ "dojo", "dojox/mobile/parser", "dojox/mobile/View", "dojox/mobile", 
    	"dojox/mobile/compat", "dojox/mobile/deviceTheme", "custom/LocationViewer" ],
    // Callback function, invoked on dependencies evaluation results
    function(dojo) {
    	dojo.ready(function() {
    
    	});
    });
    </script>
    <meta name="apple-mobile-web-app-capable" content="yes">
    </head>
    	<body onload="WL.Client.init({})" id="content" style="display: none">
    	<div data-dojo-type="dojox.mobile.View" id="view0"
    		data-dojo-props="selected:true">
    		<div data-dojo-type="custom.LocationViewer" id="locationViewer"></div>
    	</div>
    
    	<script src="js/Mashup.js"></script>
    		<script src="js/messages.js"></script>
    		<script src="js/auth.js"></script>
    	</body>
    </html>

Chạy ứng dụng

Để chạy và kiểm tra phiên bản đầu tiên của ứng dụng, bạn cần đưa ứng dụng tới máy chủ Worklight cục bộ. Worklight Studio V6 chứa một máy chủ cục bộ, bạn có thể sử dụng để kiểm tra mã nguồn. Nhấn chuột phải vào apps/Mashup và chọn Run as > Build All and Deploy. Lệnh này sẽ khởi tạo máy chủ cục bộ ở cổng 8080, chạy dự án, triển khai ứng dụng cho bạn để kiểm tra trong trình duyệt.

Hình 12. Triển khai ứng dụng trong Worklight Console
Hình 12. Ứng dụng được triển khai trong Worklight Console

Bạn có thể mở ứng dụng trong trình duyệt bằng cách nhấn vào biểu tượng hoặc liên kết Preview as Common Resources. Như mong đợi, vị trí hiện tại được hiển thị (Hình 13).

Hình 13. Xem trước ứng dụng
Hình 13. Xem trước ứng dụng

Phần ứng dụng phía máy chủ

Bước tiếp theo là thêm quyền truy cập tới tài nguyên cuối. Công cụ để thực hiện là sử dụng Worklight Adapters, kết nối các hệ thống cuối, phân tán dữ liệu đến và từ các ứng dụng di động, và thực thi bất kỳ thao tác logic trên dữ liệu bên máy chủ. Khung công tác Adapter cung cấp:

  • JavaScript mềm dẻo và mạnh mẽ bên máy chủ sinh ra mã nguồn cô đọng và dễ đọc cho việc tích hợp với các ứng dụng đầu cuối và xử lý nó. Bạn cũng có thể sử dụng XSL để truyền dữ liệu đầu cuối phân cấp tới JSON.
  • Hỗ trợ quyền read-only và giao dịch tới các hệ thống cuối.
  • Xác thực mềm dẻo thuận tiện cho việc tạo kết nối với các hệ thống cuối. Adapters đưa ra điều khiển dựa trên việc xác minh người dùng, kết nối được tạo.
  • Dữ liệu được nhận từ các ứng dụng cuối được đưa ra một cách phù hợp để bạn có thể truy cập dữ liệu đồng nhất, không quan tâm tới mã nguồn, định dạng, giao thức của nó.

Tạo LocationAdapter

Worklight cung cấp các adapter sau đây:

  • SQL adapter
  • HTTP adapter (hỗ trợ cả REST và SOAP)
  • Cast Iron adapter

Bạn sẽ sử dụng SQL adapter để truy cập thông tin được chứa bên trong cơ sở dữ liệu quan hệ.

Các thủ tục adapter được khai báo bằng cách sử dụng XML và thường được thực hiện trong JavaScript, nhưng bởi vì một adapter là một thực thể phía máy chủ, bạn có thể sử dụng đoạn mã Java trong mã adapter. Một thủ tục có thể xử lý dữ liệu trước hoặc sau khi gọi dịch vụ.

LocationAdapter là một adapter cơ bản truy vấn cơ sở dữ liệu DB2 với bảng như Liệt kê 8.

Liệt kê 8. Mã SQL để tạo cơ sở dữ liệu DB2
CREATE SCHEMA TRAVEL;
SET SCHEMA = TRAVEL;
	
DROP TABLE travel.locations;
CREATE TABLE travel.locations
	(
	city varchar(10),
	country varchar(20),
	stock varchar(10)
	);

DELETE FROM travel.locations;
INSERT INTO travel.locations values ( 'Paris', 'France', 'FCHI');
INSERT INTO travel.locations values ( 'London', 'UK', 'FTSE');
INSERT INTO travel.locations values ( 'New York', 'US', 'DJI');
INSERT INTO travel.locations values ( 'Frankfurt', 'Germany', 'GDAXI');
INSERT INTO travel.locations values ( 'Tokyo', 'Japan', 'N225');
INSERT INTO travel.locations values ( 'Madrid', 'Spain', 'IBEX');

Bạn có thể chạy mã SQL trên trong cơ sở dữ liệu của Worklight Studio hoặc trong bất kỳ công cụ nào tương tự. Để tạo LocationAdapter, nhấn chuột phải vào thư mục apps/Mashup trong Explorer và chọn New > Worklight Adapter. Cửa sổ New Worklight Adapter hiển thị (Hình 14).

Hình 14. Cửa sổ New Worklight Adapter
Hình 14. Worklight Adapter mới

Với loại Adapter, chọn SQL Adapter, và đối với tên Adapter, nhập vào LocationAdapter. Thao tác này sẽ tạo ra cấu trúc tệp dự án như hiển thị ở Hình 15.

Figure 15. Adapter file structure
Hình 15. Cấu trúc tệp Adapter

Bạn cần cập nhật LocationAdapter.xml để sử dụng kết nối cơ sở dữ liệu chính xác. Trong trường hợp này, tinh chỉnh nguồn dữ liệu cho cơ sở dữ liệu DB2 và đổi tên thủ tục chuẩn getLocations (Liệt kê 9).

Liệt kê 9. Kết nối LocationAdapter
<displayName>LocationAdapter</displayName>
<description>LocationAdapter</description>
<connectivity>
	<connectionPolicy xsi:type="sql:SQLConnectionPolicy">
		<dataSourceDefinition>
			<driverClass>com.ibm.db2.jcc.DB2Driver</driverClass>
			<url>jdbc:db2://localhost:50001/TRAVELDB</url>
		<user>user</user>
		<password>password</password> 
		</dataSourceDefinition>
</connectionPolicy>
<loadConstraints maxConcurrentConnectionsPerNode="5" />
</connectivity>
<procedure name="getLocations"/>

Bạn có thể nhấn chuột phải vào LocationAdapter.xml và chọn Open With > Adapter Editor để nhập vào cấu hình (Hình 16).

Hình 16. Trình soạn thảo Adapter
Hình 16. Adapter Editor

Logic của adapter được thực hiện trong adapters/LocationAdapter/LocationAdapter-impl.js. Một thủ tục được khai báo trong tệp XML của adapter cần được thực hiện trong tệp JavaScript tương ứng. Với câu lệnh SQL căn bản này, có hai phương thức được cung cấp bởi khung công tác Worklight adapter mà bạn có thể sử dụng:

  • WL.Server.createSQLStatement() tạo một đoạn lệnh SQL sau lời gọi WL.Server.invokeSQLStatement. Phương thức này có thể chỉ được sử dụng trong một thủ tục được khai báo trong SQL adapter. Nó cần được sử dụng bên ngoài phạm vi của hàm JavaScript. Phương thức này chấp nhận bất kỳ đoạn SQL hợp lệ bao gồm các dấu chấm hỏi (“?”) như một tham số và trả lại một đối tượng hiển thị đoạn lệnh SQL.
  • WL.Server.invokeSQLStatement() có 3 tham số:
    • Tham số preparedStatement được trả về bởi phương thức trên.
    • Một mảng các tham số tùy chọn đến câu lệnh
    • Tham số transformation: một XSL transformation tùy chọn cho phản hồi

    Phương thức trả lại một tập kết quả của câu lệnh, sau quá trình xử lý tùy chọn. (Xem bài IBM Worklight V5.0 Developer Reference Guide để biết thêm chi tiết.)

Sử dụng 2 phương thức trong quá trình thực hiện như Liệt kê 10.

Liệt kê 10. Thực hiện LocationAdapter
var procedure1Statement = WL.Server.createSQLStatement("select * from travel.locations 
	order by city");
function getLocations() {
	return WL.Server.invokeSQLStatement({
		preparedStatement : procedure1Statement,
		parameters : []
	});
}

Hãy chú ý sự đơn giản và tinh tế của đoạn mã. Một adapter như trên có thể được gọi trong bất kỳ ứng dụng Worklight, từ phía máy khách hoặc máy chủ. Nó cho phép bên gọi kết nối với nguồn dữ liệu mà không cần đưa ra các ràng buộc same-origin.

Bạn cũng cần một driver JDBC. Nếu bạn dã triển khai Worklight console trên WebSphere Application Server đã cấu hình trước, nó có thể có driver DB2 JDBC trong classpath. Với ví dụ này, bạn sẽ sử dụng công cụ Jetty HTTP được xây dựng sẵn, để hỗ trợ driver JDBC (db2jcc4.jar nếu bạn sử dụng driver loại số 4) từ quá trình cài đặt DB2 và copy nó tới thư mục server/lib, hoặc thêm vị trí của nó tới Jetty classpath.

Để chạy một kiểm thử của cấu hình và mã adapter, nhấn chuột phải vào adapters/LocationAdapter và chọn Run As > Invoke Worklight Procedure.

Hình 17. Gọi LocationAdapter
Hình 17. Gọi LocationAdapter

Trong cửa sổ Edit Configuration, chọn getLocations ở dòng Procedure name và nhấn Run. Thao tác này sẽ gọi adapter đích từ bên trong trình duyệt (Hình 18).

Hình 18. Kết quả lời gọi
Hình 18. Kết quả gọi

Tất cả bạn cần làm là triển khai adapter. Để làm điều này, nhấn chuột phải vào Adapter và chọn Run As > Deploy Worklight Adapter (Hình 19).

Hình 19. Triển khai LocationAdapter
Hình 19. Triển khai LocationAdapter

Worklight Studio lưu trữ mã adapter và triển khai nó trong máy chủ Worklight. Bạn có thể nhìn thấy adapter đã được triển khai trong Worklight Console, cùng với khởi tạo ứng dụng Mashup (Hình 20).

Hình 20. LocationAdapter được triển khai
Hình 20. LocationAdapter đã được triển khai

Chuỗi Adapter

Tương tự, bạn tạo hai adapter khác như thể hiện của HTTPAdapter. Hãy nhớ lại từ Hình 2, phần máy khách gọi NewsAadpater khi nó cần thông tin cho vị trị đặc biệt. Bạn truyền thông tin vị trí này tới server và tổ hợp dữ liệu từ hai nguồn – Google News Feed và Yahoo! Finance – phía máy chủ tổng hợp các nguồn khác nhau. Sự tổ hợp được gọi là chuỗi adapter (Hình 21).

Hình 21. Chuỗi adapter
Hình 21. Chuỗi các adapter

Chuỗi adapter cho phép tất cả quá trình xử lý bên máy chủ được thực thi bên trong một lời gọi máy khách duy nhất. Như sự tương tác “coarse grained” được xem xét là một cách thực hành tốt, và cách bạn sử dụng một mẫu tùy thuộc vào các yêu cầu cụ thể, ví dụ bao nhiêu dữ liệu cần được lưu trữ, chi phí để xử lý logic bên máy chủ là như thế nào, bạn có lưu bên phía máy khách và làm việc với dữ liệu cũ, v.v…. Tất nhiên, việc xem xét cấu trúc này là không mới hoặc bị giới hạn trong không gian lưu trữ di động, nhưng quan trọng là được tạo trong bất kỳ kiến trúc nhiều tầng nào.

Tạo các adapter còn lại

Đầu tiên bạn muốn thực hiện liên kết cuối cùng trong chuỗi, StockAdaptor. Đơn giản là gọi dịch vụ Yahoo! Finance. Kết nối được tinh chỉnh như Liệt kê 11.

Liệt kê 11. Kết nối StockAdapter
<displayName>StockAdapter</displayName>
<description>StockAdapter</description>
<connectivity>
	<connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
		<protocol>http</protocol>
		<domain>finance.yahoo.com</domain>
		<port>80</port>			
	</connectionPolicy>
	<loadConstraints maxConcurrentConnectionsPerNode="2" />
</connectivity>
<procedure name="getStock"/>

Lời gọi tới dịch vụ Yahoo! Finance cần một ký tự chứng khoán đặc biệt (mã chứng khoán nhà nước, ví dụ DJI hoặc FTSE) cùng với chi tiết cấu hình chính xác bạn muốn. Dịch vụ trả lại luồng dữ liệu CSV (Comma Separated Values). Với nguyên nhân này, đặt returnedContentType tới csv (Liệt kê 12). Đây là một chức năng tốt được cung cấp bởi khung công tác Adapter.

Liệt kê 12. Thực hiện StockAdapter
function getStock(stock) {
	var input = {
	    method : "get",
	    returnedContentType : "csv",
	    path : "d/quotes.csv",
		parameters : {
			"s" : "^" + stock,
			"f" : "sl1c1c"
		}
	};
	return WL.Server.invokeHttp(input);
}

Để gọi dịch vụ Google News, bạn cần thiết lập kết nối như hiển thị trong Liệt kê 13.

Liệt kê 13. Kết nối NewsAdapter
<displayName>NewsAdapter</displayName>
<description>NewsAdapter</description>
<connectivity>
	<connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
		<protocol>http</protocol>
		<domain>news.google.com</domain>
		<port>80</port>			
	</connectionPolicy>
	<loadConstraints maxConcurrentConnectionsPerNode="2" />
</connectivity>
<procedure name="getNews"/>

Bạn truyền thông tin vị trí và lấy về nội dung các kênh News RSS mà bạn quan tâm. Kênh RSS chứa một mảng phần tử, và để giữ dữ liệu nhỏ bạn vừa lấy phần từ đầu tiên của mảng. Chúng ta cũng sử dụng XSL để lọc nội dung mà bạn cần.

Liên kết tiếp theo trong chuỗi adapter là StockAdapter được gọi như một phần của hậu xử lý. Cách gọi sẽ được bàn luận trong phần tiếp theo. Cả 2 mẩu dữ liệu được tổ hợp vào đối tượng newsData (Liệt kê 14).

Liệt kê 14. Thực hiện NewsAdapter
function getNews(interest, stock)
{
	var input =
	{
		method : "get",
		returnedContentType : "html",
		path : "news",
		parameters :
		{
			"q" : interest,
			"output" : "rss"
		}
	};
	var newsData = WL.Server.invokeHttp(input).rss.channel.item[0];
	var stockData = WL.Server.invokeProcedure(
	{
		adapter : 'StockAdapter',
		procedure : 'getStock',
		parameters : [ stock ]
	});
	newsData["stock"] = stockData.text;
	return newsData;
}

Một cách ngắn gọn, NewsAdapter trả lại một mashup từ 2 nguồn mà bạn sẽ xử lý và hiển thị trong máy khách.

Gọi các adapter

Bạn đã hoàn thành việc thực hiện các adapter bên phía máy chủ. Bây giờ, bạn muốn gọi chúng từ máy khách. Đầu tiên, bạn cần một thành phần UI để lưu trữ dữ liệu vị trí được nhận. Chèn một ComboBox cơ bản trong tệp Mashup.html (Liệt kê 15).

Liệt kê 15. Thêm một ComboBox cho các vị trí
<body onload="WL.Client.init({})" id="content" style="display: none">
<div data-dojo-type="dojox.mobile.View" id="view0"
	data-dojo-props="selected:true">
	Available Locations <select id="availableLocations"
		onchange="javascript:changeLocation();">
		<option value="" disabled="disabled">Select a location</option>
	</select>
	<div data-dojo-type="custom.LocationViewer" id="locationViewer"></div>
</div>

Bạn đặt việc thực hiện thực tế, gọi các adapter vào js/Mashup.js. Tệp này được sinh ra tự động và là tệp JavaScript chính của ứng dụng. Nó chứa hàm wlCommonInit() sẽ được gọi trong suốt quá trình khởi động ứng dụng khi khung công tác Worklight hoàn thành khởi tạo. Nó là nơi tốt nhất để thêm mã khởi tạo ứng dụng của bạn. Hàm này cũng được sử dụng trong tệp JavaScript đặc tả môi trường để có điểm bắt đầu quá trình khởi tạo chung.

Liệt kê 16. Mã khởi tạo
var busyIndicator = null;
var adapterData = new Array();

function wlCommonInit()
{
	busyIndicator = new WL.BusyIndicator("view0");
	getLocations();
}

Tạo một busyIndicator cung cấp cho người dùng phản hồi rằng một hoạt động lâu dài đang diễn ra. Phương thức getLocation() là adapter đầu tiền gọi để điền đầy ComboBox với các vị trí hợp lệ (Liệt kê 17).

Liệt kê 17. Gọi LocationAdapter
function getLocations()
{
  busyIndicator.show();
  var invocationData =
  {
    adapter    : "LocationAdapter",
    procedure  : "getLocations",
    parameters : []
  };
  WL.Client.invokeProcedure(invocationData,
  {
    onSuccess : function(response)
    {
      busyIndicator.hide();
      if (response.invocationResult.resultSet.length != 0)
      {
        var locationList = response.invocationResult.resultSet;
        var availableLocations = document.getElementById("availableLocations");
        availableLocations.length[1] = null;
        for ( var i = 0; i < locationList.length; i++)
        {
          newLocation = new Option(locationList[i].CITY, locationList[i].CITY + ", "
 + locationList[i].COUNTRY + ":" +
                                  locationList[i].STOCK, false, true);
          availableLocations[i + 1] = newLocation;
        }
        availableLocations[0].selected = "selected";
      }
      else
      {
        WL.SimpleDialog.show("Mashup", "Adapter can't load locations. Check your 
database connection", [
        {
          text : "Reload app (via WL.Client.reloadApp)",
          handler : WL.Client.reloadApp
        } ]);
      }
    },
    onFailure : function()
    {
      busyIndicator.hide();
      WL.SimpleDialog.show("Mashup", "Adapter can't load locations. Check your 
database connection", [
      {
        text    : "Reload app (via WL.Client.reloadApp)",
        handler : WL.Client.reloadApp
      } ]);
    }
  });
}

Để gọi một thủ tục adapter, bạn cần một đối tượng invocationData mà bạn truyền tên của adapter và tên của thủ tục để gọi, cũng như một mảng các tham số tùy chọn. Khi hoàn thành lời gọi không đồng bộ, hàm onSuccess được gọi như một hàm gọi lại (callback) với đối tượng tương ứng. Hàm onFailure được gọi nếu lời gọi adapter bị lỗi. Nếu mọi thứ được thiết lập chính xác, mã khởi tạo điền đầy ComboBox (Hình 22).

Hình 22. Các vị trí hợp lệ nhận được từ adapter
Hình 22. Địa điểm có sẵn lấy thông qua adapter

Khi bạn chọn một vị trí, hàm changeLocation() được gọi. Ở đây, bạn duy trì cache cục bộ của dữ liệu adapter. Nếu bạn không ánh xạ thông tin vị trí, bạn gọi getNews() để nhận nó. Ngược lại, bạn sử dụng dữ liệu trong cache và hiển thị nó trên vị trí bản đồ phù hợp (Liệt kê 18).

Liệt kê 18. Thay đổi một vị trí
function changeLocation()
{
	var value = document.getElementById("availableLocations").value;
	var newLocation = value.split(":")[0];
	var newStock = value.split(":")[1];
	// Lazily load the Stock and News information
	if (adapterData[newLocation] == undefined)
	{
		busyIndicator.show();
		WL.Logger.debug("Load adapterData for " + newLocation);
		getNews(newLocation, newStock);
	}
	else
	{
		dijit.byId("locationViewer").refreshMap(newLocation,
				adapterData[newLocation]);
		busyIndicator.hide();
	}
}

Hàm này gọi thủ tục getNews từ NewsAdapter, nếu cần thiết và hiển thị giá trị trả lại trên bản đồ, bằng cách sử dụng mẫu lời gọi giống nhau như đã thảo luận ở trên (Liệt kê 19).

Liệt kê 19. Gọi NewsAdapter
function getNews(location, stock)
{
  var invocationData =
  {
    adapter    : 'NewsAdapter',
    procedure  : 'getNews',
    parameters : [ location, stock ]
  };
  WL.Client.invokeProcedure(invocationData,
  {
    onSuccess : function(response)
    {
      var stockData = response.invocationResult.stock.split(',');
      var news = ">b>" + location + ":>/b>>br>" +
          stockData[0].substring(2, stockData[0].length - 1) + ": " +
         stockData[1] + ">/b>" + ">font color=" +
         (stockData[2] > 0 ? "green>" : "red>" ) + " (Change: " +
         stockData[3].substring(2, stockData[3].length - 1) + ")>br>>a href=" +
         response.invocationResult.link + ">" +
         response.invocationResult.title + ">/a>";
      adapterData[location] = news;
      dijit.byId("locationViewer").refreshMap(location, news);
      busyIndicator.hide();
    },
    onFailure : function()
    {
      busyIndicator.hide();
      WL.SimpleDialog.show("Mashup",
                           "NewsAdapter can't load content for location " + location,
                 [{
                     text : "OK"
                 }]);
    }
  });
}

Hình 23 hiển thị những gì diễn ra khi bạn thử một vài vị trí.

Hình 23. Các vị trí hợp lệ nhận được thông qua adapter
Hình 23. Địa điểm có sẵn lấy thông qua adapter

Thêm một môi trường Worklight

Như trong phần giới thiệu, Worklight cung cấp cả môi trường phát triển và vận hành để hỗ trợ xây dựng ứng dụng cho các mục đích đặc biệt, bằng cách sử dụng một khái niệm gọi là environments (môi trường). Tương tự như ứng dụng web di động, Worklight Studio tạo môi trường giả lập khi bạn thêm vào một trong các môi trường.

Ví dụ, để thêm môi trường iPhone, nhấn chuột phải vào apps/Mashup và chọn New > Worklight Environment. Trong cửa sổ New Worklight Environment, chọn iPhone (Hình 24).

Hình 24. Thêm một môi trường Worklight
Hình 24. Thêm vào một môi trường Worklight

Bây giờ, Worklight tạo tất cả môi trường giả lập để chạy ứng dụng bạn đã tạo trên thiết bị iPhone. Một thư mục mới là iphone được thêm tự động tới dự án của bạn, và sẽ chỉ xuất hiện sau khi bạn build (xây dựng) và triển khai ứng dụng của bạn trên Worklight Server.

Build và triển khai ứng dụng và làm mới lại Worklight Console để xem biểu tượng mới để chạy ứng dụng trong bộ giả lập trình duyệt di động, nơi mà bạn chọn iPhone4 của Apple, Galaxy Ace của Samsung (Hình 25):

Hình 25. Chạy ứng dụng trong bộ mô phỏng trình duyệt di động
Hình 25. Mở ứng dụng trong trình di động giả lập

Kết luận

Bài này chỉ ra làm thế nào bạn có thể triển khai một ứng dụng di động lai sử dụng công nghệ mashup trong máy khách cũng như trên máy chủ. Bạn đã tạo một widget Dijit tùy biến và được sử dụng nó như một phần của ứng dụng, và cũng được phát triển một số adapter nhận dữ liệu cuối từ các nguồn khác nhau.


Tải về

Mô tảTênKích thước
Mã mẫuMashup-160812.zip6.8 MB

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=Nguồn mở
ArticleID=953097
ArticleTitle=Phát triển ứng dụng di động máy khách, máy chủ mashup với IBM Worklight
publish-date=11142013