websocket

文章目录

      • websocket介绍:
      • socketjs介绍
      • stompjs
      • 广播、单播、多播
      • 广播技术应用
      • webjars使用基本介绍特点
      • 游戏公告系统
      • websocket推送两种推送方法的区别和讲解
      • Springboot针对websocket 4类的监听器介绍和使用
      • 点对点聊天和简单消息头介绍
      • websocket结合springboot定时推送,实时监控JVM系统负载
      • 项目应用之股票行情推送实战《一》 效果展示,阿里云API介绍和httpClient工具类使用
      • websocket结合spring相关拦截器使用 拦截器介绍,及HandshakeInterceptor握手拦截器介绍
      • 16、用户在线状态维护功能介绍和登录API开发
      • spring channel拦截器介绍及用户上线下线功能开发
      • 18.实时推送在线用户功能开发

websocket介绍:

websocket协议是基于Tcp的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信–允许服务器主动发送信息给客户端。
websocket使用场景:

  • 弹幕
  • 网页聊天系统
  • 实时监控
  • 股票行情推送

socketjs介绍

socketjs是什么:

  • 是一个浏览器JavaScript库,提供了一个类似WebSocket的对象。
  • 提供了一个连贯的跨浏览器的javaScriptAPI,在浏览器和web服务器之间创建了一个低延迟、全双工,跨域的通信通道。
  • 在底层SockJS首先尝试使用本地WebSocket。如果失败了,它可以使用各种浏览器特定的传输协议,并通过类似WebSocket的抽象方式呈现他们。
  • SockJs旨在适用于所有线代浏览器和不支持WebSocket协议的环境。

学习资料:socketjs

stompjs

stompjs是什么:

  • STOMP Simple (or Streaming) Text Orientated Messaging Protocol 它定义了可互操作的连线格式,以便任何可用的STMOP客户端都可以与任何STOMP消息代理进行通信,以在语言和平台之间提供简单而广的消息互操作性(归纳一句话:是一个简单的面向文本的消息传递协议。)

学习资料:stompjs

广播、单播、多播

  • 单播(Unicast):点对点,私信私聊
  • 广播(Broadcast)(所有人):游戏公告,发布订阅
  • 多播,组播(Multicast)(特地人群) :多人聊天,发布订阅

广播技术应用

简单websocket游戏公告系统《一》主要内容:springboot框架搭建和maven依赖资料地址:spring提供的WebSocket教学

webjars使用基本介绍特点

  • 1、方便统一管理
  • 2主要解决前端框架版本不一致,文件混乱等问题3把前端资源,打包成iar包,借助maven工具进行管理

资料:webjars

游戏公告系统

使用Springboot构建基于STOMP的WebSocket广播式通信
Spring中的WebSocket架构
架构图:
websocket_第1张图片
图中各个组件介绍:
生产者型客户端(左上组件): 发送SEND命令到某个目的地址(destination)的客户端。
消费者型客户端(左下组件): 订阅某个目的地址(destination), 并接收此目的地址所推送过来的消息的客户端。
request channel: 一组用来接收生产者型客户端所推送过来的消息的线程池。
response channel: 一组用来推送消息给消费者型客户端的线程池。
broker: 消息队列管理者,也可以成为消息代理。它有自己的地址(例如“/topic”),客户端可以向其发送订阅指令,它会记录哪些订阅了这个目的地址(destination)。
应用目的地址(图中的”/app”): 发送到这类目的地址的消息在到达broker之前,会先路由到由应用写的某个方法。相当于对进入broker的消息进行一次拦截,目的是针对消息做一些业务处理。
非应用目的地址(图中的”/topic”,也是消息代理地址): 发送到这类目的地址的消息会直接转到broker。不会被应用拦截。
SimpAnnotatonMethod: 发送到应用目的地址的消息在到达broker之前, 先路由到的方法. 这部分代码是由应用控制的。
websocket_第2张图片
我们先建立服务器
首先是配置类代码:

package net.xdclass.websocketstudy.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;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    注册端点,发布或者订阅消息的时候需要连接此端点
    //withSockJS表示开始socketjs支持
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/endpoint-websocket").setAllowedOriginPatterns("*").withSockJS();
    }
    ///配置消息代理中介
    //enableSimpleBroker 服务端推送给客户端的路径前缀
    //setApplicationDestinationPrefixes 客户端推送给服务端的路径前缀
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
       registry.enableSimpleBroker("/topic","/chat");///启动SimpleBroker,使得订阅到此"topic"前缀的客户端可以收到公告
       registry.setApplicationDestinationPrefixes("/app");  在客户端推送给服务端也就是/app/v1/chat,这样就会被gameInfo方法来处理
    }
}

