开发环境(最低版本):spring 4.0+java7+tomcat7.0.47+sockjs
前端页面要引入:
<script src="http://cdn.jsdelivr.net/sockjs/1/sockjs.min.js"></script>
maven依赖:
<dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.3.10.RELEASE</version> </dependency>
前端js:
var ws = null; function openWebSocket(){ //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { ws = new WebSocket("ws://"+window.location.host+"/项目名称/visualizationWebSocket.do?type=mall"); } else { ws = new SockJS("http://"+window.location.host+"/项目名称/sockjs/visualizationWebSocket/info?type=mall"); } ws.onopen = function () { };
//这个事件是接受后端传过来的数据 ws.onmessage = function (event) { //根据业务逻辑解析数据 }; ws.onclose = function (event) { }; }
我实现连接后台的方式如下:
//页面已加载后加载后台数据 $(function (){ $.ajax({ cache:false, data:"", type:"post", url:"", success:function(data, textStatus){ if(data && data.status === "1"){ //这里可以初始化操作 openWebSocket();//websocket连接到后台 if(ws){ setTimeout(function (){ ws.send("");//发送信息到后台,开始有数据跟新就写到前端显示 },3000); } } else { alert("操作失败!"); } }, error:function(XMLHttpRequest, textStatus, errorThrown){} }); function zeroPadding(num, digit) { var zero = ''; for(var i = 0; i < digit; i++) { zero += '0'; } return (zero + num).slice(-digit); } function showDate() { var date = new Date(); var str = "" + zeroPadding(date.getFullYear(),4) + "-"; str += zeroPadding((date.getMonth() + 1),2) + "-"; str += zeroPadding(date.getDate(),2) + " "; str += zeroPadding(date.getHours(),2) + ':'; str += zeroPadding(date.getMinutes(),2) + ':'; str += zeroPadding(date.getSeconds(),2) + ''; return str; } setInterval(function () { $('.data-time').html(showDate) }, 1000); });
后端:
webSocket配置
package com.snw.supplyChain.websocket; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.socket.WebSocketHandler; 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 @EnableWebMvc public class VisualizationWebSocketConfig implements WebSocketConfigurer { public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
//这里的url要与页面的url一致 webSocketHandlerRegistry.addHandler(myHandler(),"/visualizationWebSocket.do").addInterceptors(new VisualizationHandshakeInterceptor());
//至于这里为什么要加info,我遇见的情况是,当我使用sockjs来代替websocket时,连接的后面会自动加上info webSocketHandlerRegistry.addHandler(myHandler(),"/sockjs/visualizationWebSocket/info").addInterceptors(new VisualizationHandshakeInterceptor()).withSockJS(); } @Bean public WebSocketHandler myHandler(){ return new VisualizationWebSocketHandler(); } }
回话拦截器
package com.snw.supplyChain.websocket; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; import javax.servlet.http.HttpServletRequest; import java.util.Map; //回话拦截器 public class VisualizationHandshakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//获取请求参数,首先我们要获取HttpServletRequest对象才能获取请求参数;当ServerHttpRequset的层次结构打开后其子类可以获取到我们想要的http对象,那么就简单了。
//我这里是把获取的请求数据绑定到session的map对象中(attributes) HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); String id = servletRequest.getSession().getId(); System.out.println("beforeHandshake: "+id); String type = servletRequest.getParameter("type"); attributes.put("mall",type); return super.beforeHandshake(request, response, wsHandler, attributes); } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { System.out.println("After Handshake"); super.afterHandshake(request, response, wsHandler, ex); } }
websocket处理器
处理器里面可以注入想要的service
package com.snw.supplyChain.websocket; import com.snw.supplyChain.model.VisualizationProduct; import com.snw.supplyChain.service.IVisualizationService; import net.sf.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Set; public class VisualizationWebSocketHandler extends TextWebSocketHandler { private static final Map<String,WebSocketSession> sessions = new HashMap<String, WebSocketSession>(); private static final Map<String,Thread> threads = new HashMap<String, Thread>(); private Thread polingVisualization = null; //用户标识 private static final String CLIENT_ID = "sessionId"; @Autowired private IVisualizationService visualizationService; @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("afterConnectionEstablished: "+session.getId()); Object sessionType = session.getAttributes().get("mall"); if(sessionType != null && "mall".equals(sessionType)){ sessions.put(CLIENT_ID,session); sessions.put(session.getId(),session); } super.afterConnectionEstablished(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { Thread thread = threads.get(session.getId()); if(thread != null){ thread.interrupt(); try { thread.join(); threads.remove(session.getId()); } catch (InterruptedException e) { e.printStackTrace(); } } sessions.remove(session.getId()); sessions.remove(CLIENT_ID); polingVisualization = null; try { super.afterConnectionClosed(session, status); } catch (Exception e) { } } //这里是处理前端发送的消息以及返回给前端的数据 //可以从session里面获取attributes, @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); Thread thread = threads.get(session.getId()); if(thread == null){ System.out.println("handleTextMessage: "+session.getId()); WebSocketSession sessi = sessions.get(session.getId()); if(sessi == null){ sessions.put(session.getId(),session); } else { session = sessi; } final WebSocketSession localSession = session; final TextMessage localMessage = message; String payload = message.getPayload(); if(StringUtils.isNotBlank(payload)){ String[] split = payload.split("_"); if(StringUtils.isNotBlank(split[2])){ if("mall".equals(split[1])){ final int universalid = Integer.parseInt(split[2]); //这里的Thread可以用java.util.concurrent代替 Thread polingVisualization = new Thread(new Runnable() { public void run() { while(!Thread.currentThread().isInterrupted()){ try { polingVisualization(localSession, localMessage, universalid); try { Thread.sleep(180000);//300000 } catch (InterruptedException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } } }); polingVisualization.start(); threads.put(sessi.getId(),polingVisualization); } } } } } private VisualizationProduct polingVisualization(WebSocketSession session, TextMessage message,Integer universalid) throws IOException { VisualizationProduct visualizationProduct = visualizationService.findInquiryPriceOrderVisualization(universalid); Map<String,Object> dataMap = new HashMap<String, Object>(); dataMap.put("status","1"); dataMap.put("visualizationProduct", visualizationProduct); String dataStr = JSONObject.fromObject(dataMap).toString(); TextMessage returnMessage = new TextMessage(dataStr); session.sendMessage(returnMessage); return visualizationProduct; } /** * 给正在发布的商品发送新数据 * @param universalid 发布会ID * @param sessionId */ public void sendNewProductDatas(Integer universalid, String sessionId){ if(universalid != null){ Set<String> keys = sessions.keySet(); for (String key : keys) { WebSocketSession webSocketSession = sessions.get(key); if(webSocketSession != null && webSocketSession.isOpen()){ VisualizationProduct visualizationProduct = visualizationService.findInquiryPriceOrderVisualization(universalid); Map<String,Object> dataMap = new HashMap<String, Object>(); dataMap.put("status","1"); dataMap.put("visualizationProduct", visualizationProduct); String dataStr = JSONObject.fromObject(dataMap).toString(); System.out.println(dataStr); TextMessage returnMessage = new TextMessage(dataStr); try { webSocketSession.sendMessage(returnMessage); } catch (IOException e) { e.printStackTrace(); } } } } } }
spring配置文件
文件标签,根据需要的添加,比如:websocket的xmlns和xsi:schemaLocation
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:websocket="http://www.springframework.org/schema/websocket" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<!-- 配置好处理器 --> <bean id="websocketHandler" class="com.snw.supplyChain.websocket.VisualizationWebSocketHandler"/> <!-- 配置拦截器 --> <websocket:handlers> <websocket:mapping path="/visualizationWebSocket.do" handler="websocketHandler"/><!-- 连接的URL --> <websocket:handshake-interceptors> <bean class="com.snw.supplyChain.websocket.VisualizationHandshakeInterceptor"/> </websocket:handshake-interceptors> </websocket:handlers>
欢迎各位大神指点其中不足哟。
逻辑处理