Spring4.3.3 WebSocket-STOMP协议集成 (1)-WebSocket协议通讯小栗子

            简介(个人理解,有偏差请打脸):Spring4.0以后新增支持的websocket通讯协议,应用层采用stomp协议,消息处理,默认采用内存消息中继,就是将收到和要转发的消息存储在内存中,显然,服务器重启,消息就不存在了。另外支持外接中继组件,如activeMQ/RabbitMQ等消息服务器,产品的话,官网说,为了稳定性和拓展性等各种性推荐使用第三方消息中继(路由)。(中继/路由)就是一个叫法,显得比较专业,说白了就是个消息中间件,再白就是一个消息转发/处理的服务器。


      下面先弄第一部分,认识一下webSocket,配置简单易懂(虽然我开始弄也碰一鼻子灰, 慢慢来)。

      具体实现:

      1. pom.xml(maven,不用maven的下载jar包,引入)

      spring-websocket/messaging 4.3.3.Release

      <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>javax.websocket</groupId>
	    <artifactId>javax.websocket-api</artifactId>
	    <version>1.1</version>
	    <scope>provided</scope>
	</dependency>
         fastxml 消息转化什么的要用的

         fasterxml 2.4.4

               <dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.module</groupId>
			<artifactId>jackson-module-jaxb-annotations</artifactId>
			<version>${jackson.version}</version>
		</dependency>

        其他spring依赖,根据需要添加就可以了。

         2. WebSocket配置类,用于启用webSocket

       

package com.websocket.socket;

import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * websocket 配置类, 采用websocket形式实现的通讯类似于直接使用tcp协议,属于底层协议,spring中应用层
 * 采用高层的协议进行长连接通讯,stomp
 * @author tomZ
 * @date 2016年11月2日
 * @desc TODO
 */
@Configuration
@EnableWebMvc
@EnableWebSocket
public class MyWebSocketConfig implements WebSocketConfigurer {

	@Autowired
	private MyWebSocketHander handler;
	@Autowired
	private MyHandshakeInterceptor handshakeInterceptor;
	/**
	 * 注册支持的websocket 连接
	 */
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry reg) {
		/**
		 * websocket形式连接, client连接
		 */
		reg.addHandler(handler, "/websocket").addInterceptors(handshakeInterceptor);
		
		/**
		 * 不支持websocket的,采用sockjs
		 */
		reg.addHandler(handler, "/sockjs/websocket").addInterceptors(handshakeInterceptor).withSockJS();
	}

}
       拦截器和处理器类:

package com.websocket.socket;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

/**
 * 建立连接,握手拦截器
 * @author tomZ
 * @date 2016年11月2日
 * @desc TODO
 */
@Component
public class MyHandshakeInterceptor implements HandshakeInterceptor {

	private static final Logger logger = LoggerFactory.getLogger(MyHandshakeInterceptor.class);
	
	@Override
	public void afterHandshake(ServerHttpRequest req, ServerHttpResponse resp, WebSocketHandler handler, Exception e) {
		logger.info("after hand shake {}", this.getClass().getName());
	}

	@Override
	public boolean beforeHandshake(ServerHttpRequest req, ServerHttpResponse resp, WebSocketHandler handler,
			Map<String, Object> map) throws Exception {
		logger.info("before hand shake {}", this.getClass().getName());
		 /** 
	     * This is a bug,bug fix:The extension [x-webkit-deflate-frame] is not supported 
	     */  
	    if(req.getHeaders().containsKey("Sec-WebSocket-Extensions")) {  
	    	req.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");  
	      }  
		return true;
	}

}
package com.websocket.socket;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

import com.beust.jcommander.internal.Maps;

/**
 * websocket 处理器
 * 
 * @author tomZ
 * @date 2016年11月2日
 * @desc TODO
 */
@Component
public class MyWebSocketHander implements WebSocketHandler {