enableSimpleBroker就类似于
websocket_第3张图片

ApplicationDestinationPrefixes就类似于simpAnnotationMethod
websocket_第4张图片
定义两个类,来分别表示客户端传入服务端的消息和服务端传入客户端的消息

package net.xdclass.websocketstudy.model;

import java.util.Date;

public class InMessage {
    private String from;
    private String to;
    private String content;
    private Date data;

    public InMessage() {
    }

    public InMessage(String from, String to, String content, Date data) {
        this.from = from;
        this.to = to;
        this.content = content;
        this.data = data;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Date getData() {
        return data;
    }

    public void setData(Date data) {
        this.data = data;
    }
}

```java
package net.xdclass.websocketstudy.model;

import java.util.Date;

public class OutMessage {
    private String from;
    private String content;
    private Date time=new Date();

    public OutMessage() {
    }

    public OutMessage(String content) {
        this.content = content;
    }

    public OutMessage(String from, String content, Date time) {
        this.from = from;
        this.content = content;
        this.time = time;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }
}


接着就是controller方法

```java
package net.xdclass.websocketstudy.controller.v1;

import net.xdclass.websocketstudy.model.InMessage;
import net.xdclass.websocketstudy.model.OutMessage;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.messaging.handler.annotation.MessageMapping;

import javax.websocket.OnMessage;

@Controller
public class GameInfoController {
    //MessageMapping也是一个路由,他和RequestMapping也是一样的路径映射,只不过它是针对websocket去使用的。
    @MessageMapping("v1/chat")
    /// SendTo就是发送到SimpleBroker,然后再由SimpleBroker转发到订阅到这个路径的客户。
    @SendTo("/topic/game_chat")
    public OutMessage gameInfo(InMessage message)
    {
        return new OutMessage(message.getContent());
    }
}

然后我们看js代码

var stompClient = null;
/*
这个函数就是防止重复连接
 */
function setConnected(connected) {
    $("#connect").prop("disabled", connected);
    $("#disconnect").prop("disabled", !connected);
    if (connected) {
        $("#conversation").show();
    }
    else {
        $("#conversation").hide();
    }
    $("#notice").html("");
}

function connect() {
    var socket = new SockJS('/endpoint-websocket'); //连接上端点(基站)
    
    stompClient = Stomp.over(socket);			//用stom进行包装,规范协议
    stompClient.connect({}, function (frame) {	
        setConnected(true);
        console.log('Connected: ' + frame);
        stompClient.subscribe('/topic/game_chat', function (result) {让这个客户端订阅到/topic/game_chat目的,然后只要有消息发送到该地址
        	console.info(result)///这个客户端就会接收到消息放入result中。
        	showContent(JSON.parse(result.body));
        });
    });
}

function disconnect() {
    if (stompClient !== null) {
        stompClient.disconnect();
    }
    setConnected(false);
    console.log("Disconnected");
}

function sendName() {这个函数是管理员发送公告,也就是客户端向服务端发送东西所以是以/app开头的,然后经过服务端处理,最后又会发送到
	/topic/game_chat中然后订阅该地址的客户端就能看到消息啦。
    stompClient.send("/app/v1/chat", {}, JSON.stringify({'content': $("#content").val()}));
}

function showContent(body) {
    $("#notice").append("" + body.content + " "+new Date(body.time).toLocaleString()+"");
}





$(function () {
    $("form").on('submit', function (e) {
        e.preventDefault();
    });
    $( "#connect" ).click(function() { connect(); });
    $( "#disconnect" ).click(function() { disconnect(); });
    $( "#send" ).click(function() { sendName(); });
});

websocket推送两种推送方法的区别和讲解

简介:
	讲解websocket推送方式:@SendTo注解和SimpMessagingTemplate的区别

笔记:	
	1、SendTo 不通用,固定发送给指定的订阅者
	2、SimpMessagingTemplate 灵活,支持多种发送方式
	我们可以将
	SimpMessagingTemplate放在一个service包中。
package net.xdclass.websocketstudy.service;

import net.xdclass.websocketstudy.model.InMessage;
import net.xdclass.websocketstudy.model.OutMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

/*
简单消息模板,同来推送消息
 */
@Service
public class WebSocketService {

