Ajax cho các nhà phát triển Java: Tuần tự hóa đối tượng Java cho Ajax

Năm cách để tuần tự hóa dữ liệu trong các ứng dụng Ajax

Nếu bạn đang tiến hành phát triển Web ™ bằng cách sử dụng JavaScript và XML không đồng bộ (Ajax), thì việc phân phát dữ liệu từ máy chủ cho máy khách có lẽ là mối quan tâm hàng đầu của bạn. Trong bài viết thứ hai trong loạt bài Ajax for Java developers này, Philip McCarthy cùng bạn qua năm cách tiếp cận để tuần tự hóa đối tượng Java và cung cấp cho bạn tất cả các thông tin bạn cần để chọn định dạng và công nghệ dữ liệu thích hợp tốt nhất cho ứng dụng của bạn.

Philip McCarthy, Nhà Phát triển, SmartStream Technologies Ltd

Philip McCarthy là nhà tư vấn phát triển phần mềm chuyên về các công nghệ Java và Web. Ông hiện đang làm việc trong dự án nền tảng phương tiện kỹ thuật số của Hewlett Packard tại HP Labs, Bristol. Trong những năm gần đây Phil đã phát triển một số các khách hàng Web phong phú sử dụng truyền dẫn máy chủ không đồng bộ và kịch bản lệnh DOM. Ông vui mừng vì chúng ta có một tên cho chúng. Bạn có thể liên lạc với Phil tại philmccarthy@gmail.com.



04 12 2009

Trong bài viết đầu tiên của loạt bài này, tôi đã giới thiệu cho bạn các khối tạo dựng của Ajax:

  • Cách sử dụng một đối tượng JavaScript XMLHttpRequest để gửi một yêu cầu không đồng bộ tới một máy chủ từ một trang Web.
  • Cách xử lý và trả lời yêu cầu đó bằng một Java servlet trả về một tài liệu XML tới máy khách.
  • Cách sử dụng tư liệu trả lời đó trên máy khách để cập nhật khung nhìn trang của bạn.

Bây giờ, tôi sẽ tiếp tục thảo luận về các quy tắc cơ bản về phát triển của Ajax, nhưng tôi sẽ tập trung vào những gì quan trọng nhất đối với nhiều nhà phát triển Web với Java: tạo dữ liệu cho máy khách.

Hầu hết các nhà phát triển Java đã áp dụng mẫu Model-View-Controller (MVC-Trình điều khiển-Khung nhìn-Mô hình) cho các ứng dụng Web của họ. Trong một ứng dụng Web truyền thống, thành phần khung nhìn gồm các JSP hoặc có lẽ là một công nghệ trình bày khác như các khuôn mẫu Velocity (Tốc độ). Những thành phần trình bày này cập nhật giao diện người dùng bằng cách tạo một cách động toàn bộ trang HTML mới để thay thế những gì mà người dùng đã thấy trước đó. Trong trường hợp của ứng dụng Java Web với một giao diện người dùng Ajax, tất nhiên mã khách JavaScript có trách nhiệm cuối cùng cập nhật những gì người dùng thấy, dựa vào dữ liệu được thu nhận để trả lời một XMLHttpRequest. Từ góc nhìn của máy chủ, khung nhìn này trở thành nơi biểu diễn dữ liệu mà nó sẽ gửi trả lời các yêu cầu của máy khách.

Bài viết này tập trung vào các kỹ thuật mà bạn có thể dùng để tạo các khung nhìn ở giữa dữ liệu của các đối tượng Java của bạn. Tôi sẽ giải thích nhiều phương thức mà bạn có thể sử dụng để biến JavaBeans của bạn thành các tài liệu XML và bạn sẽ tìm hiểu những ưu và khuyết điểm của mỗi phương thức. Bạn cũng sẽ thấy tại sao XML không phải luôn luôn là cách thực hiện: chuyển văn bản thuần có thể là một sự lựa chọn thích hợp cho các yêu cầu Ajax đơn giản. Cuối cùng, tôi sẽ giới thiệu cho bạn về JavaScript Object Notation (JSON- Ký hiệu đối tượng JavaScript). JSON cho phép dữ liệu được truyền đi dưới dạng các đồ thị đối tượng JavaScript được tuần tự hóa, các đồ thị này rất dễ làm việc với mã phía máy khách.

Về ví dụ này

Tôi sẽ sử dụng một ứng dụng ví dụ và một số các trường hợp sử dụng để trình bày các tính năng và các kỹ thuật công nghệ được thảo luận tại đây. Hình 1 hiển thị mô hình dữ liệu vô cùng đơn giản để minh họa các trường hợp sử dụng trong ví dụ này. Mô hình này trình bày một tài khoản của khách hàng tại một cửa hàng trực tuyến. Khách hàng có một bộ sưu tập của các đơn đặt hàng trước đó và mỗi đơn hàng có một số mục.

Hình 1. Một mô hình đối tượng đơn giản
Mô hình đối tượng biểu diễn tài khoản của khách hàng

Mặc dù XMLHttpRequest không đặt ra bất kỳ các hạn chế nào về định dạng được sử dụng để gửi dữ liệu yêu cầu, đối với hầu hết các mục đích nó thích hợp để gửi các tham số biểu mẫu truyền thống, nên do đó, việc thảo luận của tôi tập trung vào trả lời của máy chủ. Câu trả lời này cũng có thể có bất kỳ định dạng dựa trên văn bản nào nhưng, như tên gọi của nó cho thấy, XMLHttpRequest có các khả năng gắn sẵn để xử lý dữ liệu trả lời XML. Điều này làm cho XML là sự lựa chọn mặc định cho các trả lời của Ajax, vì vậy nó là một nơi tốt để bắt đầu.

