Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
66
rated 0 times [  71] [ 5]  / answers: 1 / hits: 8608  / 5 Years ago, tue, november 19, 2019, 12:00:00

I am trying to add WebSocket functionality to an existing application which uses Spring WebFlux. It uses:



  • Spring boot 2.2.1.RELEASE

  • Tomcat container

  • Configured to serve jsp pages


When I try to connect to it through JavaScript (from inside a jsp page) I am receiving the error "failed: Error during WebSocket handshake: Unexpected response code: 404"


I noted that if I create a controller class mapping url '/ws/event-emitter' (the one mapped in my websocket configuration) accepting GET requests, it receives the requests from Javascript call when it tries to open the websocket connection, which made me more confused.


What am I missing?


After read some tutorials on the Internet I set my configuration as below:


<?xml version="1.0" encoding="UTF-8"?>


4.0.0

org.springframework.boot
spring-boot-starter-parent
2.2.1.RELEASE


br.com.samsung
monitor
0.0.1-SNAPSHOT
monitor
Health Check Monitor


<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectreactor</groupId>
<artifactId>reactor-spring</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>test</scope>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Lovelace-SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>


@Configuration
public class ReactiveWebSocketConfiguration {

@Autowired
private WebSocketHandler webSocketHandler;

@Bean
public HandlerMapping webSocketHandlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/ws/event-emitter", webSocketHandler);

SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
handlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
handlerMapping.setUrlMap(map);
return handlerMapping;
}

@Bean
public WebSocketHandlerAdapter handlerAdapter(WebSocketService webSocketService) {
return new WebSocketHandlerAdapter(webSocketService);
}

@Bean
public WebSocketService webSocketService() {
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy);
}

}

and the Web socket handler class


@Component
public class ReactiveWebSocketHandler implements WebSocketHandler {

private static final ObjectMapper json = new ObjectMapper();

private Flux<String> eventFlux = Flux.generate(sink -> {
Event event = new Event(randomUUID().toString(), now().toString());
try {
sink.next(json.writeValueAsString(event));
} catch (JsonProcessingException e) {
sink.error(e);
}
});

private Flux<String> intervalFlux = Flux.interval(Duration.ofMillis(1000L))
.zipWith(eventFlux, (time, event) -> event);

@Override
public Mono<Void> handle(WebSocketSession webSocketSession) {
return webSocketSession.send(intervalFlux
.map(webSocketSession::textMessage))
.and(webSocketSession.receive()
.map(WebSocketMessage::getPayloadAsText).log());
}

}



var clientWebSocket = new WebSocket(ws://localhost:6600/ws/event-emitter);
clientWebSocket.onopen = function() {
console.log(clientWebSocket.onopen, clientWebSocket);
console.log(clientWebSocket.readyState, websocketstatus);
clientWebSocket.send(event-me-from-browser);
}
clientWebSocket.onclose = function(error) {
console.log(clientWebSocket.onclose, clientWebSocket, error);
events(Closing connection);
}
clientWebSocket.onerror = function(error) {
console.log(clientWebSocket.onerror, clientWebSocket, error);
events(An error occured);
}
clientWebSocket.onmessage = function(error) {
console.log(clientWebSocket.onmessage, clientWebSocket, error);
events(error.data);
}

function events(responseEvent) {
document.querySelector(.events).innerHTML += responseEvent + <br>;
}




More From » java

 Answers
1

I could make it work removing spring-boot-starter-web and tomcat-embed-jasper dependencies. I suppose spring-boot-starter-web might conflict with spring-boot-starter-webflux.



Also I have changed my ReactiveWebSocketConfiguration class to set WebSocketService bean using ReactorNettyRequestUpgradeStrategy instead of TomcatRequestUpgradeStrategy:



@Bean
public WebSocketService webSocketService() {
return new HandshakeWebSocketService(new ReactorNettyRequestUpgradeStrategy());
}


After those changes my jsp pages stopped working as my web container changed from Tomcat to Netty Web Server.
I had to use Thymeleaf (added spring-boot-starter-thymeleaf dependency, configured its basic strucute and converted my pages to .html files) instead of traditional jsp.



I have opted to change from traditional jsp to Thymeleaf due to time constraints as my application has few and simple pages.



I have created a very simple project with all those configuration including a dummy page connecting to the websocket via javascript.



https://github.com/atilio-araujo/spring-webflux-websocket


[#5547] Sunday, November 17, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
monica

Total Points: 308
Total Questions: 102
Total Answers: 109

Location: Saudi Arabia
Member since Sat, Aug 20, 2022
2 Years ago
monica questions
Thu, Feb 17, 22, 00:00, 2 Years ago
Wed, Jul 8, 20, 00:00, 4 Years ago
Sun, Mar 29, 20, 00:00, 4 Years ago
Wed, Oct 30, 19, 00:00, 5 Years ago
;