    @Autowired
    private SimpMessagingTemplate template;
    public void sendTopicMessage(String dest,InMessage message)
    {
        for(int i=0;i<20;i++)
        template.convertAndSend(dest,new OutMessage((message.getContent())+i));
    }

}

然后再去调用

package net.xdclass.websocketstudy.controller.v2;

import net.xdclass.websocketstudy.model.InMessage;
import net.xdclass.websocketstudy.service.WebSocketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;

@Controller
public class V2GameInfoController {
    @Autowired
    private WebSocketService ws;
    //MessageMapping也是一个路由,他和RequestMapping也是一样的路径映射,只不过它是针对websocket去使用的。
    @MessageMapping("v2/chat")
    /// SendTo就是发送到SimpleBroker,然后再由SimpleBroker转发到订阅到这个路径的客户。
    //@SendTo("/topic/game_chat")
    public void gameInfo(InMessage message){
        ws.sendTopicMessage("/topic/game_rank",message);
    }
}

Springboot针对websocket 4类的监听器介绍和使用

简介:
	SpringBoot里面websocekt监听器的使用,包含订阅、取消订阅,socekt连接和断开连接4类监听器的编写和使用

笔记:
	注意点:
		1、需要监听器类需要实现接口ApplicationListener T表示事件类型,下列几种都是对应的websocket事件类型
		2、在监听器类上注解 @Component,spring会把改类纳入管理

	websocket模块监听器类型:
		SessionSubscribeEvent 	订阅事件
		SessionUnsubscribeEvent	取消订阅事件
		SessionDisconnectEvent 	断开连接事件
		SessionDisconnectEvent 	建立连接事件

例如:

package net.xdclass.websocketstudy.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectEvent;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;

@Component
public class ConnectionEventListener implements ApplicationListener<SessionConnectEvent> {

    @Override
    public void onApplicationEvent(SessionConnectEvent event) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        System.out.println("[ConnectionEventListener监听器事件 类型]"+headerAccessor.getCommand().getMessageType());
    }
}
package net.xdclass.websocketstudy.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;
@Component
public class SubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {
    @Override
    public void onApplicationEvent(SessionSubscribeEvent event) {

        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        System.out.println("[监听器事件 类型]"+headerAccessor.getCommand().getMessageType());
    }
}

点对点聊天和简单消息头介绍

简介:
	使用socketjs订阅API,进行点对点聊天;StompHeaderAccessor简单介绍
StompHeaderAccessor简单消息传递协议中处理消息头的基类,
通过这个类,可以获取消息类型(例如:发布订阅,建立连接断开连接),会话id等。
@Controller
public class V3GameInfoController {
    @Autowired
    private WebSocketService ws;
    //MessageMapping也是一个路由,他和RequestMapping也是一样的路径映射,只不过它是针对websocket去使用的。
    @MessageMapping("v3/single/chat")
    /// SendTo就是发送到SimpleBroker,然后再由SimpleBroker转发到订阅到这个路径的客户。
    //@SendTo("/topic/game_chat")
    public void singleChat(InMessage message){
        ws.sendChatMessage(message);
    }
}
 public void sendChatMessage(InMessage message)
    {
        template.convertAndSend("/chat/single/"+message.getTo(),new OutMessage(message.getFrom()+" 发送:"+message.getContent()));
    }

这样就能实现点对点聊天。

websocket结合springboot定时推送,实时监控JVM系统负载

简介:
	websocket结合springboot的注解Scheduled实现定时推送,使用服务端定时推送注意事项;
	开发简单监控JVM监控功能

笔记:
	1、在controller的类方法上标注 @Scheduled(fixedRate = 3000) 表示这个方法会定时执行
	fixedRate表示是多少毫秒 3000就3秒

	2、需要在springboot启动类上@EnableScheduling

	3、被注解@Scheduled标记的方法,是不能有参数,不然会报错

类似的我们可以实现监控java虚拟机内存大小:

@Controller
public class V4ServerInfoController {
    @Autowired
    private WebSocketService ws;
    @MessageMapping("/v4/schedule/push")
    @Scheduled(fixedRate=3000)三秒调用///加了这个注解的方法不能带任何参数否则会报错
    public void sendServerInfo()
    {
        ws.sendServerInfo();
    }

}
 public void sendServerInfo()
    {
        int processors=Runtime.getRuntime().availableProcessors();
        long freeMem = Runtime.getRuntime().freeMemory();
        long maxMem = Runtime.getRuntime().maxMemory();
        String message=String.format("服务器可用处理器: %s;虚拟机空闲内存大小: %s; 最大内存大小: %s",processors,freeMem,maxMem);
        template.convertAndSend("/topic/server_info",new OutMessage(message));
    }

