资讯专栏INFORMATION COLUMN

spring boot websocket的实现

wuyumin / 2923人阅读

摘要:子协议只是一个消息传递的体系结构,没有指定任何的消息传递协议。是一个简单的消息传递协议,是一种为,面向消息的中间件设计的简单文本协议。的实现对内嵌的或者和使用了提供了支持。广播式广播式即服务端有消息时,会将消息发送到所有连接了当前的浏览器。

简单介绍

    WebSocket是为浏览器和服务端提供双工艺部通信功能一种工具,即浏览器可以先服务端发送消息,服务端也可以先浏览器发送消息。现在支持Websocket的浏览器有  IE10+,Crome13+,FileFox6+。

WebSocket子协议

    WebSocket只是一个消息传递的体系结构,没有指定任何的消息传递协议。与HTTP协议不同的是,WebSocket只是一个应用层的协议,它非常简单,并不能理解传入的消息,也不能对消息进行路由或处理,因此WebSocket协议只是一个应用层的协议,其上需要一个框架来理解和处理消息。

    Spring框架提供了对使用STOMP子协议的支持。STOMP,全称Streaming Text Orientated Message Protol,流文本定向协议。STOMP是一个简单的消息传递协议,是一种为MOM(Message Orientated  Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供了一个可操作的连接格式,允许STOMP客户端与任意代理(Broker)进行交互,类似于OpenWire(一种二进制协议)。

    

Spring Boot的WebSocket实现

     SpringBoot对内嵌的Tomcat(7或者8)、Jetty9和Undertow使用了WebSocket提供了支持。

广播式

广播式即服务端有消息时,会将消息发送到所有连接了当前endpoint的浏览器。

配置WebSocket

需要在配置类上使用@EnableWebSocketMessageBroker开启WebSocket支持,并通过集成AbstractWebSocketMessageBrokerConfigurer类,重写其方法来配置WebSocket。
        

package com.example.config;

import org.springframework.context.annotation.Configuration;
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;

/**
 * Created by lenovo on 2017/3/15.
 */
@Configuration
@EnableWebSocketMessageBroker //通过@EnableWebSocketMessageBroker 注解凯旗使用STOMP协议来传输基于代理(message broker)的消息
//这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{


    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/endpoint").withSockJS();//注册STOMP协议的节点,映射指定的URL,并指定使用SockJS协议
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {//配置消息代码(Message Broker)
        registry.enableSimpleBroker("/topic");//广播式应配置一个/topic消息代理
    }
}

消息的接收器、发送器和控制器

package com.example.model;

/**
 * Created by lenovo on 2017/3/15.
 */
public class MessageSender {
    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public MessageSender(String msg) {
        this.msg = msg;
    }
}
package com.example.model;

import java.io.Serializable;

/**
 * Created by lenovo on 2017/3/15.
 */
public class MessageAcceptor implements Serializable{

    private String msg;

    public String getMsg() {
        return msg;
    }

}
package com.example.websocket;

import com.example.model.MessageAcceptor;
import com.example.model.MessageSender;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by lenovo on 2017/3/15.
 */
@Controller
public class TestWeb {

    @MessageMapping(value = "/message/test")//当浏览器向服务端发送请求时,通过@MessageMapping映射的地址,类似于@RequestMapping
    @SendTo(value = "/topic/response")//当服务端有消息时,会对订阅了@SendTo中的路径的浏览器发送消息
    public MessageSender say(MessageAcceptor acceptor){
        return new MessageSender("HELLO!"+acceptor.getMsg());
    }

    @RequestMapping("index")
    public String index(){
        return "index";
    }
}
准备 WebSocket需要的前端文件。

下载stomp.min.js和sockjs.min.js文件,并放在static下,然后在templates下新建index.html页面

stomp的API参考链接:https://segmentfault.com/a/11...




    
    Title


上述代码都已经准备好了,那么一起来看一看运行效果

如预期一样,在连接了WebSocket的客户端发送消息时,其它同样连接了WebSocket的客户端浏览器也收到了消息,没有连接WebSocket的客户端则没有收到消息

看完了代码和代码的运行效果,我们再来看一看WebSocket运行中STOMP的帧
连接STOMP服务端帧:CONNECT↵accept-version:1.1,1.0↵heart-beat:10000,10000 

连接STOMP服务端成功帧:CONNECTED↵version:1.1↵heart-beat:0,0 

订阅目标/topic/response:SUBSCRIBE↵id:sub-0↵destination:/topic/response 

向目标/message/test发送消息:SEND↵destination:/message/test↵content-length:16↵↵{"msg":"测试"} 

从目标/topic/response接收到消息:MESSAGE↵destination:/topic/response↵content-type:application/json;charset=UTF-8↵subscription:sub-0↵message-id:hstpp2xl-0↵content-length:22↵↵{"msg":"HELLO!测试"} 
点对点式

广播式有自己的应用场景,但是广播式不能解决我们我们一个常见的问题,即消息由谁发送,由谁接受的问题。

1.在进行点对点传递消息的时候,必然发生在两个用户之间的行为,那么就需要添加用户相关的内容,在这里先完成一个简单的登陆。

首先添加Spring Security的starter pom:    

        
            org.springframework.boot
            spring-boot-starter-security
        

2.然后进行spring security的简单配置

  

