Google App Engine không chỉ mở rộng quy mô các ứng dụng: nó có thể giúp bạn
xây dựng ứng dụng nhanh, bằng cách sử dụng các công cụ mà bạn yêu thích.
Andrew Glover gói ghém mô hình miền domain dành cho ứng dụng khai phá
Twitter của mình, thêm các móc nối tới việc lập chỉ mục và lưu dữ liệu vào một bộ
nhớ đệm. Sau đó ông nối nó với cơ chế cấp phép OAuth của Twitter, các hàng đợi
của GAE, một chút JSON và Ajax thông qua thư viện JavaScript được nhiều người
ưa thích là JQuery.
35 trang |
Chia sẻ: lylyngoc | Lượt xem: 1375 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Phát triển Java 2.0: Khai phá Twitter với Objectify-Appengine, Phần 2, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Phát triển Java 2.0: Khai phá Twitter với
Objectify-Appengine, Phần 2
Bắt đầu tiến nhanh đến các ứng dụng web của GAE với Gaelyk, JSON và Ajax
Google App Engine không chỉ mở rộng quy mô các ứng dụng: nó có thể giúp bạn
xây dựng ứng dụng nhanh, bằng cách sử dụng các công cụ mà bạn yêu thích.
Andrew Glover gói ghém mô hình miền domain dành cho ứng dụng khai phá
Twitter của mình, thêm các móc nối tới việc lập chỉ mục và lưu dữ liệu vào một bộ
nhớ đệm. Sau đó ông nối nó với cơ chế cấp phép OAuth của Twitter, các hàng đợi
của GAE, một chút JSON và Ajax thông qua thư viện JavaScript được nhiều người
ưa thích là JQuery.
Lập chỉ mục và lưu dữ liệu vào một bộ nhớ đệm với Objectify-Appengine
Theo mặc định, tất cả các thuộc tính được định nghĩa trong một đối tượng miền
domain (và do đó, cả với API Entity mức thấp của Google) đều được lập chỉ mục.
Đúng như trong thế giới quan hệ, lập chỉ mục giúp cho việc tìm kiếm kho dữ liệu
bên dưới dễ dàng hơn và nhanh hơn đối với người dùng đầu cuối. Tuy nhiên, việc
lập chỉ mục cũng tốn chi phí: khi đối tượng mới được tạo ra — chẳng hạn như một
hàng mới, theo thuật ngữ quan hệ hoặc Entity (Thực thể) mới trong Bigtable —
bạn phải cập nhật các chỉ mục của mình để tính đến dữ liệu mới thêm vào này.
Khi bạn bắt đầu sử dụng GAE để lưu trữ và lấy ra dữ liệu từ đó, việc lập chỉ mục
trở thành một mối quan tâm trong thế giới thực (mối quan tâm này cũng giống như
với đồng đô la vậy). Khi bạn đăng ký một tài khoản GAE, bạn sẽ tự động nhận
được 200 chỉ mục miễn phí; ngoài số này ra thì bạn sẽ phải trả thêm tiền. Giống
như vậy, nếu bạn vượt quá 6,50 giờ CPU mỗi ngày, bạn sẽ bắt đầu nhận một khoản
nợ của Google. Vì vậy, lập chỉ mục có chọn lọc là việc nên làm. Nếu bạn không
cần lập chỉ mục cho một thuộc tính (tức là bạn không có kế hoạch tìm kiếm một
đối tượng miền domain theo thuộc tính riêng lẻ đó), thì việc tắt chỉ mục đó là điều
hợp lý. Trong Liệt kê 1, tôi cho bạn thấy cách sử dụng chú giải @Unindexed của
Objectify để tắt một chỉ mục cụ thể.
Tôi đã mở rộng đối tượng Retweet từ Phần 1, bằng cách thêm một số chức năng
lập chỉ mục. Bạn có thể thấy những thay đổi này trong gói mã ví dụ mẫu. Trong
Liệt kê 1, tôi đã sử dụng chú thích @Unindexed để không lập chỉ mục thuộc tính
tên thực của người dùng của đối tượng Retweet, thuộc tính đó được đặt tên là
userName chứ không phải screenName. Tôi cũng đã không lập chỉ mục URL hình
ảnh của người dùng, một tính năng mới cho phép tôi tạo báo cáo tốt hơn trên giao
diện người dùng.
Tôi không lập kế hoạch tìm kiếm các đối tượng Retweet theo các thuộc tính này,
do đó rõ ràng không cần lập chỉ mục cho chúng. Tất nhiên, tôi có thể loại bỏ chú
giải @Unindexed nếu có thứ gì đó thay đổi. Liệt kê 1 cho thấy tôi đã cải tiến các
thuộc tính của đối tượng Retweet như thế nào .
Liệt kê 1. Đối tượng Retweet được nạp lại
public class Retweet
@Id private String id;
private String screenName;
private Date date;
private String tweet;
private Long influence;
private Key owner;
private Long tweetId;
@Unindexed private String userName;
@Unindexed private String userPicture;
//...
}
Hai thuộc tính in đậm ở cuối danh sách —userName và userPicture— là các thuộc
tính mới và cả hai đều không được lập chỉ mục. Tôi đã đổi tên userName thành
screenName để tích hợp tốt hơn với Twitter. (Trong Twitter, tên người dùng chính
là tên chính thức của bạn — "Andrew Glover" — còn tên hiển thị trên màn hình là
tên làm việc của bạn — "aglover".)
Lưu dữ liệu trong memcache
Giống như việc lập chỉ mục, việc lưu dữ liệu vào một bộ nhớ đệm cải thiện trải
nghiệm của người dùng đầu cuối: nó loại bỏ yêu cầu truyền dữ liệu khứ hồi đến
kho dữ liệu và quay về, do đó giúp cho việc đọc dữ liệu nhanh hơn. Google App
Engine sử dụng bộ nhớ đệm trên web (memcache) để lưu dữ liệu và Objectify sử
dụng chú thích @Cached để cắm vào nó. Chỉ cần thêm @Cached vào các đối
tượng miền của bạn và —hô biến!— dữ liệu (không phải là đối tượng Java™
tương ứng) được lưu trữ trong memcache và có thể được lấy ra khỏi bộ nhớ khi
ứng dụng đọc.
Tôi đã thêm chú giải @Cached cho cả hai đối tượng miền của tôi —User và
Retweet. Liệt kê 2 cho thấy đối tượng User đã được cập nhật và thêm vào vài thuôc
tính @Unindexed:
Liệt kê 2. Lưu dữ liệu vào một bộ nhớ đệm thật là đơn giản!
@Cached
public class User {
@Id private String name;
@Unindexed private String token;
@Unindexed private String tokenSecret;
//...
}
Lưu ý rằng các lời gọi query của Objectify vẫn truy cập vào kho dữ liệu; tất cả các
cuộc gọi tương tác kho dữ liệu khác, như get, đều sử dụng memcache. Ví dụ, trong
đối tượng User trong Liệt kê 2, phương thức findByName sử dụng lời gọi get của
Objectify để tải đối tượng miền domain tương ứng. (Xin nhắc lại rằng, name chính
là khóa). Nếu đối tượng User đã được tạo ra rồi thì dữ liệu của nó sẽ phải được lưu
vào một bộ nhớ đệm, với các lời gọi tiếp theo tới findByName dữ liệu của đối
tượng đó được lấy ra từ bộ nhớ đệm chứ không phải từ kho dữ liệu. Hạn ngạch của
GAE về các lời gọi memcache cao hơn so với các lời gọi vào datastore (kho lưu
trữ), do đó, nó giúp sử dụng memcache hợp lý bất cứ lúc nào.
Triển khai vào GAE
Tôi đã cập nhật xong các đối tượng miền domain của mình, ít nhất là những gì tôi
có thể làm với Objectify. Bước tiếp theo là triển khai các ứng dụng vào GAE. Như
tôi đã giải thích ở bài trước, ý định của tôi là xây dựng một ứng dụng web để cho
phép những người dùng khai phá các retweet (N.D.: việc chuyển tiếp các mẩu tin
nhắn nhận được tới những người khác - sau đây sẽ gọi tắt là chuyển tiếp tin nhắn)
của họ, để có thể xem những người nào được chuyển tiếp tin nhắn bởi những người
theo dõi (followers) có ảnh hưởng nhất của họ.
Ở một mức cao, ứng dụng web, gồm đối tượng User và Retweet, sẽ làm một số
việc: Trước tiên, người dùng phải xác thực mình với Twitter thông qua OAuth.
Tiếp theo, ứng dụng sẽ yêu cầu một tiến trình chạy nền để thu thập được dữ liệu
chuyển tiếp tin nhắn của người dùng. Đồng thời, ứng dụng sẽ hiển thị một bảng
điều khiển và thực hiện một lời gọi Ajax để lấy ra dữ liệu chuyển tiếp tin nhắn, vẫn
còn lưu giữ lâu bền trong kho dữ liệu GAE (được gọi là Bigtable).
Tôi đã xây dựng các khía cạnh miền của ứng dụng vào tháng trước, nên những gì
còn lại là tích hợp nó với hệ thống cấp phép của Twitter và sau đó hiển thị dữ liệu
tương ứng được lấy ra.
Cấp phép người dùng với OAuth
Như bạn đã biết ở Phần 1, Twitter sử dụng OAuth để cấp phép cho người dùng.
Biểu mẫu OAuth cần thiết phụ thuộc vào việc ứng dụng được triển khai trên một
máy tính để bàn, trên thiết bị di động hay trong môi trường web. Ngoài ra, có hai
điều bạn thực sự cần biết về cấp phép cho người dùng với OAuth:
Ứng dụng không cần lưu trữ một tên đăng nhập và mật khẩu.
Việc cấp phép được giao cho một nhà cung cấp đáng tin cậy, như Twitter.
Việc cấp phép được thực hiện bằng các thẻ xác thực khác nhau, trao đổi được. Do
ứng dụng Retweet được triển khai vào một môi trường web, bước đầu tiên là đăng
ký ứng dụng đó với Twitter. Khi tôi đăng ký, tôi cung cấp một số thông tin, trong
đó có một URL gọi lại sẽ được sử dụng như một khóa. Tôi có thể thay đổi URL
trong thời gian chạy. Đổi lại, tôi nhận được một khóa và một bí mật của người
dùng, tất nhiên tôi cần phải giữ những thứ đó cho riêng mình.
Tiếp theo, tôi cần giấy phép của người dùng để đăng nhập vào Twitter và lấy dữ
liệu chuyển tiếp tin nhắn của họ. Người dùng cấp phép bằng cách gửi một số thông
tin đến Twitter, sau đó Twitter sẽ truy vấn URL gọi lại của tôi. Khi làm như vậy,
Twitter cũng sẽ chuyển kèm theo một số thẻ xác thực (như các tham số URL, có
thể nhận biết được qua việc lập trình).
Quá trình cấp phép
Tôi sẽ sử dụng hai servlet để xử lý quá trình cấp phép. Servlet đầu tiên sẽ tạo ra
một đối tượng Session (Phiên làm việc), đăng ký một URL gọi lại với Twitter và
hướng người dùng đến Twitter để xác thực. Quá trình xác thực cũng sẽ cho phép
ứng dụng của tôi đại diện cho người dùng, như bạn sẽ thấy ngay sau đây. Servlet
thứ hai sẽ là cuộc gọi lại của tôi; nó sẽ xử lý đáp ứng từ Twitter và tạo ra một đối
tượng User tương ứng.
Gaelyk là một framwork Groovy, tôi sẽ sử dụng cú pháp ngắn gọn và các mã viết
tắt của nó để nhanh chóng xây dựng ứng dụng web GAE của mình. Điều đầu tiên
tôi cần làm với Gaelyk là định nghĩa các URL tùy chỉnh của ứng dụng mình, để tôi
có thể thực hiện các URL tùy chỉnh đó bằng cách sử dụng các định tuyến URL.
Cấu hình định tuyến URL của Gaelyk về cơ bản là một DSL cho phép tôi (1) xây
dựng các URL dễ đọc và (2) che giấu công nghệ bên dưới. Liệt kê 3 cho thấy giai
đoạn đầu tiên của ánh xạ này:
Liệt kê 3. Bắt đầu một tệp các định tuyến
get "/login", forward: "/login.groovy"
get "/tcallback", forward: "/tcallback.groovy"
Trong Liệt kê 3, tôi đã định nghĩa hai URL tuỳ chỉnh. Hãy lưu ý cách /login che
giấu khía cạnh .groovy, giúp cho URL dễ đọc hơn. DSL mô tả một chuỗi đơn giản:
Nếu một HTTP GET được áp dụng cho một URL như là your_domain/login, thì
chuyển tiếp yêu cầu đó tới /login.groovy, đó là một servlet (hoặc đúng ra là
groovlet) trong trường hợp Gaelyk.
Groovlet đăng nhập của tôi cũng rất đơn giản, bạn có thể thấy trong Liệt kê 4:
Liệt kê 4. Groovlet đăng nhập
import twitter4j.TwitterFactory
def twitter = new TwitterFactory().getOAuthAuthorizedInstance("...", "...")
def requestToken = twitter.getOAuthRequestToken("
1.appspot.com/tcallback")
if(!session){
session = request.getSession(true)
}
session.setAttribute("requestToken_token", requestToken.token)
session.setAttribute("requestToken_secret", requestToken.tokenSecret)
redirect(requestToken.getAuthorizationURL())
Trong Liệt kê 4, tôi sử dụng khóa và bí mật (secret) người dùng để tạo ra một cá
thể TwitterFactory. TwitterFactory là một phần của thư viện Twitter4J. Sau đó tôi
thu được một cá thể RequestToken, trong quá trình chuyển đi URL gọi lại riêng
của mình ( đã định nghĩa trong Liệt kê 3), để
Twitter sẽ gọi URL gọi lại đó sau khi có người dùng cấp quyền truy cập. Cuối
cùng, tôi đặt hai mẩu thông tin vào một đối tượng HttpSession. Thông tin đó sẽ cần
đến khi dữ liệu được truyền trở lại ứng dụng web. Sau đó một trình duyệt được
chuyển hướng đến đến một URL ủy quyền trên trang web của Twitter.
Trình xử lý gọi lại
Trình xử lý gọi lại của tôi, đã định nghĩa trong Liệt kê 5, chỉ cần nhận thông tin cần
thiết từ Twitter và liên kết dữ liệu đó với những gì được tìm thấy trong đối tượng
HttpSession. Sau đó nó tạo ra một đối tượng User mới. Một khả năng khác là, nếu
kho dữ liệu này đã chứa một đối tượng User rồi, thì groovlet chỉ cần cập nhật nó
với dữ liệu thông tin đăng nhập mới.
Liệt kê 5. Một trình xử lý gọi lại
import java.util.Date
import twitter4j.TwitterFactory
import com.b50.gretweet.User
def twitter = new TwitterFactory().getOAuthAuthorizedInstance("...", "...")
def accTok = twitter.getOAuthAccessToken(
session.getAttribute("requestToken_token"),
session.getAttribute("requestToken_secret"),
request.getParameter("oauth_verifier"))
def scrname = twitter.getScreenName()
session.setAttribute("screenname", scrname)
new User(scrname, accTok.getToken(), accTok.getTokenSecret()).save()
defaultQueue << [
countdownMillis: 1, url: "/retweetpull",
taskName: "twitter-pull-${new Date().time}",
method: 'POST', params: [id: scrname]
]
redirect "/dashboard/${scrname}"
Khi được gọi, groovlet nhận được một tham số khóa từ Twitter: oauth_verifier.
Tham số này, được kết hợp với một khóa và bí mật, sẽ được dùng làm giấy phép để
đại diện cho người dùng tiếp tục làm việc. Groovlet cũng cập nhật đối tượng
session với việc xử lý Twitter của người dùng, rồi đối tượng User hoặc được tạo ra
hoặc được cập nhật.
Mã xử lý defaultQueue là phép thuật của Gaelyk để đặt một yêu cầu vào một hàng
đợi GAE và tôi sẽ thảo luận thêm về nó trong phần tiếp theo. Ở lệnh cuối cùng
trong Liệt kê 5, trình duyệt của người dùng được chuyển hướng đến một URL mới,
có ánh xạ get "/dashboard/@name", forward: "/dashboard.gtpl?tname=@name".
URL này được nối với một trang web để nhận một tham số có tên là tname, là tên
màn hình Twitter của người dùng.
Vào/ra và hiệu năng của GAE
Nếu bạn muốn xây dựng các ứng dụng của mình trên GAE, bạn phải tuân theo một
số quy tắc. Google định nghĩa những thư viện nào mà bạn có thể và không thể sử
dụng và cũng đặt ra một giới hạn thời gian phản hồi của servlet. Giới hạn thời gian
lớn nhất mà một servlet dùng để xử lý một yêu cầu gửi đến là khoảng 30 giây. Nếu
một servlet mất nhiều thời gian hơn lượng thời gian nói trên để đưa ra một phản
hồi, thì GAE sinh ra một lỗi dưới dạng một mã HTTP 500.
Google đã có lý do chính đáng để áp đặt thời hạn này: nó cần có khả năng mở rộng
quy mô ứng dụng của bạn khi cần thiết, mà không có sự trợ giúp của bạn. Vì vậy,
nếu bạn thấy rằng đoạn mã mà bạn đã viết đòi hỏi quá nhiều thời gian để xử lý —
có nghĩa là, nó tương tác với các hệ thống khác mà bạn không có quyền kiểm soát
(hoặc chỉ đơn giản là mã code đã được viết không tốt) — thì có lẽ bạn cần xem xét
lại ứng dụng của mình.
Là một nhà phát triển GAE, bạn không có quyền truy cập vào các máy tính bên
dưới đang chạy ứng dụng của mình; trên thực tế, bạn sẽ không biết cấu hình của
chúng hoặc thậm chí chúng có bao nhiêu bộ nhớ. Nhưng có lẽ đây không phải là
nơi các vấn đề hiệu năng sẽ xuất đầu lộ diện. Vấn đề Vào/ra là thủ phạm phổ biến
của hiệu năng kém và trong GAE, các vấn đề Vào/ra thường sẽ bất ngờ xảy ra khi
bạn tương tác với các hệ thống khác, như Twitter.
Việc thực hiện các lời gọi API tới Twitter có thể không đáng tin cậy vì (như mọi
người dùng Twitter đều biết) Twitter thỉnh thoảng cũng bị "sập". Thời gian phản
hồi cũng có thể chậm ổ đĩa cứng bị quá tải. Vì vậy, việc xây dựng một ứng dụng
dựa vào dữ liệu của Twitter cần phải lập kế hoạch một chút. Trong GAE, còn cần
phải xếp hàng nữa.
Bộ đếm thời gian phản hồi của GAE
Google App Engine cung cấp một cơ chế hàng đợi để cho phép các tác vụ được xử
lý không đồng bộ khi chạy ngầm. Thật thú vị, bản thân mỗi tác vụ là một servlet và
cái bạn đưa vào một hàng đợi là một URL, cùng với các tham số nếu có. Bạn có
thể thấy tất cả điều này tại Liệt kê 5. Các hàng đợi GAE cho phép bạn chọn ra các
tiến trình có khả năng chạy lâu dài, chia tách chúng thành các tác vụ (các servlet)
ngắn gọn và đưa các tác vụ đó vào các hàng đợi để được thực hiện trong nền sau.
Tất nhiên, nếu một tác vụ làm một việc gì đó thú vị, bạn có thể lưu dữ liệu này vào
kho dữ liệu và lấy nó ra tại một thời điểm nào đó sau này — đó là những gì tôi sắp
làm với các dữ liệu chuyển tiếp tin nhắn trên Twitter của người dùng.
Một khi người dùng đã xác thực với Twitter, tôi sẽ tạo ra một URL dẫn tới servlet
khác để nhận được các dữ liệu chuyển tiếp tin nhắn thông qua API của Twitter và
đưa URL đó vào một hàng đợi. Tôi sẽ sử dụng hàng đợi mặc định của GAE (có tên
là "default"), mặc dù tôi có thể tạo ra một hàng đợi duy nhất nếu tôi muốn. Liệt kê
6 cho thấy mã để đặt một yêu cầu vào hàng đợi mặc định của GAE, cũng như bạn
đã thấy lần đầu trong Liệt kê 5:
Liệt kê 6. Đặt một yêu cầu vào một hàng đợi
defaultQueue << [
countdownMillis: 1, url: "/retweetpull",
taskName: "twitter-pull-${new Date().time}",
method: 'POST', params: [id: scrname]
]
Tôi đã đặt một yêu cầu cho URL /retweetpull, được ánh xạ đúng là post
"/retweetpull", forward: "/retweetpull.groovy". Lưu ý rằng đây là một yêu cầu
HTTP POST. Tôi cũng đã chuyển kèm theo tham số id, là tên màn hình của người
dùng. Lưu ý rằng tên của các tác vụ hàng đợi phải là duy nhất. Tôi nhận ra rằng sẽ
thật thuận tiện nếu lấy thời gian hiện hành nối với tên hàng đợi đợi để tạo ra một
tên duy nhất. Một tùy chọn khác được trình bày trong Liệt kê 6 là định nghĩa một
thời gian đếm ngược, sẽ chạy cho đến khi tác vụ được thực hiện.
Một tác vụ trong một hàng đợi GAE chính là một servlet. Do đó, một "trình đọc"
hàng đợi sẽ gọi ra URL và servlet cụ thể mà tôi muốn thực hiện thể hiện trong Liệt
kê 7:
Liệt kê 7. Một servlet được thực hiện không đồng bộ
import twitter4j.TwitterFactory
import twitter4j.http.AccessToken
import com.b50.gretweet.User
import com.b50.gretweet.Retweet
def user = User.findByName(params['id'])
def twitter = getTwitter(user)
def retweets = []
def statuses = twitter.getRetweetsOfMe()
statuses.each { status ->
def tid = status.getId()
def dt = status.getCreatedAt()
def txt = status.getText()
users = twitter.getRetweetedBy(status.getId())
users.each { usr ->
retweets << new Retweet(usr.getScreenName(), tid, dt, txt,
usr.getFollowersCount(), usr.getProfileImageURL().toString(),
usr.getName())
}
}
user.addRetweets(retweets)
def getTwitter(user){
return new TwitterFactory().getOAuthAuthorizedInstance("...",
"...", new AccessToken(user.token, user.tokenSecret))
}
Việc đầu tiên mà servlet trong Liệt kê 7 làm là tìm một cá thể User, trên thực tế nó
lấy cá thể đó từ memcache. Tiếp theo, vì được ủy quyền để làm, nên servlet thực
hiện vai trò của người dùng để thiết lập một phiên làm việc Twitter. Dùng API của
Twitter4J, nó nhận được một danh sách các dữ liệu chuyển tiếp tin nhắn — ví dụ,
twitter.getRetweetsOfMe(). Nó xử lý từng cuộc chuyển tiếp tin nhắn thành một đối
tượng Retweet và đặt tất cả các đối tượng Retweet vào một List ((bằng cách sử
dụng toán tử << tiện dụng của Groovy, thực ra chỉ là một phương thức add). Khi
đối tượng đó được thêm vào cá thể User thông qua phương thức addRetweets) nó
sẽ được lưu.
Như vậy, tôi đã viết xong vài đoạn mã trọng yếu trong ứng dụng web của mình.
Tiếp theo là tìm hiểu xem cách giao tiếp như thế nào — có nghĩa là, tôi sẽ sử dụng
định dạng nào khi phát hành một yêu cầu để lấy dữ liệu ứng dụng.
Định dạng yêu cầu: JSON
Một số người nói rằng JSON đã thay thế XML làm ngôn ngữ chung mới để trao
đổi dữ liệu Internet. JSON gọn nhẹ hơn so với XML, làm cho việc đọc và phân tích
cú pháp dễ dàng hơn. Bạn có thể tự mình nhận thấy sự khác biệt bằng cách xem xét
hai liệt kê dưới đây. Liệt kê đầu tiên cho thấy dữ liệu chuyển tiếp tin nhắn được
biểu diễn bằng XML:
BarackObama
5901913
2010-11-11
"I want our veterans to know: We remember..."
2758011831459840
"Barack Obama"
Liệt kê dưới đây cho thấy cũng dữ liệu đó nhưng được biểu diễn bằng JSON:
{
"screenname":"BarackObama",
"influence":5901913,
"date":"2010-11-11"
"tweet":"I want our veterans to know: We remember...",
"tweetid":2758011831459840,
"picture":"",
"username":"Barack Obama"
}
Lưu ý rằng tài liệu JSON trông rất giống như một ánh xạ. Có các tên cùng với các
giá trị. Điều này giúp cho việc biểu diễn một đối tượng miền domain trở nên khá
đơn giản, nhưng đừng để cho tính đơn giản của JSON đánh lừa bạn. JSON có thể
biểu diễn các danh sách, có thể cũng là các giá trị. Cách đánh dấu của JSON ít dài
dòng hơn so với XML và dữ liệu tương ứng dễ hiểu bằng trực quan hơn. Tính ngắn
gọn của JSON cũng có thể là một ưu điểm trong các hệ thống Ajax, do hệ thống
Ajax thường có xu hướng đòi hỏi xử lý trình duyệt và băng thông mạng nhiều hơn.
Vì những lý do này, tôi thích JSON hơn XML để truyền thông từ trình duyệt đến
máy chủ. Điều này đặc biệt đúng cho các ứng dụng sử dụng Ajax ở mặt trước, như
ứng dụng này. Cũng như phương thức toString của java.lang.Object cung cấp một
cơ chế thuận tiện để mã hóa một đối tượng, tôi thấy rằng làm cho các đối tượng
miền domain trong một ứng dụng web có khả năng JSON thông qua một phương
thức toJSON là có ích. Bước đầu tiên của tôi là thực thi một hợp đồng có khả năng
JSON thông qua giao diện trong Liệt kê 8:
Liệt kê 8. Một hợp đồng toJSON
public interface JSONable {
String toJSON();
}
Tiếp theo, tôi cho cá