text:
Giới thiệu
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
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
- Ứng dụng web di động được tải từ máy chủ Worklight.
- 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.
- Ứng dụng gọi adapter bên phía máy chủ để cung cấp danh sách các vị trí.
- 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.
- 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.
- Đầu tiên, NewsAdapter chọn dữ liệu từ Google News Feed.
- 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.
- 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
- Đặ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
- Đặ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
Đế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 documentation và Là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
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:
- 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:
- 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
- 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
- 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
- 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õ
declvà nhấn Ctrl+Space (Hình 9).
Hình 9. Định nghĩa Dijit widget không sử dụng wizard
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
' + Found using HTML5 Geolocation' }); 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) { … }
- 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

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.
- 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.
- 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
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ú . 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
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>   <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" />        <meta name="apple-mobile-web-app-capable" content="yes">

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
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
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
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
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
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
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
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
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
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
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í

 Available Locations <select id="availableLocations" onchange="javascript:changeLocation();"> <option value="" disabled="disabled">Select a location</option> </select>

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
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
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
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
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ề
Tài nguyên
Học tập
- Tài liệu người dùng IBM Worklight
- Các tính năng và lợi ích của IBM Worklight
- Loạt bài: Làm việc với Worklight
- Video: Worklight Studio 5.0 với Dojo
- Video: Dojo Mobile Showcase demonstrations
- Tài liệu Dojo
- Tạo một widget tùy chọn
- Tạo một widget Dojo tùy chọn
- Google Maps JavaScript API v3
- Tải về dữ liệu Yahoo
- Tạo một Widget Mashup Dojo
- Vùng di động trên IBM developerWorks
- IBM developerWorks WebSphere
Lấy sản phẩm và công nghệ
Thảo luận
Bình luận
-
Vùng dữ liệu trên developerWorks
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
-
Vùng mã nguồn mở trên developerWorks
Xem các bài viết về HTML, CSS, JavaScript,...
-
Điện toán đám mây
Tìm hiểu về điện toán đám mây