项目应用之股票行情推送实战《一》 效果展示,阿里云API介绍和httpClient工具类使用

简介:
	展示简单股票行情推送的效果,及介绍阿里云API市场,httpClient工具类的使用

笔记:
	访问地址:localhost:8080/v5/index.html
	阿里云API市场: https://market.aliyun.com/data?spm=5176.8142029.388261.183.346bc16fAs3slP
	HttpClientUtils下载: https://github.com/aliyun/api-gateway-demo-sign-java

这样我们就可以利用阿里云API的数据然后通过服务器发送到客户端。

websocket结合spring相关拦截器使用 拦截器介绍,及HandshakeInterceptor握手拦截器介绍

简介:
	拦截器介绍,springBoot结合websocket相关拦截器使用,握手拦截器的开发和使用

笔记:
	1、编写一个类,实现一个接口HandshakeInterceptor;写完之后需要在websocket配置里面启用
	.addInterceptors(new HttpHandShakeIntecepter())
	
	2、实现两个方法beforeHandshake和afterHandshake,在里面可以获取resuest和response
package net.xdclass.websocketstudy.intecepter;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import javax.servlet.http.HttpSession;
import java.util.Map;
/*
http握手拦截器,可以通过这个类的方法获取request,和response
 */
@Component
public class HttpHandShakeIntecepter implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("握手拦截器 beforeHandshake");
        if(request instanceof ServletServerHttpRequest)
        {
            ServletServerHttpRequest servletRequest= (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession();
            String id = session.getId();
            System.out.println("握手拦截器 beforeHandshake sessionId="+id);
            attributes.put("sessionId",id);在这里放入之后到后面的listener也可以拿到
        }
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("握手拦截器 afterHandshake");
    }
}

我们可以拿到HttpServletRequest,在这里面我们可以干很多事情,
websocket_第5张图片之后到监视器还能拿到我们在拦截器里面设置的数据。

        System.out.println("[ConnectionEventListener监听器事件 类型]"+headerAccessor.getSessionAttributes().get("sessionId"));

16、用户在线状态维护功能介绍和登录API开发

简介:
	用户状态功能相关接口开发和登录API接口开发
package net.xdclass.websocketstudy.controller.v6;

import net.xdclass.websocketstudy.service.WebSocketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

@Controller
public class UserChatController {
    @Autowired
    private WebSocketService ws;
    ///模拟数据库用户的数据
    public static Map<String,String>userMap=new HashMap<>();
    static{
        userMap.put("jack","123");
        userMap.put("mary","456");
        userMap.put("tom","789");
        userMap.put("tim","000");
        userMap.put("小D","666");
    }
    public static Map<String,User>onlineUser=new HashMap<>();
    static{
        onlineUser.put("123",new User("admin","888"));
    }
    @RequestMapping(value = "login",method= RequestMethod.POST)
    public String userlogin(@RequestParam(value="username",required = true) String username, @RequestParam(value = "pwd",
    required = true) String pwd, HttpSession session)
    {
        String password = userMap.get(username);
        if(pwd!=null&&pwd.equals(password))
        {
            User user=new User(username,pwd);
            String sessionId=session.getId();
            onlineUser.put(sessionId,user);
            return "redirect:/v6/chat.html";
        }
        return "redirect:/v6/error.html";
    }
}

spring channel拦截器介绍及用户上线下线功能开发

简介:
	channel频道拦截器使用讲解,结合StompHeaderAccessor实现用户上线下线功能
笔记:
	1、ChannelInterceptorAdapter 频道拦截器适配器,具体实现的接口是ChannelIntecepter
	
	2、需要ChannelInterceptorAdapter子类重写override对应的方法,实现自己的逻辑,主要是
	public void postSend(Message message, MessageChannel channel, boolean sent) 

	3、ChannelInterceptorAdapter子类需要在配置Websocket的配置里面加入

	4、在配置类里面加入
		@Override
		public void configureClientInboundChannel(ChannelRegistration registration) {
			registration.interceptors( new SocketChannelIntecepter());
		}

		@Override
		public void configureClientOutboundChannel(ChannelRegistration registration) {
			registration.interceptors( new SocketChannelIntecepter());
		}


资料:
	https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/messaging/support/ChannelInterceptorAdapter.html
