Thứ Ba, 12 tháng 6, 2018

Topic: Áp dụng mô hình MVC bên phía client – Nhận file pdf bằng blob

Áp dụng mô hình MVC bên phía client – Nhận file pdf bằng blob

Tác giả: Nguyễn Thế Phương

Mục đích

-          Sử dụng mô hình MVC bên phía client trong việc xây dựng ứng dụng với JavaScript thuần nhằm mục đích cải thiện việc xây dựng giao diện kết hợp với xử lý ở Front-end và hỗ trợ việc nâng cấp và bảo trì ứng dụng một cách dễ dàng

-          Thực hiện việc trình bày dữ liệu của một tài liệu văn bản dưới dạng pdf được truyền từ client đến server dưới dạng streaming ở phía client sử dụng JavaScript.

 

Các kiến thức yêu cầu

·         Nắm vững về các kiến thức của OO và cách thực lập trình với OOP, cụ thể là Java

·         Nắm vững khái niệm về XML Schema – định nghĩa, cách viết XML Schema, áp dụng XML Schema cho validation nội dung của tài liệu XML http://www.kieutrongkhanh.net/2016/08/gioi-thieu-ve-xml-schema-inh-nghia-cach.html )

 

Ứng dụng mô hình MVC trong việc xây dựng client với JavaScript thuần

·         Tổng quát các ý tuởng

o   Model

§  Chúng ta sử dụng đối tượng này để lưu dữ liệu tạm thời.

§  Trong bài với online shopping cart, chúng ta sử dụng đối tượng này để lưu trữ danh sách các sản phẩm và giỏ hàng để đón nhận các thông tin của sản phẩm

o   View

§  Chúng ta sử dụng đối tượng này để lưu các Dom Element liên quan đến UI, và hiển thị dữ liệu từ Model

§  Trong bài này chúng ta sử dụng chúng thực hiện việc trình bày kết quả Search,

o   Controller

§  Chúng ta sử dụng các đối tượng này để lưu các hàm xử lý, lắng nghe các event

§  Cụ thể trong bài này, chính là các chức năng điều phối trong việc gọi lấy dữ liệu từ phía server về phía client, xử lý thông tin để phục vụ cho việc lấy danh mục sản phẩm và đưa vào trong giỏ hàng, …

o   LocalStorage: chúng ta sử dụng thành phần này để lưu dữ liệu lâu dài hơn(giống với database bên phía server)

·         Các nội dung chuẩn bị cho việc xây dựng mô hình

o   Đầu tiên, chúng ta ta tạo 3 Json Object để đại diện cho Model, View và Controller.

o   Chúng ta tạo tập tin mvc.js với 03 đối tượng đã nêu

o   Sử dụng call back method với function

§  Khi gọi một function làm việc với network thì phần đợi response của function đó sẽ được tách thành một thread mới, vì vậy chúng ta không thể xử lý tuần tự được.

§  Với đặc thù được nêu trên, khi gọi hàm làm việc với network, chúng ta cần truyền vào một function để xử lý những công việc sau khi response trả về.

§  Ở phần response của function làm việc với network, chúng ta phải gọi callBackMethod khi chúng ta xử lý hoàn tất công việc.

§  Ví dụ

 

Áp dụng mô hình MVC bên phía client vào một yêu cầu cụ thể

Chúng ta cần lấy một list khoảng 200 sản phẩm lưu bên phía client. Sau đó, chúng ta sẽ sử dụng  dữ liệu này hỗ trợ cho chức năng search, và lưu trữ thông tin giỏ hàng bên phía client.

Chúng ta xây dựng schema cho danh sách các sản phẩm. Chúng ta tạo 02 schema, một để lưu trữ toàn bộ danh mục sản phẩm, tập tin còn lại dùng để lưu trữ đặc tả của từng sản phẩm

·         Schema mô tả một list các sản phẩm có tên là Products.xsd

·         Schema mô tả các thành phần trong sản phẩm với tên Product.xsl

·         Định dạng XML kết xuất dữ liệu của các sản phẩm mà hệ thống đưa đến client sẽ có dạng như hình bên dưới

Khi load bất kì 1 trang nào ở phía client, chúng ta đều phải kiểm tra nếu chưa có list products thì chúng ta sẽ gọi về server để lấy toàn bộ list các sản phẩm đem về client và thực hiện lưu xuống LocalStorage.

Tuy nhiên, để tránh cho dữ liệu bị out of date thì chúng ta set expired date cho list products này là 1 giờ, sau 1 giờ chúng ta phải reload lại list products.

Khi lưu xuống LocalStorage, chúng ta sẽ lưu list products này dưới dạng string xml. Nhằm tăng tính hiệu hiệu của Model trong việc truy xuất nhanh dữ liệu, chúng ta sẽ lưu list sản phẩm này dưới dạng Map sử dụng ProductID làm key và Product là value.

Chúng ta cần lưu ý methods quan trọng được sử dụng nhiều trong bài viết. Các phương thức này được cài đặt trong tập tin common.js

·         Controller.getXMLDoc(url, callBackMethod): Hàm này dùng để request xml

