- vừa được xem lúc

Setup project Spring boot 2.x + Socket.io Client 4.x

0 0 24

Người đăng: Vũ Văn Huy

Theo Viblo Asia

Hí mn, Hôm nay mình sẽ hướng dẫn mn setup 1 project Java Spring boot + Socket.io Client đơn giản nhất.

MÌnh đã research trên internet các tutorial về đề tài này, hầu hết chúng đều hướng dẫn sử dụng lib này https://github.com/mrniko/netty-socketio.

Có một nhược điểm của nó là nó được implement trên một server Netty có sẵn, thế nên nếu sử dụng Spring boot để tích hợp thì chúng ta sẽ phải sử dụng 2 port.

  • Khiến cho proj setup bị phức tạp khi ta phải config 2 domain trong quá trình dev và prod.
  • Khó khăn trong việc tích hợp security giữa Socket.io server và Spring security.

Không dài dòng nữa, chúng ta bắt tay vào làm thôi.

Website quen thuộc của Springer dev. https://start.spring.io/

Dependencies:

  • JDK 17
  • Spring boot 2.x
  • Spring web
  • Websocket

Đây là github của Socket.io java server

Mn thêm dependency này vào nha.

<dependency> <groupId>io.socket</groupId> <artifactId>socket.io-server</artifactId> <version>4.0.1</version>
</dependency>

Tạo proj dir theo cấu trúc ntn.

Classes.

/**
* @Author HuyVu
* @CreatedDate 2/24/2023 1:41 PM
*/
package io.huyvu.springbootsocketio.config.socketio; import io.socket.engineio.server.EngineIoServer;
import io.socket.engineio.server.EngineIoServerOptions;
import io.socket.socketio.server.SocketIoNamespace;
import io.socket.socketio.server.SocketIoServer;
import io.socket.socketio.server.SocketIoSocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration
public class BeanConfig { @Bean EngineIoServer engineIoServer() { EngineIoServerOptions opt = EngineIoServerOptions.newFromDefault(); opt.setCorsHandlingDisabled(true); EngineIoServer eioServer = new EngineIoServer(opt); return eioServer; } @Bean SocketIoServer socketIoServer(EngineIoServer eioServer) { SocketIoServer sioServer = new SocketIoServer(eioServer); SocketIoNamespace namespace = sioServer.namespace("/mynamespace"); namespace.on("connection", args -> { SocketIoSocket socket = (SocketIoSocket) args[0]; System.out.println("Client " + socket.getId() + " (" + socket.getInitialHeaders().get("remote_addr") + ") has connected."); socket.on("message", args1 -> { System.out.println("[Client " + socket.getId() + "] " + List.of(args1)); socket.send("hello", "Heo khô đi những kỉ niệm xưa kia"); }); }); return sioServer; } } 
package io.huyvu.springbootsocketio.config.socketio; import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration
@EnableWebSocket
public class EngineIoConfigurator implements WebSocketConfigurer { private final EngineIoHandler mEngineIoHandler; public EngineIoConfigurator(EngineIoHandler engineIoHandler) { mEngineIoHandler = engineIoHandler; } @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(mEngineIoHandler, "/socket.io/") .addInterceptors(mEngineIoHandler) .setAllowedOrigins("*"); }
}
package io.huyvu.springbootsocketio.config.socketio; import io.socket.engineio.server.EngineIoServer;
import io.socket.engineio.server.EngineIoWebSocket;
import io.socket.engineio.server.utils.ParseQS;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.socket.*;
import org.springframework.web.socket.server.HandshakeInterceptor; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map; @Controller
public class EngineIoHandler implements HandshakeInterceptor, WebSocketHandler { private static final String ATTRIBUTE_ENGINE_IO_BRIDGE = "engine.io.bridge"; private static final String ATTRIBUTE_ENGINE_IO_QUERY = "engine.io.query"; private static final String ATTRIBUTE_ENGINE_IO_HEADERS = "engine.io.headers"; private final EngineIoServer mEngineIoServer; public EngineIoHandler(EngineIoServer engineIoServer) { mEngineIoServer = engineIoServer; } @RequestMapping( value = "/socket.io/", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS}, headers = "Connection!=Upgrade") public void httpHandler(HttpServletRequest request, HttpServletResponse response) throws IOException { mEngineIoServer.handleRequest(request, response); } /* HandshakeInterceptor */ @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) { attributes.put(ATTRIBUTE_ENGINE_IO_QUERY, request.getURI().getQuery()); attributes.put(ATTRIBUTE_ENGINE_IO_HEADERS, request.getHeaders()); return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { } /* WebSocketHandler */ @Override public boolean supportsPartialMessages() { return false; } @Override public void afterConnectionEstablished(WebSocketSession webSocketSession) { final EngineIoSpringWebSocket webSocket = new EngineIoSpringWebSocket(webSocketSession); webSocketSession.getAttributes().put(ATTRIBUTE_ENGINE_IO_BRIDGE, webSocket); mEngineIoServer.handleWebSocket(webSocket); } @Override public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) { ((EngineIoSpringWebSocket)webSocketSession.getAttributes().get(ATTRIBUTE_ENGINE_IO_BRIDGE)) .afterConnectionClosed(closeStatus); } @Override public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) { ((EngineIoSpringWebSocket)webSocketSession.getAttributes().get(ATTRIBUTE_ENGINE_IO_BRIDGE)) .handleMessage(webSocketMessage); } @Override public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) { ((EngineIoSpringWebSocket)webSocketSession.getAttributes().get(ATTRIBUTE_ENGINE_IO_BRIDGE)) .handleTransportError(throwable); } private static final class EngineIoSpringWebSocket extends EngineIoWebSocket { private final WebSocketSession mSession; private final Map<String, String> mQuery; private final Map<String, List<String>> mHeaders; EngineIoSpringWebSocket(WebSocketSession session) { mSession = session; final String queryString = (String)mSession.getAttributes().get(ATTRIBUTE_ENGINE_IO_QUERY); if (queryString != null) { mQuery = ParseQS.decode(queryString); } else { mQuery = new HashMap<>(); } this.mHeaders = (Map<String, List<String>>) mSession.getAttributes().get(ATTRIBUTE_ENGINE_IO_HEADERS); } /* EngineIoWebSocket */ @Override public Map<String, String> getQuery() { return mQuery; } @Override public Map<String, List<String>> getConnectionHeaders() { return mHeaders; } @Override public void write(String message) throws IOException { mSession.sendMessage(new TextMessage(message)); } @Override public void write(byte[] message) throws IOException { mSession.sendMessage(new BinaryMessage(message)); } @Override public void close() { try { mSession.close(); } catch (IOException ignore) { } } /* WebSocketHandler */ void afterConnectionClosed(CloseStatus closeStatus) { emit("close"); } void handleMessage(WebSocketMessage<?> message) { if (message.getPayload() instanceof String || message.getPayload() instanceof byte[]) { emit("message", (Object) message.getPayload()); } else { throw new RuntimeException(String.format( "Invalid message type received: %s. Expected String or byte[].", message.getPayload().getClass().getName())); } } void handleTransportError(Throwable exception) { emit("error", "write error", exception.getMessage()); } }
}