握手拦截器 beforeHandshake
握手拦截器 beforeHandshake sessionId=17DD2BFBD372D1461B0FC27E0A030D26
握手拦截器 afterHandshake
SocketChannelIntecepter->preSend
SocketChannelIntecepter->postSend
SocketChannelIntecepter ->sessionId=17DD2BFBD372D1461B0FC27E0A030D26
connect sessionId=17DD2BFBD372D1461B0FC27E0A030D26
SocketChannelIntecepter->afterSendCompletion
[ConnectionEventListener监听器事件 类型]CONNECT
[ConnectionEventListener监听器事件 类型]17DD2BFBD372D1461B0FC27E0A030D26
SocketChannelIntecepter->preSend
SocketChannelIntecepter->postSend
SocketChannelIntecepter->afterSendCompletion
SocketChannelIntecepter->preSend
SocketChannelIntecepter->postSend
SocketChannelIntecepter ->sessionId=17DD2BFBD372D1461B0FC27E0A030D26
SocketChannelIntecepter->afterSendCompletion
[监听器事件 类型]SUBSCRIBE

由此可见
SocketChannelIntecepter是一个从外到里再从里到外的过程,使用这个拦截器,我咋感觉更像监听器,只要连接或者不连接订阅或者不订阅的时候我们都能监听到,这样我们就能做出用户上线或者下线的操作,只要用户下线,意思就是断开连接,然后我们可以通过StompHeaderAccessor获取到session,然后通过getCommand方法,获取状态,判断状态,如果断开连接,我们就把用户数据根据sessionId移除掉就好了。

package net.xdclass.websocketstudy.intecepter;

import net.xdclass.websocketstudy.controller.v6.UserChatController;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;

/*
频道拦截器,类似管道,可以获取消息的一些meta数据
 */
public class SocketChannelIntecepter extends ChannelInterceptorAdapter {

    /*
    在消息实际发送到频道之前调用
     */
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        System.out.println("SocketChannelIntecepter->preSend");
        return super.preSend(message, channel);
    }
    /*
    发送消息调用后立即调用
     */
    @Override
    public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
        System.out.println("SocketChannelIntecepter->postSend");
        StompHeaderAccessor headerAccessor=StompHeaderAccessor.wrap(message);
        if(headerAccessor.getCommand()==null)return ;
        String sessionId = headerAccessor.getSessionAttributes().get("sessionId").toString();
        System.out.println("SocketChannelIntecepter ->sessionId="+sessionId);
        switch (headerAccessor.getCommand())
        {
            case CONNECT:
                connect(sessionId);
                break;
            case DISCONNECT:
                disconnect(sessionId);
                break;
            case SUBSCRIBE:
                break;
            case UNSUBSCRIBE:
                break;
        }

    }
    void connect(String sessionId)
    {
        System.out.println("connect sessionId="+sessionId);
    }
    void disconnect(String sessionId)
    {
        System.out.println("disconnect sessionId="+sessionId);
        ///用户下线操作

        UserChatController.onlineUser.remove(sessionId);
    }


    /*
    在发送完成之后完成调用,不管是否有异常发生,一般用于资源释放
     */
    @Override
    public void afterSendCompletion(Message<?> message, MessageChannel channel, boolean sent, Exception ex) {
        System.out.println("SocketChannelIntecepter->afterSendCompletion");
        super.afterSendCompletion(message, channel, sent, ex);
    }
}

18.实时推送在线用户功能开发

简介:使用schdule注解,推送在线用户接口开发
 @Scheduled(fixedRate = 2000)
    public void onlinUser()
    {
        ws.sendOnlineUser(onlineUser);
    }

实时推送我们的onlineUser。

public void sendOnlineUser(Map<String, User> onlineUser) {
        String msg="";
        for(Map.Entry<String,User>entry:onlineUser.entrySet())
        {
            msg=msg.concat(entry.getValue().getUsername()+" || ");
        }
        template.convertAndSend("/topic/onlineuser",new OutMessage(msg));
    }

然后是多人在线聊天。

 @MessageMapping("v6/chat")
    //SimpMessageHeaderAccessor headerAccessor
    public void topicChat(InMessage message, SimpMessageHeaderAccessor headerAccessor)
    {
        String sessionId = headerAccessor.getSessionAttributes().get("sessionId").toString();
        User user=onlineUser.get(sessionId);
        message.setFrom(user.getUsername());
        ws.sendTopicChat(message);
    }

多人聊天很简单,只要通过sessionId找到发出信息的用户,然后展示在客户端上就行了。

你可能感兴趣的:(websocket,websocket,网络协议,网络)