Tạo XML từ các lớp Java

Có rất nhiều lý do phân phát các trả lời của Ajax như XML: mỗi trình duyệt có khả năng Ajax có các phương thức điều hướng các tài liệu XML và cũng có rất nhiều công nghệ phía máy chủ làm việc với dữ liệu XML. Thật dễ dàng xác định cam kết giữa máy khách và máy chủ Ajax của bạn bằng cách tạo một lược đồ mô tả các kiểu tài liệu sẽ được trao đổi và nếu bạn có một cách tiếp cận hướng dịch vụ tới kiến trúc phía máy chủ của bạn, việc sử dụng XML cho phép các khách hàng không phải Ajax cùng dùng các nguồn cung cấp dữ liệu của bạn.

Tôi sẽ xem xét ba trong những cách mà bạn có thể tạo dữ liệu XML từ các đối tượng Java của bạn và thảo luận về những ưu và khuyết điểm của mỗi cách.


Tự tuần tự hóa

Trước hết, bạn có thể tạo XML theo cách lập trình từ đồ thị đối tượng của bạn. Cách tiếp cận này có thể đơn giản như việc thực hiện một phương thức toXml() trong mỗi một trong các lớp JavaBean của bạn. Sau đó, bạn sẽ chọn một XML API và có một bean phát ra các phần tử để thể hiện trạng thái của nó và gọi đồ thị đối tượng xuống theo cách đệ quy tới các thành viên của nó. Rõ ràng, cách tiếp cận này không mở rộng tốt với một số lượng lớn các lớp vì mỗi một lớp cần có mã tạo XML riêng của mình được viết riêng cho nó. Ở phía trên, đó là một phương thức đơn giản thực hiện, không có bất kỳ chi phí hoạt động nào về cấu hình tăng thêm hay một quá trình xây dựng phức tạp hơn và bất kỳ đồ thị nào gồm JavaBeans của bạn có thể được chuyển thành một tài liệu XML với cặp các cuộc gọi.

Trong đoạn mã ví dụ cho bài viết trước trong loạt bài này, tôi đã thực hiện các phương thức toXml() bằng cách gắn thêm chuỗi đánh dấu XML với nhau. Như tôi đã đề cập lúc trước, đây là một cách tiếp cận xấu vì nó đặt gánh nặng nhằm bảo đảm các thẻ được cân bằng, các thực thể được mã hóa v.v trên mỗi mã của phương thức toXml(). Một số các XML API có sẵn trên nền Java thực hiện tất cả công việc này cho bạn, cho phép tập trung vào nội dung của XML. Liệt kê 1 sử dụng JDOM API để thực hiện toXml() trên lớp đang thể hiện một đơn đặt hàng trong ví dụ cửa hàng trực tuyến (xem Hình 1).

Liệt kê 1. Thực hiện JDOM của toXml () cho lớp đơn hàng
public Element toXml() 
{ Element elOrder = new Element("order"); 
  elOrder.setAttribute("id",id);
  elOrder.setAttribute("cost",getFormattedCost()); 
  Element elDate = new Element("date").addContent(date); elOrder.addContent(elDate); 
  Element elItems = new Element("items"); 
  for (Iterator<Item> iter = items.iterator() ; iter.hasNext(); ) 
  { elItems.addContent(iter.next().toXml()); } 
  elOrder.addContent(elItems); 
  return elOrder; 
}

Ở đây bạn có thể thấy để tạo các phần tử, thiết lập các thuộc tính và thêm nội dung phần tử bằng cách sử dụng JDOM đơn giản như thế nào. Các cuộc gọi đệ quy đến các phương thức toXml() của JavaBeans đã kết hợp lại được thực hiện để nhận được các thể hiện Element (phần tử) của đồ thị con của chúng. Ví dụ, nội dung của các phần tử items được tạo ở đây bằng cách gọi toXml() trên mỗi đối tượng Item được tập hợp theo Order (đơn hàng) này.

Một khi tất cả các JavaBeans của bạn thực hiện một phương thức toXml(), nó chỉ đơn giản là tuần tự hóa bất kỳ đồ thị tùy ý nào vào trong một tài liệu XML và trả nó về tới một máy khách Ajax, như trong Liệt kê 2.

Liệt kê 2. Tạo một trả lời XML từ một phần tử JDOM
public void doGet(HttpServletRequest req, HttpServletResponse res) 
throws java.io.IOException, ServletException { 
String custId = req.getParameter("username"); 
Customer customer = getCustomer(custId); 
Element responseElem = customer.toXml(); 
Document responseDoc = new Document(responseElem); 
res.setContentType("application/xml"); 
new XMLOutputter().output(responseDoc,res.getWriter()); }

Một lần nữa JDOM lại khiến mọi việc ở đây thành đơn giản. Bạn chỉ cần bọc một Document quanh phần tử XML được đồ thị đối tượng trả về và sau đó sử dụng XMLOutputter để viết tài liệu đầy đủ cho trả lời servlet. Liệt kê 3 hiển thị một mẫu XML được tạo theo cách này, được định dạng kỹ lưỡng bằng cách khởi tạo XMLOutputter với Format.getPrettyFormat(). Trong ví dụ này, khách hàng chỉ có một đơn hàng với hai mục.