Client

index.html

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Socket io client</title> <script src="https://cdn.socket.io/4.4.1/socket.io.min.js"></script>
</head>
<body>
<script> const socket = io('/mynamespace') socket.on('hello', (arg) => { console.log('connected', arg) }) socket.on('disconnect', () => { console.log('disconnect', socket.id) // undefined }) function submit() { const txt = document.getElementById('input').value socket.emit('message', txt) } </script> <input id="input" type="text"/>
<button onclick="submit()">Submit</button> </body>
</html>

Và đây là thành quả. github src: https://github.com/huyvu8051/springboot-socketio

Nhanh gọn lẹ đúng không nào, nếu có bất cứ câu hỏi nào plz leave comments. Thank.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tổng hợp các bài hướng dẫn về Design Pattern - 23 mẫu cơ bản của GoF

Link bài viết gốc: https://gpcoder.com/4164-gioi-thieu-design-patterns/. Design Patterns là gì. Design Patterns không phải là ngôn ngữ cụ thể nào cả.

0 0 302

- vừa được xem lúc

Học Spring Boot bắt đầu từ đâu?

1. Giới thiệu Spring Boot. 1.1.

0 0 277

- vừa được xem lúc

Cần chuẩn bị gì để bắt đầu học Java

Cần chuẩn bị những gì để bắt đầu lập trình Java. 1.1. Cài JDK hay JRE.

0 0 50

- vừa được xem lúc

Sử dụng ModelMapper trong Spring Boot

Bài hôm nay sẽ là cách sử dụng thư viện ModelMapper để mapping qua lại giữa các object trong Spring nhé. Trang chủ của ModelMapper đây http://modelmapper.org/, đọc rất dễ hiểu dành cho các bạn muốn tìm hiểu sâu hơn. 1.

0 0 194

- vừa được xem lúc

[Java] 1 vài tip nhỏ khi sử dụng String hoặc Collection part 1

. Hello các bạn, hôm nay mình sẽ chia sẻ về mẹo check String null hay full space một cách tiện lợi. Mình sẽ sử dụng thư viện Lớp StringUtils download file jar để import vào thư viện tại (link).

0 0 71

- vừa được xem lúc

Deep Learning với Java - Tại sao không?

Muốn tìm hiểu về Machine Learning / Deep Learning nhưng với background là Java thì sẽ như thế nào và bắt đầu từ đâu? Để tìm được câu trả lời, hãy đọc bài viết này - có thể kỹ năng Java vốn có sẽ giúp bạn có những chuyến phiêu lưu thú vị. DJL là tên viết tắt của Deep Java Library - một thư viện mã ng

0 0 139