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

来源:互联网 发布:sql forceseek 编辑:程序博客网 时间:2024/05/14 23:05

        前面说到,使用websocket通讯,现在说说应用上的通讯,stomp - streaming / simple text oriented protocol. 流/简单 文本协议。应用方面,一般采用该种协议,是websocket协议的一个子协议,了解一下既可。
        stomp协议,配置时注意一个地方,stomp协议使用的中继器(路由)或者叫消息中介,默认在configureMessageBroker方法中,registry.enableSimpleBroker是使用内存中介,不依赖第三方组件,registry.enableStompBrokerRelay是使用第三方中间件,需要事先下载安装中间件,如activeMQ/RabbitMQ.本例子中使用内存中继。

        具体代码实现:

        1. WebSocketMessageBrokerConfigurer配置类,继承AbstractWebSocketMessageBrokerConfigurer重写下面方法。

package com.websocket.stomp;import java.util.List;import org.springframework.context.annotation.Configuration;import org.springframework.messaging.converter.MessageConverter;import org.springframework.messaging.simp.config.ChannelRegistration;import org.springframework.messaging.simp.config.MessageBrokerRegistry;import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;import org.springframework.web.socket.config.annotation.StompEndpointRegistry;import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;/** * stomp websocket的子协议,stomp: simple/streaming text oriented message protocol. 简单/流 文本消息协议,  * 选择使用内存中级,还是使用activeMQ等中间件服务器 * @author tomZ * @date 2016年11月3日 * @desc TODO */@Configuration@EnableWebSocketMessageBrokerpublic class MyWebSocketMessageBrokerConfig extends AbstractWebSocketMessageBrokerConfigurer {/** * 连接的端点,客户端建立连接时需要连接这里配置的端点 */@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {//为java stomp client提供链接registry.addEndpoint("/client").setAllowedOrigins("*").setHandshakeHandler(new MyHandshakeHandler()).addInterceptors(new MyHandshakeInterceptor());//为js客户端提供链接registry.addEndpoint("/hello").setAllowedOrigins("*").setHandshakeHandler(new MyHandshakeHandler()).addInterceptors(new MyHandshakeInterceptor()).withSockJS();}/** * applicationDestinationPrefixes应用前缀,所有请求的消息将会路由到@MessageMapping的controller上, * enableStompBrokerRelay是代理前缀,而返回的消息将会路由到代理上,所有订阅该代理的将收到响应的消息。 *  */@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.setApplicationDestinationPrefixes("/app");registry.setUserDestinationPrefix("/user");registry.enableSimpleBroker("/topic", "/queue")//registry.enableStompBrokerRelay("/topic", "/queue")//下面这配置为默认配置,如有变动修改配置启用就可以了//.setRelayHost("127.0.0.1") //activeMq服务器地址//.setRelayPort(61613)//activemq 服务器服务端口//.setClientLogin("guest")//登陆账户//.setClientPasscode("guest") // ;}/** * 消息传输参数配置 */@Overridepublic void configureWebSocketTransport(WebSocketTransportRegistration registration) {//super.configureWebSocketTransport(registration);registration.setMessageSizeLimit(8192).setSendBufferSizeLimit(8192).setSendTimeLimit(10000);}/** * 输入通道参数设置 */@Overridepublic void configureClientInboundChannel(ChannelRegistration registration) {//super.configureClientInboundChannel(registration);//线程信息registration.taskExecutor().corePoolSize(4).maxPoolSize(8).keepAliveSeconds(60);}/** * 输出通道参数配置 */@Overridepublic void configureClientOutboundChannel(ChannelRegistration registration) {//super.configureClientOutboundChannel(registration);//线程信息registration.taskExecutor().corePoolSize(4).maxPoolSize(8);}@Overridepublic boolean configureMessageConverters(List<MessageConverter> messageConverters) {//return super.configureMessageConverters(messageConverters);return true;}}

        Handler类:处理器类

package com.websocket.stomp;import java.security.Principal;import java.util.Map;import org.springframework.http.server.ServerHttpRequest;import org.springframework.web.socket.WebSocketHandler;import org.springframework.web.socket.server.support.DefaultHandshakeHandler;/** * stomp 处理器 * @author tomZ * @date 2016年11月4日 * @desc TODO */public class MyHandshakeHandler extends DefaultHandshakeHandler {///该方法可以重写用来为用户 添加标识 返回principal@Overrideprotected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,Map<String, Object> attributes) {// TODO Auto-generated method stubreturn super.determineUser(request, wsHandler, attributes);}}
        Interceptor类。拦截器

package com.websocket.stomp;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.web.socket.WebSocketHandler;import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;/** * stomp握手拦截器 * @author tomZ * @date 2016年11月4日 * @desc TODO */public class MyHandshakeInterceptor extends HttpSessionHandshakeInterceptor {private static final Logger logger = LoggerFactory.getLogger( MyHandshakeInterceptor.class);@Overridepublic 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);}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,Exception ex) {logger.info("===============after handshake=============");super.afterHandshake(request, response, wsHandler, ex);}}

         2. 最后在spring-context.xml (application-context.xml)中扫描上面类所在的包即可。

         3. controller, @MessageMapping用法和@RequestMapping相似,@SendTo是将消息发到指定的映射路由uri上去,@Subscribe是订阅uri注解,此外还有@SendToUser/@DestinationVariable等注解,可以查一下。

     