Liệt kê 3. Tài liệu XML mẫu thể hiện một khách hàng
<?xml version="1.0" encoding="UTF-8"?>
<customer username="jimmy66"> 
<realname>James Hyrax </realname> 
<orders> 
    <order id="o-11123" cost="$349.98"> 
    <date>08-26-2005</date>
    <items> 
       <item id="i-55768"> 
       <name>Oolong 512MB CF Card</name> 
       <description>512 Megabyte Type 1 CompactFlash card. 
             Manufactured by Oolong Industries</description>
       <price>$49.99</price> 
    </item> 
    <item id="i-74491"> 
       <name>Fujak Superpix72 Camera</name>
       <description>7.2 Megapixel digital camera 
             featuring six shooting modes and 3x optical zoom. Silver.</description>
       <price>$299.99</price> 
     </item>
     </items> 
     </order> 
</orders>
</customer>

Nhược điểm của việc tự tuần tự hóa

Điều thú vị là, các mã trong Liệt kê 3 cho thấy một trong những hạn chế chính của việc có JavaBeans tự tuần tự hóa thành XML. Giả sử tài liệu này đã được sử dụng để giới thiệu một khung nhìn Order History (Lịch sử đơn hàng) cho khách hàng. Trong trường hợp đó, không chắc là bạn sẽ muốn hiển thị mô tả đầy đủ về mọi mục trong mỗi đơn hàng đã qua hoặc báo cho người sử dụng tên của họ. Nhưng nếu ứng dụng có một lớp ProductSearch trả về các kết quả tìm kiếm của nó như là một danh sách các bean Item, sẽ có ích nếu tính đến các mô tả có trong thể hiện XML của các Item. Hơn nữa, một trường bổ sung trên lớp Item thể hiện mức cổ phiếu hiện nay sẽ là thông tin có ích để hiển thị trong khung nhìn Product Search (Tìm kiếm sản phẩm). Tuy nhiên, sau đó trường này sẽ được tuần tự hóa từ bất kỳ đồ thị đối tượng nào có liên quan đến Item, dù có sự không thích hợp của mức cổ phiếu hiện tại với Order History của khách hàng.

Từ một góc nhìn thiết kế, đây là một vấn đề kinh điển của mô hình dữ liệu đang được kết hợp với việc tạo khung nhìn. Mỗi bean chỉ có thể tự tuần tự hóa theo một chiều và cách tiếp cận một kích cỡ phù hợp cho tất cả có nghĩa là các tương tác Ajax kết thúc trao đổi dữ liệu mà chúng không cần, làm cho công việc mã khách hàng khó định vị các thông tin được yêu cầu từ tài liệu, cũng như làm tăng việc sử dụng băng thông và thời gian phân tích cú pháp XML ở phía máy khách. Hệ quả khác của việc kết hợp này là ngữ pháp XML không thể phát triển một cách độc lập với các lớp Java. Ví dụ, việc thực hiện thay đổi lược đồ tài liệu khách hàng có thể tác động đến một số lớp Java mà sau đó sẽ phải được sửa đổi và được biên dịch lại.

Tôi sẽ tập trung vào các mối quan tâm này sau, nhưng trước tiên hãy xem xét một giải pháp cho các vấn đề mở rộng cách tiếp cận tự tuần tự hóa: các khung công tác liên kết XML.


Các khung công tác liên kết XML

Trong những năm gần đây, một số các Java API đã được phát triển để đơn giản hóa quá trình liên kết các tài liệu XML với các thể hiện đồ thị đối tượng Java. Hầu hết cung cấp cả hai cách sắp xếp theo thứ tự và không sắp xếp theo thứ tự XML, nghĩa là chúng thực hiện các chuyển đổi hai chiều giữa các đồ thị đối tượng Java và XML. Các khung công tác này chứa tất cả công việc xử lý XML, nghĩa là mã ứng dụng chỉ phải xử lý với các đối tượng thuần Java. Chúng cũng có xu hướng cung cấp các hàm phụ thuộc có ích như việc xác nhận tài liệu hợp lệ. Nói chung, các khung công tác này có hai phương thức tiếp cận khác nhau: tạo mã và ánh xạ đối tượng tới XML. Tôi sẽ giải thích cả hai.

Cách tiếp cận tạo mã

Các khung công tác liên kết sử dụng việc tạo mã gồm XMLBeans, JAXB, Zeus và JBind. Castor cũng có thể sử dụng kỹ thuật này. Điểm khởi đầu cho bất kỳ các khung công tác này là lược đồ XML mô tả các kiểu dữ liệu của các tài liệu của bạn. Sử dụng các công cụ được khung công tác cung cấp, sau đó bạn tạo các lớp Java để thể hiện các kiểu lược đồ được định nghĩa này. Cuối cùng, bạn viết ứng dụng của bạn bằng cách sử dụng các lớp được tạo này để thể hiện dữ liệu mô hình của bạn và tuần tự hóa chúng sang XML thông qua một số cơ chế thuận tiện do khung công tác tạo ra.

