GWT - การสื่อสาร RPC
โดยทั่วไปแอปพลิเคชันที่ใช้ GWT ประกอบด้วยโมดูลฝั่งไคลเอ็นต์และโมดูลฝั่งเซิร์ฟเวอร์ โค้ดฝั่งไคลเอ็นต์ทำงานในเบราว์เซอร์และโค้ดฝั่งเซิร์ฟเวอร์ทำงานในเว็บเซิร์ฟเวอร์ โค้ดฝั่งไคลเอ็นต์ต้องทำการร้องขอ HTTP ทั่วทั้งเครือข่ายเพื่อเข้าถึงข้อมูลฝั่งเซิร์ฟเวอร์
RPC, Remote Procedure Call คือกลไกที่ GWT ใช้ซึ่งโค้ดไคลเอ็นต์สามารถเรียกใช้เมธอดฝั่งเซิร์ฟเวอร์ได้โดยตรง
GWT RPC ขึ้นอยู่กับ servlet
GWT RPC เป็นแบบอะซิงโครนัสและไคลเอนต์จะไม่ถูกบล็อกระหว่างการสื่อสาร
การใช้ GWT RPC ออบเจ็กต์ Java สามารถส่งได้โดยตรงระหว่างไคลเอนต์และเซิร์ฟเวอร์ (ซึ่งต่อเนื่องกันโดยอัตโนมัติโดยเฟรมเวิร์ก GWT)
servlet ฝั่งเซิร์ฟเวอร์เรียกว่า service.
การเรียกโพรซีเดอร์ระยะไกลที่เรียกเมธอดของ servlets ฝั่งเซิร์ฟเวอร์จากโค้ดฝั่งไคลเอ็นต์เรียกว่า invoking a service.
ส่วนประกอบ GWT RPC
ต่อไปนี้เป็นส่วนประกอบสามอย่างที่ใช้ในกลไกการสื่อสาร GWT RPC
- บริการระยะไกล (servlet ฝั่งเซิร์ฟเวอร์) ที่ทำงานบนเซิร์ฟเวอร์
- รหัสไคลเอ็นต์เพื่อเรียกใช้บริการนั้น
- วัตถุข้อมูล Java ซึ่งจะถูกส่งผ่านระหว่างไคลเอนต์และเซิร์ฟเวอร์
ไคลเอ็นต์และเซิร์ฟเวอร์ GWT ทั้งซีเรียลไลซ์และดีซีเรียลไลซ์ข้อมูลโดยอัตโนมัติดังนั้นนักพัฒนาจึงไม่จำเป็นต้องซีเรียลไลซ์ / ดีซีเรียลไลซ์อ็อบเจ็กต์และอ็อบเจ็กต์ข้อมูลสามารถเดินทางผ่าน HTTP
แผนภาพต่อไปนี้แสดงสถาปัตยกรรม RPC
ในการเริ่มใช้ RPC เราจำเป็นต้องปฏิบัติตามอนุสัญญา GWT
เวิร์กโฟลว์การสื่อสาร RPC
ขั้นตอนที่ 1 - สร้างคลาสโมเดลต่อเนื่องได้
กำหนดวัตถุโมเดล java ที่ฝั่งไคลเอนต์ซึ่งควรทำให้เป็นอนุกรมได้
public class Message implements Serializable {
...
private String message;
public Message(){};
public void setMessage(String message) {
this.message = message;
}
...
}
ขั้นตอนที่ 2 - สร้างอินเทอร์เฟซบริการ
กำหนดอินเทอร์เฟซสำหรับบริการบนฝั่งไคลเอ็นต์ที่ขยาย RemoteService แสดงรายการวิธีการบริการทั้งหมด
ใช้คำอธิบายประกอบ @RemoteServiceRelativePath เพื่อแม็พเซอร์วิสกับพา ธ ดีฟอลต์ของรีโมต servlet ที่สัมพันธ์กับ URL ฐานของโมดูล
@RemoteServiceRelativePath("message")
public interface MessageService extends RemoteService {
Message getMessage(String input);
}
ขั้นตอนที่ 3 - สร้าง Async Service Interface
กำหนดอินเทอร์เฟซแบบอะซิงโครนัสสำหรับบริการบนฝั่งไคลเอ็นต์ (ที่ตำแหน่งเดียวกับบริการที่กล่าวถึงข้างต้น) ซึ่งจะใช้ในรหัสไคลเอ็นต์ GWT
public interface MessageServiceAsync {
void getMessage(String input, AsyncCallback<Message> callback);
}
ขั้นตอนที่ 4 - สร้างคลาส Servlet การใช้งานบริการ
ใช้อินเทอร์เฟซที่ฝั่งเซิร์ฟเวอร์และคลาสนั้นควรขยายคลาส RemoteServiceServlet
public class MessageServiceImpl extends RemoteServiceServlet
implements MessageService{
...
public Message getMessage(String input) {
String messageString = "Hello " + input + "!";
Message message = new Message();
message.setMessage(messageString);
return message;
}
}
ขั้นตอนที่ 5 - อัปเดต Web.xml เพื่อรวมการประกาศ Servlet
แก้ไขตัวอธิบายการปรับใช้เว็บแอปพลิเคชัน (web.xml) เพื่อรวมการประกาศ MessageServiceImpl Servlet
<web-app>
...
<servlet>
<servlet-name>messageServiceImpl</servlet-name>
<servlet-class>com.tutorialspoint.server.MessageServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>messageServiceImpl</servlet-name>
<url-pattern>/helloworld/message</url-pattern>
</servlet-mapping>
</web-app>
ขั้นตอนที่ 6 - โทรโพรซีเดอร์ระยะไกลใน Application Code
สร้างคลาสพร็อกซีบริการ
MessageServiceAsync messageService = GWT.create(MessageService.class);
สร้าง AsyncCallback Handler เพื่อจัดการการเรียกกลับ RPC ที่เซิร์ฟเวอร์ส่งคืนข้อความกลับไปยังไคลเอนต์
class MessageCallBack implements AsyncCallback<Message> {
@Override
public void onFailure(Throwable caught) {
Window.alert("Unable to obtain server response: "
+ caught.getMessage());
}
@Override
public void onSuccess(Message result) {
Window.alert(result.getMessage());
}
}
เรียกใช้บริการระยะไกลเมื่อผู้ใช้โต้ตอบกับ UI
public class HelloWorld implements EntryPoint {
...
public void onModuleLoad() {
...
buttonMessage.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
messageService.getMessage(txtName.getValue(),
new MessageCallBack());
}
});
...
}
}
ตัวอย่างการสื่อสาร RPC ที่สมบูรณ์
ตัวอย่างนี้จะนำคุณผ่านขั้นตอนง่ายๆในการแสดงตัวอย่างของการสื่อสาร RPC ใน GWT ทำตามขั้นตอนต่อไปนี้เพื่ออัปเดตแอปพลิเคชัน GWT ที่เราสร้างในGWT - สร้างบทแอปพลิเคชัน -
ขั้นตอน | คำอธิบาย |
---|---|
1 | สร้างโครงการที่มีชื่อHelloWorldภายใต้แพคเกจcom.tutorialspointตามที่อธิบายไว้ในGWT - สร้างแอพลิเคชันบท |
2 | แก้ไขHelloWorld.gwt.xml , HelloWorld.css , HelloWorld.htmlและHelloWorld.javaตามที่อธิบายด้านล่าง เก็บไฟล์ที่เหลือไว้ไม่เปลี่ยนแปลง |
3 | คอมไพล์และเรียกใช้แอปพลิเคชันเพื่อตรวจสอบผลลัพธ์ของตรรกะที่ใช้งาน |
ต่อไปนี้เป็นเนื้อหาของตัวอธิบายโมดูลที่แก้ไข src/com.tutorialspoint/HelloWorld.gwt.xml.
<?xml version = "1.0" encoding = "UTF-8"?>
<module rename-to = 'helloworld'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name = 'com.google.gwt.user.User'/>
<!-- Inherit the default GWT style sheet. -->
<inherits name = 'com.google.gwt.user.theme.clean.Clean'/>
<!-- Inherit the UiBinder module. -->
<inherits name = "com.google.gwt.uibinder.UiBinder"/>
<!-- Specify the app entry point class. -->
<entry-point class = 'com.tutorialspoint.client.HelloWorld'/>
<!-- Specify the paths for translatable code -->
<source path = 'client'/>
<source path = 'shared'/>
</module>
ต่อไปนี้เป็นเนื้อหาของไฟล์ Style Sheet ที่แก้ไข war/HelloWorld.css.
body {
text-align: center;
font-family: verdana, sans-serif;
}
h1 {
font-size: 2em;
font-weight: bold;
color: #777777;
margin: 40px 0px 70px;
text-align: center;
}
ต่อไปนี้เป็นเนื้อหาของไฟล์โฮสต์ HTML ที่แก้ไข war/HelloWorld.html.
<html>
<head>
<title>Hello World</title>
<link rel = "stylesheet" href = "HelloWorld.css"/>
<script language = "javascript" src = "helloworld/helloworld.nocache.js">
</script>
</head>
<body>
<h1>RPC Communication Demonstration</h1>
<div id = "gwtContainer"></div>
</body>
</html>
ตอนนี้สร้างไฟล์ Message.java ในรูปแบบ src/com.tutorialspoint/client แพคเกจและวางเนื้อหาต่อไปนี้ไว้ในนั้น
package com.tutorialspoint.client;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private String message;
public Message(){};
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
ตอนนี้สร้างไฟล์ MessageService.java ในไฟล์ src/com.tutorialspoint/client แพคเกจและวางเนื้อหาต่อไปนี้ไว้ในนั้น
package com.tutorialspoint.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("message")
public interface MessageService extends RemoteService {
Message getMessage(String input);
}
ตอนนี้สร้างไฟล์ MessageServiceAsync.java ในไฟล์ src/com.tutorialspoint/client แพคเกจและวางเนื้อหาต่อไปนี้ไว้ในนั้น
package com.tutorialspoint.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface MessageServiceAsync {
void getMessage(String input, AsyncCallback<Message> callback);
}
ตอนนี้สร้างไฟล์ MessageServiceImpl.java ในไฟล์ src/com.tutorialspoint/server แพคเกจและวางเนื้อหาต่อไปนี้ไว้ในนั้น
package com.tutorialspoint.server;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.tutorialspoint.client.Message;
import com.tutorialspoint.client.MessageService;
public class MessageServiceImpl extends RemoteServiceServlet
implements MessageService{
private static final long serialVersionUID = 1L;
public Message getMessage(String input) {
String messageString = "Hello " + input + "!";
Message message = new Message();
message.setMessage(messageString);
return message;
}
}
อัพเดตเนื้อหาของตัวอธิบายการปรับใช้เว็บแอ็พพลิเคชันที่แก้ไข war/WEB-INF/web.xml เพื่อรวมการประกาศ MessageServiceImpl Servlet
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>HelloWorld.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>messageServiceImpl</servlet-name>
<servlet-class>com.tutorialspoint.server.MessageServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>messageServiceImpl</servlet-name>
<url-pattern>/helloworld/message</url-pattern>
</servlet-mapping>
</web-app>
แทนที่เนื้อหาของ HelloWorld.java ใน src/com.tutorialspoint/client แพคเกจดังต่อไปนี้
package com.tutorialspoint.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
public class HelloWorld implements EntryPoint {
private MessageServiceAsync messageService =
GWT.create(MessageService.class);
private class MessageCallBack implements AsyncCallback<Message> {
@Override
public void onFailure(Throwable caught) {
/* server side error occured */
Window.alert("Unable to obtain server response: " + caught.getMessage());
}
@Override
public void onSuccess(Message result) {
/* server returned result, show user the message */
Window.alert(result.getMessage());
}
}
public void onModuleLoad() {
/*create UI */
final TextBox txtName = new TextBox();
txtName.setWidth("200");
txtName.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER){
/* make remote call to server to get the message */
messageService.getMessage(txtName.getValue(),
new MessageCallBack());
}
}
});
Label lblName = new Label("Enter your name: ");
Button buttonMessage = new Button("Click Me!");
buttonMessage.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
/* make remote call to server to get the message */
messageService.getMessage(txtName.getValue(),
new MessageCallBack());
}
});
HorizontalPanel hPanel = new HorizontalPanel();
hPanel.add(lblName);
hPanel.add(txtName);
hPanel.setCellWidth(lblName, "130");
VerticalPanel vPanel = new VerticalPanel();
vPanel.setSpacing(10);
vPanel.add(hPanel);
vPanel.add(buttonMessage);
vPanel.setCellHorizontalAlignment(buttonMessage,
HasHorizontalAlignment.ALIGN_RIGHT);
DecoratorPanel panel = new DecoratorPanel();
panel.add(vPanel);
// Add widgets to the root panel.
RootPanel.get("gwtContainer").add(panel);
}
}
เมื่อคุณพร้อมกับการเปลี่ยนแปลงทั้งหมดแล้วให้เรารวบรวมและเรียกใช้แอปพลิเคชันในโหมดการพัฒนาเหมือนที่เราทำในGWT - สร้างบทแอปพลิเคชัน หากทุกอย่างเรียบร้อยกับแอปพลิเคชันของคุณสิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -