本文共 6409 字,大约阅读时间需要 21 分钟。
基于 tomcat 的 WebSocket 实现
这种方式需要 tomcat 7.x,JEE7 的支持。
首先创建一个 springboot 项目,在 pom.xml 中导入 websocket 所需要的依赖
org.springframework
spring-websocket
5.0.12.RELEASE
复制代码
然后开启 WebSocket 的自动注册(如果使用的是独立的 servlet 容器,而不是 spring boot 的内置容器,就不需要注入这个,它将由容器自己提供和管理)
package com.example.demowebsocket.demowebsocket.socket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author yuanyiwen
* @create 2019-12-03 18:38
* @description
*/
@Configuration
public class WebSocketConfig{
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
复制代码
然后就可以创建 WebSocket 服务端啦!主要在于两个部分 :
通过注解 @ServerEndpoint 来声明实例化 WebSocket 服务端
通过注解 @OnOpen、@OnMessage、@OnClose、@OnError 来声明回调函数
package com.example.demowebsocket.demowebsocket.socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author yuanyiwen
* @create 2019-12-03 18:48
* @description
*/
@ServerEndpoint(value = "/demoSocket/{userId}")
@Component
public class SocketServer{
// 这里使用一个map来维护全部客户端用户
private static Map userMap = new ConcurrentHashMap<>();
// 日志
private Logger logger = LoggerFactory.getLogger(SocketServer.class);
// 用户id
private Long userId;
/**
* 打开连接时触发事件
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Long userId) throws IOException{
this.userId = userId;
userMap.put(userId, session);
logger.info("用户" + userId + "已上线");
}
/**
* 收到消息时触发事件
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException, InterruptedException{
logger.info("用户" + userId + "发来的消息为 :" + message);
session.getBasicRemote().sendText("你用户" + userId + "的喜悦,我服某器收到了! ");
// 向全体在线成员推送这条消息
sendMessageFromOneToAll(userId, message);
}
/**
* 关闭连接时触发事件
*/
@OnClose
public void onClose(){
userMap.remove(userId);
logger.info("用户" + userId + "已下线");
}
/**
* 传输消息错误时触发事件
*/
@OnError
public void onError(Throwable error){
logger.error("错误发生");
error.printStackTrace();
}
/**
* 给某个用户发送消息
*/
public void sendMessageToOne(Long userId, String message){
}
/**
* 给所有在线用户发送消息
*/
public void sendMessageToAll(String message){
}
/**
* 由某一用户向全体在线用户推送消息
* @param userId 哪个用户
* @param message 什么消息
*/
public void sendMessageFromOneToAll(Long userId, String message){
userMap.forEach((id, session) -> {
try {
session.getBasicRemote().sendText("用户" + userId + "发消息来啦:" + message);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
复制代码
最后让我们来检验一下成果!首先用在线 WebSocket 测试开三个用户,然后让用户 2 发一条消息
可以看到在用户 2 的消息发送后,每个在线用户都能够收到来自服务器的主动推送 业务完美qwq
基于 Spring 的 WebSocket 实现
这种方式需要 spring4.x 的支持。由于使用了 socketjs,对于不支持 WebSocket 的浏览器可以模拟 WebSocket 的使用。
首先还是创建一个 spring boot 项目,导入依赖
org.springframework.boot
spring-boot-starter-websocket
2.1.3.RELEASE
复制代码
然后新建一个配置类,用于添加服务端点,以接收客户端的连接
package com.example.demowebsocket.demowebsocket.springsocket;
import org.springframework.context.annotation.Bean;
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;
/**
* @author yuanyiwen
* @create 2019-12-04 21:40
* @description
*/
@EnableWebSocket
@Configuration
public class WebSocketConfig implements WebSocketConfigurer{
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
// 这里的路径就是访问时的路径
registry.addHandler(myHandler(), "/demoWebsocket").setAllowedOrigins("*");
}
@Bean
public MyWebSocketHandler myHandler(){
return new MyWebSocketHandler();
}
}
复制代码
最后构建服务端,具体的方法基本与上面对应,数据通过 session 进行传输
package com.example.demowebsocket.demowebsocket.springsocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author yuanyiwen
* @create 2019-12-05 20:52
* @description
*/
@Component
public class MyWebSocketHandler extends AbstractWebSocketHandler implements HandlerInterceptor{
// 这里使用一个map来维护全部客户端用户
private static Map userMap = new ConcurrentHashMap<>();
// 日志
private Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class);
// 用户id
private Long userId;
/**
* 打开连接时触发事件
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception{
this.userId = (Long) session.getAttributes().get("userId");
userMap.put(userId, session);
logger.info("用户" + userId + "已上线");
}
/**
* 收到消息时触发事件
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception{
logger.info("用户" + userId + "发来的消息为 :" + message);
session.sendMessage(new TextMessage("你用户" + userId + "的喜悦,我服某器收到了! "));
// 向全体在线成员推送这条消息
sendMessageFromOneToAll(userId, message);
}
/**
* 关闭连接时触发事件
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception{
userMap.remove(userId);
logger.info("用户" + userId + "已下线");
}
/**
* 传输消息错误时触发事件
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception{
logger.error("错误发生");
exception.printStackTrace();
}
/**
* 给某个用户发送消息
*/
public void sendMessageToUser(Long userId, TextMessage message){
}
/**
* 给所有在线用户发送消息
*/
public void sendMessageToUsers(TextMessage message){
}
/**
* 由某一用户向全体在线用户推送消息
* @param userId 哪个用户
* @param message 什么消息
*/
public void sendMessageFromOneToAll(Long userId, TextMessage message){
userMap.forEach((id, session) -> {
try {
session.sendMessage(new TextMessage("用户" + userId + "发消息来啦:" + message));
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
复制代码
最后检查一下消息发送情况(这里测试的时候是把代码中从session获取userId改成了直接令 userId = 1L)
完成!(。・`ω´・)
转载地址:http://cvqll.baihongyu.com/