Phát triển Java 2.0: Khai phá Twitter với Objectify-Appengine, Phần 2

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.

pdf35 trang | Chia sẻ: lylyngoc | Lượt xem: 1275 | Lượt tải: 1download
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á
Tài liệu liên quan