o   Hàm này sẽ gửi request để lấy file xml, hoặc stream xml từ url truyền vào. Khi gọi thành công thì sẽ gọi callBackMethod và truyền vào parameter là xml đã được response.


 

·         Controller.traversalDOMTreeProducts(dom): Đây là hàm dùng để duyệt cây dom để lấy từng product lưu xuống Model

o   Hàm thực hiện đệ quy để duyệt cây Dom, khi gặp node có localName là “ProductType”, chúng ta sẽ lấy dữ liệu của Product rồi add vào Map trên Model

·         Controller.storeXMLDomToLocalStorage(dom, localStorageKey): Hàm này dùng để lưu dom xuống localStorage.

o   Chúng ta sử dụng XMLSerializer để serialize DOM thành string rồi lưu xuống LocalStorage

·         Controller.parserXMLFromStringToDOM(xmlString): Hàm này dùng để parse string thành DOM rồi trả về.

o   Tùy thuộc trình duyệt mà chúng ta đang sử dụng mà chúng ta sẽ dùng DOMParser hoặc ActiveXObject để parse string thành DOM.

·         Controller.syncProductsDomToLocalStorage(): Hàm này dùng để tạo cây dom từ list products ở model sau đó dùng hàm Controller.storeXMLDomToLocalStorage để lưu cây dom xuống localStorage.

o   Chúng ta tạo Cây dom từ List Products ở Model với rootNode là node Products, sau đó Lưu cây dom này xuống LocalStorage

·         Controller.syncListProductsToModel(): Hàm này dùng để load list products từ LocalStorage lên Model.

o   Chúng ta sẽ lấy xml string từ LocalStorage lên, nếu list này bị expire thì chúng ta return false để load lại list. Nếu chưa expried thì ta parse thành dom rồi dùng hà traversalDomTreeProducts để duyệt dom và lưu vào Model

o   Tiếp theo, chúng ta sẽ Load List Product: Khi file common.js được load, thì hàm Controller.loadListProducts sẽ được gọi. nếu syncListProcductsToModel không thành công thì chúng ta sẽ gửi request để lấy List  Product

o   Khi lấy được list product, chúng ta sẽ setExpiredDate cho list product, sau đó sẽ traversalDomTree để load dữ liệu lên Model, cuối cùng là sync list product từ Model xuống database.

Sau thời điểm này, chúng ta đã có dữ liệu ở phía client. Phần nội dung tiếp theo của bài này, chúng ta sẽ thực hiện implement shopping cart ở phía client trong tác vụ hỗ trợ mua hàng trên các web ứng dụng

Dựa trên các nội dung chuẩn bị ở trên, chúng ta đã có list products đang hiện diện ở client. Việc thao tác trên giỏ hàng, chúng ta chỉ cần quan tâm đến 02 thành phần của sản phẩm là productID và quantity. Vì sản phẩm trong giỏ là duy nhất, chúng ta sẽ sử dụng kiểu cấu trúc dữ liệu Map đã lưu trữ thông tin của các sản phẩm trong giỏ hàng. Thông tin của giỏ hàng được tổ chức trong model.

Danh sách các sản phẩm list products chỉ load giới hạn một số sản phẩm. Do vậy, chúng ta có thể thực hiện thêm chức năng load more để đem dữ liệu từ DB vào trong list products, sau đó thực hiện sync xuống LocalStorage (nội dung này sẽ không được đề cập trong bài viết).

Tổng quan mô hình tương tác như sau

A picture containing animal

Description generated with high confidence

Những việc cần làm ở shopping cart

-          Giao diện của nút add to cart sẽ được binding đến chức năng add to cart được điều phối bởi controller với tên gọi Controller.addProductToCart

-          Mỗi khi load trang mới, hoặc refresh lại trang, chúng ta cần sync Cart từ LocalStorage lên Model.

-          Khi người dùng ấn add to cart, nếu product này đã ở trong giỏ hàng thì ta tăng quantity lên còn ngược lại thì ta set quantity = 1 rồi add vào Map ở Model

-          Sau đó, chúng ta thực hiện sync cart từ Model xuống LocalStorage để tránh việc người dùng tắt trang thì dữ liệu không được lưu xuống LocalStorage.

Chúng ta đã vừa hoàn thành việc xây dựng các chức năng hỗ trợ việc thêm sản phẩm vào giỏ hàng.

Các bước tiếp theo trong nội dung bài viết, chúng ta sẽ tiến hành hiển thị giỏ hàng

·         Tổng quát những bước làm:

o   Đầu tiên, chúng ta sync list products và cart của chúng từ localStorage lên Model.

o   Tiếp theo, chúng ta sẽ tạo XML Dom từ cart và list products.

o   Cuối cùng, chúng ta sẽ dùng XML Dom và xsl để transform thành html rồi hiển thị lên.

o   Mô hình tổng quát của chức năng này như sau

A close up of a map

Description generated with high confidence

o   Cart của chúng ta sẽ có cấu trúc như sau

o   Các thành phần trong cart của chúng ta có cấu trúc như sau

