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 -