markdown:
## Giới thiệu
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](http://www-01.ibm.com/software/mobile-solutions/worklight/components/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](http://www-01.ibm.com/software/mobile-solutions/worklight/components/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](http://www-01.ibm.com/software/mobile-solutions/worklight/components/runtime/)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](http://www-01.ibm.com/software/mobile-solutions/worklight/components/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](images/image001.jpg)
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](images/image002.jpg)
- Ứng dụng web di động được tải từ máy chủ Worklight.
- 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.
- Ứng dụng gọi adapter bên phía máy chủ để cung cấp danh sách các vị trí.
- 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.
- 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.
- Đầu tiên, NewsAdapter chọn dữ liệu từ Google News Feed.
- 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.
- 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
- Đặ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
- Đặ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
Đế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 documentation](http://www.ibm.com/developerworks/vn/library/12/mo-aim1206-working-with-worklight-1/index.html) và [Là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](http://www.ibm.com/developerworks/vn/library/12/mo-aim1206-working-with-worklight-1/index.html) để
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](images/image006.jpg)
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:
**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:
- 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
- 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
- Nhấn chuột phải vào thư mục
**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](#amdside)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õ
declvà nhấn Ctrl+Space (Hình 9).
##### Hình 9. Định nghĩa Dijit widget không sử dụng wizard
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
' + Found using HTML5 Geolocation' }); 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) { … }
**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

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.
- 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.
- 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
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ú **. 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](http://public.dhe.ibm.com/ibmdl/export/pub/software/mobile-solutions/worklight/docs/Module_03_5_-_Rich_Page_Editor.pdf).)
##### Hình 11. Design mode 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>   <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" />
**** <meta name="apple-mobile-web-app-capable" content="yes">

### 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](images/image012.jpg)
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](images/image013.jpg)
## 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](images/image014.jpg)
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](images/image015.jpg)
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](images/image016.jpg)
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](http://public.dhe.ibm.com/ibmdl/export/pub/software/mobile-solutions/worklight/docs/wl_5_0_dev_env_install.pdf)để 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](images/image017.jpg)
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](images/image018.jpg)
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](images/image019.jpg)
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](images/image020.jpg)
### 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](images/image021.jpg)
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í

 Available Locations <select id="availableLocations" onchange="javascript:changeLocation();"> <option value="" disabled="disabled">Select a location</option> </select>

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](images/image022.jpg)
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](images/image023.jpg)
## 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](images/image024.jpg)
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](images/image025.jpg)
## 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ên||Kích thước|
|Mã mẫu|
## Tài nguyên
### Học tập
[Tài liệu người dùng IBM Worklight](http://www-01.ibm.com/software/mobile-solutions/worklight/library/) [Các tính năng và lợi ích của IBM Worklight](http://www-01.ibm.com/software/mobile-solutions/worklight/features/)
- Loạt bài:
[Làm việc với Worklight](http://www.ibm.com/developerworks/mobile/library/mo-aim1206-working-with-worklight-1/index.html)
- Video:
[Worklight Studio 5.0 với Dojo](http://www.youtube.com/watch?v=snkUTBVxLBw)
- Video:
[Dojo Mobile Showcase demonstrations](http://chrism.dojotoolkit.org/mobile-rc1/release/demos/demos/mobileGallery/demo-iphone.html) [Tài liệu Dojo](http://dojotoolkit.org/documentation/) [Tạo một widget tùy chọn](http://dojotoolkit.org/documentation/tutorials/1.7/recipes/custom_widget/) [Tạo một widget Dojo tùy chọn](http://publib.boulder.ibm.com/infocenter/radhelp/v8r5/index.jsp?topic=%2Fcom.ibm.etools.webtoolscore.doc%2Ftutorials%2Floan%2Floan_lesson2.html) [Google Maps JavaScript API v3](https://developers.google.com/maps/documentation/javascript) [Tải về dữ liệu Yahoo](http://www.aaiilosangeles.org/DonsPage/YahooDownload.htm) [Tạo một Widget Mashup Dojo](http://www.openlogic.com/wazi/bid/188024/) [Vùng di động trên IBM developerWorks](http://www.ibm.com/developerworks/mobile/?S_TACT=105AGY75) [IBM developerWorks WebSphere](http://www.ibm.com/developerworks/websphere/?S_TACT=105AGY75)
### Lấy sản phẩm và công nghệ
### Thảo luận
## Bình luận
[Vùng dữ liệu trên developerWorks](http://www.ibm.com/developerworks/vn/views/data/libraryview.jsp)
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
[Vùng mã nguồn mở trên developerWorks](http://www.ibm.com/developerworks/vn/views/opensource/libraryview.jsp)
Xem các bài viết về HTML, CSS, JavaScript,...
[Điện toán đám mây](http://www.ibm.com/developerworks/vn/views/cloud/libraryview.jsp)
Tìm hiểu về điện toán đám mây

Content-Language: en-US

Kp-eeAlive: timeout=10, max=92


text:
Giao Hàng Toàn Quốc - Thanh Toán Khi Nhận Hàng
Cam kết cho đổi trả, hoàn tiền 100% nếu không hài lòng về sản phẩm
Best Breast Enlargement Cream là cứu tinh cho vòng một khiếm khuyết của chị em.
Best Breast Enlargement Cream Xuất xứ Thụy Điển
Sản phẩm được đánh giá hiệu quả nở ngực tốt nhất hiện nay
Giá gốc : 1,500,000 vnd
1,400,000 vnd
Kem "Best Breast Enlargement Cream" có tác dụng giúp vòng một căng tròn ,săn chắc và mịn màng, đẹp tự nhiên cho những phụ nữ có vòng ngực khiêm tốn, bầu ngực nhỏ hoặc không có ngực, lấy lại sự tự tin cho bạn trong từng bước đi. Kem còn có tác dụng trị nhăn ở vùng ngực cho những phụ nữ đã có tuổi hoặc sau khi sinh bầu ngực bị nhỏ và teo lại .
Ngoài ra, kem nở ngực "Best Breast Enlargement Cream" còn có công dụng làm hồng nhũ hoa cho những phụ nữ có đầu nhũ bị sạm đen, xù xì, thô ráp kem giúp làm mềm và cải thiện rõ rệt đầu nhũ Với thành phần 100% dược thảo tự nhiên kem "Best Breast Enlargement Cream" không gây kích ứng da, không bị ửng đỏ, ngứa hoặc bất kỳ tác dụng phụ nào và đã được kiểm nghiệm rất kỹ lưỡng về độ an toàn, tính nguyên chất và sự hiệu quả để mang lại những tác dụng nhanh chóng!
Những hiệu quả chính:
- Tăng kích thước và làm mở rộng cấu trúc tế bào của bộ ngực một cách đều đặn.
- Thúc đẩy sự phát triển của các hốc và các thuỳ trong ngực, tăng tính đàn hồi của các mô ngực.
- Cảm nhận được kết quả chỉ trongthời gian ngắn !
- 100% sản phẩm tự nhiên sẽ đi đôi với việc trông thấy và cảm nhận bộ ngực tự nhiên.
- Sử dụng cho tất cả các chị em phụ nữ, không phân biệt sắc dân.
- Giúp điều hòa hóc môn nữ và giảm các triệu chứng đau ngực trong thời kỳ kinh nguyệt.
- Cải thiện hình dáng và kích thước của bộ ngực để bạn hấp dẫn hơn
- Kích thích máu nuôi dưỡng da vùng ngực tốt hơn
- Chống chảy sệ và làm săn chắc bộ ngực của bạn.
- Không gây tăng cân, an toàn & hiệu quả, không có tác dụng phụ gây hại, - Phương pháp thay thế hiệu quả tuyệt đối so với phẫu thuật thẩm mỹ.
Sau khi tắm sạch. Bạn lấy một lượng kem vừa đủ ra lòng bàn tay. Thoa đều lên bầu ngực, dùng tay massage nhẹ nhàng theo chiều kim đồng hồ từ ngoài vào trong, từ dưới lên trên, vừa vuốt nhẹ tay vừa kéo ngực lên và đẩy vào giữa. Mỗi ngày có thể sử dụng 2 lần. buổi sáng sau khi masage khoảng 5_10 Phút bạn có thể mặc áo ngực để đi làm bình thường. Và một lần vào buổi tối khi bạn có thể dành hoàn toàn thời gian để chăm sóc vẻ đẹp cho mình.Chỉ trong thời gian ngắn sử dụng đêu đặn bạn sẽ cảm nhận ngay sự khác biệt mà phẩm Best Breast Enlargement Cream mang lại.
Lưu ý: Không dùng cho phụ nữ đang trong thời kỳ cho con bú.
Đóng gói: 50 gram/lọ.
Để phát huy hiệu quả tốt nhất nên dùng kết hợp viên uống nở ngực
Viên uống nở ngực nhau thi cừu Queen 9 Làm tăng kích thước bộ ngực, chống chảy xệ - Làm săn chắc ngực - Làm đẹp da - Khử vết nám, sạm da - Điều hòa kinh nguyệt - Chống lão hóa
480,000 vnd
CÔNG TY MỸ PHẨM WHITE DOCTORS
Địa Chỉ : 262/05 Cách Mạng Tháng 8, Phường 10, Quận 3, TP. HCM

markdown:
Best Breast Enlargement Cream là cứu tinh cho vòng một khiếm khuyết của chị em.
Best Breast Enlargement Cream Xuất xứ Thụy Điển
Sản phẩm được đánh giá hiệu quả nở ngực tốt nhất hiện nay
Giá gốc : 1,500,000 vnd
**1,400,000 vnd**
Kem "Best Breast Enlargement Cream" có tác dụng giúp vòng một căng tròn ,săn chắc và mịn màng, đẹp tự nhiên cho những phụ nữ có vòng ngực khiêm tốn, bầu ngực nhỏ hoặc không có ngực, lấy lại sự tự tin cho bạn trong từng bước đi. Kem còn có tác dụng trị nhăn ở vùng ngực cho những phụ nữ đã có tuổi hoặc sau khi sinh bầu ngực bị nhỏ và teo lại .
Ngoài ra, kem nở ngực "Best Breast Enlargement Cream" còn có công dụng làm hồng nhũ hoa cho những phụ nữ có đầu nhũ bị sạm đen, xù xì, thô ráp kem giúp làm mềm và cải thiện rõ rệt đầu nhũ Với thành phần 100% dược thảo tự nhiên kem "Best Breast Enlargement Cream" không gây kích ứng da, không bị ửng đỏ, ngứa hoặc bất kỳ tác dụng phụ nào và đã được kiểm nghiệm rất kỹ lưỡng về độ an toàn, tính nguyên chất và sự hiệu quả để mang lại những tác dụng nhanh chóng!
Những hiệu quả chính:
- Tăng kích thước và làm mở rộng cấu trúc tế bào của bộ ngực một cách đều đặn.
- Thúc đẩy sự phát triển của các hốc và các thuỳ trong ngực, tăng tính đàn hồi của các mô ngực.
- Cảm nhận được kết quả chỉ trongthời gian ngắn !
- 100% sản phẩm tự nhiên sẽ đi đôi với việc trông thấy và cảm nhận bộ ngực tự nhiên.
- Sử dụng cho tất cả các chị em phụ nữ, không phân biệt sắc dân.
- Giúp điều hòa hóc môn nữ và giảm các triệu chứng đau ngực trong thời kỳ kinh nguyệt.
- Cải thiện hình dáng và kích thước của bộ ngực để bạn hấp dẫn hơn
- Kích thích máu nuôi dưỡng da vùng ngực tốt hơn
- Chống chảy sệ và làm săn chắc bộ ngực của bạn.
- Không gây tăng cân, an toàn & hiệu quả, không có tác dụng phụ gây hại, - Phương pháp thay thế hiệu quả tuyệt đối so với phẫu thuật thẩm mỹ.
**Cách sử dụng kem: **
Sau khi tắm sạch. Bạn lấy một lượng kem vừa đủ ra lòng bàn tay. Thoa đều lên bầu ngực, dùng tay massage nhẹ nhàng theo chiều kim đồng hồ từ ngoài vào trong, từ dưới lên trên, vừa vuốt nhẹ tay vừa kéo ngực lên và đẩy vào giữa. Mỗi ngày có thể sử dụng 2 lần. buổi sáng sau khi masage khoảng 5_10 Phút bạn có thể mặc áo ngực để đi làm bình thường. Và một lần vào buổi tối khi bạn có thể dành hoàn toàn thời gian để chăm sóc vẻ đẹp cho mình.Chỉ trong thời gian ngắn sử dụng đêu đặn bạn sẽ cảm nhận ngay sự khác biệt mà phẩm Best Breast Enlargement Cream mang lại.
Lưu ý: Không dùng cho phụ nữ đang trong thời kỳ cho con bú.
Đóng gói: 50 gram/lọ.
**Để phát huy hiệu quả tốt nhất nên dùng kết hợp viên uống nở ngực **
|
|

WARC-Type: response

Content-Type: application/http; msgtype=response

WARC-Truncated: length

Content-Encoding: gzip

Vary: Accept-Encoding

Server: LiteSpeed

Connection: close

P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"

Set-Cookie: ja_nickel_tpl=ja_nickel; expires=Wed, 12-Aug-2015 01:57:49 GMT; path=/

Content-Type: text/html; charset=utf-8

Cache-Control: post-check=0, pre-check=0

Pragma: no-cache


text: Hẳn là có rất nhiều bạn gặp lỗi này khi up rom cho 9900/9930: - Cài đủ các loại rom vào nhưng máy vẫn không chịu nhận (dù đã xóa vendor.xml trong Apploader) - Up lên 7.1, muốn xuống 7.0 nhưng cài 7.0 kiểu gì máy cũng nhận, đành quay lại 7.1 - Các lỗi tương tự khi up rom, nói chung là máy không nhận rom theo ý muốn Mình có tìm hiểu và thấy rằng lỗi phần lớn xảy ra do nguyên nhân này: các loại rom 7.0, 7.1 còn cài đặt thêm 1 file vendor.xml nữa ở đây: •64-bit: Computer\C:\Users\{USER NAME}\AppData\Roaming\Research In Motion\BlackBerry\Loader XML •32-bit: Computer\C:\Documents and Settings\{USER NAME}\Application Data\Research In Motion\BlackBerry\Loader XML Chính file này khiến cho máy không nhận rom. Giải pháp: 1. Các bạn có thể vào tận folder như trên để xóa vendor.xml 2. Nhanh nhất, các bạn download chương trình Vendor XML Remover. Hướng dẫn sử dụng: - Chạy chương trình - Chọn English - Chọn Delete. Thế là xong, tất cả các file vendor.xml đã được xóa, bạn thử up rom lại xem kết quả có khác không nhé

Cache-control: private, max-age=0

X-Frame-Options: SAMEORIGIN

Content-Type: text/html; charset=UTF-8

Vary: User-Agent


text:
Mua máy ảnh cũ giá cao
chuyên Sửa chữa máy ảnh kỷ thuật số,máy quay phim,camera tại HCM (uy tín -chất lượng)
Cty TNHH 1 TV TM & KTS LÊ SAN
ĐC:402 Nguyễn Công Trứ Phường Cầu ông Lãnh Quận 1 Tp.HCM
www.lesancamera.com : www.lesancamera.net
HOTLINE: 0907.008.752 ( Phong)
A1000 168 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
A1100 189 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
SD1200 219 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
SD970 365 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXUS 95 223 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXUS 100 263 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXUS 110 292 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXUS 990 370 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXY 110 215 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXY 920 242 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
IXY 510 265 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
G10 500 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
SX200 365 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
SX1 IS 518 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini
Máy ảnh KTS Sony
S930 2.511.000 VND ( BH 24 tháng toàn quốc )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
W180 170 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
W190 190 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
W210 199 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
W220 205 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
W230 215 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
W270 230 $ ( BH 12 tháng )
Khuyến mãi : bao da + miếng dán LCD + chân mini
W290 258 $ ( BH 12 tháng )
Khuyến mãi : bao da + miếng dán LCD + chân mini
T900 333 $ ( BH 12 tháng )
Khuyến mãi : bao da + miếng dán LCD + chân mini
T90 290 $ ( BH 12 tháng )
Khuyến mãi : bao da + miếng dán LCD + chân mini
H20 303 $ ( BH 12 tháng )
Khuyến mãi : bao da + miếng dán LCD + chân mini
HX1 9.890.000 VND ( BH 24 tháng toàn quốc )
Khuyến mãi : Thẻ nhớ Sony 2GB + bao da + miếng dán LCD + chân mini
Máy ảnh KTS Olympus
M1070 220 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ CF 2GB + bao da + miếng dán LCD
M7000 285 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ CF 4GB + bao da + miếng dán LCD
Máy ảnh KTS Nikon
L19 120 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
L20 178 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
L100 300 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD
P90 420 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD
Máy ảnh KTS Panasonic
TZ4 235 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
FX580 305 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
TZ7 415 $ ( BH 12 tháng )
Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini
Máy ảnh KTS Fujifilm
A100 109 $ ( BH 24 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
J10 127 $ ( BH 24 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
J20 139 $ ( BH 24 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
J100 150 $ ( BH 24 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
F480 137 $ ( BH 24 tháng )
Khuyến mãi : Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini
Sony CyberShot DSC-W55
Olympus Stylus-810 (Olympus Mju-810 / Olympus µ-810)
Olympus CAMEDIA SP-700
Canon PowerShot A580 - Mỹ / Canada
Canon PowerShot G10 - Nhật
Canon PowerShot SX520 HS
Canon PowerShot SX400 IS
Olympus Stylus TG-835
Casio Exilim EX-100
Casio Exilim EX-M2
Casio Exilim EX-S2
Sanyo VPC-E2100
Samsung Galaxy Camera Wi-Fi EK-GC110 (Black)
Canon PowerShot S200
Fujifilm AX600
Canon IXUS 155 - Châu Âu
Canon IXUS 145
Sony Cybershot DSC-RX100 III
GoPro HERO3+ Silver Edition
GoPro HERO3 White Edition Slim
GoPro HERO3+ Black Edition (Outdoor Cover)
GoPro HERO3+ Black Edition Surf
GoPro HERO3+ Black Edition (Motorsport Cover)
Nikon Coolpix S810c
Olympus Tough TG-3
Olympus Stylus SH-1
Digipo DC-T400
Digipo DC-1100

markdown:
Mua máy ảnh cũ giá cao
chuyên Sửa chữa máy ảnh kỷ thuật số,máy quay phim,camera tại HCM (uy tín -chất lượng)
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|Siêu VIP còn trống
|
Liên hệ Q.Cáo
0915.753.589
|
|
Tin rao vặt này đã hết hạn! Tin lưu trữ..
Bạn hãy vào mục
|
|
|
|
|
|
|Đăng bởi :||
|![]()
|Thông tin chung||
|
|Hãng sản xuất|
|Thông tin chi tiết||
|
*Cty TNHH 1 TV TM & KTS LÊ SAN*
ĐC:402 Nguyễn Công Trứ Phường Cầu ông Lãnh Quận 1 Tp.HCM
[www.lesancamera.com](http://www.lesancamera.com/) : [www.lesancamera.net](http://www.lesancamera.net/) **HOTLINE: 0907.008.752 ( Phong) ** ** A1000 168 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** A1100 189 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **SD1200 219 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **SD970 365 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** IXUS 95 223 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** IXUS 100 263 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **IXUS 110 292 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **IXUS 990 370 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **IXY 110 215 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** IXY 920 242 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** IXY 510 265 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** G10 500 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** ** SX200 365 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **SX1 IS 518 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ SD 4GB + bao da + miếng dán LCD + chân mini** **Máy ảnh KTS Sony** ** S930 2.511.000 VND ** **( BH 24 tháng toàn quốc** ** )** **Khuyến mãi : Thẻ nhớ 2GB **+ **bao da + miếng dán LCD + chân mini** **W180 170 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** ** W190 190 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** ** W210 199 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** ** W220 205 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** **W230 215 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** **W270 230 $ ** **( BH 12 tháng )** **Khuyến mãi : bao da + miếng dán LCD + chân mini** **W290 258 $ ** **( BH 12 tháng )** **Khuyến mãi : bao da + miếng dán LCD + chân mini** **T900 333 $** ** ( BH 12 tháng )** **Khuyến mãi : bao da + miếng dán LCD + chân mini** **T90 290 $** ** ( BH 12 tháng )** **Khuyến mãi : bao da + miếng dán LCD + chân mini** **H20 303 $** ** ( BH 12 tháng )** **Khuyến mãi : bao da + miếng dán LCD + chân mini** **HX1 9.890.000 VND ** **( BH 24 tháng toàn quốc** ** )** **Khuyến mãi : Thẻ nhớ Sony 2GB + bao da + miếng dán LCD + chân mini** **Máy ảnh KTS Olympus ** ** M1070 220 $ ** **( BH 12 tháng )** ** Khuyến mãi : ** **Thẻ nhớ CF 2GB + bao da + miếng dán LCD** **M7000 285 $ ** **( BH 12 tháng )** ** Khuyến mãi : ** **Thẻ nhớ CF 4GB + bao da + miếng dán LCD** **Máy ảnh KTS Nikon** **L19 120 $ ** **( BH 12 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini** **L20 178 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB +** **bao da + miếng dán LCD + chân mini** **L100 300 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB +** **bao da + miếng dán LCD ** **P90 420 $ ** **( BH 12 tháng )** **Khuyến mãi : Thẻ nhớ 4GB +** **bao da + miếng dán LCD ** **Máy ảnh KTS Panasonic** ** TZ4 235 $ (** ** BH 12 tháng )** **Khuyến mãi : ** **Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** **FX580 305 $ ** **(** ** BH 12 tháng )** **Khuyến mãi : ** **Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** **TZ7** ** 415 $ ** **(** ** BH 12 tháng )** **Khuyến mãi : ** **Thẻ nhớ 4GB + bao da + miếng dán LCD + chân mini** **Máy ảnh KTS Fujifilm ** **A100 109 $ ** **(** ** BH 24 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini** **J10** ** 127 $ ** **(** ** BH 24 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini** **J20** ** 139 $ ** **(** ** BH 24 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini** **J100** ** 150 $ ** **(** ** BH 24 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini** **F480** ** 137 $ ** **(** ** BH 24 tháng )** **Khuyến mãi : ** **Thẻ nhớ 2GB + bao da + miếng dán LCD + chân mini**
Sony CyberShot DSC-W55
Olympus Stylus-810 (Olympus Mju-810 / Olympus µ-810)
Olympus CAMEDIA SP-700
Canon PowerShot A580 - Mỹ / Canada
Canon PowerShot G10 - Nhật
Canon PowerShot SX520 HS
Canon PowerShot SX400 IS
Olympus Stylus TG-835
Casio Exilim EX-100
Casio Exilim EX-M2
Casio Exilim EX-S2
Sanyo VPC-E2100
Samsung Galaxy Camera Wi-Fi EK-GC110 (Black)
Canon PowerShot S200
Fujifilm AX600
Canon IXUS 155 - Châu Âu
Canon IXUS 145
Sony Cybershot DSC-RX100 III
GoPro HERO3+ Silver Edition
GoPro HERO3 White Edition Slim
GoPro HERO3+ Black Edition (Outdoor Cover)
GoPro HERO3+ Black Edition Surf
GoPro HERO3+ Black Edition (Motorsport Cover)
Nikon Coolpix S810c
Olympus Tough TG-3
Olympus Stylus SH-1
Digipo DC-T400
Digipo DC-1100

Server: Apache

Set-Cookie: history_raovat=1219741%7C0; path=/

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0