Như đã đề cập ở trên, chúng ta sẽ sync list products và cart của chúng từ localStorage lên Model và tạo XML DOM thông qua hàm loadShoppingCartToDOM với rootNode sẽ là node Cart.

CTa sử dụng String phía dưới để tạo XML DOM cho Cart

Hàm loadShoppingCartToDOM được cài đặt với nội dung như sau

Sau khi đã có XML DOM, chúng ta sử dụng hàm displayGridProductUsingXSL để kết hợp XML DOM và file XSL ở server transform thành một đoạn html chứa giỏ hàng của chúng ta.

Các parameters của hàm displayGridProductUsingXSL bao gồm:

·         node là XML DOM của cart vừa mới tạo ở trên.

·         xslUrl là đường dẫn của file XSL ở server

·         gridRoot là một HTML DOM Element dùng để chứa giỏ hàng của chúng ta, bài viết đang sử dụng thẻ “bodyPage”

·         callBackMethod là hàm xử lý sau khi đã có html chứa giỏ hàng, ví dụ như hiển thị tổng tiền của giỏ hàng (nội dung này sẽ không được đề cập trong bài viết)

Đường dẫn tương đối của file xsl ở server

Cụ thể hàm displayGridProductUsingXSL:

-          Đầu tiên chúng ta sẽ gọi hàm Controller.getXMLDoc để lấy file xsl từ server.

-          Sau khi có file xsl, chúng ta dùng XSLTProcessor để transform từ XDOM và XSL thành đoạn html chứa các sản phẩm của giỏ hàng

-          Cuối cùng, chúng ta chỉ việc insert đoạn html vừa trả về vào trang hiển thị giỏ hàng thông qua hàm appendChild

Trong đoạn kết trên, hàm getXMLTProcessor được cài đặt như sau

Hình bên dưới là file XSL của Cart

Chúng ta đã hoàn thành xong công việc hiển thị giỏ hàng

Tiếp theo chúng ta xử lý việc trình bày hóa đơn ở phía client dưới dạng pdf sử dụng cơ chế blob

Khi user check out, chúng ta sẽ gửi order dưới dạng xml string về server để xử lý, sau đó server sẽ trả về file pdf dưới dạng stream.

Để thực hiện các công việc này chúng ta cần xác định các cấu trúc dữ liệu của Order và User để để giao thao tác và trao đổi thông tin giữa client và server

·         Order của chúng ta sẽ có cấu trúc như sau

·         User mà chúng ta hiện thực sẽ có cấu trúc như sau

Sau khi đã verify dữ liệu, chúng ta gọi hàm createOrderXMLString để tạo xml string của order

Với XML String để tạo Order là:

Hàm createOrderXMLString được hiện thực như sau

Chúng ta cũng lấy XML String của User với cấu trúc nêu trên đang được lưu ở localStorage khi mà user login (nội dung này quí vị tự thực hiện và  không được đề cập trong bài viết, quí vị tự thực hiện nội dung này)

Sau khi đã có XML String của Order, chúng ta tiến hành gửi request gửi data về server

·         Vì server trả về file pdf theo kiểu stream nên chúng ta sẽ set responseType = “blob” để nhận response là Blob object chứa binary data. ( responseType của XMLHttpRequest)

·         Tiếp theo, chúng ta sẽ khởi tạo các giá trị cho request thông qua hàm XMLHttpRequest.open(). Để bảo mật dữ liệu, chúng ta sử dụng method “POSTtrong quá trình gửi yêu cầu về phía server.

·         Sau đó, chúng ta send request với body message là xml String của order (Model.myOrder)

·         Khi response được trả về:

o   Từ binary data vừa mới nhận về, chúng ta tạo mới  object Blob với type là pdf.

o   Từ Blob này, chúng ta tạo URL để có thể mở file trên tab mới hoặc download file về. (link tham khảo)

Tiếp theo chúng ta cần xử lý việc tạo pdf ở phía server để có thể đón nhận ở client

-          Đầu tiên, chúng ta setContentType cho response là kiểu pdf: response.setContentType(“application/pdf”)

-          Tiếp theo, chúng ta đọc xml string từ InputStream của request được gửi đến từ client

-          Sau khi có xml String, chúng ta kết hợp với file xsl để transform thành file fo

-          Từ file fo vừa mới tạo ra, chúng ta tiếp tục transform file fo thành pdf (kiểu FileArrayOutputStream)

-          Cuối cùng là response pdf về dưới dạng stream

File xsl để kết xuất ra order như sau

Vài mẫu test demo từ ứng dụng hoàn chỉnh (Quí vị vui long tự xây dựng giao diện kết hợp với mô hình cùng chức năng đã mô tả để làm hoàn tất bài)

·         View Giỏ hàng

·         Xuất hóa đơn khi sử dụng phương thức check out

Chúc mừng quí vị đã hoàn tất việc ứng dụng thao tác ở client với ý tưởng về mô hình MVC và xử lý việc trình bày pdf ở client. Hẹn gặp quí vị ở chủ đề khác

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

Đăng nhận xét