	private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHander.class);

	private static final Map<String, WebSocketSession> sessions = Maps.newHashMap();

	// 连接建立后操作
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		logger.info("connection established . sessionId {}, remote addr {}", session.getId(),
				session.getRemoteAddress());
		sessions.put(session.getId(), session);
	}

	// 处理收到消息操作
	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> msg) throws Exception {
		logger.info("handler message. sessionId {}, remote addr {}, message {}", session.getId(),
				session.getRemoteAddress(), msg.getPayload());
		sendMessage(msg);
	}

	// 消息处理错误操作
	@Override
	public void handleTransportError(WebSocketSession session, Throwable e) throws Exception {
		if (session.isOpen()) {
			sessions.remove(session.getId());
			session.close();
		}
		logger.error("handle trainsport error", e);
	}

	// 是否支持大消息分部分发送
	@Override
	public boolean supportsPartialMessages() {
		return false;
	}

	// 连接关闭后操作
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		logger.info("connection closed . sessionId {}, remote addr {}", session.getId(), session.getRemoteAddress());
		sessions.remove(session.getId());
	}

	/**
	 * 发送信息
	 * 
	 * @param msg
	 */
	private void sendMessage(WebSocketMessage<?> msg) {
		for (Entry<String, WebSocketSession> ses : sessions.entrySet()) {
			WebSocketSession s = ses.getValue();
			try {
				if (s.isOpen()) {
					s.sendMessage(msg);
				} else {
					sessions.remove(s.getId());
				}
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}
		}
	}

}

       3.上面就是WebSocket基本配置,最后在spring-context.xml (application-context.xml)中扫描上面类所在的包即可。

       <context:component-scan base-package="com.websocket.socket"  ><!-- base-package 如果多个,用“,”分隔 -->
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>

      4. jsp页面,websocket.jsp,网上找的页面,自己改了改,有用到bootstrap样式/js,socket.js, jquery

      

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="ctxStatic" value="${pageContext.request.contextPath}/static"/>
<%
	String path = request.getContextPath();
	String basePath = request.getServerName() + ":" + request.getServerPort() + path + "/";
	
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head lang="en">
    <script src="${ctxStatic }/websocket/sockjs-0.3.min.js"></script>
    <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="${ctxStatic }/bootstrap/3.3.0/css/bootstrap.min.css">
    <!-- 可选的Bootstrap主题文件(一般不用引入) -->
    <link rel="stylesheet" href="${ctxStatic }/bootstrap/3.3.0/css/bootstrap-theme.min.css">
    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
    <script src="${ctxStatic}/jquery/jquery-1.9.1.min.js" type="text/javascript"></script>
    <!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>-->
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="${ctxStatic }/bootstrap/3.3.0/js/bootstrap.min.js"></script>
    <title>webSocket测试</title>
    <script type="text/javascript">
    $(document).ready(function() {
        var websocket;
        if ('WebSocket' in window) {
            alert("WebSocket");
            websocket = new WebSocket("ws://localhost:18080/项目名称/websocket");
        } else if ('MozWebSocket' in window) {
            alert("MozWebSocket");
           websocket = new MozWebSocket("ws://echo");
        } else {
            alert("SockJS");
            websocket = new SockJS("http://localhost:18080/项目名称/sockjs/websocket");
        }
        websocket.onopen = function (evnt) {
            $("#tou").html("链接服务器成功!")
        };
        websocket.onmessage = function (evnt) {
           $("#msg").html("Received: " + 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 class="page-header" id="tou">
    webSocket即时消息测试
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
    <div class="input-group">
        <input type="text" class="form-control" placeholder="发送信息..." id="message">
      <span class="input-group-btn">
        <button class="btn btn-default" type="button" id="send" >发送</button>
      </span>
    </div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</body>
</html>
        5.请求jsp页面,并发送,自己就能接收到了。http://localhost:18080/项目/socket


     



         

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值