Cách tiếp cận tạo mã là một cách tiếp cận tốt khi ứng dụng của bạn sử dụng một ngữ pháp XML lớn. Vấn đề mở rộng cách viết các phương thức tuần tự hóa XML tùy chỉnh qua hàng chục lớp biến mất. Mặt khác, bạn không còn bắt đầu định nghĩa JavaBeans của riêng bạn. Các lớp Java của khung công tác được tạo thường làm theo rất giống các cấu trúc của XML, có thể làm cho chúng hơi khó sử dụng để tạo mã lại. Ngoài ra, các lớp được tạo trở thành các thùng chứa dữ liệu câm vì bạn không thể thêm hành vi vào chúng. Nói chung, bạn cần phải thực hiện các thỏa hiệp trong mã ứng dụng của bạn để xử lý với các kiểu lược đồ được tạo. Khó khăn khác là một sự thay đổi trong lược đồ gây ra các thay đổi cho các lớp được tạo ra, lần lượt có một phản ứng dây chuyền cho bất kỳ mã nào mà bạn đã viết xung quanh chúng.

Các khung công tác liên kết XML của kiểu này có ích nhất trong việc không sắp xếp dữ liệu theo thứ tự (ví dụ, sử dụng các tài liệu XML và chuyển đổi chúng thành các đối tượng Java). Trừ khi bạn có một mô hình dữ liệu rất lớn và sẽ được lợi từ các lớp đã tạo cho bạn, các khung công tác dựa trên việc tạo mã có thể phá hỏng một ứng dụng Ajax.

Cách tiếp cận ánh xạ

Các khung công tác sử dụng ánh xạ gồm Castor và Apache Commons Betwixt (Giữa các dữ liệu chia sẻ chung của Apache). Nói chung, việc ánh xạ thường là giải pháp linh hoạt và đơn giản hơn so với việc tạo mã. Trước tiên, bạn tạo mã JavaBeans của bạn như bạn thường làm gồm bất kỳ hành vi nào và mọi phương thức tiện ích mà bạn muốn. Sau đó, trong thời gian chạy, bạn gọi trình sắp xếp thứ tự (marshaler) dựa vào nội tại của khung công tác và nó tạo một tài liệu XML dựa trên các kiểu, các tên và các giá trị của các bộ phận của đối tượng của bạn. Bằng cách định nghĩa các tệp ánh xạ cho các lớp, bạn có thể ghi đè lên chiến lược liên kết mặc định và báo cho trình sắp xếp thứ tự cách bạn muốn các lớp của bạn được thể hiện trong XML.

Cách tiếp cận này là một sự thỏa hiệp tốt đẹp giữa khả năng mở rộng và tính linh hoạt. Bạn bắt đầu viết các lớp Java của bạn theo cách bạn muốn chúng như thế và trình sắp xếp thứ tự tiết kiệm cho bạn khỏi xử lý với XML. Tuy nhiên, mặc dù các tệp định nghĩa ánh xạ chỉ đơn giản để viết và mở rộng hợp lý, các quy tắc ánh xạ chỉ có thể thay đổi rất nhiều hành vi liên kết tiêu chuẩn và một số mức kết nối giữa cấu trúc của các đối tượng của bạn và sự thể hiện XML của chúng sẽ luôn luôn giữ nguyên. Cuối cùng, bạn có thể phải thỏa hiệp hoặc thể hiện Java của bạn hoặc định dạng XML cho cách tiếp cận ánh xa tới công việc.

Tóm tắt liên kết dữ liệu

Dennis Sosnoski đã viết sâu về đề tài của các API liên kết dữ liệu XML với cả tính chất độc đáo của việc tạo mã lẫn ánh xạ mã. Tôi muốn giới thiệu các bài viết xuất xắc của ông trên Castor và trên các khung công tác tạo mã nếu bạn muốn nghiên cứu kỹ hơn lĩnh vực này (xem Tài nguyên để có các liên kết).

Về tổng thể, cách tiếp cận tạo mã thỏa hiệp quá nhiều tính linh hoạt và sự thuận tiện có ích cho ứng dụng Ajax điển hình. Mặt khác, các khung công tác dựa trên ánh xạ có thể phục vụ tốt cho bạn, miễn là bạn có thể thay đổi các chiến lược ánh xạ của mình đủ để tạo XML mong muốn từ các đối tượng của bạn.

Tất cả các API liên kết XML có chung một hạn chế lớn với kỹ thuật tuần tự hóa thủ công: việc kết nối của mô hình và khung nhìn. Việc bị hạn chế với chỉ một thể hiện XML của mỗi kiểu đối tượng có nghĩa là có khả năng luôn có một số dữ liệu dư thừa dịch chuyển trên mạng. Một vấn đề quan trọng hơn là mã khách không thể có một khung nhìn chuyên dụng khi tình hình đòi hỏi nó và có thể có một thời gian khó khăn khi cố gắng đối phó với khung nhìn một kích cỡ phù hợp với tất cả đã thỏa hiệp của đồ thị đối tượng cụ thể.

Trong việc phát triển ứng dụng Web truyền thống, các hệ thống tạo khuôn mẫu trang được sử dụng để dễ dàng tách việc tạo khung nhìn khỏi logic của trình điều khiển và dữ liệu mô hình. Đây là một cách tiếp cận cũng có thể trợ giúp trong một kịch bản Ajax.


Các hệ thống tạo khuôn mẫu trang

Bất kỳ công nghệ tạo khuôn mẫu trang nào cũng có thể dùng để tạo XML, cho phép các ứng dụng Ajax tạo bất kỳ tài liệu trả lời XML nào từ các mô hình dữ liệu của chúng. Một lợi ích phụ là các khuôn mẫu có thể được viết bằng cách sử dụng ngôn ngữ đánh dấu đơn giản và truyền cảm, trái với lần lượt từ dòng này sang dòng khác của mã Java. Liệt kê 4 là một trang JSP có một bean Customer (khách hàng) và trả lại một khung nhìn XML tùy chỉnh thích hợp với mã khách hàng để tạo một thành phần Order History.

