How to do it...

Let us build a fast and asynchronous messenger using Reactive WebSocket by performing the following steps:

  1. Just like in the previous recipe, convert ch12-messenger to a Spring Boot 2.0 application by adding the Spring Boot 2.0.0.M2 starter POM dependencies, like webflux, actuator for project status monitoring and management, and the websocket protocol we recently used.
There is no Reactive counterpart for the POM starter WebSocket.
  1. Inside the core package org.packt.messenger.core, add the following Bootstrap class:
@SpringBootApplication 
public class ChatBootApplication {     
  public static void main(String[] args) throws Exception { 
        SpringApplication.run(ChatBootApplication.class,  
            args); 
    } 
} 
  1. The application.properties file inside the src/main/resources directory will be just the same as in the previous recipe.
  2. Enable logging using logback and SLF4J.
  3. Implement org.springframework.web.reactive.socket.WebSocketHandler, which is the appropriate custom handler for incoming Reactive sessions wrapped in an org.springframework.web.reactive.socket.WebSocketSession. It has a handle()method that manages the communication between the client and server by retrieving the message payloads in the form of the Flux<WebSocketMessage> streams that no converters or serializers can process, but only through a reactor server. Drop @Component inside org.packt.messaging.core.handler:
@Component 
public class MessageWebSocketHandler implements WebSocketHandler { 
    
    @Override 
    public Mono<Void> handle(WebSocketSession session) { 
      return session.send(session.receive() 
       .map(str -> str.getPayloadAsText()) 
       .map(str -> "Howdy, " + str  
+ "? Welcome to the Portal!") 
       .map(session::textMessage)) 
       .delayElement(Duration.ofMillis(2)).log();            
    } 
} 
In WebSocketHandler, it is mandatory for a server to broadcast its reply in the form of a textMessage() method. Also, it is essential to always include the delayElement() backpressure operator during simultaneous Flux<WebSocketMessage> exchanges to avoid server-related exceptions.
  1. To enable WebSocket support and to build an entry point for each custom handler, implement the following WebSocket configuration inside the org.packt.messaging.core.config package. Unlike the non-reactive version, this configuration requires three beans to be injected into the container, namely the org.springframework.web.reactive.HandlerMapping, org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter, and org.springframework.web.reactive.socket.server.WebSocketService packages. The WebSocketHandlerAdapter and WebSocketService methods automatically check and detect any container-specific RequestUpgradeStrategy that is needed to implement Reactive WebSocket handshakes through the endpoints:
@Configuration 
@EnableWebSocket 
public class ReactiveChatSocketConfig { 
 
   @Autowired 
   private WebSocketHandler messageWebSocketHandler; 
 
   @Bean 
   public HandlerMapping webSocketMapping() { 
      Map<String, WebSocketHandler> map = new HashMap<>(); 
      map.put("/react", messageWebSocketHandler); 
      SimpleUrlHandlerMapping mapping =  
new SimpleUrlHandlerMapping(); 
      mapping.setOrder(10); 
      mapping.setUrlMap(map); 
      return mapping; 
   } 
 
   @Bean 
   public WebSocketHandlerAdapter handlerAdapter() { 
      return new WebSocketHandlerAdapter( 
webSocketService()); 
   } 
 
   @Bean 
   public WebSocketService webSocketService() { 
      return new HandshakeWebSocketService( 
new ReactorNettyRequestUpgradeStrategy()); 
   } 
}
  1. In order to create a Reactive WebSocket handshake, which will eventually transfer Flux<WebSocketMessage> from client to server and vice versa, a server-specific strategy used to initiate the WebSocket exchange is required. The embedded Tomcat does not have this so called RequestUpgradeStrategy, but the Reactor Netty server has. Drop this Reactor Netty configuration class, used in the previous chapters, in order to run our reactive chatroom:
@Configuration 
@EnableWebFlux 
public class HttpServerConfig implements WebFluxConfigurer{ 
    
   @Bean 
   public NettyContext nettyContext(ApplicationContext context) { 
      HttpHandler handler =  
         DispatcherHandler.toHttpHandler(context); 
      ReactorHttpHandlerAdapter adapter =  
new ReactorHttpHandlerAdapter(handler); 
      HttpServer httpServer =  
HttpServer.create("localhost",  
   Integer.valueOf("8908")); 
      return httpServer.newHandler(adapter).block(); 
   } 
} 
  1. At this point, we are finished building the server side aspect of this Reactive WebSocket project. Let's start building the client side by having an HTML 5 client.html page inside the src/main/resources/static folder of the application:
<!DOCTYPE html> 
<html> 
<head> 
    <title>Chapter 12</title> 
    <link href="./bootstrap.min.css" rel="stylesheet"> 
    <link href="./main.css" rel="stylesheet"> 
    <script src="./jquery-1.10.2.min.js"></script> 
</head> 
<body> 
<div id="main-content" class="container"> 
    <div class="row"> 
        <H2>GreetMe Portal</H2> 
        <div class="col-md-12"> 
            <form class="form-inline"> 
                <div id="greetForm" class="form-group"> 
                    <label for="name">What is your name? 
 </label> 
                    <input type="text" id="name"  
class="form-control"  
placeholder="Your name here..."> 
                    <label for="greet">Say your greetings? 
 </label> 
                    <input type="text" id="greet"  
class="form-control"  
placeholder="Your greeting here..."> 
                    <button id="send"  
class="btn btn-success"  
                        type="submit">Send</button> 
                </div> 
            </form> 
        </div> 
    </div> 
    <div class="row"> 
        <div class="col-md-12"> 
            <table id="greetings" class="table  
table-hover"> 
                <thead> 
                <tr> 
                    <th>Conversation with Portal</th> 
                </tr> 
                </thead> 
                <tbody id="conversations"> 
                </tbody> 
            </table> 
        </div> 
    </div> 
</div> 
</body> 
</html> 
Ensure that you assign the element tag ID to the form components.
  1. Now, implement the WebSocket client event handlers, namely onopen() and onmessage(). Drop the reactivesocketapp.js file as a static resource inside the static folder:
$(document).ready(function () { 
        var socket = new WebSocket("ws://localhost:8908/react"); 
        socket.onopen = function (event) { 
            var newMessage = document.createElement('p'); 
            newMessage.textContent =  
"--- CONVERSATION READY"; 
            document.getElementById('conversations') 
.appendChild(newMessage); 
            socket.onmessage = function (e) { 
                var newMessage =  
                  document.createElement('p'); 
                newMessage.textContent =  
"--- PORTAL: " + e.data; 
                document.getElementById('conversations') 
.appendChild(newMessage); 
            } 
            $("#send").click(function (e) { 
                e.preventDefault(); 
                var message = $("#name").val(); 
                socket.send(message); 
                var newMessage =  
                  document.createElement('p'); 
                newMessage.textContent =  
"--- GUEST: " + message; 
                document.getElementById('conversations') 
.appendChild(newMessage); 
            }); 
        } 
}); 
The IP address and port of the Reactor Netty server must be the details used in establishing a Reactive WebSocket connection.
  1. Import reactivesocketapps.js inside client.html using the <script> tag.
  2. Save all files. Clean, build, and deploy the Spring Boot application.
  1. Open a browser and go to http://localhost:8085/ch12-messenger/client.html:
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.209.201