zoukankan      html  css  js  c++  java
  • spring websocket 使用@SendToUser

    spring websocket 使用@SendToUser

    原文链接:https://blog.csdn.net/yingxiake/article/details/51224569

    之前我们利用@SendTo在方法上进行注解,方法的返回值会被messageconverter转化并推送到消息代理器中,由消息代理器广播到订阅路径去

    @MessageMapping("bar") //@MessageMapping接收客户端消息
    @SendTo("/topic/brocast") //@SendTo广播消息出去
    public String handle1(String msg) {
    return msg;
    }

    上面msg会被广播到”/topic/brocast”这个订阅路径中,只要客户端订阅了这条路径,不管是哪个用户,都会接收到消息

    那么需求来了,如果我只是想简单的用websocket向服务器请求资源而已,然后服务器你就把资源给我就行了,别的用户就不用你广播推送了,简单点,就是我请求,你就推送给我。

    spring websocket 可以使用@SendToUser做到这一点,在使用@SendToUser之前,我们需要明白以下几点:

    1.spring webscoket通道的建立最开始还是源于http协议的第一次握手,握手成功之后,就打开了浏览器和服务器的webscoket通过,这时,httprequest中的登录授权信息即javax.security.Principal会被绑定到websocket的session中

    2.spring webscoket能识别带”/user”的订阅路径并做出处理,例如,如果浏览器客户端,订阅了’/user/topic/greetings’这条路径,

    stompClient.subscribe('/user/topic/greetings', function(data) {
    //...
    });

    就会被spring websocket利用UserDestinationMessageHandler进行转化成”/topic/greetings-usererbgz2rq”,”usererbgz2rq”中,user是关键字,erbgz2rq是sessionid,这样子就把用户和订阅路径唯一的匹配起来了

    3.spring webscoket在使用@SendToUser广播消息的时候,

    @MessageMapping("handle")
    @SendToUser("/topic/greetings")
    public String handle(String msg) {
    //...
    return msg;
    }
     
    “/topic/greetings”会被UserDestinationMessageHandler转化成”/user/role1/topic/greetings”,role1是用户的登录帐号,这样子就把消息唯一的推送到请求者的订阅路径中去,这时候,如果一个帐号打开了多个浏览器窗口,也就是打开了多个websocket session通道,这时,spring webscoket默认会把消息推送到同一个帐号不同的session,你可以利用broadcast = false把避免推送到所有的session中

    @MessageMapping("handle")
    @SendToUser(value = "/topic/greetings",broadcast = false)
    public String handle(String msg) {
    //...
    return name;
    }

    下面来做个demo,首先是服务器要配置登录验证权限,这里利用tomcat的basic安全验证,在web.xml里面配置

    <security-constraint>
    <web-resource-collection>
    <web-resource-name>protect resources </web-resource-name>
    <url-pattern>/*</url-pattern>
    <http-method>HEAD</http-method>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    <http-method>PUT</http-method>
    <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>role1</role-name>
    </auth-constraint>
    <user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
    </security-constraint>
    <login-config>
    <auth-method>BASIC</auth-method>
    </login-config>
    <security-role>
    <description>Role1</description>
    <role-name>role1</role-name>
    </security-role>  


    role1是登录的角色名,其中验证信息可以在tomcat-users.xml里面配置

    <role rolename="tomcat"/>
    <role rolename="role1"/>
    <user username="tomcat" password="tomcat" roles="tomcat"/>
    <user username="both" password="tomcat" roles="tomcat,role1"/>
    <user username="role1" password="tomcat" roles="role1"/>



    这里有俩个帐号,role1和both,角色都有role1,password都是tomcat,我们可以利用这俩个帐号在IE9和谷歌浏览器进行登录

    然后服务器,我们分别使用@SendTo和@SendToUser进行广播推送和精准推送

    首先我们注册下spring webscoket服务器

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {

    //portfolio-stomp就是websocket的端点,客户端需要注册这个端点进行链接,withSockJS允许客户端利用sockjs进行浏览器兼容性处理
    registry.addEndpoint("/portfolio-stomp").withSockJS();

    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic"); //设置服务器广播消息的基础路径
    registry.setApplicationDestinationPrefixes("/app"); //设置客户端订阅消息的基础路径
    registry.setPathMatcher(new AntPathMatcher(".")); //可以已“.”来分割路径,看看类级别的@messageMapping和方法级别的@messageMapping
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {

    return true;
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
    // TODO Auto-generated method stub
    registry.addDecoratorFactory(new MyWebSocketHandlerDecoratorFactory());
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new MyChannelInterceptor());
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
    // TODO Auto-generated method stub

    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    // TODO Auto-generated method stub

    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
    // TODO Auto-generated method stub

    }

    }
     

    然后写下服务的的接收和发送

    @Controller
    @RequestMapping("/webSocket")
    @MessageMapping("foo")
    public class WebSocketController {

    /**
    * 精准推送
    * @param msg
    * @param principal
    * @return
    */
    @MessageMapping("handle1") 
    @SendToUser(value = "/topic/greetings1",broadcast = false)
    public String handle1(String msg,Principal principal) {

    return "精准推送,只推送到" + principal.getName();
    }


    /**
    * 广播推送
    * @param msg
    * @param principal
    * @return
    */
    @MessageMapping("handle2") 
    @SendTo("topic/greetings2")
    public String handle2(String msg,Principal principal) {

    return "广播推送,所有用户都收得到";

    }

     最后在浏览器客户端,我们利用sockjs和stomp.js链接并发送和订阅消息,其中在websocket.js代码就是这样子的

    var socket = new SockJS('/whats/portfolio-stomp');
    var stompClient = Stomp.over(socket);
    stompClient.connect({}, function(frame) {

    stompClient.subscribe('/user/topic/greetings1', function(data) {
    $("#ret").text(data.body);
    });

    stompClient.subscribe('/topic/greetings2', function(data) {
    $("#ret").text(data.body);
    });
    });

    /**
    * 精准推送
    */
    document.getElementById("ws1").onclick = function() {
    stompClient.send("/app/foo.handle2",{},{
    msg : "精准推送"
    });
    }

    /**
    * 广播推送
    */
    document.getElementById("ws").onclick = function() {

    stompClient.send("/app/foo.handle1",{},{
    msg : "广播推送"
    });

    }
     

     jsp页面其实就是这样子的

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html >
    <html>
    <head>
    <meta charset="UTF-8">
    <title>websocket</title>

    </head>
    <body>

    <h1>hello websocket client !!</h1>

    <button id = "ws">精准推送</button>
    <button id = "ws1">广播推送</button>

    <span id ="ret"></span>

    <script type="text/javascript" src="${pageContext.request.contextPath}/content/uilib/websocket/sockjs-1.0.3.js"></script>
    <script type="text/javascript" src="${pageContext.request.contextPath}/content/uilib/websocket/stomp.js"></script>
    <script type="text/javascript" src="${pageContext.request.contextPath}/content/js/websocket/websocket.js"></script>
    </body>
    </html>

    到这里就完成了功能了

    精准推送

     

    广播推送 

  • 相关阅读:
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第3节 maven标准目录结构和常用命令_07maven常用命令
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第3节 maven标准目录结构和常用命令_06maven标准目录结构
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第2节 maven的安装和仓库种类_05仓库的种类和彼此关系
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第2节 maven的安装和仓库种类_04maven的安装
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第1节 基本概念_03maven一键构建概念
    阶段2 JavaWeb+黑马旅游网_15-Maven基础_第1节 基本概念_02maven依赖管理的概念
    kmalloc、vmalloc、__get_free_pages()的区别
    如何增加内核模块
    VFS四大对象之四-struct file
    VFS四大对象之三 struct dentry
  • 原文地址:https://www.cnblogs.com/personsiglewine/p/12038300.html
Copyright © 2011-2022 走看看