Liệt kê 4. Một trang JSP tạo một tài liệu lịch sử đơn hàng
<?xml version="1.0"?> 
<%@ page contentType="application/xml" %> 
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
<c:set var="cust" value="${requestScope.customer}"/> 
<orderhistory username="${cust.username}"> 
<c:forEach var="order" items="${cust.orders}"> 
  <order id="${order.id}" cost="${order.formattedCost}"> 
  <date>${order.date}</date>
  <items> 
      <c:forEach var="item" items="${order.items}">
        <item id="${item.id}"> 
          <name><c:out value="${item.name}" escapeXml="true"/></name>
          <price>${item.formattedPrice}</price> 
        </item>
      </c:forEach> 
  </items> 
  </order>
</c:forEach> 
</orderhistory>

Khuôn mẫu ngắn gọn này chỉ cung cấp dữ liệu cần thiết cho một khung nhìn Order History và không phải là những thứ thích hợp như là mỗi sự mô tả của mục. Nó sẽ giống như việc dễ dàng để tạo XML tùy chỉnh cho khung nhìn Product Search, gồm sự mô tả đầy đủ và mức cổ phiếu cho mỗi mục.

Các sự cố với khuôn mẫu

Mặt trái của vấn đề là ở chỗ bây giờ cần phải tạo một JSP mới cho mỗi khung nhìn khác nhau mà tôi yêu cầu, trái với việc chỉ lắp ráp đồ thị đối tượng cần thiết và tuần tự hóa nó. Từ một góc nhìn thiết kế, nhiều người cho rằng dù thế nào đi nữa đây là một điều tốt vì nó có nghĩa là sự suy nghĩ chính thức về các kiểu tài liệu mà máy chủ sẽ tạo. Ngoài ra, vì tôi bây giờ đang làm việc với một môi trường tạo khuôn mẫu chung chung và không phải là một API XML cụ thể, đó là trách nhiệm của tôi để đảm bảo chắc chắn các thẻ được cân bằng, thứ tự của phần tử và thuộc tính là chính xác và bất kỳ các thực thể XML nào (ví dụ < hay &) được thoát khỏi chương trình. Thẻ out của lõi JSP làm cho nhiệm vụ sau này dễ dàng, nhưng không phải tất cả các công nghệ tạo khuôn mẫu cung cấp một cơ chế như vậy. Cuối cùng, không có cách dễ dàng nào để xác nhận hợp lệ các tài liệu XML được tạo so với một lược đồ ở phía máy chủ, nhưng dù thế nào đi nữa đây không phải là điều mà bạn muốn làm trong một môi trường sản xuất và bạn có thể dễ dàng làm việc xung quanh nó trong quá trình phát triển.


Dữ liệu trả lời không có XML

Cho đến nay, tôi đã trình bày tất cả các kỹ thuật tạo trả lời của máy chủ dưới dạng một tài liệu XML. Tuy nhiên có một vài vấn đề với XML. Một trong những vấn đề này liên quan đến độ trễ. Các trình duyệt không phân tích cú pháp các tài liệu XML và tạo các mô hình DOM ngay lập tức và điều này có thể làm giảm cảm giác "sống động" cần thiết bởi một số thành phần Ajax, đặc biệt là khi phân tích cú pháp các tài liệu lớn trên máy tính chạy chậm hơn. Một ví dụ là "live search" (tìm kiếm trực tiếp), ở đây các kết quả tìm kiếm được lấy từ máy chủ và được hiển thị cho người dùng khi họ gõ vào các điều kiện tìm kiếm của họ. Đó là điều quan trọng đối với một thành phần tìm kiếm trực tiếp để trả lời một cách nhanh chóng cho đầu vào, nhưng đồng thời nó cần phải phân tích cú pháp các trả lời của máy chủ một cách nhanh chóng và liên tục.

Độ trễ là một lý do quan trọng, nhưng lý do lớn nhất để tránh XML là một DOM API phía máy khách rất rắc rối. Liệt kê 5 cho thấy các vòng mà bạn thường phải nhảy qua để đạt tới một giá trị thông qua DOM, theo cách tương thích của trình duyệt giao nhau.

Liệt kê 5. Chuyển hướng một tài liệu trả lời XML trong JavaScript
// Find name of first item in customer's last
order var orderHistoryDoc = req.responseXML; 
var orders = orderHistoryDoc.getElementsByTagName("order"); 
var lastOrder = orders[orders.length - 1];
var firstItem = lastOrder.getElementsByTagName("item")[0]; 
var itemNameElement = firstItem.firstChild; 
var itemNameText = itemNameElement.firstChild.data;

Những điều trở nên phức tạp hơn khi có khoảng trống giữa các thành phần, vì lúc nào mỗi firstChild của phần tử sẽ là một nút văn bản khoảng trống. Các thư viện JavaScript sẵn sàng xử lí các tài liệu XML ít khó khăn hơn. Chúng gồm Sarissa (xem Tài nguyên), và Google-ajaXSLT, cả hai đều thêm các khả năng XPath cho hầu hết các trình duyệt.

Tuy nhiên, thật đáng suy nghĩ về các sự lựa chọn. Ngoài responseXML, đối tượng XMLHttpRequest cung cấp một đặc tính có tên là responseText, đặc tính này chỉ cung cấp phần thân trả lời của máy chủ như là một chuỗi.

