在SpringMVC中使用WebSocket

Spring WebSocket 实现
本文介绍如何在Spring MVC项目中利用Spring WebSocket和spring-messaging实现WebSocket功能,包括搭建环境、配置及核心代码示例。

SpringMvc项目的搭建在这里就不做多解释,要在Spring中实现 WebSocket 必须加上 spring-websocket和

spring-messaging两个包,同样,完整的pom.xml给出如下:

< project xmlns = "http://maven.apache.org/POM/4.0.0"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
     < modelVersion >4.0.0</ modelVersion >
     < groupId >com.656463</ groupId >
     < artifactId >demo-websocket</ artifactId >
     < packaging >war</ packaging >
     < name >demo-websocket Maven Webapp</ name >
     < version >0.0.1-SNAPSHOT</ version >
     < url >http://maven.apache.org</ url >
     < properties >
         < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding >
         < spring.version >4.1.6.RELEASE</ spring.version >
     </ properties >
     < dependencies >
         <!-- spring相关 -->
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-context</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-core</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-beans</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-aop</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-context-support</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-jdbc</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-web</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-webmvc</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-websocket</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.springframework</ groupId >
             < artifactId >spring-messaging</ artifactId >
             < version >${spring.version}</ version >
         </ dependency >
         < dependency >
             < groupId >org.aspectj</ groupId >
             < artifactId >aspectjweaver</ artifactId >
             < version >1.7.4</ version >
         </ dependency >
         < dependency >
             < groupId >com.google.code.gson</ groupId >
             < artifactId >gson</ artifactId >
             < version >2.7</ version >
         </ dependency >
         < dependency >
             < groupId >jstl</ groupId >
             < artifactId >jstl</ artifactId >
             < version >1.2</ version >
         </ dependency >
         < dependency >
             < groupId >taglibs</ groupId >
             < artifactId >standard</ artifactId >
             < version >1.1.2</ version >
         </ dependency >
         < dependency >
             < groupId >javax.websocket</ groupId >
             < artifactId >javax.websocket-api</ artifactId >
             < version >1.1</ version >
             < scope >provided</ scope >
         </ dependency >
         < dependency >
             < groupId >javax</ groupId >
             < artifactId >javaee-api</ artifactId >
             < version >7.0</ version >
             < scope >provided</ scope >
         </ dependency >
     </ dependencies >
     < build >
         < finalName >demo-websocket</ finalName >
         < plugins >
             < plugin >
                 < groupId >org.apache.maven.plugins</ groupId >
                 < artifactId >maven-compiler-plugin</ artifactId >
                 < version >3.0</ version >
                 < configuration >
                     < source >1.7</ source >
                     < target >1.7</ target >
                 </ configuration >
             </ plugin >
             < plugin >
                 < groupId >org.apache.tomcat.maven</ groupId >
                 < artifactId >tomcat7-maven-plugin</ artifactId >
                 < version >2.2</ version >
                 < configuration >
                     < port >8080</ port >
                     < path >/</ path >
                 </ configuration >
             </ plugin >
         </ plugins >
     </ build >
</ project >
定义一个简单的WebSocket客户端页面,这里只有一个连接和发送消息的功能,这个示例和上个示例的功能类似
<%@ page language= "java" contentType= "text/html; charset=UTF-8"
          pageEncoding= "UTF-8" %>
<!DOCTYPE html>
<html lang= "en" >
<head>
     <meta charset= "utf-8" >
     <title></title>
     <script type= "text/javascript" src= "/static/js/jquery-1.9.1.js" ></script>
     <script type= "text/javascript" >
         $(function () {
             var websocket;
             var target = "ws://192.168.56.101:8080/hello.htm" ;
             if ( 'WebSocket' in window) {
                 websocket = new WebSocket(target);
             } else if ( 'MozWebSocket' in window) {
                 websocket = new MozWebSocket(target);
             } else {
                 alert( 'WebSocket is not supported by this browser.' );
                 return ;
             }
             websocket.onopen = function (evnt) {
                 $( "#tou" ).html( "链接服务器成功!" )
             };
             websocket.onmessage = function (evnt) {
                 $( "#msg" ).html($( "#msg" ).html() + "<br/>" + evnt.data);
             };
             websocket.onerror = function (evnt) {
             };
             websocket.onclose = function (evnt) {
                 $( "#tou" ).html( "与服务器断开了链接!" )
             }
             $( '#send' ).bind( 'click' , function () {
                 send();
             });
             function send() {
                 if (websocket != null ) {
                     var message = document.getElementById( 'message' ).value;
                     websocket.send(message);
                 } else {
                     alert( '未与服务器链接.' );
                 }
             }
         });
     </script>
</head>
<body>
<div id= "tou" > webSocket及时聊天Demo程序</div>
<div id= "msg" ></div>
<input type= "text" id= "message" >
<button type= "button" id= "send" > 发送</button>
</body>
</html>


