引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
创建websocket 方法实现类
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@Component
@Slf4j
@ServerEndpoint("/ws/test/chat/{clientId}")
public class WsTestController {
//clientId可以使用系统的userID,或者其他id做唯一标识,用于与对应的session绑定
//可以根据实际业务需求增加方法逻辑和增强代码健壮性,比如存入缓存或者加入消息队列以及对异常情况的处理
/**
* 建立连接
* @param clientId
* @param session
*/
@OnOpen
public void openSession(@PathParam("clientId") String clientId, Session session) {
log.info("已上线,准备创建连接!{}", clientId);
WebSocketUtils.sessionMap().put(clientId, session);
log.info("当前连接数:" + WebSocketUtils.sessionMap().size());
}
/**
* 接收消息
* @param clientId
* @param session
* @param message
*/
@OnMessage
public void onMessage(@PathParam("clientId") String clientId, Session session, String message) {
log.info("收到客户端直接发来的消息 clientId = {} session = {} message = {}", clientId, session, message);
session.getAsyncRemote().sendText("收到消息:" + message);
}
/**
* 关闭连接
* @param clientId
* @param session
*/
@OnClose
public void onClose(@PathParam("clientId") String clientId, Session session) {
log.info("关闭连接 clientId = {} session = {}", clientId, session);
WebSocketUtils.sessionMap().remove(clientId);
log.info("当前连接数:" + WebSocketUtils.sessionMap().size());
}
/**
* 异常处理
* @param session
* @param throwable
*/
@OnError
public void onError(Session session, Throwable throwable) {
try {
log.error("WebSocket连接错误", throwable);
session.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
创建session存储工具类
import javax.websocket.Session;
import java.util.HashMap;
import java.util.Map;
public class WebSocketUtils {
//可以根据实际业务场景,添加更多的绑定关系或方法逻辑
private static Map<String, Session> sessionMap =new HashMap<>();
public static Map<String, Session> sessionMap() {
return sessionMap;
}
}
注册工具类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter (){
ServerEndpointExporter exporter = new ServerEndpointExporter();
// 手动注册 WebSocket 端点
exporter.setAnnotatedEndpointClasses(WsTestController.class);
return exporter;
}
}
模拟业务中对前端发送消息
import org.springframework.web.bind.annotation.*;
import javax.websocket.Session;
@RestController
@RequestMapping("/ws")
public class WsServiceController {
@GetMapping("/sendMsg/{clientId}")
public void sendMsg(@PathVariable("clientId") String clientId, @RequestParam String msg) {
Session session = WebSocketUtils.sessionMap().get(clientId);
session.getAsyncRemote().sendText(msg);
}
}
使用Apifox进行测试
使用Apifox请求模拟业务接口,并通知对应的websocket