Đặc tính responseText

Đặc tính responseText đặc biệt thuận tiện khi máy chủ cần gửi các giá trị rất đơn giản cho máy khách, tránh các chi phí băng thông và các chi phí xử lý XML. Ví dụ, một trả lời đúng/sai đơn giản có thể được máy chủ trả về như là văn bản thuần, có thể là một danh sách có phân tách dấu phẩy đơn giản của các số hay các tên. Nói chung, tuy nhiên, tốt nhất là không trộn lẫn và phối hợp các trả lời XML và các trả lời văn bản thuần trong cùng ứng dụng; việc bám chặt vào chỉ một định dạng dữ liệu làm cho mã trừu tượng và việc tái sử dụng đơn giản hơn.

responseText cũng có thể có ích về dữ liệu trả lời XML. Trong một kịch bản ở đó bạn chỉ cần lấy một giá trị từ một tài liệu trả lời, nó có thể thuận tiện hơn cho "sự lừa đảo", xử lý XML như là một chuỗi các văn bản chứ không phải là một tài liệu có cấu trúc. Ví dụ, Liệt kê 6 cho thấy cách một biểu thức chính quy có thể được sử dụng để lấy ra ngày tháng của đơn hàng đầu tiên trong Order History của khách hàng. Điều này thực sự chỉ là một nỗ lực thành công, mặc dù -- nhìn chung bạn không nên dựa vào sự thể hiện từ vựng của một tài liệu XML.

Liệt kê 6. Sử dụng một biểu thức chính quy với đối tượng responseText của XMLHttpRequest
var orderHistoryText = req.responseText; 
var matches = orderHistoryText.match(/<date>(.*?)<\/date>/); 
var date = matches[1];

Sử dụng responseText trong mẫu đặc biệt này có thể thuận tiện trong một số trường hợp. Tất nhiên, lý tưởng là có một cách để thể hiện dữ liệu có cấu trúc, phức tạp trong một định dạng có thể dễ dàng được chuyển hướng trong JavaScript và không có các chi phí xử lý của XML. Như vận may sẽ có nó, giống như một định dạng tồn tại.


Ký hiệu đối tượng JavaScript

Dưới vỏ đậy này, các đối tượng JavaScript cho hầu hết các phần gồm các mảng kết hợp, các mảng được lập chỉ mục theo số lượng, các chuỗi, các số hoặc các kết hợp lồng nhau của các kiểu này. Vì tất cả các kiểu có thể được khai báo theo dạng chữ trong JavaScript, có thể định nghĩa tĩnh một đồ thị đối tượng trong một câu lệnh. Liệt kê 7 khai báo một đối tượng khi sử dụng cú pháp JSON và chỉ ra cách truy cập nó. Các dấu ngoặc móc biểu thị một mảng kết hợp (tức là một đối tượng), với cặp giá trị quan trọng của nó được phân tách bằng dấu phẩy. Các dấu ngoặc vuông biểu thị một mảng được lập chỉ mục theo số lượng.

Liệt kê 7. Khai báo một đối tượng đơn giản theo dạng chữ trong JavaScript, khi sử dụng JSON
var band = { name: "The Beatles", 
members: [{ name: "John", instruments: ["Vocals","Guitar","Piano"] }, 
{ name: "Paul", instruments :["Vocals","Bass","Piano","Guitar"] }, 
{ name: "George", instruments: ["Guitar","Vocals"] },
{ name: "Ringo", instruments: ["Drums","Vocals"] } ] }; 
// Interrogate the band object 
var musician = band.members[3]; 
alert( musician.name + " played " + musician.instruments[0] + "with " + band.name );

Do JSON là một tính năng ngôn ngữ thú vị, nhưng với Ajax nó phải làm gì? Phần cuối của câu chuyện là bạn có thể sử dụng JSON để gửi một đồ thị đối tượng JavaScript qua mạng dưới dạng trả lời của máy chủ Ajax. Điều này có nghĩa là một sự thoát ra khỏi chuyển hướng XML trên máy khách thông qua DOM API -- bạn chỉ cần đánh giá câu trả lời JSON và bạn ngay lập tức có một đồ thị đối tượng JavaScript có thể truy cập. Tất nhiên, trước tiên cần chuyển JavaBeans của bạn thành JSON.

Tạo JSON từ các lớp Java

Những ưu điểm và nhược điểm giống nhau áp dụng cho các kỹ thuật tạo XML khác nhau cũng áp dụng để tạo JSON. Người ta cho rằng, có một trường hợp để sử dụng các công nghệ tạo lại khuôn mẫu trình bày. Tuy nhiên, việc sử dụng JSON kỹ hơn để chuyển các đối tượng được tuần tự hóa giữa các tầng ứng dụng hơn là để tạo một khung nhìn trạng thái của ứng dụng. Tôi sẽ chỉ cho bạn cách sử dụng Java API org.json để tạo các phương thức toJSONObject() trên các lớp Java của bạn. Rồi các JSONObject của bạn có thể được tuần tự hóa đơn giản tới JSON. Liệt kê 8 kiểm tra lại Liệt kê 1 từ cuộc thảo luận XML, hiển thị việc thực hiện toJSONObject() cho lớp Order.

