Ajax hoặc JavaScript và XML không đồng bộ, là một cách tiếp cận để phát triển ứng dụng Web có sử dụng tạo kịch bản lệnh phía-khách để trao đổi dữ liệu với máy chủ Web.. Với Ajax, bạn có
Trang 1Ajax cho các nhà phát triển Java: Xây dựng các ứng dụng Java động
Ajax mở đường cho các ứng dụng Web tốt hơn
Philip McCarthy, Nhà Phát triển, SmartStream Technologies Ltd
Tóm tắt: Chu trình nạp lại-trang trình bày một trong những trở ngại của tiện ích
lớn nhất trong việc phát triển ứng dụng Web và là một thách thức quan trọng cho các nhà phát triển Java™ Trong loạt bài này, tác giả Philip McCarthy giới thiệu một cách tiếp cận có tính đột phá để tạo ra những trải nghiệm ứng dụng Web động Ajax (Asynchronous JavaScript và XML) là một kỹ thuật lập trình cho phép bạn kết hợp các công nghệ Java, XML và JavaScript cho các ứng dụng Web dựa trên Java để ngắt mô hình nạp lại-trang
Ajax hoặc JavaScript và XML không đồng bộ, là một cách tiếp cận để phát triển ứng dụng Web có sử dụng tạo kịch bản lệnh phía-khách để trao đổi dữ liệu với máy chủ Web Kết quả là, các trang Web được cập nhật động mà không phải làm mới toàn bộ trang khi ngắt luồng tương tác Với Ajax, bạn có thể tạo các giao diện người dùng ứng dụng Web động hơn, phong phú hơn để tiếp cận trực tiếp và khả năng sử dụng các ứng dụng máy tính bản địa
Ajax không là một công nghệ, nó còn hơn một mẫu một cách để nhận biết và
mô tả một kỹ thuật thiết kế có lợi Về ý nghĩa nào đó Ajax là mới nên nhiều nhà phát triển chỉ đang bắt đầu nhận biết về nó, nhưng tất cả các thành phần triển khai thực hiện một ứng dụng Ajax đã tồn tại trong nhiều năm Các tin đồn hiện nay là
do sự nổi lên trong năm 2004 và 2005 của các giao diện người dùng (UI) động quan trọng dựa vào công nghệ Ajax, đáng chú ý nhất là các ứng dụng GMail và Maps của Google và trang chia sẻ hình ảnh Flickr Các UI này đã có đủ tính đột phá được một số nhà phát triển gọi là "Web 2.0", khiến người ta quan tâm nhiều đến ứng dụng Ajax
Trong loạt bài này, tôi sẽ cung cấp cho bạn tất cả các công cụ mà bạn cần để bắt đầu phát triển các ứng dụng riêng của bạn khi sử dụng Ajax Trong bài viết đầu tiên này, tôi sẽ giải thích các khái niệm đằng sau Ajax và trình diễn các bước cơ bản để tạo ra một giao diện Ajax cho ứng dụng Web dựa trên Java Tôi sẽ sử dụng các ví dụ mã để biểu thị cả mã Java phía máy chủ lẫn mã JavaScript phía máy khách để tạo ra các ứng dụng Ajax động Cuối cùng, tôi sẽ chỉ ra một số khó khăn của cách tiếp cận Ajax, cũng như các khả năng sử dụng rộng hơn và về khả năng tiếp cận mà bạn cần cân nhắc khi tạo các ứng dụng Ajax
Một giỏ mua hàng tốt hơn
Trang 2Bạn có thể sử dụng Ajax để nâng cao các ứng dụng Web truyền thống, sắp xếp hợp lý hóa tương tác bằng cách loại bỏ việc nạp trang Để giải thích điều này, tôi
sẽ sử dụng các ví dụ đơn giản về một giỏ mua hàng được tự động cập nhật khi các mục hàng được thêm vào giỏ Được tích hợp trong cửa hàng trực tuyến, cách tiếp cận này sẽ cho phép những người dùng tiếp tục duyệt và thêm các mục hàng vào giỏ hàng của họ mà không cần phải chờ sau mỗi lần nhấp chuột để cập nhật một trang đầy đủ Trong khi một số mã trong bài viết này dành riêng cho ví dụ giỏ hàng, các kỹ thuật được minh họa có thể được áp dụng cho bất kỳ ứng dụng Ajax nào Liệt kê 1 cho thấy mã HTML được ví dụ giỏ mua hàng này sử dụng Tôi sẽ quay lại mã HTML này trong suốt bài viết
Liệt kê 1 Các đoạn mã có liên quan của ví dụ giỏ mua hàng
<! Table of products from store's catalog, one row per item >
<th>Name</th> <th>Description</th> <th>Price</th> <th></th>
<! Click button to add item to cart via Ajax request >
<button onclick="addToCart('hat001')">Add to Cart</button>
</td>
</tr>
Trang 3
<! Representation of shopping cart, updated asynchronously >
<ul id="cart-contents">
<! List-items will be added here for each item in the cart >
</ul>
<! Total cost of items in cart displayed inside span element >
Total cost: <span id="total">$0.00</span>
Chu trình vòng tròn (roundtrip) của Ajax
Một tương tác Ajax bắt đầu bằng một đối tượng JavaScript tên là
XMLHttpRequest (Yêu cầu XMLHttp) Như tên cho thấy, nó cho phép một kịch bản lệnh phía máy khách thực hiện các yêu cầu HTTP và nó sẽ phân tích cú pháp câu trả lời của máy chủ XML Bước đầu tiên trong chu trình vòng tròn Ajax là tạo một cá thể XMLHttpRequest Phương thức HTTP để sử dụng cho các yêu cầu (GET hoặc POST) và URL đích sau đó được đặt trên đối tượng XMLHttpRequest
Bây giờ, bạn có nhớ tại sao chữ a đầu tiên trong Ajax là chữ viết tắt của không đồng bộ (asynchronous) không? Khi bạn gửi yêu cầu HTTP đó, bạn không muốn
trình duyệt bị treo khi chờ máy chủ trả lời Thay vào đó, bạn muốn nó tiếp tục phản ứng lại với sự tương tác của người dùng với trang đó và xử lý trả lời đến từ máy chủ Để thực hiện việc này, bạn có thể đăng ký một hàm gọi lại với
XMLHttpRequest rồi gửi đi XMLHttpRequest không đồng bộ Rồi kiểm soát các trả về tới trình duyệt, trừ ra hàm gọi lại sẽ được gọi khi trả lời của máy chủ đến
Trang 4Trên máy chủ Web Java, yêu cầu đến giống như bất kỳ HttpServletRequest khác nào Sau khi phân tích cú pháp các tham số yêu cầu, servlet gọi logic ứng dụng cần thiết, tuần tự hóa trả lời của nó thành XML và ghi nó vào HttpServletResponse
Quay lại phía máy khách, hàm gọi lại được đăng ký trên XMLHttpRequest bây giờ được gọi để xử lý tài liệu XML do máy chủ trả về Cuối cùng, giao diện người dùng được cập nhật đáp lại dữ liệu từ máy chủ, khi sử dụng JavaScript để thao tác HTML DOM của các trang Hình 1 là một sơ đồ trình tự của chu trình vòng tròn Ajax
Trang 5Hình 1 Chu trình vòng tròn Ajax
Bây giờ bạn có một khung nhìn mức cao về chu trình vòng tròn Ajax, tôi sẽ phóng
to để xem xét chi tiết hơn ở mỗi bước trên đường đi Quay trở lại Hình 1 nếu bạn không tìm thấy vị trí của mình, trình tự này không hoàn toàn dễ hiểu do tính chất không đồng bộ của cách tiếp cận Ajax
Trang 6
Gửi đi một XMLHttpRequest
Tôi sẽ xuất phát tại điểm bắt đầu của trình tự Ajax: tạo và gửi đi một
XMLHttpRequest từ trình duyệt Thật không may, phương thức để tạo ra một XMLHttpRequest khác với từ trình duyệt đến trình duyệt Hàm JavaScript trong Liệt kê 2 làm phẳng các nếp gấp phụ thuộc trình duyệt này, tìm ra cách tiếp cận đúng cho trình duyệt hiện tại và trả về một XMLHttpRequest đã sẵn sàng để sử dụng Thật tốt để nghĩ về điều này như là mã soạn sẵn: chỉ cần chép nó vào trong thư viện JavaScript của bạn và sử dụng nó khi bạn cần một XMLHttpRequest
Liệt kê 2 Tạo một XMLHttpRequest của trình duyệt chéo
// Create XMLHttpRequest object in non-Microsoft browsers
xmlreq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
Trang 7// Create XMLHttpRequest via MS ActiveX
Trang 8}
return xmlreq;
}
Sau đó, tôi sẽ thảo luận các kỹ thuật để xử lý các trình duyệt không hỗ trợ
XMLHttpRequest Bây giờ, các ví dụ giả định rằng hàm newXMLHttpRequest từ Liệt kê 2 sẽ luôn luôn trả về một cá thể XMLHttpRequest
Quay trở lại kịch bản ví dụ giỏ mua hàng, tôi muốn gọi một sự tương tác Ajax bất
cứ khi nào người dùng nhấn vào nút Add to Cart (Thêm vào giỏ hàng) với một mục hàng Trình xử lý (handler) onclick có tên là addToCart() có trách nhiệm cập nhật trạng thái giỏ hàng thông qua một cuộc gọi Ajax (xem Liệt kê 1) Như thể hiện trong Liệt kê 3, điều đầu tiên mà addToCart() cần làm là nhận một cá thể XMLHttpRequest bằng cách gọi hàm newXMLHttpRequest() từ Liệt kê 2 Tiếp theo, nó đăng ký một hàm gọi lại để nhận được trả lời của máy chủ (tôi sẽ giải thích chi tiết điều này sau; xem Liệt kê 6)
Do yêu cầu này sẽ thay đổi trạng thái trên máy chủ, tôi sẽ sử dụng một HTTP POST để làm chứng thư Việc gửi dữ liệu thông qua POST yêu cầu ba bước Đầu tiên, tôi cần phải mở một kết nối POST tới nguồn tài nguyên của máy chủ mà tôi giao tiếp trong trường hợp này một servlet được ánh xạ đến địa chỉ URL cart.do Tiếp theo, tôi đặt ra một tiêu đề trên XMLHttpRequest để nói rằng nội dung của yêu cầu là dữ liệu biểu mẫu có mã hóa Cuối cùng, tôi gửi yêu cầu đó với dữ liệu biểu mẫu có mã hóa làm phần thân
Liệt kê 3 kết hợp các bước này lại với nhau
Liệt kê 3 Gửi một XMLHttpRequest Thêm vào giỏ hàng
/*
Trang 9* Adds an item, identified by its product code,
* to the shopping cart
* itemCode - product code of the item to add
*/
function addToCart(itemCode) {
// Obtain an XMLHttpRequest instance
var req = newXMLHttpRequest();
// Set the handler function to receive callback notifications // from the request object
var handlerFunction = getReadyStateHandler(req, updateCart); req.onreadystatechange = handlerFunction;
// Open an HTTP POST connection to the shopping cart servlet // Third parameter specifies request is asynchronous
req.open("POST", "cart.do", true);
// Specify that the body of the request contains form data
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
Trang 10// Send form encoded data stating that I want to add the
// specified item to the cart
req.send("action=add&item="+itemCode);
}
Và ngay sau đó, bạn đã nhìn thấy phần đầu tiên của việc thiết lập chu trình vòng tròn Ajax cụ thể là việc tạo ra và gửi đi yêu cầu HTTP từ phía máy khách Tiếp theo là mã servlet Java được sử dụng để xử lý yêu cầu này
Xử lý yêu cầu servlet
Việc xử lý một XMLHttpRequest bằng một servlet phần lớn giống như việc xử lý một yêu cầu HTTP thông thường từ trình duyệt Dữ liệu biểu mẫu đã mã hóa được gửi trong phần thân của yêu cầu của POST có thể được các cuộc gọi
HttpServletRequest.getParameter() thu nhận Các yêu cầu Ajax tham gia vào HttpSession giống như các yêu cầu Web thông thường từ ứng dụng Điều này có ích cho kịch bản trong ví dụ giỏ mua hàng vì nó cho phép tôi tóm lược trạng thái giỏ hàng của người dùng trong một JavaBean và vẫn tiếp tục trạng thái đó cho phiên làm việc giữa các yêu cầu
Liệt kê 4 là một phần của một servlet đơn giản có xử lý các yêu cầu Ajax để cập nhật giỏ hàng Một bean Cart được lấy từ phiên làm việc của người dùng và trạng thái của nó được cập nhật theo các tham số yêu cầu Cart sau đó được tuần tự hóa tới XML và XML đó được ghi vào ServletResponse Quan trọng là thiết lập kiểu nội dung cho application/xml, nếu không XMLHttpRequest sẽ không phân tích cú pháp nội dung trả lời trong một XML DOM
Liệt kê 4 Mã servlet để xử lý các yêu cầu Ajax
Trang 11public void doPost(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {
Cart cart = getCartFromSession(req);
String action = req.getParameter("action"); String item = req.getParameter("item");
if ((action != null)&&(item != null)) {
// Add or remove items from the Cart
if ("add".equals(action)) {
cart.addItem(item);
} else if ("remove".equals(action)) { cart.removeItems(item);
}
}
Trang 12// Serialize the Cart's state to XML
String cartXml = cart.toXml();
Liệt kê 5 Ví dụ tuần tự hóa XML của đối tượng Cart
Trang 13Vì vậy, bây giờ bạn đã biết cách CartServlet đáp ứng với một XMLHttpRequest Điều kế tiếp là trả về phía máy khách, ở đó bạn có thể xem cách trả lời của XML được sử dụng để cập nhật trạng thái trang
Xử lý trả lời bằng JavaScript
Đặc tính readyState của XMLHttpRequest là một giá trị số cho trạng thái chu trình của yêu cầu Nó thay đổi từ 0 ứng với "chưa khởi động" đến 4 ứng với "hoàn thành" Mỗi khi readyState thay đổi, sự kiện readystatechange bắt đầu thực hiện và gọi hàm trình xử lý được gắn kèm qua đặc tính onreadystatechange
Trong Liệt kê 3, bạn thấy cách hàm getReadyStateHandler() đã được gọi để tạo ra một hàm trình xử lý Hàm trình xử lý này sau đó đã được gán cho đặc tính
onreadystatechange Hàm getReadyStateHandler() khai thác một thực tế rằng các
Trang 14hàm là đối tượng lớp đầu tiên trong JavaScript Điều này có nghĩa là các hàm có thể là các tham số cho các hàm khác và cũng có thể tạo và trả về các hàm khác Đây là công việc của getReadyStateHandler() để trả về một hàm kiểm tra xem XMLHttpRequest đã hoàn thành chưa và chuyển trả lời XML lên hàm trình xử lý được trình gọi xác định Liệt kê 6 là mã cho hàm getReadyStateHandler()
Liệt kê 6 Hàm getReadyStateHandler ()
/*
* Returns a function that waits for the specified XMLHttpRequest
* to complete, then passes its XML response
* to the given handler function
* req - The XMLHttpRequest whose state is changing
* responseXmlHandler - Function to pass the XML response to
*/
function getReadyStateHandler(req, responseXmlHandler) {
// Return an anonymous function that listens to the
Trang 15// An HTTP problem has occurred
alert("HTTP error: "+req.status);
Trong Liệt kê 6, đặc tính status (trạng thái) của XMLHttpRequest được thử
nghiệm để xem yêu cầu đó đã hoàn thành thành công chưa status chứa mã trạng thái HTTP của trả lời của máy chủ Khi thực hiện các yêu cầu đơn giản GET và POST bạn có thể giả định rằng bất kỳ mã nào khác 200 (OK) là một lỗi Nếu máy chủ gửi một trả lời chuyển hướng (ví dụ, 301 hoặc 302), thì trình duyệt tiếp tục chuyển hướng trong suốt và tìm nguồn tài nguyên từ vị trí mới; XMLHttpRequest không thấy mã trạng thái chuyển hướng Ngoài ra, trình duyệt sẽ tự động thêm một tiêu đề Cache-Control: no-cache cho tất cả các XMLHttpRequest, do đó mã máy khách sẽ không bao giờ phải đối phó với trả lời máy chủ 304 (không đổi)
Về getReadyStateHandler()
Trang 16getReadyStateHandler() là một đoạn mã tương đối phức tạp, đặc biệt là nếu bạn không sử dụng để đọc JavaScript Thỏa hiệp ở đây là việc đặt hàm này trong thư viện JavaScript, bạn chỉ có thể xử lý các trả lời máy chủ Ajax mà không cần phải đối phó với các phần nội tại của XMLHttpRequest Điều quan trọng là bạn hiểu cách sử dụng getReadyStateHandler() trong mã của riêng mình
Trong Liệt kê 3, bạn thấy getReadyStateHandler() được gọi như sau:
handlerFunction = getReadyStateHandler(req, updateCart) Hàm được
getReadyStateHandler() trả về trong trường hợp này sẽ kiểm tra xem
XMLHttpRequest trong biến req đã hoàn thành chưa và rồi gọi một hàm có tên updateCart với XML trả lời
Trích xuất dữ liệu giỏ hàng
Liệt kê 7 là mã updateCart() của chính nó Hàm kiểm tra tư liệu XML giỏ mua hàng bằng cách sử dụng các cuộc gọi DOM và cập nhật trang Web (xem Liệt kê 1)
để phản ánh các nội dung giỏ hàng mới Ở đây tập trung vào các cuộc gọi được sử dụng để trích xuất dữ liệu từ XML DOM Thuộc tính generated (được tạo ra) trên phần tử cart (giỏ mua hàng), một dấu thời gian được tạo ra khi Cart được tuần tự hóa theo XML, được kiểm tra để đảm bảo rằng dữ liệu giỏ hàng mới hơn không bị
dữ liệu giỏ hàng cũ ghi đè lên Các yêu cầu Ajax vốn không đồng bộ, do đó việc kiểm tra này đảm bảo an toàn đối với các trả lời từ máy chủ đến không theo trình
tự
Liệt kê 7 Cập nhật trang để phản ánh tư liệu XML của giỏ hàng
function updateCart(cartXML) {
// Get the root "cart" element from the document
var cart = cartXML.getElementsByTagName("cart")[0];
// Check that a more recent cart document hasn't been processed
// already
Trang 17var generated = cart.getAttribute("generated");
if (generated > lastCartUpdate) {
lastCartUpdate = generated;
// Clear the HTML list used to display the cart contents
var contents = document.getElementById("cart-contents"); contents.innerHTML = "";
// Loop over the items in the cart
var items = cart.getElementsByTagName("item");
for (var I = 0 ; I < items.length ; I++) {
var item = items[I];
// Extract the text nodes from the name and quantity elements var name = item.getElementsByTagName("name")[0]