package com.tom.jeesite.web.stomp;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.messaging.handler.annotation.MessageMapping;import org.springframework.messaging.handler.annotation.SendTo;import org.springframework.messaging.simp.annotation.SubscribeMapping;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** *  * @author tom * @version 2016-06-12 */@Controllerpublic class MyStompTestController {/** * @MessageMapping 是app路由地址,客户端请求将交由其处理,@SendTo是返回消息路由到指定地址,订阅该地址的将接收到消息 * @param incoming * @return */@MessageMapping("/hi")@SendTo("/topic/hi")public String handleHi(String incoming) {System.out.println("receive message : " + incoming);return "hello, " + incoming; }/** * 订阅,当有客户端订阅该内容,会有一次性响应 * @return */@SubscribeMapping("/subscribeme")public String subscribeThing() {System.out.println("subscribe message called.");return "thank you subscribe my channel";}}


         4. Jsp页面:

     

<%@ 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"/><c:set var="ctx" value="${pageContext.request.contextPath}"/><%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> --%>    <script src="http://cdn.sockjs.org/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>    <%-- <script src="${ctxStatic }/stomp/stomp.mini.js"></script> --%>    <script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>        <title>stomp测试</title><script type="text/javascript">$(document).ready(function() {    var sock = new SockJS("${ctx}/hello");    var stomp = Stomp.over(sock);        stomp.connect('guest', 'guest', function(frame) {        console.log('*****  Connected  *****');        $('#msg').append("<b>*****  Connected  *****</b><br/>");        //一次性订阅,只返回一次        stomp.subscribe("/app/subscribeme", handleOneTime);        //订阅代理,代理发消息将会接收到        stomp.subscribe("/topic/hi", handleMsg);    }, function(error) {    console.log('error:'+error);        });        function handleOneTime(message) {    //alert('123');        console.log('Received: ', message);        $('#msg').append("<b>handleOneTime - Received: " +               message.body + "</b><br/>");    }    function handleMsg(message) {        console.log('Received: ', message);        $('#msg').append("<b>Received: " +                message.body + "</b><br/>");       // if (JSON.parse(message.body).message === 'Polo!') {       //     setTimeout(function(){sayMarco()}, 2000);       // }    }    function handleErrors(message) {        console.log('RECEIVED ERROR: ', message);        $('#msg').append("<b>GOT AN ERROR!!!: " +                JSON.parse(message.body).message + "</b><br/>");    }    function send() {        console.log('Sending msg!');        //发送        stomp.send("/app/hi", {},                JSON.stringify({ 'message':  $('#message').val()}));//        stomp.send("/topic/marco", {},//                JSON.stringify({ 'message': 'Marco!' }));        $('#msg').append("<b>Send: " + $('#message').val() + "!</b><br/>");    }    $('#stop').click(function() {    sock.close();      $('#msg').append("<b>Connection closed!</b><br/>");     });        $('#send').bind('click', function() {        send();    });    });</script></head><body><div class="page-header" id="tou">    webSocket-stomp测试程序     <button class="btn btn-default" type="button" id="stop" >关闭连接</button></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>
       启动运行,效果如下:

       浏览器:


       服务器:



0 0
原创粉丝点击