Liệt kê 8. Thực hiện phương thức toJSONObject () cho lớp Order
public JSONObject toJSONObject() 
{ JSONObject json = new JSONObject(); 
  json.put("id",id); 
  json.put("cost",getFormattedCost()); 
  json.put("date",date); 
  JSONArray jsonItems = new JSONArray(); 
  for (Iterator<Item> iter = items.iterator() ; iter.hasNext() ; ) 
  { jsonItems.put(iter.next().toJSONObject()); } 
  json.put("items",jsonItems); return json; 
}

Như bạn có thể thấy, API org.json rất đơn giản. JSONObject thể hiện một đối tượng JavaScript (tức một mảng kết hợp) và có các phương thức put() khác nhau lấy một khoá String và giá trị là một kiểu nguyên thủy, một kiểu String, hoặc một kiểu JSON khác. JSONArray thể hiện một mảng có lập chỉ mục, để cho phương thức put() của nó chỉ có một giá trị. Lưu ý rằng trong Liệt kê 8, một sự lựa chọn cho việc tạo mảng jsonItems và sau đó gắn nó vào đối tượng json với put() sẽ gọi json.accumulate("items",iter.next().toJSONObject()); cho mỗi mục. Phương thức accumulate() giống như put() trừ việc nó gắn thêm giá trị của mình cho một mảng có lập chỉ mục được xác định bằng khoá.

Liệt kê 9 cho thấy cách để tuần tự hóa một JSONObject và viết nó vào một trả lời của servlet.

Liệt kê 9. Tạo một trả lời JSON được tuần tự hóa từ một JSONObject
public void doGet(HttpServletRequest req, HttpServletResponse res) 
throws java.io.IOException, ServletException 
{ String custId = req.getParameter("username"); 
  Customer customer = getCustomer(custId);
  res.setContentType("application/x-json"); 
  res.getWriter().print(customer.toJSONObject()); 
}

Như bạn thấy, thực sự không có gì với nó. Phương thức toString() trên JSONObject, được gọi ngầm ở đây, thực hiện tất cả công việc. Lưu ý rằng kiểu nội dung application/x-json ít tin cậy -- tại thời điểm của bài viết này không có sự nhất trí nào về những gì mà kiểu MIME của JSON sẽ có. Tuy nhiên, application/x-json là một lựa chọn nhạy cảm trong lúc này. Liệt kê 10 hiển thị một ví dụ trả lời từ mã servlet này.

Liệt kê 10. Thể hiện JSON của một bean Customer
{ "orders": 
  [ { "items": 
     [ { "price": "$49.99", 
         "description": "512 Megabyte Type 1 CompactFlash card. 
            Manufactured by Oolong Industries", 
         "name": "Oolong 512MB CF Card", 
         "id": "i-55768" }, 
       { "price": "$299.99", 
         "description": "7.2 Megapixel digital camera featuring 
            six shooting modes and 3x optical zoom. Silver.", 
         "name": "Fujak Superpix72 Camera", 
         "id": "i-74491" } 
      ], 

      "date": "08-26-2005", 
      "cost": "$349.98", 
      "id": "o-11123" } 
   ], 

   "realname": "James Hyrax", 
   "username": "jimmy66" 
}

Sử dụng JSON trên máy khách

Bước cuối cùng trong tiến trình là chuyển dữ liệu JSON thành các đối tượng JavaScript trên máy khách. Điều này có thể được thực hiện bằng một cuộc gọi đơn giản tới eval(), hàm diễn giải các chuỗi có chứa các biểu thức JavaScript đang hoạt động. Liệt kê 11 chuyển đổi một trả lời của JSON thành đồ thị đối tượng JavaScript và sau đó thực hiện nhiệm vụ của Liệt kê 5 về việc nhận được tên của mục đầu tiên từ đơn hàng cuối cùng của khách hàng.

Liệt kê 11. Đánh giá một trả lời của JSON
var jsonExpression = "(" + req.responseText + ")"; 
var customer = eval(jsonExpression); 
// Find name of first item in customer's last order 
var lastOrder = customer.orders[customer.orders.length-1]; 
var name = lastOrder.items[0].name;

So sánh với Liệt kê 11 với Liệt kê 5 minh họa sự thuận lợi cho máy khách khi sử dụng JSON. Nếu dự án Ajax của bạn liên quan đến rất nhiều việc chuyển hướng của các trả lời máy chủ phức tạp trên máy khách, thì JSON cũng hấp dẫn với bạn. Việc đặt JSON và XMLHttpRequest với nhau cũng tạo một sự khởi đầu tương tác Ajax trông giống như một cuộc gọi RPC hơn là một yêu cầu SOA, có thể có sự liên quan đến việc thiết kế ứng dụng của bạn. Trong bài viết tiếp theo, tôi sẽ xem xét các khung công tác được thiết kế rõ ràng để cho phép mã JavaScript thực hiện các cuộc gọi phương thức từ xa trên các đối tượng phía máy chủ.

Nhược điểm của JSON

JSON có nhược điểm của nó. Việc sử dụng cách tiếp cận JSON minh họa ở đây, không có cách nào để điều chỉnh sự tuần tự hóa của đối tượng trên cơ sở cho mỗi yêu cầu, vì vậy các trường không cần thiết thường có thể được gửi qua mạng. Ngoài ra, việc bổ sung thêm phương thức toJSONObject() cho mỗi JavaBean không mở rộng hơn, mặc dù nó sẽ hoàn toàn dễ hiểu để viết JavaBean chung cho một trình tuần tự hóa (serializer) JSON khi sử dụng xem xét nội tại và các chú thích. Cuối cùng, nếu mã phía máy chủ của bạn theo hướng dịch vụ và không biến đổi chỉ để xử lý các yêu cầu từ một máy khách Ajax, thì XML là một lựa chọn tốt hơn do sự hỗ trợ phổ biến của nó.