创建握手拦截器的类 HandInterceptor ,此类实现 HandshakeInterceptor接口。此类的功能有点类似于使用原始J2EE实现的@OnOpen注解
package com._656463.demo.websocket.spring;
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.HandshakeInterceptor;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
  * 拦截器(握手)
  */
public class HandInterceptor implements HandshakeInterceptor {
     @Override
     public boolean beforeHandshake(ServerHttpRequest request,
             ServerHttpResponse response, WebSocketHandler handler,
             Map<String, Object> map) throws Exception {
         if (request instanceof ServletServerHttpRequest) {
             HttpServletRequest req = ((ServletServerHttpRequest) request).getServletRequest();
             String userName = "default-user" ;
             // 使用userName区分WebSocketHandler,以便定向发送消息
             // String userName = (String)
             // session.getAttribute("WEBSOCKET_USERNAME");
             map.put( "WEBSOCKET_USERNAME" , userName);
             req.getSession().setAttribute( "WEBSOCKET_USERNAME" , userName);
         }
         return true ;
     }
     @Override
     public void afterHandshake(ServerHttpRequest serverHttpRequest,
             ServerHttpResponse serverHttpResponse,
             WebSocketHandler webSocketHandler, Exception e) {
     }
}


创建一个类 WebSocketHander,实现 WebSocketHandler接口,此类的主要功能是消息处理中心,相当于使用原始J2EE API实现中的@OnMessage和@OnClose注解功能
package com._656463.demo.websocket.spring;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
  * 消息处理中心
  */
public class WebSocketHander implements WebSocketHandler {
     private static final List<WebSocketSession> users = new ArrayList<WebSocketSession>();
     /**
      * 初次链接成功执行
      *
      * @param session
      * @throws Exception
      */
     @Override
     public void afterConnectionEstablished(WebSocketSession session) throws Exception {
         System.out.println( "链接成功......" );
         users.add(session);
         String userName = (String) session.getAttributes().get( "WEBSOCKET_USERNAME" );
         if (userName != null ) {
             //查询未读消息
             int count = 5 ;
             session.sendMessage( new TextMessage(count + "" ));
         }
     }
     /**
      * 接受消息处理消息
      *
      * @param session
      * @param message
      * @throws Exception
      */
     @Override
     public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
         sendMessageToUsers( new TextMessage(message.getPayload() + "" ));
     }
     @Override
     public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {
         if (session.isOpen()) {
             session.close();
         }
         System.out.println( "链接出错,关闭链接......" );
         users.remove(session);
     }
     @Override
     public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
         System.out.println( "链接关闭......" + status.toString());
         users.remove(session);
     }
     @Override
     public boolean supportsPartialMessages() {
         return false ;
     }
     /**
      * 给所有在线用户发送消息
      *
      * @param message
      */
     public void sendMessageToUsers(TextMessage message) {
         for (WebSocketSession user : users) {
             try {
                 if (user.isOpen()) {
                     user.sendMessage(message);
                 }
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
     /**
      * 给某个用户发送消息
      *
      * @param userName
      * @param message
      */
     public void sendMessageToUser(String userName, TextMessage message) {
         for (WebSocketSession user : users) {
             if (user.getAttributes().get( "WEBSOCKET_USERNAME" ).equals(userName)) {
                 try {
                     if (user.isOpen()) {
                         user.sendMessage(message);
                     }
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
                 break ;
             }
         }
     }
}


有了握手拦截器和消息处理中心之后,要开启WebSocket,让他工作起来。
开启WebSocket有两种方式,一种是基于注解的方式,二是基本XML配置的方式
1、基于注解的方式
在springmvc的配置文件中,配置扫描包
<!-- websocket相关扫描,主要扫描:WebSocketConfig.java 这个类路径 -->
<context:component-scan base-package="com._656463.demo.websocket.spring"/>
创建WebSocketConfig,开启WebSocket,并注册WebSocket的请求路径
package com._656463.demo.websocket.spring;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
  * EnableWebSocket 开启websocket
  *
  * @EnableWebMvc //这个标注可以不加,如果有加,要extends WebMvcConfigurerAdapter
  */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
     @Override
     public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
         // 支持websocket 的访问链接
         registry.addHandler( new WebSocketHander(), "/hello.htm" )
                 .addInterceptors( new HandInterceptor());
         // 不支持websocket的访问链接
         registry.addHandler( new WebSocketHander(), "/sockjs/hello.htm" )
                 .addInterceptors( new HandInterceptor())
                 .withSockJS();
     }
}


2、基于XML配置的方式
在springmvc的配置文件中,通过websocket标签配置WebSocket
<!-- 可以在这里配置websocket的相关类,也可以用注解,详细可以查看com._656463.demo.websocket.spring.WebSocketConfig -->
<bean id= "websocket" class = "com._656463.demo.websocket.spring.WebSocketHander" />
<websocket:handlers>
     <websocket:mapping path= "/hello.htm" handler= "websocket" />
     <websocket:handshake-interceptors>
         <bean class = "com._656463.demo.websocket.spring.HandInterceptor" />
     </websocket:handshake-interceptors>
</websocket:handlers>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值