Thứ Ba, 13 tháng 2, 2018

Topic: Xây dựng ứng dụng CRUD với framework Sencha Touch

Xây dựng ứng dụng CRUD với framework Sencha Touch

Tác giả: Phạm Công Thành

 

Mục đích: Trong bài viết này, chúng ta sẽ tạo ra ứng dụng với các chức năng từ thêm, xóa, sửa, hiển thị và lọc từ tất cả dữ liệu đang có, hiển thi thông tin chi tiết và tìm kiếm thông tin dữ liệu dưới DB. Qua việc thực hiện ứng dụng, chúng ta sẽ tìm hiểu thêm một số control được sử dụng để tạo nên giao diện và xử lý giao diện trong việc trình bày dữ liệu trong quá trình ứng dụng đang được thực thi. Ứng dụng được xây dựng thể hiện sự kết nối giữa client, server và khả năng thực thi trên đa nền tảng (multipe platform). Với giao diện là sự kết hợp giữa Sencha Touch (sử dụng Sencha cmd) và JavaScript cùng với các chức năng cung cấp từ backend, cụ thể là web server với mô hình ứng dụng JavaEE xây dựng với MVC2 Design Pattern. Qua bài này, chúng ta cùng tìm hiểu cách tích hợp framework không có sẵn vào tool lập trình, cụ thể ở đây sẽ là kết hợp Sencha Touch với Netbeans.

 

Các nội dung yêu cầu

·         Có kiến thức về việc xây dựng ứng dụng web kết hợp với việc truy xuất DB sử dụng mô hình MVC2 với JavaEE

·         Có kiến thức về lập trình JavaScripts

·         Có kiến thức về lập trình hướng đối tượng

·         Đã xây dựng ứng dụng web trên nền JavaEE sử dụng Servlet làm controller trong MVC2