package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * Created by lenovo on 2017/3/17.
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 权限管理配置构造器
     *
     * @param auth 权限管理
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置了两个用户和对应的密码,并且申明了他们的角色
        auth.inMemoryAuthentication().withUser("muxiao").password("123456").roles("USER")
                .and().withUser("hahaha").password("123456").roles("USER");//在内存中分别配置两个用户muxiao和hahaha
    }

    /**
     * Web安全配置
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //静态资源不做安全校验
        web.ignoring().antMatchers("/resources/static/**");///resources/static/目录下的静态资源,不拦截
    }

    /**
     * 配置http安全
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //简单的配置运行点对点所需要的登陆权限
        http.authorizeRequests()
                .antMatchers("/","login").permitAll()//设置Spring Security对/和/login路径不拦截
                .anyRequest().authenticated()
                .and().formLogin().loginPage("/login")//设置登录页面访问的路径为/login
                .defaultSuccessUrl("/chat").permitAll()//登陆成功后转向chat页面
                .and().logout().permitAll();
    }
}
        然后在TestWeb中增加一个MessageMapping接口:

  

  @Autowired private SimpMessagingTemplate messagingTemplate;//spring实现的一个发送模板类 

    @MessageMapping("/chat")
    public void handlerChat(Principal principal, String msg) {//springmvc中可以直接在参数中获得pricipal,pricipal中包含当前永不的信息
        if (principal.getName().equalsIgnoreCase("muxiao")) {
            messagingTemplate.convertAndSendToUser("hahaha","/queue/notice",principal.getName()+":"+msg);
        } else {
            messagingTemplate.convertAndSendToUser("muxiao","/queue/notice",principal.getName()+":"+msg);
            //通过messaginTemplate.converAndSendTiUser向用户发送消息,第一次参数是接受信息的用户,第二个是浏览器订阅的地址,第三个是消息本身
        }
    }

3.同时定义需要的页面访问路径:

package com.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * Created by lenovo on 2017/3/17.
 */
@Configuration
public class WebViewConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/chat").setViewName("/chat");
        registry.addViewController("/login").setViewName("/login");
    }
}

4.我们已经准备好了所需要的后台,这时候就开始实现我们需要的功能的前端编写了。

首先,实现登陆页面,在浏览器中访问除过"/","/index"之外的其它页面,都会来到login页面以进行登陆,即下面的页面:




    
    Title


             输入我们在内存中指定的用户名和密码,登陆进入chat页面 Title

同时在两个浏览器上面,用在内存中指定的两个用户登陆,这样两个用户就可以互相发送消息了,延时效果如下:

            

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89910.html

相关文章

  • [直播视频] 《Java 微服务实践 - Spring Boot 系列》限时折扣

    摘要:作为微服务的基础设施之一,背靠强大的生态社区,支撑技术体系。微服务实践为系列讲座,专题直播节,时长高达小时,包括目前最流行技术,深入源码分析,授人以渔的方式,帮助初学者深入浅出地掌握,为高阶从业人员抛砖引玉。 简介 目前业界最流行的微服务架构正在或者已被各种规模的互联网公司广泛接受和认可,业已成为互联网开发人员必备技术。无论是互联网、云计算还是大数据,Java平台已成为全栈的生态体系,...

    Enlightenment 评论0 收藏0
  • [直播视频] 《Java 微服务实践 - Spring Boot 系列》限时折扣

    摘要:作为微服务的基础设施之一,背靠强大的生态社区,支撑技术体系。微服务实践为系列讲座,专题直播节,时长高达小时,包括目前最流行技术,深入源码分析,授人以渔的方式,帮助初学者深入浅出地掌握,为高阶从业人员抛砖引玉。 简介 目前业界最流行的微服务架构正在或者已被各种规模的互联网公司广泛接受和认可,业已成为互联网开发人员必备技术。无论是互联网、云计算还是大数据,Java平台已成为全栈的生态体系,...

    winterdawn 评论0 收藏0
  • Spring Boot 2.x 系列教程:WebFlux 系列教程大纲(一)

    摘要:使用则需要及以上版本。开发使用框架七系列教程目录系列教程大纲快速入门实践实践整合整合中和实践整合中实现缓存中实现通信集成测试及部署实战图书管理系统 WebFlux 系列教程大纲 一、背景 大家都知道,Spring Framework 是 Java/Spring 应用程序跨平台开发框架,也是 Java EE(Java Enterprise Edition) 轻量级框架,其 Spring ...

    jone5679 评论0 收藏0
  • 两年了,我写了这些干货!

    摘要:开公众号差不多两年了,有不少原创教程,当原创越来越多时,大家搜索起来就很不方便,因此做了一个索引帮助大家快速找到需要的文章系列处理登录请求前后端分离一使用完美处理权限问题前后端分离二使用完美处理权限问题前后端分离三中密码加盐与中异常统一处理 开公众号差不多两年了,有不少原创教程,当原创越来越多时,大家搜索起来就很不方便,因此做了一个索引帮助大家快速找到需要的文章! Spring Boo...

    宋华 评论0 收藏0
  • 两年了,我写了这些干货!

    摘要:开公众号差不多两年了,有不少原创教程,当原创越来越多时,大家搜索起来就很不方便,因此做了一个索引帮助大家快速找到需要的文章系列处理登录请求前后端分离一使用完美处理权限问题前后端分离二使用完美处理权限问题前后端分离三中密码加盐与中异常统一处理 开公众号差不多两年了,有不少原创教程,当原创越来越多时,大家搜索起来就很不方便,因此做了一个索引帮助大家快速找到需要的文章! Spring Boo...

    huayeluoliuhen 评论0 收藏0

发表评论

0条评论

wuyumin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<