GWT - Связь RPC
Приложение на основе GWT обычно состоит из модуля на стороне клиента и модуля на стороне сервера. Код на стороне клиента выполняется в браузере, а код на стороне сервера - на веб-сервере. Код на стороне клиента должен сделать HTTP-запрос по сети для доступа к данным на стороне сервера.
RPC, удаленный вызов процедур - это механизм, используемый GWT, в котором клиентский код может напрямую выполнять методы на стороне сервера.
GWT RPC основан на сервлетах.
GWT RPC является асинхронным, и клиент никогда не блокируется во время связи.
Используя GWT, объекты RPC Java могут быть отправлены напрямую между клиентом и сервером (которые автоматически сериализуются платформой GWT).
Сервлет на стороне сервера называется service.
Вызов удаленной процедуры, которая вызывает методы сервлетов на стороне сервера из кода на стороне клиента, называется invoking a service.
Компоненты GWT RPC
Ниже приведены три компонента, используемые в механизме связи GWT RPC.
- Удаленная служба (сервлет на стороне сервера), работающая на сервере.
- Клиентский код для вызова этой службы.
- Объекты данных 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, чтобы сопоставить службу с путем по умолчанию удаленного сервлета относительно базового URL-адреса модуля.
@RemoteServiceRelativePath("message")
public interface MessageService extends RemoteService {
Message getMessage(String input);
}
Шаг 3 - Создайте интерфейс асинхронной службы
Определите асинхронный интерфейс для обслуживания на стороне клиента (в том же месте, что и служба, упомянутая выше), который будет использоваться в коде клиента GWT.
public interface MessageServiceAsync {
void getMessage(String input, AsyncCallback<Message> callback);
}
Шаг 4. Создайте класс сервлета реализации службы
Реализуйте интерфейс на стороне сервера, и этот класс должен расширять класс 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, чтобы включить объявление сервлета
Измените дескриптор развертывания веб-приложения (web.xml), чтобы включить объявление сервлета MessageServiceImpl.
<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 - Сделайте удаленный вызов процедуры в коде приложения
Создайте служебный прокси-класс.
MessageServiceAsync messageService = GWT.create(MessageService.class);
Создайте обработчик AsyncCallback для обработки обратного вызова 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());
}
}
Вызов удаленной службы, когда пользователь взаимодействует с пользовательским интерфейсом
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>
Ниже приводится содержимое измененного файла таблицы стилей. 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.
<?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 - Создание приложения . Если с вашим приложением все в порядке, это даст следующий результат: