spring整合websocket通信
1. maven依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dxss.websocket</groupId> <artifactId>WebSocketProGram</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>WebSocketProGram Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- 添加Spring支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <!-- 添加对websocket的支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.6.2</version> </dependency> </dependencies> <build> <finalName>WebSocketProGram</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/WebSocketProGram</path> <port>9092</port> </configuration> </plugin> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.0.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.20.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.0</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
2. servletContext.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-4.0.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd"> <!-- 配置处理器 --> <bean id="websocket" class="com.web.common.util.websocket.MyWebSocketHander" /> <!-- 配置拦截器 --> <websocket:handlers>
<!-- 跟前端请求的url相关 --> <websocket:mapping path="/visualizationWebSocket.do" handler="websocket" /> <websocket:handshake-interceptors> <bean class="com.web.common.util.websocket.HandshakeInterceptor" /> </websocket:handshake-interceptors> </websocket:handlers> </beans>
3. servletContext-mvc.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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <context:component-scan base-package="com.dxss.java.controller"/> <mvc:default-servlet-handler/> <mvc:annotation-driven/> <bean id="configProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <array> <value>classpath:db.properties</value> </array> </property> <property name="fileEncoding" value="UTF-8"></property> <property name="ignoreUnresolvablePlaceholders" value="true"></property> </bean> <!-- 页面前缀 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
4. webSocket配置
package com.web.common.util.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.servlet.config.annotation.WebMvcConfigurerAdapter; 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; /** * webSocket配置 : 注册websocket地址和处理类 */ @Configuration @EnableWebMvc @EnableWebSocket public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // 这里的url要与页面的url一致 // 前台 可以使用websocket环境 registry.addHandler(myWebSocketHandler(),"/visualizationWebSocket.do").addInterceptors(new HandshakeInterceptor()); //至于这里为什么要加info,我遇见的情况是,当我使用sockjs来代替websocket时,连接的后面会自动加上info //前台 不可以使用websocket环境,则使用sockjs进行模拟连接 registry.addHandler(myWebSocketHandler(), "/sockjs/visualizationWebSocket/info").addInterceptors(new HandshakeInterceptor()) .withSockJS(); } /** * websocket 处理类 * * @return */ @Bean public WebSocketHandler myWebSocketHandler(){ return new MyWebSocketHander(); } }
5. 会话拦截器
package com.web.common.util.websocket; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; import java.util.Map; /** * 创建握手(handshake)接口/拦截器 * desc : 这个的主要作用是可以在握手前做一些事,把所需要的东西放入到attributes里面, * 然后可以在WebSocketHandler的session中,取到相应的值,具体可参考HttpSessionHandshakeInterceptor, * 这儿也可以实现HandshakeInterceptor接口 * * @author lenovo */ public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes ) throws Exception { /** * 获取请求参数,首先我们要获取HttpServletRequest对象才能获取请求参数; * 当ServerHttpRequset的层次结构打开后其子类可以获取到我们想要的http对象,那么就简单了。 我这里是把获取的请求数据绑定到session的map对象中(attributes) */ System.out.println( " HandshakeInterceptor: beforeHandshake, attributes is : " + attributes ); return super.beforeHandshake( request, response, wsHandler, attributes ); } /** * 握手后 */ @Override public void afterHandshake( ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex ) { System.out.println(" HandshakeInterceptor: afterHandshake "); super.afterHandshake(request, response, wsHandler, ex); } }
6. websocket处理器
处理器里面可以注入想要的service
package com.web.common.util.websocket; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import org.springframework.web.socket.*; import java.io.IOException; import java.util.ArrayList; import java.util.Map; /** * websocket处理类就是处理:连接开始、关闭、处理信息等方法 * * @author lenovo */ public class MyWebSocketHander implements WebSocketHandler { /** * 保存所有的用户session */ private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>(); /** * 连接就绪时 */ @Override public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception { System.out.println("connection success ...... "); users.add(webSocketSession); } /** * 处理信息 * * @param webSocketSession * @param webSocketMessage * @throws Exception */ @Override public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception { Gson gson = new Gson(); Map<String, Object> msg = gson.fromJson(webSocketMessage.getPayload().toString(), new TypeToken<Map<String, Object>>() {}.getType()); // 处理消息 msgContent消息内容 TextMessage textMessage = new TextMessage(msg.get("msgContent").toString(), true); System.out.println("页面传递的消息为: "+ msg.get("msgContent").toString()); // 调用方法(发送消息给所有人) sendMsgToAllUsers(textMessage); } private void sendMsgToAllUsers(TextMessage textMessage) { System.out.println("users list is : "+users); for (WebSocketSession user : users) { try { user.sendMessage(textMessage); } catch (IOException e) { e.printStackTrace(); } } } /** * 处理传输时异常 * * @param webSocketSession * @param throwable * @throws Exception */ @Override public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception { System.out.println(" Transport occur error ......"); } /** * 关闭连接时 * * @param webSocketSession * @param closeStatus * @throws Exception */ @Override public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { System.out.println("connection close ......"); } @Override public boolean supportsPartialMessages() { return false; } }
7. 示例页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="en"> <head> <title>首页</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="renderer" content="webkit"> <!-- 引入 JQuery --> <script type="text/javascript" src="js/jquery/jquery-1.12.4.js"></script> <!-- 引入 sockJS --> <script type="text/javascript" src="js/websocket/sockjs.min.js" ></script> <!-- 自定义JS文件 --> </head> <body> <!-- 最外边框 --> <div style="margin: 20px auto; border: 1px solid blue; width: 300px; height: 500px;"> <!-- 消息展示框 --> <div id="msg" style="width: 100%; height: 70%; border: 1px solid yellow;overflow: auto;"></div> <!-- 消息编辑框 --> <textarea id="tx" style="width: 100%; height: 20%;"></textarea> <!-- 消息发送按钮 --> <button id="TXBTN" style="width: 100%; height: 8%;">发送数据</button> </div> </body> </html> <script type="text/javascript" src="js/index/index.js"></script>
8. 页面js
$(function() { var websocket; // 首先判断是否 支持 WebSocket if('WebSocket' in window) { websocket = new WebSocket("ws://localhost:9092/WebSocketProGram/visualizationWebSocket.do"); } else if('MozWebSocket' in window) { websocket = new MozWebSocket("ws://localhost:9092/WebSocketProGram/visualizationWebSocket.do"); } else { websocket = new SockJS("http://localhost:9092/WebSocketProGram/sockjs/visualizationWebSocket.do"); } // 打开时 websocket.onopen = function(evnt) { console.log("websocket.onopen "); }; // 处理消息时 websocket.onmessage = function(evnt) { $("#msg").append("<p>(<font color='red'>" + evnt.data + "</font>)</p>"); console.log(" websocket.onmessage "); }; websocket.onerror = function(evnt) { console.log(" websocket.onerror "); }; websocket.onclose = function(evnt) { console.log(" websocket.onclose "); }; // 点击了发送消息按钮的响应事件 $("#TXBTN").click(function(){ // 获取消息内容 var text = $("#tx").val(); // 判断 if(text == null || text == ""){ alert(" content can not empty!!"); return false; } var msg = { msgContent: text, postsId: 1 }; // 发送消息 websocket.send(JSON.stringify(msg)); }); });