·         Đã cấu hình Sencha Touch chạy trên máy tính (địa chỉ tham khảo http://www.kieutrongkhanh.net/2018/01/cau-hinh-framework-sencha-touch-trong.html )

·         Công cụ thực hiện nội dung trong bài này là Netbeans, Microsoft SQL Server, Tomcat Server, Sencha CMD, Sencha Touch

 

Cơ sở dữ liệu – DB

DB thực hiện ứng dụng trong bài này có cấu trúc như sau

Database.png

Sau khi tạo xong DB với cấu trúc như trên, quí vị tự nhập dữ liệu để khi kiểm tra với mỗi chức năng khi thực hiện xong

 

Các bước thực hiện

·         Bước 1: Tạo ứng dụng

Sử dụng Sencha cmd để tạo ứng dụng

Chúng ta sẽ tạo ứng dụng với tên ContextPath là SenchaDemo trong thư mục có tên là DemoSencha

1.png

Chúng ta tiếp tục sử dụng NetBeans để tạo project web có tên là SenchaDemo

Thực hiện copy toàn bộ file trong thư mục DemoSencha được tạo trong bước trên vào thư mục web của project được tạo bằng NetBeans.

·         Hình chụp thể hiện nội dung thư mục web của project được copy nội dung phát sinh bằng Sencha cmd

1.png

·         Thể hiện trong Netbeans sau khi copy nội dung vào thư mục web

2.png

Sau khi copy thì chúng ta sẽ thấy project trong Netbeans có những dấu ! đỏ trong project. Công cụ NetBeans sẽ báo lỗi trong các file JSON bởi vì NetBean chưa hỗ trợ đọc một số cú pháp trong JSON. Việc này không có ảnh hưởng gì đến việc build và deploy ứng dụng. Do vậy, chúng ta không cần quan tâm đến những lỗi này

A screenshot of a social media post

Description generated with very high confidence

Chúng ta thực hiện test thử trên Netbeans bằng cách Clean and Build, Deploy và chạy thử ứng dụng.

Chúng ta sẽ thấy được kết quả tương tự như chúng ta đã cấu hình và tạo ứng dụng với Sencha cmd

o   Test thử trên browser của desktop

2.png

o   Test thử trên browser của điện thoại

1.png

Bước 2: Thực hiện chức năng insert trong ứng dụng

Chức năng Insert sẽ có giao diện như sau

2.png

Để thực hiện chức năng này, chúng ta thực hiên tuần tự các bước theo hướng dẫn tiếp theo trên Netbeans

Trước hết, mở file app.js để xác định lại Main.js là giao diện sẽ được kích hoạt đầu tiên khi run project

3.png

6.png

Tiếp theo, mở file Main.js (thư mục app → view → Main.js) và thực hiện chỉnh sửa lại nội dung như hình chụp bên dưới

4.png

7.png

Các nội dung tô đỏ trong code có ý nghĩa như sau

o   Khung 1: cấu hình các icon điều hướng các tab (tab panel được sử dụng trên các app)

o   Khung 2: cấu hình nội dung hiển thị trên thanh tiêu đề

Chú ý: trong quá trình chỉnh sửa code, chúng ta cần kiểm tra các cặp ngoặc của items: [{ }] để đảm bảo đúng cú pháp để code có thể thực thi đúng.

Tiếp theo, chúng ta thực hiện bổ sung các control nhập liệu để thực hiện cho việc insert, cụ thể là 03 textfield Username, Fullname và Role kết hợp với 01 password field để đón nhận password

8.png

Cuối cùng, chúng ta bổ sung nút Insert kèm theo xử lý.

Mục tiêu của chức năng này hướng tới việc đón nhận hành động click nút Insert thì ứng dụng sẽ truyền dữ liệu về phía server và thực hiện insert dữ liệu vào DB

9.png

Chúng ta vừa hoàn thành xong bước xây dựng giao diện cho chức năng insert

Chúng ta thực hiện tạo ra Servlet với tên InsertServlet để xử lý các yêu cầu insert được gửi từ phía client

5.png

Code cài đặt xử lý trong InsertServlet được bổ sung như sau

10.png

Thực hiện tạo DAO với RegistrationDAO để bổ sung tính năng insert xuống DB  

6.png

Thực hiện viết code để insert xuống DB như sau

8.png

7.png

            Nội dung của việc kết nối CSDL như sau

9.png

Trong bài demo, chúng ta đang thực hiện kết nối DB dạng tĩnh. Quí vị khi làm thực tế nên kết nối DB động để thuận lợi cho việc triển khai và bảo trì ứng dụng (Tham khảo cách kết nối DB động tại địa chỉ http://www.kieutrongkhanh.net/2016/08/tao-ket-noi-ong-en-db-trong-mo-hinh-mvc.html )

Mở file index.html bổ sung thêm code JavaScript reference đến với mục đích điều hướng sencha trong quá trình gửi request lên server là thực thi các nội dung trong file app.js:

7.png

Chú ý

o   Nếu chúng ta không bổ sung đoạn code trên vào file index.html, Chúng ta sẽ thấy được cảnh báo sau khi chúng ta thực hiện deploy ứng dụng, NetBeans

4.png

o   Giao diện ứng dụng vẫn hiển thị. Tuy nhiên, khi chúng ta nút Insert thì dữ liệu sẽ không được truyền về phía server để thực thi

Chúng ta kiểm tra nội dung project của chúng ta vừa làm

Thực hiện clean and build và deploy ứng dụng

o   Màn hình bắt đầu khi thực thi

8.png

o   Thực hiện nhập liệu

9.png

o   Nhấn nút Insert

10.png

o   Kết quả kiểm tra tương ứng khi thực hiện trên điện thoại

2.png

3.png

4.png

Chúng ta vừa hoàn thành xong chức năng insert

·         Bước 3: Thực hiện chức năng Filter của tất cả dữ liệu được load toàn bộ từ DB để trình bày nhóm dữ liệu cần quan tâm

Ở chức năng này, chúng ta sẽ thực hiện chức năng này thông qua việc lọc – filter tên đầy đủ - Fullname của các account trong hệ thống.

Giao diện chức năng search được yêu cầu như hình bên dưới

11.png

Các thông tin chi tiết của giao diện này

o   1: ô để nhập thông tin cần filter, ở đây là Fullname

o   2: Nút chuyển giữa các tab panel, ở đây là chức năng Filter với Tab thể hiện là Filter Account

o   3: là một list chứa danh sách những account thỏa điều kiện, ở đây chúng ta sẽ dùng NestedList để có thể hiển thị chi tiết thông tin của record được chọn

Sau khi click vào một record bất kỳ trên list kết quả được Filter, thông tin chi tiết của từng account sẽ được hiển thị như sau

12.png

Giao diện chi tiết nêu trên cho phép người dùng cập nhật thông tin hoặc xóa record và trên thanh tiêu đề hiện lên username và 01 button “Filter Account” để hỗ trợ người sử dụng quay về màn hình kết quả Filter trước đó.

Các bước thực hiện cho chức năng này như sau

Vào file Main.js, di chuyển đến phần items. Thực hiện bổ sung code xử lý vào ngay bên dưới phần chức năng Insert đã thực hiên trong bước 2 nội dung như sau (chú ý Insert và Filter Account cách nhau bởi dấu phẩy - ",")

Các thuộc tính trong nội dung này có ý nghĩa như sau

o   id: định danh của NestedList cần xử lý

o   displayField: nội dung sẽ hiển thị trên thanh tiêu đề khi người dùng chọn 1 record

o   items: những thành phần trên trang

o   store: định nghĩa dữ liệu bên trong NestedList

o   listConfig: cấu hình hiển thị từng dòng bên trong NestedList

o   detailCard: Nội dung sẽ hiển thị khi người dùng chọn 1 dòng trên NestedList

o   listeners: ngay dưới detailCard sẽ bắt sự kiện khi người dùng click chuột lên 1 dòng trên NestedList, có thể tạo lại nội dung của detailCard.

Chúng ta bắt đầu với việc xử lý của NestedList tại phần số màu đỏ được đánh dấu trong hình trên

1.      Bắt đầu xử lý với items

14.png

o   id: định danh của ô dữ liệu nhập cần xử lý

o   xtype: loại control dùng để search

o   placeHolder: từ gợi ý sẵn trong control

·         Xử lý listeners, thực hiện bổ sung nội dung code phần listeners như sau

13.png

o Listener dùng để xử lý sự kiện khi người dùng nhập liệu vào ô search trên góc trên bên trái

o Người dùng sau khi nhập thông tin cần tìm sẽ nhấn enter, ứng dụng sẽ filter trong danh sách đã lấy về từ khi người dùng chọn tab All Account.

o Phương thức clearFilter để xóa đi những dữ liệu đã filter trước đó nhằm đảm bảo mỗi lẫn filter là danh sách mới được trình bày dựa trên nội dung filter. Nếu điều này không thực hiện, danh sách hiển thị sẽ bao gồm kết quả filter của lần trước đó cập nhật thêm kết quả filter vừa thực thi (kết quả sai lệch không như mong đợi)

o Function RegExp(queryString, "i"): thực hiện tìm kiếm không phân biệt hoa/thường (i: Perform case-insensitive matching)

o Phương thức test() dùng để tìm dữ liệu có trong string theo regular expression, nếu tìm thấy trả về true, tìm không thấy trả về false.

o Dòng code var store = Ext.getStore('StartGetAllAccount'); chính là id store của NestedList (số 2 màu đỏ trong hình trước)

14.png

o Dòng code 116 và 117 thể hiện việc xử lý dữ liệu.

·         Với data chứa kết quả tìm thấy, chúng ta bỏ dấu phẩy “,” cuối cùng trong chuỗi datafilter và ghép thêm cặp ngoặc vuông “[ ]” cho đúng cú pháp của JSON

·         Mỗi record được tìm thấy sẽ được nạp vào biến dataFilter kiểu chuỗi theo định dạng của JSON.

o Sau đó, chúng ta tạo ra biến filterResultStore kiểu TreeStore (là kiểu dữ liệu mà NestedList hỗ trợ) để đổ toàn bộ chuỗi JSON tìm được vào store này (sử dụng method setStore).

o Để từ đó, chúng ta có thể đưa nội dung của store này vào NestedList (theo id) để hiển thị (sử dụng phương thức show)

15.png

2.      Xử lý store

·         Chúng ta sẽ định dạng dữ liệu bên trong store và sử dụng ajax để lấy dữ liệu từ servlet.

·         Chú ý các fields trong store cần tương ứng với dữ liệu trong chuỗi JSON

16.png

·         Việc khai báo proxy cho phép chúng ta gọi server theo đường dẫn url đến resource chỉ định. Ở đây, chúng ta sẽ gọi GetAllAccountServlet ở web server

·         Tiếp theo, chúng ta sẽ tạo RegistrationDTO ở phía web server để chứa dựng thông tin truy vấn ở server và chuyển về client dưới dạng JSON

17.png

o Các thuộc tính được định nghĩa mapping với table được thể hiện như sau

18.png

o Chú ý: thuộc tính leaf của DTO được dùng để xác định là điểm dừng của NestedList khi ứng dụng đọc dữ liệu để lấy phần thông tin chi tiết

o Cài đặt đầy đủ các phương thức yêu cầu của DTO (getter, setter và constructor)

·         Mở class ResgistrationDAO để bổ sung thêm code xử lý lấy dữ liệu trả về

o Phương thức getAllAccount() được bổ sung code như sau

19.png

·         Thực hiện tạo Servlet có tên là GetAllAccountServlet

18.png

·         Bổ sung code xử lý code Servlet như sau

20.png
19.png

o Object JSONArray, JSONObject, phương thức fromObject được lấy từ thư viện json-lib-2.2.2-jdk15.jar.

o Phương thức fromObject sẽ chuyển đổi RegistrationDTO thành JSONObject và đặt vào trong mảng JSONArray được khai báo.

o Dòng code out.println trong code được dùng convert mảng json thành chuỗi để đặt vào output stream của response object. Container sẽ convert response object trở thành message với json được đặt trong message body của response và chuyển về client. Ở client, Sencha sẽ dùng JavaScript xử lý chuỗi JSON khi tiếp nhận được response chuyển về từ server.

3.      Xử lý listConfig

Đây là nội dung sẽ hiển thị trong từng dòng trên NestedList

Chúng ta thực hiện bổ sung code như sau

21.png

·         Việc chỉnh sửa các dòng code như trên sẽ hỗ trợ kết xuất trong giao diện như hình bên dưới. Nếu việc này không được thực hiện, Sencha sẽ tự động dùng những nội dung mặc định có trong displayField, cụ thể trong trường hợp này giao diện sẽ chỉ hiển thị duy nhất username

21.png

4.      Xử lý detailCard

·         Đối với NestedList khi click vào một dòng kết xuất thì thông tin chi tiết của dòng lựa chọn đó sẽ được hiển thị

·         Thực hiện chỉnh sửa và bổ sung nội dung của detail Card như sau

22.png

·         Xtype được gán với trị ‘panel’: xác định control trên detail Card là 1 panel

·         Scrollable được gán trị là true: khi thông tin vượt qua khả năng trình bày của màn hình thì giao diện sẽ xuất hiện thanh cuộn cho phép người dùng trượt xuống dưới để xem tiếp

·         styleHtmlContentđược gán là true: tự động định dạng HTML bên trong nội dung trình bày

5.      Xử lý listeners

·         Listeners sẽ xử lý sự kiện khi người dùng chọn một dòng từ NestedList

22.png

·         Chi tiết bên trong listeners thể hiện trong hình bên dưới

23.png

·         Phương thức getDetailCard dùng để thể hiện chi tiết của NestedList (ngữ nghĩa của hàm này đã được chúng ta tìm hiểu ở nội dung phần trên của bài viết)

 

·         Dòng alert sẽ hiển thị thông báo khi người dùng chọn vào một dòng trên list (nội dung số 1 trong hình bên dưới)

·         Nội dung được thiết lập trong phương thức detailCard.setHtml sẽ hỗ trợ hiển thị nội dung như như số 2 trong hình bên dưới

 

22.png

·         Phần tabPanel sẽ hỗ trợ trình bày nội dung chi tiết của account khi người dùng click vào account được hiển thị trên màn hình:

24.png

25.png

Chúng ta vừa hoàn tất chức năng Filter và trình bày chi tiết của nhóm thông tin mà người sử dụng lọc để dễ dàng tra cứu

Chúng ta thực hiện kiểm tra lại công việc đã làm bằng cách clean and build, deploy và test thử ứng dụng chạy

24.png

·         Thực hiện nhập giá trị vào ô Full name để thực hiện Filter

25.png

·         Kết quả thực hiện

26.png

·         Click vào dòng kết quả được Filter

27.png

·         Kết quả thực thi tương ứng khi sử dụng điện thoại

5.png

6.png

7.png

8.png

9.png

·         Bước 4: Thực hiện chức năng Update

Chức năng Update sẽ truyền toàn bộ nội dung được người dùng nhập liệu trên giao diện gồm username, password, fullname và role để gửi đến server. Container sẽ đưa yêu cầu đến UpdateServlet để thực hiện. Nếu quá trình này được  thực hiện thành công thì sẽ có message thông báo kết quả của công việc

Chúng ta mở file Main.js, tìm đến function của button Update:

28.png

Thực hiện bổ sung code Update như hình sau

26.png

·         Username có thể được lấy bằng record.get(‘username’).

o   Giá trị của username nhận được thông qua các bước chọn username trực tiếp trên list

o   Bên cạnh đó, giá trị của username cũng có thể lấy được thông qua Ext.getCmp đọc trực tiếp từ data của NestedList

·         Chúng ta thực hiện tương tự cho các field password, fullname, role

·         Chúng ta thực hiện xử lý gọi ajax để đẩy dữ liệu về web server thông qua method được chỉ định (ở đây, chúng ta sẽ dùng GET) với các giá trị đã được lấy từ phần trên

o   Nếu xử lý thành công, giao diện sẽ hiển thị respose code (200) và load lại giao diện ban đầu

·         Chúng ta thực hiện tạo UpdateServlet và bổ sung nội dung xử lý như sau

29.png

·         Code xử lý chức năng update được bổ sung vào RegistrationDAO như sau

30.png

·         Thực hiện clean and build, deploy và kiểm tra chức năng bằng việc thực hiện chạy thử

31.png

o   Thực hiện nhập liệu và nhấn Update

32.png

o   Thực hiện kết quả tương tự trên điện thoại

11.png

12.png

13.png

Chúng ta vừa hooàn thành chức năng Update dữ liệu xuống DB

·         Bước 5: Thực hiện chức năng Delete

Chức năng này dùng để người dùng xóa một dòng dữ liệu được chọn bằng cách nhấn nút Delete trên màn hình hiển thị chi tiết

Chúng ta thực hiện bằng cách mở file Main.js, tại function của button Delete bổ sung code như sau:

27.png

Thực hiện tạo DeleteServlet và bổ sung nội dung xử lý như hình bên dưới

33.png

Chúng ta vào trong RegistrationDAO để cập nhật việc xử lý delete như sau

34.png

·         Chúng ta thực hiện clean and build, deploy và test thử

A screenshot of a cell phone

Description generated with very high confidence

o   Chọn dòng dữ liệu trên danh sách hiển thị

A screenshot of a cell phone

Description generated with very high confidence

o   Nhấn nút Delete

A screenshot of a cell phone

Description generated with very high confidence

o   Kết quả sau khi thực thi

A screenshot of a cell phone

Description generated with very high confidence

o   Test trên thiết bị di động

A screenshot of a cell phone

Description generated with very high confidenceA screenshot of a cell phone

Description generated with very high confidenceA screenshot of a cell phone

Description generated with very high confidenceA screenshot of a cell phone

Description generated with very high confidence

            Chúng ta vừa hoàn thành chức năng Delete dữ liệu được lựa chọn.

·         Bước 6: Thực hiện chức năng tìm kiếm dữ liệu

Chức năng này dùng để tìm kiếm (Search) dữ liệu từ tập dữ liệu dưới DB để có những thông tin cần thiết. Chức năng này hoàn toàn khác chức năng Filter ở điểm là Filter ở trên là hiển thị toàn bộ dữ liệu có trong DB rồi người dùng mới lọc dữ liệu trong toàn bộ dữ liệu được hiển thị trên list.

Chúng ta mở lại file Main.js, thêm item Search Account(ngang cấp với item Filter, Insert), Như đã đề cập, việc xử lý Search, khác với Filter phía trên,  mỗi lần người dùng nhấn search, ứng dụng sẽ query xuống database để lấy dữ liệu trả về.

Chúng ta thực hiện bổ sung thêm code như sau

28.png

Chúng ta tập trung xử lý vào phần items khi query dữ liệu từ DB. Nội dung của 03 phần listConfig, detailCard và listeners, quí vị thực hiện tương tự với chức năng filter ở bước 3

Thực hiện tạo SearchServlet và bổ sung code có nội dung như sau

35.png

Mở RegistrationDAO, bổ sung hàm findByLikeFullname có nội dung như sau

36.png

Chúng ta quay trở lại file Main.js, chúng ta tìm kiếm items để chỉnh sửa với mục đích tạo thanh search tách rời

30.png

·         Thực hiện bổ sung phần items thứ 2 định nghĩa search và hiển thị

31.png

o   listeners: bổ sung thực hiện chức năng khi người dùng nhập giá trị vào ô search  và nhấn enter:

32.png

o   Biến SearchStore được tạo ra để lưu trữ cấu trúc của NestedList nhằm hiển thị kết quả trả về từ Search Servlet

33.png

Thực hiện clean and build, deploy và test thử

·         Giao diện của chức năng Search

o   Trên Desktop

A screenshot of a cell phone

Description generated with very high confidence

o   Trên thiết bị di động

A screenshot of a cell phone

Description generated with very high confidence

·         Kết quả khi nhấn nút Search sẽ giống như List hiển thị trong filter

Chúc mừng quí vị đã hoàn tất toàn bộ chức năng thao tác trên DB từ thêm, xóa, sửa, tìm kiếm, hiển thị toàn bộ dữ liệu đến lọc dữ liệu và thể hiện chi tiết của một thông tin được chọn lựa dưới DB sử dụng framework Sencha Touch với hỗ trợ của Sencha cmd kết hợp JavaScript để tạo ứng dụng chạy đa nền platform. Qua bài này chúng ta đã học được cách tạo ứng dụng sử dụng framework và sử dụng tool Netbeans để phát triển. Ứng dụng sử dụng backend với ứng dụng web sử dụng MVC2 để cung cấp chức năng cho giao diện

Rất mong quí vị đóng góp về nội dung của chủ đề này và hẹn gặp quí vị ở chủ đề khác

 

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

Đăng nhận xét