So sánh các kỹ thuật tuần tự hóa

Bây giờ bạn đã thấy năm kỹ thuật khác nhau để chuyển trạng thái phía máy chủ Java cho một máy khách Ajax. Tôi đã thảo luận sự tuần tự hóa XML với mã hóa thủ công riêng của bạn, liên kết XML qua việc tạo mã, liên kết XML thông qua một cơ chế ánh xạ, việc tạo XML dựa trên khuôn mẫu và cuối cùng tuần tự hóa mã hóa thủ công tới JSON. Mỗi cái có những lợi thế và bất lợi riêng của nó và phù hợp tốt nhất với các kiến trúc ứng dụng khác nhau.

Trong một nỗ lực tổng kết những lợi ích và hạn chế của từng cách tiếp cận, Bảng 1 gán các điểm số gần đúng theo sáu loại:

Khả năng mở rộng
Mô tả cách tiếp cận thích nghi với một số lượng lớn các kiểu dữ liệu tốt như thế nào. Liệu khối lượng công việc mã hóa và cấu hình của bạn sẽ tăng theo mỗi kiểu bổ sung không?
Dễ dàng tích hợp
Đánh giá cách đơn giản để tích hợp công nghệ vào dự án của bạn. Nó có đòi hỏi quy trình xây dựng phức tạp hơn không? Liệu nó làm tăng tính phức tạp triển khai không?
API của lớp Java
Mô tả cách dễ dàng làm việc với các đối tượng Java phía máy chủ được sử dụng trong cách tiếp cận này. Bạn có bắt đầu viết các bean thông thường không hoặc bạn sẽ phải làm việc với các thể hiện tài liệu rắc rối không?
Kiểm soát đầu ra
Mô tả bạn có thể kiểm soát việc thể hiện tuần tự hóa của các lớp của bạn chính xác như thế nào.
Tính linh hoạt của khung nhìn
Đánh giá xem sự tuần tự hóa dữ liệu có tùy chỉnh, khác nhau có thể được tạo từ cùng một tập các đối tượng.
Truy cập dữ liệu khách
Mô tả mã JavaScript làm việc với dữ liệu trả lời của máy chủ dễ dàng như thế nào.
Bảng 1. Các hành động có liên quan của các kỹ thuật tạo dữ liệu
Tự XMLLiên kết XML qua việc tạo mãLiên kết XML qua ánh xạ XML tạo khuôn mẫu trang Tuần tự hóa JSSON mã hóa thủ công
Khả năng mở rộngKémTốtTrung bìnhTrung bìnhKém
Dễ tích hợpTốtKémTrung bìnhTrung bìnhTốt
API của lớp JavaTốtKémTốtTốtTốt
Kiểm soát đầu raTốtTốtTrung bìnhTốtTốt
Tính linh hoạt của khung nhìnKémKémKémTốtKém
Truy cập dữ liệu kháchKémKémKémTrung bìnhTốt

Kết luận

Dữ liệu được biên dịch trong Bảng 1 không có ý muốn nói rằng bất kỳ trong số các công nghệ tuần tự hóa nào tốt hơn so với các công nghệ khác. Xét cho cùng, tầm quan trọng tương đối của mỗi một trong sáu loại phụ thuộc vào các chi tiết của dự án của bạn. Ví dụ, nếu bạn đang làm việc với hàng trăm kiểu dữ liệu, bạn muốn có khả năng mở rộng, vì thế việc tạo mã có lẽ là suy nghĩ tốt nhất của bạn. Nếu bạn cần phải tạo các khung nhìn khác nhau cho cùng một mô hình dữ liệu, việc tạo khuôn mẫu trang là cách thực hiện. Nếu bạn đang làm việc với một dự án quy mô nhỏ và muốn giảm bớt số lượng mã JavaScript mà bạn sẽ phải viết, hãy xem JSON.

Hy vọng rằng bài viết này đã cho bạn những thông tin cần thiết để chọn một công nghệ tuần tự hóa phù hợp với ứng dụng của bạn. Xem phần Tài nguyên để tìm hiểu thêm về các công nghệ đã thảo luận tại đây. Bạn cũng nên để ý đến các phần tiếp theo của loạt bài này, ở đây tôi sẽ cho bạn thấy cách viết một ứng dụng Java Ajax bằng cách sử dụng Direct Web Remoting (DWR-Truy cập Web trực tiếp từ xa). Khung công tác DWR cho phép bạn gọi các phương thức trên các lớp Java của bạn trực tiếp từ mã JavaScript. Nói cách khác, nó sẽ giữ gìn công việc tuần tự hóa dữ liệu cho bạn để cho bạn có thể sử dụng Ajax ở một mức độ trừu tượng cao hơn.

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

  • Sarissa: Một thư viện JavaScript của trình duyệt giao nhau với sự hỗ trợ cho XPath.
  • Jakarta Commons Betwixt: Một thư viện liên kết XML dựa trên ánh xạ linh hoạt.
  • JSON: Các API của ký hiệu đối tượng JavaScript cho ngôn ngữ Java và các ngôn ngữ khác.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Công nghệ Java
ArticleID=452519
ArticleTitle=Ajax cho các nhà phát triển Java: Tuần tự hóa đối tượng Java cho Ajax
publish-date=12042009