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).
Chúng
ta thực hiện sửa file config của Hibernate và file DTO
Đồ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
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ộ.
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)
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
Đồ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.
Ở
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
Trong
class MainActivity, chúng ta sửa code để hiển thị tổng số tiền của các
transaction
Hàm
reload được gọi mỗi khi thêm bớt xóa sửa
Sửa
lại 1 số code insert, update, delete, quý vị chú ý những đoạn bôi đỏ
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.
Giao
diện
Database
sau khi sửa đổi
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
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.
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.
Chúng
ta thực hiện mapping các function đã viết trong file struts.xml
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).
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)
Sửa
các function vừa viết thành private, sau đó viết function service
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
Khi
dùng service này, ta giữ nguyên url là service.action,
chỉ cần truyền param “action” và là được
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.
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