Thứ Sáu, 2 tháng 9, 2016

Tạo ứng dụng mobile thực hiện quản lý chi tiêu của cá nhân trên Android sử dụng Web Services

Xây dựng một hệ thống ứng dụng sử dụng trên Web Site lẫn thiết bị di động. Ứng dụng này cho phép thiết bị di động kết nối Web Service để yêu cầu xử lý chức năng. Ngoài ra, ứng dụng có thể đồng bộ giữa thiết bị di động và Web Site

Part 4: Tạo web service trả về định dạng JSON và consume webservice sử dụng ứng dụng trên nền Android

Tác giả: Phạm Huy Hoàng

Mục đích: Tiếp nối chủ đề đã trình bày ở phần 3 (http://www.kieutrongkhanh.net/2016/09/tao-ung-dung-mobile-thuc-hien-quan-ly_2.html ), chúng tôi sẽ hướng dẫn cách tạo Web Service với định dạng trả về JSON cho client. Bên cạnh đó, chúng tôi sẽ hướng dẫn cách consume web service từ client, thông qua thư viện Http Apache có sẵn của Android.

Part 4: Tạo web service trả về định dạng JSON và consume webservice sử dụng ứng dụng trên nền Android

Tác giả: Phạm Huy Hoàng

Mục đích: Tiếp nối chủ đề đã trình bày ở phần 3 (http://www.kieutrongkhanh.net/2016/09/tao-ung-dung-mobile-thuc-hien-quan-ly_2.html ), chúng tôi sẽ hướng dẫn cách tạo Web Service với định dạng trả về JSON cho client. Bên cạnh đó, chúng tôi sẽ hướng dẫn cách consume web service từ client, thông qua thư viện Http Apache có sẵn của Android.

Yêu cầu về kiến thức cơ bản:

·         Nắm vững khái niệm về ngôn ngữ lập trình Java, lập trình thao tác hướng đối tượng .

·         Biết một số khái niệm cơ bản về Web Service, cách gửi nhận, bind dữ liệu tới Web Service.

·         Biết cách đọc, viết, parse JSON.

·         Có kiến thức cơ bản về giao thức HTTP, các giao thức GET, POST, cách post form v….v

 

Như đã đề cập ở part 1 (http://www.kieutrongkhanh.net/2016/09/xay-dung-mot-he-thong-ung-dung-su-dung.html ), chúng ta sẽ bổ sung thêm 1 số field vào Database để thực hiện công việc đồng bộ (nội dung này sẽ đề cập ở part 5 trong loạt bài viết này).

Chúng ta bổ sung thêm field LastEdited và IsActive trong bảng Transaction, chuyển lại thời gian là smalldatetime thay vì datetime. (Smalldatetime lưu thời gian theo phút, datetime lưu thời gian theo milisecond, do đó dùng datetime tốn ít bộ nhớ + dễ so sánh thời gian hơn).

Description: C:\Users\Hoang\Desktop\2.JPG

Chúng ta thực hiện sửa file config của Hibernate và file DTO

Description: C:\Users\Hoang\Desktop\1.JPG

Description: C:\Users\Hoang\Desktop\4.JPG

Đồng thời, chúng ta thực hiện sửa lại câu query trong TransactionDAO. Ở hàm insert, chúng ta cho return giá trị int, đây là giá trị ID được server auto-generate khi insert.

Tiếp theo, chúng ta bổ sung một số trường cần lưu, cũng như inActive một transaction thay cho delete. Chúng  ta cập nhật những bổ sung này trong file TransactionAction

Description: C:\Users\Hoang\Desktop\5.JPG

Deploy & Run, chúng ta được kết quả như cũ, chỉ khác một số trường lưu trữ trong database. Mỗi khi chúng ta edit hay delete một transaction, giá trị lastEdited sẽ được cập nhật. Sau này chúng ta sẽ dựa theo giá trị này để thực hiện việc đồng bộ.

 

Description: C:\Users\Hoang\Desktop\6.JPG

Chúng ta tiếp tục sửa database bên ứng dụng android.

Bổ sung thêm 1 số property cho class Transaction (ServerID mặc định khi tạo là 0. Sau khi đồng bộ, ID này chính là TransactionID nằm trên database của server. Khi có edit ở client, chúng ta dựa theo id này để edit transaction tương ứng trên server)

Description: C:\Users\Hoang\Desktop\7.JPG

Chúng ta bổ sung thêm 1 số cột trong DatabaseUtils. Quý vị nhớ tăng database version để hàm onUpgrade được gọi, tạo lại bảng. Chúng ta cũng thực hiện việc sửa lại format time để có thể lưu được 24h, bỏ giây

 

Chúng ta sửa câu lệnh SQL tạo bảng

Description: C:\Users\Hoang\Desktop\12.JPG

Đồng thời, chúng ta sửa một số hàm thêm bớt xóa sửa.

Ở hàm getAll, chúng ta chỉ lấy câu những transaction có trạng thái là active. Do đó, chúng ta sửa lại câu lệnh SQL truyền vào.

 

Description: C:\Users\Hoang\Desktop\8.JPG

 

Description: C:\Users\Hoang\Desktop\9.JPG

Description: C:\Users\Hoang\Desktop\10.JPG

Ở hàm delete, chúng ta không delete mà chuyển qua transaction qua thành inactive.

Chúng ta mở file layout của activity main, sửa lại id của label

Description: C:\Users\Hoang\Desktop\13.JPG

Trong class MainActivity, chúng ta sửa code để hiển thị tổng số tiền của các transaction

Description: C:\Users\Hoang\Desktop\14.JPG

 

Hàm reload được gọi mỗi khi thêm bớt xóa sửa

Description: C:\Users\Hoang\Desktop\15.JPG

Sửa lại 1 số code insert, update, delete, quý vị chú ý những đoạn bôi đỏ

Description: C:\Users\Hoang\Desktop\16.JPG

Thực hiện chạy chương trình. Chúng ta sẽ không thấy gì vì database đã tạo lại nên ta sẽ không thấy entry nào.

Description: C:\Users\Hoang\Desktop\16_2.JPG

Giao diện

Description: C:\Users\Hoang\Desktop\17.JPGDescription: C:\Users\Hoang\Desktop\18.JPGDescription: C:\Users\Hoang\Desktop\19.JPGDescription: C:\Users\Hoang\Desktop\20.JPG

Database sau khi sửa đổi

Description: C:\Users\Hoang\Desktop\21.JPG

Chúng ta đã bổ sung đầy đủ những field cần thiết trong database ở server và client.

=====================================================

Nguyên lý: Vì một Action của Struts2 có khả năng nhận thông tin truyền về server dưới giao thức POST/GET, tự động mapping vào property của action, đồng thời có thể đưa ra kết quả dưới dạng JSON/XML. Do đó, thay vì tạo một Web Service mới, chúng ta có thể dùng một Action thay thế Web Service, việc config, mapping v..v sẽ đơn giản hơn rất nhiều.

 

Bước tiếp theo, chúng tôi sẽ hướng dẫn quý vị cách viết Web Service đơn giản, sử dụng Action của Struts2.

 

Đầu tiên, chúng ta sửa lại 1 chút hàm insert trong TransactionDAO, hàm này sẽ trả ra ID của transaction vừa tạo (sẽ dùng vào bài sau). Đồng thời bổ sung thêm function clear. (Chúng ta dùng Raw SQL nên bảng Transaction phải có ngoặc vuông).

Quý vị cài đặt thư viện gson mới nhất vào project, cách cài đặt xem lại ở đầu bài viết này: http://www.kieutrongkhanh.net/2016/08/phan-2-tim-hieu-ve-google-calendar-api.html

Phần library sau khi cài đặt

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Da

 

 

Chúng ta tiếp tục tạo một action với tên gọi là ServiceAction

Description: C:\Users\Hoang\Desktop\1.JPG

Như chúng ta đã biết, khi user gửi về thông tin về server (Dưới dạng POST form hoặc thông qua query string), các giá trị này sẽ được map vào property tương ứng của action (Lưu ý: quý vị cần tạo getter setter thì các property này mới được map vào, nếu không các property này sẽ luôn luôn null). Do đó, ở client, chúng ta sẽ sử dụng thư viện HTTP Apache, thực hiện việc post dữ liệu tới action này.

 

Trong action thông thường, chúng ta return string để redirect tới trang. Ở đây, vì chúng ta tạo web service, do đó chúng ta sẽ không redirect mà sẽ đưa kết quả ra dưới dạng JSON. Quý vị nhớ setEncoding và contentType.

Description: C:\Users\Hoang\Desktop\2.JPG

Mỗi function của action tương đương với mỗi function của web service, cho nên chúng ta return null để Struts không redirect, chỉ in ra JSON.

Description: C:\Users\Hoang\Desktop\3.JPG

Description: C:\Users\Hoang\Desktop\4.JPG

Chúng ta thực hiện mapping các function đã viết trong file struts.xml

Description: C:\Users\Hoang\Desktop\5.JPG

Chúng ta deploy, test service vừa viết. (Ở đây, chúng tôi truyền params dưới dạng query string, quý vị cần gọi đúng action + truyền đúng params).

Description: C:\Users\Hoang\Desktop\6.JPG

Description: C:\Users\Hoang\Desktop\7.JPG

Description: C:\Users\Hoang\Desktop\8.JPG

Description: C:\Users\Hoang\Desktop\9.JPG

Description: C:\Users\Hoang\Desktop\10.JPG

Cách viết web service vừa rồi còn 1 số khuyết điểm:

·         Cần phải mapping nhiều action.

·         Người dùng web service phải thay đổi url nhiều lần theo tên action.

·         Mỗi lần thêm 1 function cho webservice, ta phải mapping thêm trong file XML

Chúng ta thực hiện cải tiến lại như sau

 

Bổ sung thêm một property là action, (Lưu ý: phải tạo getter setter cho property này)

Description: C:\Users\Hoang\Desktop\11.JPG

Sửa các function vừa viết thành private, sau đó viết function service

Description: C:\Users\Hoang\Desktop\12.JPG

Mapping lại XML, bỏ toàn bộ những action trong package service đã mapping, chỉ mapping một action duy nhất là service

Description: C:\Users\Hoang\Desktop\13.JPG

Khi dùng service này, ta giữ nguyên url là service.action, chỉ cần truyền param “action” và là được

Description: C:\Users\Hoang\Desktop\14.JPG

Ví dụ muốn bổ sung function clear, chúng ta chỉ cần viết thêm function, đồng thời sửa function service.

Tới đây, chúng ta đã hoàn thành phần web service, tiếp theo, chúng ta sẽ viết phần consume web service trên android.

Để dễ hiểu, quý vị vui lòng xem ảnh minh họa flow xử lý dữ liệu

Giải thích:

1.    Các property của 1 object được chuyển thành form.

2.    Form này sẽ được post lên server, gọi web service dựa theo chuỗi Url

3.    Ở server, web service sẽ map các params trong form với property của Action, xử lý và trả ra chuỗi JSON.

4.    Từ chuỗi JSON trả về, client sẽ parse thành một object (hoặc một list các object) hoàn chỉnh.

5.  Quá trình gửi nhận dữ liệu thông qua form và chuỗi JSON, do đó hoàn toàn platform-independence. Server có thể code bằng mọi ngôn ngữ, chỉ cần có thể đọc params từ form, trả ra chuỗi json. Tương tự, Client có thể code bằng mọi ngôn ngữ, chỉ cần có thể truyền params dưới dạng form, parse chuỗi json ra object.

 

Ở Android, việc gọi URL, truyền params theo form đã được hỗ trợ bởi thư viện HTTP Apache tích hợp sẵn trong Android. Tuy nhiên chúng ta cần add thêm thư viện Gson hỗ trợ việc parse JSON. Quý vị chỉ cần paste file jar vào thư mục libs của project android hiện hành.

Chúng ta bổ sung thêm class Account, đồng thời bổ sung annotation cho class DTO

Chúng ta thực hiện mapping field transactionId trong chuỗi json vào property serverId. Vì vậy, chúng ta phải bổ sung annotation SerializedName.

Chúng ta bắt đầu viết class ServiceUtils, đây là class để gọi web serivce.

Quý vị vui lòng đọc comment để hiểu cách thực hiện trực tiếp trên các câu lệnh. 

Lưu ý: Ở đây, chúng tôi sử dụng giả lập, ta đổi giá trị localhost là 10.0.2.2. Nếu quý vị test trên device thật, quý vị phải để device và máy chủ host Tomcat chung network, thay giá trị localhost bằng IP của máy chủ.

Bấm Details...

 

Chúng ta bắt đầu viết các hàm gọi web service. Chúng tôi đã cố gắng thuyết minh rõ ràng bằng comment trong function checkLogin, các function còn lại quí vị thực hiện tương tự.

 

Chúng ta sẽ chuyển chương trình đã viết sang online. Đầu tiên, chúng ta tạo 1 layout chứa form login.

Description: C:\Users\Hoang\Desktop\16.JPG

Quý vị kéo thả layout để có kết quả như sau, chú ý id của các control.

Quý vị copy class MainActivity ra một file khác, đặt tên là MainActivityOnl. Cấu trúc project hiện hành

Quý vị chú ý một số chỗ cần sửa trong class MainActivityOnl

Chúng ta bổ sung hàm showLoginDialog. Lấy username, password mà user nhập vào, sau đó lưu userId lại, dùng cho việc gọi web serivce (Get Transactions, Insert, Delete v…v).

Chúng ta bổ sung thêm 1 button Refresh cạnh button Clear

 

Bước cuối cùng, chúng ta vào Android Mainfest, sửa Activity được gọi là MainActivityOnl.

Vì chúng ta gọi WebService nên quý vị phải bổ sung permission INTERNET, nếu không sẽ bị lỗi “connection refuse”

Mọi việc đã xong. Để chương trình chạy, quý vị cần:

Chạy NetBean, deploy cho ứng dụng chạy trên Server Tomcat.

Chạy ứng dụng Android trên máy ảo, hoặc cài ứng dụng vào chạy trên device thật.

 

Chúng ta thử tạo 1 register 1 tài khoản mới trên web: hoangcute.

Khi chạy ứng dụng

Login sai

Login đúng trên Web và Mobile

Chúng ta thêm 2 transaction trên Web, sau đó bấm Refresh trên mobile

Chúng ta edit transaction 1, bấm F5 trên web

Chúng ta tạo thêm 1 transaction trên mobile, refresh web

Thoát ứng dụng android, login lại bằng tài khoản admin, danh sách transactions đã có trên web sẽ show ra

 

Tới đây, chúng ta đã hoàn thành xong part 4 của bài hướng dẫn. Trong phần này, chúng ta đã viết 1 web service bằng action của Struts2, đồng thời consume web service này trên client Android.

Như đã đề cập ở part 1, cấu trúc + thiết kế mà chúng tôi đưa ra chỉ là một trong những cấu trúc dựng web service, consume hoạt động được. Cấu trúc này vẫn còn 1 số nhược điểm, rất mong sự đóng góp của quí vị

Ở phần tiếp theo - part 5, chúng tôi sẽ hướng dẫn quý vị cách đồng bộ thông tin giữa database client (SQLite) và database trên server, thông qua web service.

Không có nhận xét nào:

Đăng nhận xét