websocket与Spring整合

本文介绍了如何将WebSocket技术与Spring框架整合。首先,需要将Spring相关jar包升级到4.0.0及以上,并修改web.xml的版本为3.0。接着,配置web.xml以启用WebSocket支持,包括定义HandshakeInterceptor来处理握手过程。同时,在前端的webSocket.js文件中编写了建立连接的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先将与Spring有关的jar包的版本都升级为4.0.0以上,并且在web.xml中将<web-app>里面的version改为"3.0"。然后在web.xml添加以下配置:

    <servlet>
        <servlet-name>websocketServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:META-INF/spring/websocketmessage-applicationContext.xml</param-value>
        </init-param>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>websocketServlet</servlet-name>
        <url-pattern>/websocket/*</url-pattern>
    </servlet-mapping>
在后台需要添加两个类,HandshakeInterceptor和WebsocketEndPoint。

HandshakeInterceptor类的作用创建握手,即前台与后台进行连接。其实现为:

public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
    private static final PlatformLogger logger = PlatformLogger.getLogger(WebsocketEndPoint.class);

    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
                                   ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        logger.info("Before Handshake");
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request,
                               ServerHttpResponse response, WebSocketHandler wsHandler,
                               Exception ex) {
        logger.info("After Handshake");
        super.afterHandshake(request, response, wsHandler, ex);
    }
}
WebsocketEndPoint是websocket处理类

public class WebsocketEndPoint extends TextWebSocketHandler {
    private static final PlatformLogger logger = PlatformLogger.getLogger(WebsocketEndPoint.class);
    private static Map<WebSocketSession,String> map=new HashMap<WebSocketSession, String>(); // 一个session对应一个message 维护 session和message的关系
    private static Map<WebSocketSession,Long> sessionAndAppIdMap= new HashMap<WebSocketSession,Long>();  //维护session和appId的关系,

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //以下三行获得此session对应的租户
        Map<String,Object> sessionAttributesMap= session.getHandshakeAttributes();
        Object credential=((SecurityContext) sessionAttributesMap.values().toArray()[0]).getAuthentication().getPrincipal();
        Long appId=((MyUserDetail) credential).getAppId();
        Long userId=((MyUserDetail) credential).getId();
        logger.info("appId= " + appId);
        logger.info("userId= " + userId);
        //维护起session和appId的关系,一个session可以对应多个appId
        sessionAndAppIdMap.put(session,appId);
        //得到前台发来的消息,里面可能包含多个sNum
        String  ReceivedMessage = message.getPayload();
        map.put(session,ReceivedMessage);
        JSONObject dataJson=new JSONObject(ReceivedMessage);
        //得到sNum的数组
        JSONArray sNum= dataJson.getJSONArray("sensors");
        //得到前台发来的命令:取消订阅、订阅
        String command=dataJson.getString("c");
        if (command.equals("cancelSubscribe")){    //取消订阅
            CommandProcessing.cancelSubscribe(ReceivedMessage, appId, userId);
        } else if (command.equals("Subscribe")){    //订阅
            CommandProcessing.subscribe(appId, userId, sNum, session);
        }
        super.handleTextMessage(session, message);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        CommandProcessing.cancelSubscribe(map,session,sessionAndAppIdMap);
        map.remove(session);
        sessionAndAppIdMap.remove(session);
        logger.info("连接关闭!");
        super.afterConnectionClosed(session, status);
    }
    public static Map<String,List<WebSocketSession>> getWsImpMap(){
        return CommandProcessing.wsImpMap;
    }
}
在websocketmessage-applicationContext.xml中的配置为:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:websocket="http://www.springframework.org/schema/websocket"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">

    <websocket:handlers>
        <websocket:mapping path="/hello" handler="websocketEndPoint"/>
        <websocket:handshake-interceptors>
            <bean class="org.whut.platform.fundamental.websocket.handler.HandshakeInterceptor"/>
        </websocket:handshake-interceptors>
    </websocket:handlers>
    <!-- 定义跳转的文件的前后缀 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>
在前台,我们需要做的工作有以下:打开一个连接,为连接创建事件监听器,断开连接,发送消息返回到服务器,关闭连接。具体代码如下:

// 创建一个Socket实例
var socket = new WebSocket(url); //url的地址为...../websocket/hello   前面的路径由你的项目决定  websocket在web.xml中的拦截路径中有配置,hello在
websocketmessage-applicationContext.xml中有配置
 // 打开Socket 
socket.onopen = function(event) { 

  // 发送一个初始化消息
  socket.send('I am the client and I\'m listening!'); 

  // 监听消息
  socket.onmessage = function(event) { 
    console.log('Client received a message',event); 
  }; 

  // 监听Socket的关闭
  socket.onclose = function(event) { 
    console.log('Client notified socket has closed',event); 
  }; 

  // 关闭Socket.... 
  //socket.close() 
};
我们可以将这些处理在前台封装在一个js中,在以后有用到websocket的时候,我们可以直接进行调用。

webSocket.js中的代码:

 $.extend({
     initWebSocket:function initWebSocket(s,method){
       var url= $.URL.websocket.register;//配置地址的路径
       ws = new WebSocket(url);
       ws.onopen = function(){
           setInterval(function(){$.post($.URL.user.keepAlive,null,null)},1000*60);
           console.log("open"); ws.send(s);};
       ws.onmessage=function (event){method(event.data);};
       ws.onclose =function onclose(evt){console.log("WebSocketClosed!");};
       ws.onerror =function onerror(evt){console.log("WebSocketError!");};
    },
     WebSocketClose:function WebSocketClose(){ws.close();ws=null},
     WebSocketSend:function WebSocketSend(str){ws.send(str)},
     WebSocketConnect:function WebSocketConnect(){return ws}
 });
在调用websocket的初始化的时候,有一个回调方法的参数method,如果前台需要对后台传过来的数据进行处理,可以前台调用时,定义一个回调函数,然后将函数名作为参数传递过来(这里用到了闭包的技术)即可。
$.initWebSocket(s,webSocketCallback);
function webSocketCallback(data){
     //对data进行处理
}
如果前台需要向后台传送数据,可将数据封装在参数s中进行传送。如下面的代码:

 $.initWebSocket($.subscription(data),webSocketCallback);
$.extend({
    subscription:function subscription(data){
             //封装data,并return data
});



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值