GWT - Comunicación RPC

Una aplicación basada en GWT generalmente consta de un módulo del lado del cliente y un módulo del lado del servidor. El código del lado del cliente se ejecuta en el navegador y el código del lado del servidor se ejecuta en el servidor web. El código del lado del cliente tiene que realizar una solicitud HTTP a través de la red para acceder a los datos del lado del servidor.

RPC, Remote Procedure Call es el mecanismo utilizado por GWT en el que el código del cliente puede ejecutar directamente los métodos del lado del servidor.

  • GWT RPC está basado en servlets.

  • GWT RPC es asincrónico y el cliente nunca se bloquea durante la comunicación.

  • Usando GWT RPC, los objetos Java se pueden enviar directamente entre el cliente y el servidor (que son serializados automáticamente por el marco de GWT).

  • El servlet del lado del servidor se denomina service.

  • La llamada a procedimiento remoto que llama a métodos de servlets del lado del servidor desde el código del lado del cliente se denomina invoking a service.

Componentes de GWT RPC

A continuación se muestran los tres componentes utilizados en el mecanismo de comunicación GWT RPC

  • Un servicio remoto (servlet del lado del servidor) que se ejecuta en el servidor.
  • Código de cliente para invocar ese servicio.
  • Objetos de datos Java que se pasarán entre el cliente y el servidor.

El cliente y el servidor de GWT serializan y deserializan datos automáticamente para que los desarrolladores no tengan que serializar / deserializar objetos y los objetos de datos pueden viajar a través de HTTP.

El siguiente diagrama muestra la arquitectura RPC.

Para comenzar a usar RPC, debemos seguir las convenciones de GWT.

Flujo de trabajo de comunicación RPC

Paso 1: crear una clase de modelo serializable

Defina un objeto de modelo java en el lado del cliente que debería ser serializable.

public class Message implements Serializable {
   ...
   private String message;
   public Message(){};

   public void setMessage(String message) {
      this.message = message;
   }
   ...
}

Paso 2: crear una interfaz de servicio

Defina una interfaz para el servicio en el lado del cliente que amplíe RemoteService y enumere todos los métodos de servicio.

Utilice la anotación @RemoteServiceRelativePath para asignar el servicio con una ruta predeterminada del servlet remoto en relación con la URL base del módulo.

@RemoteServiceRelativePath("message")
public interface MessageService extends RemoteService {
   Message getMessage(String input);
}

Paso 3: crear una interfaz de servicio asincrónica

Defina una interfaz asincrónica para el servicio en el lado del cliente (en la misma ubicación que el servicio mencionado anteriormente) que se utilizará en el código de cliente GWT.

public interface MessageServiceAsync {
   void getMessage(String input, AsyncCallback<Message> callback);
}

Paso 4: crear una clase de servlet de implementación de servicios

Implemente la interfaz en el lado del servidor y esa clase debería extender la clase 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;
   }
}

Paso 5: actualice Web.xml para incluir la declaración de servlet

Edite el descriptor de implementación de la aplicación web (web.xml) para incluir la declaración 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>

Paso 6: realice la llamada al procedimiento remoto en el código de aplicación

Cree la clase de proxy de servicio.

MessageServiceAsync messageService = GWT.create(MessageService.class);

Cree el controlador AsyncCallback para manejar la devolución de llamada RPC en la que el servidor devuelve el mensaje al cliente

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()); 
   }	   
}

Llamar al servicio remoto cuando el usuario interactúa con la interfaz de usuario

public class HelloWorld implements EntryPoint {
   ... 
   public void onModuleLoad() {
   ...
      buttonMessage.addClickHandler(new ClickHandler() {			
         @Override
         public void onClick(ClickEvent event) {
            messageService.getMessage(txtName.getValue(), 
            new MessageCallBack());
         }
      });
   ...
   }
}

Ejemplo completo de comunicación RPC

Este ejemplo lo llevará a través de pasos simples para mostrar un ejemplo de una comunicación RPC en GWT. Siga los siguientes pasos para actualizar la aplicación GWT que creamos en GWT - Capítulo Crear aplicación -

Paso Descripción
1 Cree un proyecto con un nombre HelloWorld en un paquete com.tutorialspoint como se explica en el capítulo GWT - Crear aplicación .
2 Modifique HelloWorld.gwt.xml , HelloWorld.css , HelloWorld.html y HelloWorld.java como se explica a continuación. Mantenga el resto de los archivos sin cambios.
3 Compile y ejecute la aplicación para verificar el resultado de la lógica implementada.

A continuación se muestra el contenido del descriptor de módulo modificado 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>

A continuación se muestra el contenido del archivo de hoja de estilo modificado 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;
}

A continuación se muestra el contenido del archivo de host HTML modificado 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>

Ahora cree el archivo Message.java en el src/com.tutorialspoint/client empaque y coloque el siguiente contenido en él

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;
   }
}

Ahora cree el archivo MessageService.java en el src/com.tutorialspoint/client empaque y coloque el siguiente contenido en él

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);
}

Ahora cree el archivo MessageServiceAsync.java en el src/com.tutorialspoint/client empaque y coloque el siguiente contenido en él

package com.tutorialspoint.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface MessageServiceAsync {
   void getMessage(String input, AsyncCallback<Message> callback);
}

Ahora cree el archivo MessageServiceImpl.java en el src/com.tutorialspoint/server empaque y coloque el siguiente contenido en él

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;
   }   
}

Actualizar el contenido del descriptor de implementación de la aplicación web modificado war/WEB-INF/web.xml para incluir la declaración 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>

Reemplace el contenido de HelloWorld.java en src/com.tutorialspoint/client paquete con lo siguiente

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);
   }    
}

Una vez que esté listo con todos los cambios realizados, compilemos y ejecutemos la aplicación en modo de desarrollo como hicimos en el capítulo GWT - Crear aplicación . Si todo está bien con su aplicación, esto producirá el siguiente resultado: