GWT - komunikacja RPC
Aplikacja oparta na GWT składa się zazwyczaj z modułu po stronie klienta i modułu po stronie serwera. Kod po stronie klienta działa w przeglądarce, a kod po stronie serwera na serwerze WWW. Kod po stronie klienta musi wysłać żądanie HTTP przez sieć, aby uzyskać dostęp do danych po stronie serwera.
RPC, Remote Procedure Call to mechanizm używany przez GWT, w którym kod klienta może bezpośrednio wykonywać metody po stronie serwera.
GWT RPC jest oparty na serwletach.
GWT RPC jest asynchroniczne, a klient nigdy nie jest blokowany podczas komunikacji.
Używając GWT RPC obiekty Java mogą być przesyłane bezpośrednio między klientem a serwerem (które są automatycznie serializowane przez strukturę GWT).
Serwlet po stronie serwera jest określany jako service.
Zdalne wywołanie procedury, które wywołuje metody serwletów po stronie serwera z kodu po stronie klienta, jest nazywane invoking a service.
Komponenty GWT RPC
Poniżej przedstawiono trzy komponenty wykorzystywane w mechanizmie komunikacji GWT RPC
- Usługa zdalna (serwlet po stronie serwera), która działa na serwerze.
- Kod klienta do wywołania tej usługi.
- Obiekty danych Java, które będą przekazywane między klientem a serwerem.
Klient i serwer GWT zarówno serializują, jak i deserializują dane automatycznie, więc deweloperzy nie muszą serializować / deserializować obiektów, a obiekty danych mogą podróżować przez HTTP.
Poniższy diagram przedstawia architekturę RPC.
Aby rozpocząć korzystanie z RPC, musimy przestrzegać konwencji GWT.
Przepływ pracy w komunikacji RPC
Krok 1 - Utwórz serializowalną klasę modelu
Zdefiniuj obiekt modelu Java po stronie klienta, który powinien być możliwy do serializacji.
public class Message implements Serializable {
...
private String message;
public Message(){};
public void setMessage(String message) {
this.message = message;
}
...
}
Krok 2 - Utwórz interfejs usługi
Zdefiniuj interfejs dla usługi po stronie klienta, który rozszerza RemoteService wykaz wszystkich metod usług.
Użyj adnotacji @RemoteServiceRelativePath, aby zmapować usługę z domyślną ścieżką zdalnego serwletu względem podstawowego adresu URL modułu.
@RemoteServiceRelativePath("message")
public interface MessageService extends RemoteService {
Message getMessage(String input);
}
Krok 3 - Utwórz interfejs usługi asynchronicznej
Zdefiniuj asynchroniczny interfejs do usługi po stronie klienta (w tej samej lokalizacji co usługa wspomniana powyżej), który będzie używany w kodzie klienta GWT.
public interface MessageServiceAsync {
void getMessage(String input, AsyncCallback<Message> callback);
}
Krok 4 - Utwórz klasę serwletu implementacji usługi
Zaimplementuj interfejs po stronie serwera, a ta klasa powinna rozszerzać klasę 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;
}
}
Krok 5 - Zaktualizuj plik Web.xml, aby zawierał deklarację serwletu
Edytuj deskryptor wdrażania aplikacji WWW (web.xml), tak aby zawierał deklarację serwletu 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>
Krok 6 - Wykonaj zdalne wywołanie procedury w kodzie aplikacji
Utwórz klasę serwera proxy usług.
MessageServiceAsync messageService = GWT.create(MessageService.class);
Utwórz program obsługi AsyncCallback, aby obsłużyć wywołanie zwrotne RPC, w którym serwer zwraca komunikat z powrotem do klienta
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());
}
}
Wywołaj usługę zdalną, gdy użytkownik współdziała z interfejsem użytkownika
public class HelloWorld implements EntryPoint {
...
public void onModuleLoad() {
...
buttonMessage.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
messageService.getMessage(txtName.getValue(),
new MessageCallBack());
}
});
...
}
}
Przykład kompletnej komunikacji RPC
Ten przykład poprowadzi Cię przez proste kroki, aby pokazać przykład komunikacji RPC w GWT. Wykonaj następujące kroki, aby zaktualizować aplikację GWT, którą utworzyliśmy w GWT - rozdział Tworzenie aplikacji -
Krok | Opis |
---|---|
1 | Utwórz projekt o nazwie HelloWorld pod pakietem com.tutorialspoint, jak wyjaśniono w rozdziale GWT - Tworzenie aplikacji . |
2 | Zmodyfikuj HelloWorld.gwt.xml , HelloWorld.css , HelloWorld.html i HelloWorld.java, jak wyjaśniono poniżej. Resztę plików nie zmieniaj. |
3 | Skompiluj i uruchom aplikację, aby zweryfikować wynik zaimplementowanej logiki. |
Poniżej znajduje się treść zmodyfikowanego deskryptora modułu 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>
Poniżej znajduje się zawartość zmodyfikowanego pliku arkusza stylów 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;
}
Poniżej znajduje się zawartość zmodyfikowanego pliku hosta 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>
Teraz utwórz plik Message.java w src/com.tutorialspoint/client opakowanie i umieść w nim następującą zawartość
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;
}
}
Teraz utwórz plik MessageService.java w src/com.tutorialspoint/client opakowanie i umieść w nim następującą zawartość
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);
}
Teraz utwórz plik MessageServiceAsync.java w pliku src/com.tutorialspoint/client opakowanie i umieść w nim następującą zawartość
package com.tutorialspoint.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface MessageServiceAsync {
void getMessage(String input, AsyncCallback<Message> callback);
}
Teraz utwórz plik MessageServiceImpl.java w src/com.tutorialspoint/server opakowanie i umieść w nim następującą zawartość
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;
}
}
Zaktualizuj zawartość zmodyfikowanego deskryptora wdrażania aplikacji WWW war/WEB-INF/web.xml aby dołączyć deklarację serwletu 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>
Zastąp zawartość HelloWorld.java w src/com.tutorialspoint/client pakiet z następującymi
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);
}
}
Gdy będziesz gotowy ze wszystkimi wprowadzonymi zmianami, skompilujmy i uruchom aplikację w trybie programistycznym, tak jak zrobiliśmy to w GWT - rozdział Tworzenie aplikacji . Jeśli wszystko jest w porządku z twoją aplikacją, da to następujący wynik -