PDF:

Máy ứng dụng của Google cho Java: Phần 2: Xây dựng
ứng dụng sát thủ
Xây dựng ứng dụng quản lý liên hệ riêng của bạn trong Máy ứng dụng
Rick Hightower
Giám đốc
eBlox
28 05 2010
Toàn bộ ý nghĩa của một nền tảng đám mây giống như Máy ứng dụng của Google (Google App
Engine) cho Java™ là ở chỗ có thể tưởng tượng, xây dựng và triển khai các ứng dụng sát thủ
có chất lượng chuyên nghiệp có thể mở rộng — không phải phá sản ngân hàng hoặc biến mình
thành người mất trí. Trong phần thứ hai của bài viết ba phần của mình giới thiệu về Máy ứng
dụng của Google cho Java, Rick Hightower sẽ đưa bạn vượt ra ngoài các ví dụ làm sẵn của Phần
1 bằng một hướng dẫn từng bước để viết và triển khai một ứng dụng quản lý liên hệ đơn giản
bằng cách sử dụng Máy ứng dụng cho Java.
Xem thêm bài trong loạt bài này
Trong Phần 1 của bài giới thiệu này về xây dựng các ứng dụng Java có khả năng mở rộng với Máy
ứng dụng (App Engine) cho Java, bạn đã tìm hiểu bộ công cụ Eclipse và cơ sở hạ tầng của nền tảng
điện toán đám mây của Google (hay PAAS) cho các nhà phát triển Java. Các ví dụ trong bài viết
đã có sẵn, để cho bạn có thể tập trung vào việc tích hợp Máy ứng dụng cho Java với Eclipse và
nhanh chóng thực hành xây dựng và triển khai các kiểu ứng dụng khác nhau — cụ thể là xây dựng
một ứng dụng bằng cách sử dụng Bộ công cụ Web của Google (Google Web Toolkit - GWT) và một
ứng dụng dựa trên servlet. Bài viết này xây dựng trên nền tảng đó và cũng chuẩn bị cho bạn các bài
tập lập trình nâng cao hơn trong Phần 3 của bài viết này.
Ứng dụng quản lý-liên hệ mà bạn sẽ xây dựng cho phép một người sử dụng lưu trữ thông tin liên hệ
cơ bản như tên, địa chỉ thư điện tử (e-mail) và số điện thoại. Để tạo ứng dụng này, bạn sẽ sử dụng
trình thủ thuật tạo dự án GWT của Eclipse.
Từ CRUD đến liên hệ
Bước đầu tiên để xây dựng một ứng dụng mới trong Máy ứng dụng cho Java, bây giờ như bạn biết,
là khởi chạy trình thủ thuật tạo dự án trong Eclipse. Khi đó, bạn có thể khởi chạy trình thủ thuật bộ
© Copyright IBM Corporation 2010
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Nhẫn hiệu đăng ký
Trang 1 của 18
developerWorks®
ibm.com/developerWorks/vn/
khởi động dự án GWT để tạo ra một dự án GWT. (Phần 1 của bài viết này trình bày các chỉ dẫn chi
tiết để tạo một dự án GWT trong Máy ứng dụng cho Java.)
Để thực hiện bài tập này, bạn sẽ bắt đầu bằng một ứng dụng CRUD đơn giản và sau đó thêm kho
lưu trữ thực. Bây giờ, hãy sử dụng một đối tượng truy cập dữ liệu (DAO) với triển khai thực hiện giả,
như thấy trong Liệt kê 1:
Liệt kê 1. Giao diện với ContactDAO
package gaej.example.contact.server;
import java.util.List;
import gaej.example.contact.client.Contact;
public interface ContactDAO {
void addContact(Contact contact);
void removeContact(Contact contact);
void updateContact(Contact contact);
List<Contact> listContacts();
}
thêm các phương thức để thêm một mối liên hệ, loại bỏ một mối liên hệ, cập nhật một
mối liên hệ và trả về một danh sách tất cả các mối liên hệ. Nó là một giao diện CRUD rất cơ bản để
quản lý các mối liên hệ. Lớp Contact (Liên hệ) là đối tượng miền của bạn, như thấy trong Liệt kê 2:
ContactDAO
Liệt kê 2. Đối tượng miền liên hệ (gaej.example.contact.client.Contact)
package gaej.example.contact.client;
import java.io.Serializable;
public class Contact implements Serializable {
private
private
private
private
static
String
String
String
final long serialVersionUID = 1L;
name;
email;
phone;
public Contact() {
}
public Contact(String name, String email, String phone) {
super();
this.name = name;
this.email = email;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 2 của 18
ibm.com/developerWorks/vn/
developerWorks®
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Đối với phiên bản đầu tiên của ứng dụng này, bạn sẽ làm việc với một đối tượng giả, lưu trữ các mối
liên hệ trong một bộ sưu tập nằm ngay trong bộ nhớ, như thấy trong Liệt kê 3:
Liệt kê 3. Lớp DAO giả
package gaej.example.contact.server;
import gaej.example.contact.client.Contact;
import
import
import
import
import
java.util.ArrayList;
java.util.Collections;
java.util.LinkedHashMap;
java.util.List;
java.util.Map;
public class ContactDAOMock implements ContactDAO {
Map<String, Contact> map = new LinkedHashMap<String, Contact>();
{
map.put("[email protected]",
new Contact("Rick Hightower", "[email protected]", "520-555-1212"));
map.put("[email protected]",
new Contact("Scott Fauerbach", "[email protected]", "520-555-1213"));
map.put("[email protected]",
new Contact("Bob Dean", "[email protected]", "520-555-1214"));
}
public void addContact(Contact contact) {
String email = contact.getEmail();
map.put(email, contact);
}
public List<Contact> listContacts() {
return Collections.unmodifiableList(new ArrayList<Contact>(map.values()));
}
public void removeContact(Contact contact) {
map.remove(contact.getEmail());
}
public void updateContact(Contact contact) {
map.put(contact.getEmail(), contact);
}
}
Tạo các dịch vụ từ xa
Bây giờ mục tiêu của bạn là tạo ra một giao diện người dùng đồ họa GWT, cho phép bạn sử dụng
DAO. Nó sẽ sử dụng tất cả các phương thức trên giao diện ContactDAO. Bước đầu tiên là bao bọc
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 3 của 18
developerWorks®
ibm.com/developerWorks/vn/
chức năng của lớp DAO (phiên bản tương lai sẽ thực sự trao đổi với kho lưu trữ dữ liệu trên phía
máy chủ vì thế nó phải ở trên máy chủ) trong một dịch vụ, như cho thấy trong Liệt kê 4:
Liệt kê 4. ContactServiceImpl
package gaej.example.contact.server;
import java.util.ArrayList;
import java.util.List;
import gaej.example.contact.client.Contact;
import gaej.example.contact.client.ContactService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class ContactServiceImpl extends RemoteServiceServlet implements ContactService {
private static final long serialVersionUID = 1L;
private ContactDAO contactDAO = new ContactDAOMock();
public void addContact(Contact contact) {
contactDAO.addContact(contact);
}
public List<Contact> listContacts() {
List<Contact> listContacts = contactDAO.listContacts();
return new ArrayList<Contact> (listContacts);
}
public void removeContact(Contact contact) {
contactDAO.removeContact(contact);
}
public void updateContact(Contact contact) {
contactDAO.updateContact(contact);
}
}
Chú ý rằng ContactServiceImpl thực hiện RemoteServiceServlet và sau đó định nghĩa các
phương thức để thêm một mối liên hệ, liệt kê các mối liên hệ, loại bỏ một mối liên hệ và cập nhật
một mối liên hệ. Nó ủy quyền tất cả các hoạt động này cho ContactDAOMock. ContactServiceImpl
chỉ là một trình bao bọc (wrapper) xung quanh ContactDAO để trưng ra chức năng của ContactDAO
cho GUI GWT. ContactServiceImpl được ánh xạ trong tệp web.xml tới URI /contactlist/
contacts trong tệp web.xml, như chỉ ra trong Liệt kê 5:
Liệt kê 5. web.xml for ContactService
<servlet>
<servlet-name>contacts</servlet-name>
<servlet-class>gaej.example.contact.server.ContactServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>/contactlist/contacts</url-pattern>
</servlet-mapping>
Để cho phép mặt trước GUI truy cập vào dịch vụ này, bạn cần phải định nghĩa cả hai giao diện dịch
vụ từ xa và giao diện dịch vụ từ xa không đồng bộ, như hiển thị trong các Liệt kê 6 và 7:
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 4 của 18
ibm.com/developerWorks/vn/
developerWorks®
Liệt kê 6. ContactService
package gaej.example.contact.client;
import java.util.List;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("contacts")
public interface ContactService extends RemoteService {
List<Contact> listContacts();
void addContact(Contact contact);
void removeContact(Contact contact);
void updateContact(Contact contact);
}
Liệt kê 7. ContactServiceAsync
package gaej.example.contact.client;
import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface ContactServiceAsync {
void listContacts(AsyncCallback<List <Contact>> callback);
void addContact(Contact contact, AsyncCallback<Void> callback);
void removeContact(Contact contact, AsyncCallback<Void> callback);
void updateContact(Contact contact, AsyncCallback<Void> callback);
}
Chú ý rằng ContactService triển khai thực hiện giao diện RemoteService và định nghĩa một
@RemoteServiceRelativePath, chỉ rõ một đường dẫn tương đối của "các mối liên hệ". Đường dẫn
tương đối này tương ứng với đường dẫn mà bạn đã định nghĩa cho dịch vụ này trong tệp web.xml
(chúng phải khớp). ContactServiceAsync có các đối tượng gọi lại sao cho GWT GUI có thể được
thông báo về các cuộc gọi từ máy chủ mà không chặn hoạt động của máy khách khác.
Đi tắt qua mã rối (spaghetti code)
Tôi không phải là một người hâm mộ viết mã rắc rối và tôi tránh viết như thế bất cứ khi nào tôi có
thể. Một ví dụ về mã rối sẽ là một nhóm các lớp bên trong ẩn danh mà các phương thức của nó xác
định các lớp vô danh bên trong. Các lớp bên trong này, đến lượt chúng, lại thực hiện các cuộc gọi
lại để gọi các phương thức, mà sau đó các phương thức này được định nghĩa nội tuyến trong một
lớp bên trong. Eo ôi! Thành thật mà nói, tôi không thể đọc hoặc hiểu mã bị làm rối tung lên, ngay
cả khi nó chính là mã tôi viết! Vì vậy, để dàn phẳng những thứ này ra một chút, tôi muốn đề nghị
chia GUI GWT thành ba phần:
• ContactListEntryPoint
• ContactServiceDelegate
• ContactListGUI
ContactListEntryPoint là điểm vào chính; nó thực hiện việc kết nối sự kiện GUI.
ContactServiceDelegate bao bọc chức năng ContactService và ẩn giấu việc kết nối các cuộc gọi
lại của lớp bên trong. ContactListGUI quản lý tất cả các thành phần GUI và xử lý các sự kiện từ GUI
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 5 của 18
developerWorks®
ibm.com/developerWorks/vn/
và Service (Dịch vụ). ContactListGUI sử dụng ContactServiceDelegate để tạo ra các yêu cầu của
ContactService.
Tệp ContactList.gwt.xml (một nguồn tài nguyên trong gaej.example.contact) chỉ rõ
ContactListEntryPoint là điểm vào chính cho ứng dụng này bằng cách sử dụng phần tử entrypoint (điểm vào) như chỉ ra trong Liệt kê 8:
Liệt kê 8. ContactList.gwt.xml
<entry-point class='gaej.example.contact.client.ContactListEntryPoint'/>
Lớp ContactListEntryPoint triển khai thực hiện giao diện EntryPoint từ GWT
(com.google.gwt.core.client.EntryPoint), báo hiệu rằng lớp này sẽ được gọi để khởi tạo
GUI. ContactListEntryPoint không làm nhiều việc. Nó tạo ra một cá thể của ContactListGUI
và một cá thể của ContactServiceDelegate, và sau đó cho phép chúng biết về nhau để cho
chúng có thể cộng tác. ContactListEntryPoint sau đó thực hiện việc kết nối sự kiện GUI.
ContactListEntryPoint được hiển thị trong Liệt kê 9:
Liệt kê 9. ContactListEntryPoint
package gaej.example.contact.client;
import
import
import
import
com.google.gwt.core.client.EntryPoint;
com.google.gwt.event.dom.client.ClickEvent;
com.google.gwt.event.dom.client.ClickHandler;
com.google.gwt.user.client.ui.HTMLTable.Cell;
/**
* Entry point classes define onModuleLoad().
*/
public class ContactListEntryPoint implements EntryPoint {
private ContactListGUI gui;
private ContactServiceDelegate delegate;
/**
* This is the entry point method.
*/
public void onModuleLoad() {
gui = new ContactListGUI();
delegate = new ContactServiceDelegate();
gui.contactService = delegate;
delegate.gui = gui;
gui.init();
delegate.listContacts();
wireGUIEvents();
}
private void wireGUIEvents() {
gui.contactGrid.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
Cell cellForEvent = gui.contactGrid.getCellForEvent(event);
gui.gui_eventContactGridClicked(cellForEvent);
}});
gui.addButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
gui.gui_eventAddButtonClicked();
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 6 của 18
ibm.com/developerWorks/vn/
developerWorks®
}});
gui.updateButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
gui.gui_eventUpdateButtonClicked();
}});
gui.addNewButton.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
gui.gui_eventAddNewButtonClicked();
}});
}
}
Chú ý rằng ContactListEntryPoint kết nối các sự kiện dành cho addButton, updateButton,
contactGrid và addNewButton. Nó làm điều này bằng cách đăng ký các lớp bên trong vô danh đã
triển khai thực hiện giao diện lắng nghe (listener) các sự kiện của các tiện ích GUI ấy. Đó là một
kỹ thuật rất giống với xử lý sự kiện trong Swing. Các sự kiện tiện ích GUI là từ các tiện ích được
GUI (ContactListGUI) tạo ra, tôi sẽ thảo luận nó một chút. Chú ý rằng lớp GUI có các phương thức
gui_eventXXX để đáp lại các sự kiện GUI.
tạo các tiện ích GUI và đáp lại các sự kiện từ chúng. ContactListGUI dịch
các sự kiện GUI thành các hành động mà người dùng muốn thực hiện trên ContactsService.
ContactListGUI sử dụng ContactServiceDelegate để gọi các phương thức trên ContactService.
ContactServiceDelegate tạo ra một giao diện không đồng bộ với ContactService và sử
dụng nó để tiến hành các cuộc gọi Ajax không đồng bộ. ContactServiceDelegate sẽ thông
báo cho ContactListGUI về các các sự kiện (trả về thành công hay thất bại) từ dịch vụ này.
ContactServiceDelegate được hiển thị trong Liệt kê 10:
ContactListGUI
Liệt kê 10. ContactServiceDelegatepackage gaej.example.contact.client;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
public class ContactServiceDelegate {
private ContactServiceAsync contactService = GWT.create(ContactService.class);
ContactListGUI gui;
void listContacts() {
contactService.listContacts(new AsyncCallback<List<Contact>> () {
public void onFailure(Throwable caught) {
gui.service_eventListContactsFailed(caught);
}
public void onSuccess(List<Contact> result) {
gui.service_eventListRetrievedFromService(result);
}
}//end of inner class
);//end of listContacts method call.
}
void addContact(final Contact contact) {
contactService.addContact(contact, new AsyncCallback<Void> () {
public void onFailure(Throwable caught) {
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 7 của 18
developerWorks®
ibm.com/developerWorks/vn/
gui.service_eventAddContactFailed(caught);
}
public void onSuccess(Void result) {
gui.service_eventAddContactSuccessful();
}
}//end of inner class
);//end of addContact method call.
}
void updateContact(final Contact contact) {
contactService.updateContact(contact, new AsyncCallback<Void> () {
public void onFailure(Throwable caught) {
gui.service_eventUpdateContactFailed(caught);
}
public void onSuccess(Void result) {
gui.service_eventUpdateSuccessful();
}
}//end of inner class
);//end of updateContact method call.
}
void removeContact(final Contact contact) {
contactService.removeContact(contact, new AsyncCallback<Void> () {
public void onFailure(Throwable caught) {
gui.service_eventRemoveContactFailed(caught);
}
public void onSuccess(Void result) {
gui.service_eventRemoveContactSuccessful();
}
}//end of inner class
);//end of updateContact method call.
}
}
Chú ý rằng ContactServiceDelegate thông báo cho ContactListGUI về các sự kiện dịch vụ thông
qua các phương thức bắt đầu bằng service_eventXXX. Như đã đề cập trước đó, một trong những
mục tiêu của tôi khi viết ContactListGUI là tránh các lớp bên trong bị lồng nhau và tạo ra một lớp
GUI tương đối bằng phẳng (để tôi có thể dễ dàng đọc và làm việc với nó sau này). ContactListGUI
chỉ dài 186 dòng và khá đơn giản. ContactListGUI quản lý chín tiện ích GUI và cũng cộng tác với
ContactServiceDelegate để quản lý một danh sách CRUD, như trong Liệt kê 11:
Liệt kê 11. ContactListGUI đang hoạt động
package gaej.example.contact.client;
import java.util.List;
import
import
import
import
import
import
import
com.google.gwt.user.client.ui.Button;
com.google.gwt.user.client.ui.Grid;
com.google.gwt.user.client.ui.Hyperlink;
com.google.gwt.user.client.ui.Label;
com.google.gwt.user.client.ui.RootPanel;
com.google.gwt.user.client.ui.TextBox;
com.google.gwt.user.client.ui.HTMLTable.Cell;
public class ContactListGUI {
/* Constants. */
private static final String CONTACT_LISTING_ROOT_PANEL = "contactListing";
private static final String CONTACT_FORM_ROOT_PANEL = "contactForm";
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 8 của 18
ibm.com/developerWorks/vn/
private
private
private
private
static
static
static
static
final
final
final
final
developerWorks®
String CONTACT_STATUS_ROOT_PANEL = "contactStatus";
String CONTACT_TOOL_BAR_ROOT_PANEL = "contactToolBar";
int EDIT_LINK = 3;
int REMOVE_LINK = 4;
/* GUI Widgets */
protected Button addButton;
protected Button updateButton;
protected Button addNewButton;
protected TextBox nameField;
protected TextBox emailField;
protected TextBox phoneField;
protected Label status;
protected Grid contactGrid;
protected Grid formGrid;
/* Data model */
private List<Contact> contacts;
private Contact currentContact;
protected ContactServiceDelegate contactService;
Chú ý rằng ContactListGUI theo dõi mối liên hệ hiện tại được nạp vào biểu mẫu (currentContact)
và danh sách các mối liên hệ trong danh sách (contacts). Hình 1 cho thấy các tiện ích tương ứng
với GUI được tạo ra như thế nào:
Hình 1. Các tiện ích hoạt động trong GUI quản lý liên hệ
Liệt kê 12 cho thấy ContactListGUI tạo các tiện ích và biểu mẫu về một mối liên hệ và sau đó đặt
các tiện ích trong biểu mẫu đó:
Liệt kê 12. ContactListGUI tạo và đặt các tiện ích
public class ContactListGUI {
/* Constants. */
private static final String CONTACT_LISTING_ROOT_PANEL = "contactListing";
private static final String CONTACT_FORM_ROOT_PANEL = "contactForm";
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 9 của 18
developerWorks®
ibm.com/developerWorks/vn/
private static final String CONTACT_STATUS_ROOT_PANEL = "contactStatus";
private static final String CONTACT_TOOL_BAR_ROOT_PANEL = "contactToolBar";
...
public void init() {
addButton = new Button("Add new contact");
addNewButton = new Button("Add new contact");
updateButton = new Button("Update contact");
nameField = new TextBox();
emailField = new TextBox();
phoneField = new TextBox();
status = new Label();
contactGrid = new Grid(2,5);
buildForm();
placeWidgets();
}
private void buildForm() {
formGrid = new Grid(4,3);
formGrid.setVisible(false);
formGrid.setWidget(0, 0, new Label("Name"));
formGrid.setWidget(0, 1, nameField);
formGrid.setWidget(1, 0, new Label("email"));
formGrid.setWidget(1, 1, emailField);
formGrid.setWidget(2, 0, new Label("phone"));
formGrid.setWidget(2, 1, phoneField);
formGrid.setWidget(3, 0, updateButton);
formGrid.setWidget(3, 1, addButton);
}
private void placeWidgets() {
RootPanel.get(CONTACT_LISTING_ROOT_PANEL).add(contactGrid);
RootPanel.get(CONTACT_FORM_ROOT_PANEL).add(formGrid);
RootPanel.get(CONTACT_STATUS_ROOT_PANEL).add(status);
RootPanel.get(CONTACT_TOOL_BAR_ROOT_PANEL).add(addNewButton);
}
Phương thức ContactListEntryPoint.onModuleLoad gọi phương thức ContactListGUIinit. Phương
thức init gọi phương thức buildForm để tạo ra một biểu mẫu mới và điền các trường để chỉnh
sửa các dữ liệu liên hệ. Phương thức init sau đó gọi phương thức placeWidgets, để đặt các tiện
ích contactGrid, formGrid, status và addNewButton vào các khe được định nghĩa trong các trang
HTML chứa ứng dụng GUI này, được định nghĩa trong Liệt kê 13:
Liệt kê 13. ContactList.html định nghĩa các khe cho các tiên ích
<h1>Contact List Example</h1>
<table align="center">
<tr>
<td id="contactStatus"></td> <td id="contactToolBar"></td>
</tr>
<tr>
<td id="contactForm"></td>
</tr>
<tr>
<td id="contactListing"></td>
</tr>
</table>
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 10 của 18
ibm.com/developerWorks/vn/
developerWorks®
Các hằng số (như CONTACT_LISTING_ROOT_PANEL="contactListing") tương ứng với các mã nhận
dạng (ID) của các phần tử (như (like id="contactListing") được định nghĩa trong trang HTML.
Điều này cho phép một nhà thiết kế trang có quyền kiểm soát nhiều hơn đối với cách bố trí các tiện
ích của ứng dụng.
Với ứng dụng cơ bản đã xây dựng, chúng ta hãy đi qua một vài kịch bản sử dụng thông thường.
Hiển thị một danh sách khi nạp trang
Khi trang của ứng dụng quản lý liên hệ nạp lần đầu tiên nó gọi phương thức onModuleLoad
của ContactListEntryPoint. onModuleLoad gọi phương thức listContacts của
ContactServiceDelegate, phương thức listContacts gọi phương thức listContact của dịch
vụ một cách không đồng bộ. Khi phương thức listContact trả về, một lớp bên trong vô danh
được định trong ContactServiceDelegate gọi phương thức trình xử lý sự kiện dịch vụ có tên là
service_eventListRetrievedFromService, như thấy trong Liệt kê 14:
Liệt kê 14. Gọi trình xử lý sự kiện listContact
public class ContactListGUI {
...
public void service_eventListRetrievedFromService(List<Contact> result) {
status.setText("Retrieved contact list");
this.contacts = result;
this.contactGrid.clear();
this.contactGrid.resizeRows(this.contacts.size());
int row = 0;
for (Contact contact : result) {
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
row ++;
}
0, new Label(contact.getName()));
1, new Label (contact.getPhone()));
2, new Label (contact.getEmail()));
EDIT_LINK, new Hyperlink("Edit", null));
REMOVE_LINK, new Hyperlink("Remove", null));
}
Phương thức trình xử lý sự kiện service_eventListRetrievedFromService lưu trữ danh sách các
mối liên hệ do máy chủ gửi đi. Sau đó, nó xóa contactGrid có hiển thị danh sách các mối liên hệ.
Nó định lại kích thước về số hàng để khớp với kích thước của danh sách các mối liên hệ được trả
về từ máy chủ. Sau đó nó lặp lại qua toàn bộ danh sách liên hệ, đưa tên, số điện thoại và e-mail
của mỗi mối liên hệ vào ba cột đầu tiên của mỗi hàng. Nó cũng cung cấp một đường liên kết Edit
(Chỉnh sửa) và một đường liên kết Remove (Loại bỏ) cho mỗi mối liên hệ, cho phép người dùng dễ
dàng loại bỏ và sửa mối liên hệ.
Người dùng sửa đổi một mối liên hệ hiện có
Khi người dùng nhấn vào một đường liên kết Edit từ danh sách các các mối liên hệ,
gui_eventContactGridClicked được gọi, như chỉ ra trong Liệt kê 15:
Liệt kê 15. Phương thức trình xử lý sự kiện gui_eventContactGridClicked của
ContactListGUI
public class ContactListGUI {
...
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 11 của 18
developerWorks®
ibm.com/developerWorks/vn/
public void gui_eventContactGridClicked(Cell cellClicked) {
int row = cellClicked.getRowIndex();
int col = cellClicked.getCellIndex();
Contact contact = this.contacts.get(row);
this.status.setText("Name was " + contact.getName() + " clicked ");
if (col==EDIT_LINK) {
this.addNewButton.setVisible(false);
this.updateButton.setVisible(true);
this.addButton.setVisible(false);
this.emailField.setReadOnly(true);
loadForm(contact);
} else if (col==REMOVE_LINK) {
this.contactService.removeContact(contact);
}
}
...
private void loadForm(Contact contact) {
this.formGrid.setVisible(true);
currentContact = contact;
this.emailField.setText(contact.getEmail());
this.phoneField.setText(contact.getPhone());
this.nameField.setText(contact.getName());
}
Phương thức gui_eventContactGridClicked phải xác định xem liên kết Edit hay là liên kết Remove
đã được nhấn. Nó thực hiện điều này bằng cách tìm hiểu xem cột nào được nhấn. Sau đó nó sẽ
che dấu addNewButton và addButton và làm cho thấy rõ updateButton. updateButton hiển thị trong
formGrid và cho phép người dùng gửi thông tin cập nhật quay trở về ContactService. Nó cũng
làm cho emailField chỉ đọc để cho người dùng không thể chỉnh sửa trường e-mail này. Tiếp theo,
gui_eventContactGridClicked gọi loadForm (như thấy trong Liệt kê 15), đặt trạng thái formGrid
thành visible (nhìn thấy được), đặt trạng thái mối liên hệ là đang được chỉnh sửa và sau đó sao
chép các thuộc tính của mối liên hệ này vào các tiện ích emailField, phoneField và nameField.
Khi người dùng nhấn vào updateButton, phương thức trình xử lý sự kiện
gui_eventUpdateButtonClicked được gọi, như trong Liệt kê 16. Phương thức này làm cho
addNewButton nhìn thấy được (như vậy người sử dụng có thể thêm số liên hệ mới) và che dấu
formGrid. Sau đó nó gọi copyFieldDateToContact, sao chép văn bản từ các tiện ích emailField,
phoneField và nameField trở lại vào các thuộc tính của currentContact. Rồi nó gọi phương thức
ContactServiceDelegateupdateContact để chuyển mối liên hệ vừa được cập nhật trở lại cho dịch
vụ.
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 12 của 18
ibm.com/developerWorks/vn/
developerWorks®
Liệt kê 16.Phương thức trình xử lý sự kiện gui_eventUpdateButtonClicked của
ContactListGUI
public class ContactListGUI {
...
public void gui_eventUpdateButtonClicked() {
addNewButton.setVisible(true);
formGrid.setVisible(false);
copyFieldDateToContact();
this.contactService.updateContact(currentContact);
}
private void copyFieldDateToContact() {
currentContact.setEmail(emailField.getText());
currentContact.setName(nameField.getText());
currentContact.setPhone(phoneField.getText());
}
Hai kịch bản này sẽ cho bạn một ý tưởng về cách ứng dụng làm việc, cũng như cách nó lấy ra cơ sở
hạ tầng được Máy ứng dụng cho Java cung cấp như thế nào. Mã đầy đủ của ContactListGUI được
hiển thị trong Liệt kê 17:
Liệt kê 17. Mã đầy đủ của ContactListGUI
package gaej.example.contact.client;
import java.util.List;
import
import
import
import
import
import
import
com.google.gwt.user.client.ui.Button;
com.google.gwt.user.client.ui.Grid;
com.google.gwt.user.client.ui.Hyperlink;
com.google.gwt.user.client.ui.Label;
com.google.gwt.user.client.ui.RootPanel;
com.google.gwt.user.client.ui.TextBox;
com.google.gwt.user.client.ui.HTMLTable.Cell;
public class ContactListGUI {
/* Constants. */
private static final String CONTACT_LISTING_ROOT_PANEL = "contactListing";
private static final String CONTACT_FORM_ROOT_PANEL = "contactForm";
private static final String CONTACT_STATUS_ROOT_PANEL = "contactStatus";
private static final String CONTACT_TOOL_BAR_ROOT_PANEL = "contactToolBar";
private static final int EDIT_LINK = 3;
private static final int REMOVE_LINK = 4;
/* GUI Widgets */
protected Button addButton;
protected Button updateButton;
protected Button addNewButton;
protected TextBox nameField;
protected TextBox emailField;
protected TextBox phoneField;
protected Label status;
protected Grid contactGrid;
protected Grid formGrid;
/* Data model */
private List<Contact> contacts;
private Contact currentContact;
protected ContactServiceDelegate contactService;
public void init() {
addButton = new Button("Add new contact");
addNewButton = new Button("Add new contact");
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 13 của 18
developerWorks®
ibm.com/developerWorks/vn/
updateButton = new Button("Update contact");
nameField = new TextBox();
emailField = new TextBox();
phoneField = new TextBox();
status = new Label();
contactGrid = new Grid(2,5);
buildForm();
placeWidgets();
}
private void buildForm() {
formGrid = new Grid(4,3);
formGrid.setVisible(false);
formGrid.setWidget(0, 0, new Label("Name"));
formGrid.setWidget(0, 1, nameField);
formGrid.setWidget(1, 0, new Label("email"));
formGrid.setWidget(1, 1, emailField);
formGrid.setWidget(2, 0, new Label("phone"));
formGrid.setWidget(2, 1, phoneField);
formGrid.setWidget(3, 0, updateButton);
formGrid.setWidget(3, 1, addButton);
}
private void placeWidgets() {
RootPanel.get(CONTACT_LISTING_ROOT_PANEL).add(contactGrid);
RootPanel.get(CONTACT_FORM_ROOT_PANEL).add(formGrid);
RootPanel.get(CONTACT_STATUS_ROOT_PANEL).add(status);
RootPanel.get(CONTACT_TOOL_BAR_ROOT_PANEL).add(addNewButton);
}
private void loadForm(Contact contact) {
this.formGrid.setVisible(true);
currentContact = contact;
this.emailField.setText(contact.getEmail());
this.phoneField.setText(contact.getPhone());
this.nameField.setText(contact.getName());
}
private void copyFieldDateToContact() {
currentContact.setEmail(emailField.getText());
currentContact.setName(nameField.getText());
currentContact.setPhone(phoneField.getText());
}
public void gui_eventContactGridClicked(Cell cellClicked) {
int row = cellClicked.getRowIndex();
int col = cellClicked.getCellIndex();
Contact contact = this.contacts.get(row);
this.status.setText("Name was " + contact.getName() + " clicked ");
if (col==EDIT_LINK) {
this.addNewButton.setVisible(false);
this.updateButton.setVisible(true);
this.addButton.setVisible(false);
this.emailField.setReadOnly(true);
loadForm(contact);
} else if (col==REMOVE_LINK) {
this.contactService.removeContact(contact);
}
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 14 của 18
ibm.com/developerWorks/vn/
developerWorks®
}
public void gui_eventAddButtonClicked() {
addNewButton.setVisible(true);
formGrid.setVisible(false);
copyFieldDateToContact();
this.phoneField.getText();
this.contactService.addContact(currentContact);
}
public void gui_eventUpdateButtonClicked() {
addNewButton.setVisible(true);
formGrid.setVisible(false);
copyFieldDateToContact();
this.contactService.updateContact(currentContact);
}
public void gui_eventAddNewButtonClicked() {
this.addNewButton.setVisible(false);
this.updateButton.setVisible(false);
this.addButton.setVisible(true);
this.emailField.setReadOnly(false);
loadForm(new Contact());
}
public void service_eventListRetrievedFromService(List<Contact> result) {
status.setText("Retrieved contact list");
this.contacts = result;
this.contactGrid.clear();
this.contactGrid.resizeRows(this.contacts.size());
int row = 0;
for (Contact contact : result) {
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
this.contactGrid.setWidget(row,
row ++;
}
0, new Label(contact.getName()));
1, new Label (contact.getPhone()));
2, new Label (contact.getEmail()));
EDIT_LINK, new Hyperlink("Edit", null));
REMOVE_LINK, new Hyperlink("Remove", null));
}
public void service_eventAddContactSuccessful() {
status.setText("Contact was successfully added");
this.contactService.listContacts();
}
public void service_eventUpdateSuccessful() {
status.setText("Contact was successfully updated");
this.contactService.listContacts();
}
public void service_eventRemoveContactSuccessful() {
status.setText("Contact was removed");
this.contactService.listContacts();
}
public void service_eventUpdateContactFailed(Throwable caught) {
status.setText("Update contact failed");
}
public void service_eventAddContactFailed(Throwable caught) {
status.setText("Unable to update contact");
}
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 15 của 18
developerWorks®
ibm.com/developerWorks/vn/
public void service_eventRemoveContactFailed(Throwable caught) {
status.setText("Remove contact failed");
}
public void service_eventListContactsFailed(Throwable caught) {
status.setText("Unable to get contact list");
}
}
Kết luận
Phần thứ hai này của bài giới thiệu ba phần về Máy ứng dụng của Google cho Java đã giới thiệu
cho bạn về quá trình tạo một ứng dụng GWT tùy chỉnh bằng cách sử dụng các công cụ của trình
cắm thêm (plugin) Eclipse cho Máy ứng dụng cho Java. Trong quá trình xây dựng ứng dụng quản lý
liên hệ đơn giản, bạn đã học được cách:
• Xây dựng các dịch vụ từ xa hoạt động không đồng bộ.
• Tổ chức mã GUI để tránh các khai báo lớp bên trong lồng nhau.
• Sử dụng GWT để triển khai thực hiện chức năng đối với hai trường hợp sử dụng chủ yếu.
Hãy đọc tiếp Phần 3 của bài viết này, ở đây bạn sẽ cải thiện ứng dụng quản lý liên hệ và bổ sung
thêm sự hỗ trợ để tiếp tục duy trì các đối tượng Contact với các phương tiện kho lưu trữ dữ liệu của
Máy ứng dụng cho Java.
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 16 của 18
ibm.com/developerWorks/vn/
developerWorks®
Tài nguyên
Học tập
• "Máy ứng dụng của Google cho Java, Phần 1: Rồ máy lên!" (Rick Hightower, developerWorks,
08.2009): Bắt đầu với các trình cắm thêm Eclipse cho Máy ứng dụng cho Java và tìm hiểu làm
thế nào để nhanh chóng xây dựng các ứng dụng đơn giản có thể mở rộng.
• "Xây dựng một ứng dụng Ajax khi sử dụng Bộ công cụ Web của Google, Apache Derby và
Eclipse, Phần 1: Mặt tiền vui mắt" (Noel Rappin, developerWorks, 10.2006): Khởi động bài
hướng dẫn bốn phần giới thiệu về lập trình Ajax với Bộ công cụ Web của Google.
• "Nối đến đám mây, Phần 1: Sử dụng đám mây trong các ứng dụng" (Mark O'Neill,
developerWorks, 04.2009): Một tổng quan ba phần về các nền tảng điện toán đám mây từ
các nhà cung cấp lớn: Amazon, Google, Microsoft® và SalesForce.com.
• Trang chủ của Máy ứng dụng của Google: Tìm hiểu thêm về Máy ứng dụng.
• Các tài liệu Java của Máy ứng dụng của Google: Thông tin thêm về việc phát triển Java với
Máy ứng dụng cho Java.
• Nó có chạy được trong Máy ứng dụng cho Java không?: Tìm hiểu các Java API tiêu chuẩn và
các khung công tác nào tương thích với Máy ứng dụng cho Java.
• BigTable là gì?: Đọc ấn phẩm nghiên cứu của Google để tìm hiểu.
• "GWT: Thông báo quan trọng nhất tại JavaOne?" (Rick Hightower, Java Developers Journal,
06.2006): Thêm thông tin về lý do tại sao GWT cũng là một bước tiến cho phát triển ứng dụng
Java.
Lấy sản phẩm và công nghệ
• Các trình cắm thêm của Google cho Eclipse: Tải về các trình cắm thêm để bắt đầu.
• Tài khoản của Máy ứng dụng: Bạn sẽ cần một tài khoản để triển khai ứng dụng sát thủ của bạn
khi sử dụng cơ sở hạ tầng Máy ứng dụng của Google.
Thảo luận
• Nhóm thảo luận của Máy ứng dụng cho Java: Đăng ký vào nhóm này để đóng góp và nhận sự
giúp đỡ và lời khuyên khi bạn tìm hiểu về Máy ứng dụng cho Java.
• Dành tâm trí cho cộng đồng My developerWorks.
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 17 của 18
developerWorks®
ibm.com/developerWorks/vn/
Đôi nét về tác giả
Rick Hightower
Rick Hightower phục vụ với tư cách là giám đốc công nghệ cho Mammatus Inc., một
công ty đào tạo chuyên về phát triển điện toán đám mây, GWT, Java EE, Spring và
Hibernate. Ông là đồng tác giả của cuốn sách nổi tiếng Các công cụ Java cho lập trình
cực biên (Java Tools for Extreme Programming) và tác giả của ấn bản đầu tiên của
Struts Live — được tải về nhiều nhất trên TheServerSide.com trong nhiều năm. Ông
cũng đã viết các bài báo và các hướng dẫn cho developerWorks của IBM và ở trong
Ban biên tập của Tạp chí nhà phát triển Java, cũng như là một cộng tác viên thường
xuyên về các chủ đề Java và Groovy trên DZone
© Copyright IBM Corporation 2010
(www.ibm.com/legal/copytrade.shtml)
Nhẫn hiệu đăng ký
(www.ibm.com/developerworks/vn/ibm/trademarks/)
Máy ứng dụng của Google cho Java: Phần 2: Xây dựng ứng dụng
sát thủ
Trang 18 của 18