websocket集成,基于自己封装的starter

使用基于stom协议的websocket实现,自己封装了一个简单易用的websocket-starter,方便使用,具体集成如下所示:

1. 导入websocket-spring-boot-starter
在pom.xml文件导入websocket-spring-boot-starter依赖包,包在文末会提供,由于是自己封装的包,所以拿到后需要在本地仓库进行注册,如下所示:

<dependency>
	<groupId>com.lydon</groupId>
	<artifactId>websocket-spring-boot-starter</artifactId>
	<version>2.0.1</version>
</dependency>

2. 配置相关信息
在springboot的yml配置以下配置信息:

spring:
    websocket:
        endpoint: chat #示例值
        subscribe-prefixs: /public/,/notice/ #示例值,名称前后使用/符号
        destination-prefixes: /app  #示例值

其中字段释义如下所示:
endpoint: 客户端连接服务端的端点信息,客户端根据此端点连接服务端。
subscribe-prefixs: 服务端的订阅地址前缀,客户端根据此地址前缀订阅服务端的发布,服务端发布时需指定发该地址前缀。
destination-prefixes: 服务端提供的接收客户端信息的地址前缀,当客户端需向服务端发消息时,需指定服务端地址。

3. 实现拦截器
当需要对客户端与服务端交互的信息进行拦截处理时,可通过新增拦截类实现WebSocketInterceptor接口类并重写的preSend方法对消息进行拦截,并在类头上加注解@TgWebSocketInterceptor,示例代码如下所示:

package com.lydon.websocket.example;

import com.sun.security.auth.*;
import com.lydon.websocket.annotation.TgWebSocketInterceptor;
import com.lydon.websocket.subscribe.WebSocketInterceptor;
import org.springframework.messaging.Message;
import org.springframework.messaging.*;
import org.springframework.messaging.simp.*;
import org.springframework.messaging.simp.stomp.*;
import org.springframework.messaging.support.*;
import org.springframework.stereotype.*;
import org.springframework.util.*;

import java.security.*;
import java.util.*;


@TgWebSocketInterceptor
public class WebSocketInterceptorDemo implements WebSocketInterceptor {

    /**
     * 绑定user到websocket conn上
     * @param message
     * @param channel
     * @return
     */
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        System.out.println("----------------------:");
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            Object raw = message.getHeaders().get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
            if (raw instanceof Map) {
                System.out.println(raw);
            }
            System.out.println(">>>>>>>>>>>>>>");
            String username = accessor.getFirstNativeHeader("username");
            String token = accessor.getFirstNativeHeader("token");

            System.out.println("token:" + token);

            if (StringUtils.isEmpty(username)) {
                return null;
            }
            // 绑定user
            Principal principal = new UserPrincipal(username);
            accessor.setUser(principal);
        }
        return message;
    }
}

其中accessor.getCommand()为获取当前操作,与StompCommand.CONNECT进行匹配,具体可匹配的类型有如下所示:
CONNECT:连接操作
DISCONNECT:断开操作
SUBSCRIBE:订阅操作
UNSUBSCRIBE:取消订阅操作
SEND:发送操作
MESSAGE:消息
ERROR:错误

示例代码中的红色字样为重要代码实现,若无此实现则无法辨别websocket用户,并进行精准推送。

4. 示例代码
前端在编写websocket代码前需引入sockjs.min.js、stomp.min.js、jquery.js三个js文件(文件在调用demo有):

后端需引入SimpMessagingTemplate类来实现消息发布,如:

    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

4.1. 建立连接
前端代码示例:

//chat为上述章节“配置相关信息”中的endpoint值

		var socket = new SockJS("http://127.0.0.1:8080/chat");
        client = Stomp.over(socket);
        client.connect({
            username: username,//用户名,在WebSocketInterceptor中绑定websocket用户
            token:'我是token'   //自定义参数
        }, function (succ) {
            console.log('client connect success:', succ);
        }, function (error) {
            console.log('client connect error:', error);
        });

4.2. 订阅
前端订阅代码一般写在建立连接成功之后,如下图所示:

4.2.1. 公共订阅

前端订阅公共消息代码:
// /message/public中的public为上述章节“配置相关信息”中的subscribe-prefixs值,/message为固定前缀,不可更改

client.subscribe("/message ", function (res) {
                console.log('收到消息---/message:',res);
            });

后端发布订阅代码:

Message message=new Message();//自定义的消息结构体
        message.setContent("后台通知消息");
        message.setFrom("admin");
        simpMessagingTemplate.convertAndSend( "/message", message);//发送给所有订阅的人,

message为上述章节“配置相关信息”中的subscribe-prefixs值

4.2.2. 个人订阅
个人订阅是指后端发布消息到指定的已订阅客户端,一般用于精准推送。
前端个人订阅:
// /user/notice中的notice为上述章节“配置相关信息”中的subscribe-prefixs值,/user为固定前缀,不可更改

client.subscribe("/user/notice", function (res) {
          console.log('个人消息:',res)
            });

后端发布个人订阅:
相比公共订阅的发送方法多了一个发送者的参数,字段类型为String,需指定目标订阅者。

		Message message=new Message();
        message.setContent("后台通知消息");
        message.setFrom("admin");
        message.setTo(userName);
        simpMessagingTemplate.convertAndSendToUser(message.getTo(), "/notice", message); //发送

给指定订阅的人,notice为上述章节“配置相关信息”中的subscribe-prefixs值

4.3发送消息
前端发送代码:

   var messageModel = {};//自定义参数
   messageModel.type = 1;
   messageModel.content = '你好,' + new Date().getTime();
   messageModel.from = username;
           client.send("/app/hello", {}, JSON.stringify(messageModel));

其中/app为上述章节“配置相关信息”中的destination-prefixes值,hello为后端接收的接口名,messageModel为自定义参数结构体,与后端接收的结构体保持一致。
后端接收代码:

    @MessageMapping("/hello")
    public void hello(@Payload Message message) {
        System.out.println(message);
    }

其中@MessageMapping注解配置的hello为前端请求的地址后缀,两者需匹配上,自定义接收参数的结构体加上@Payload注解。

整体的示例代码如下所示:

package com.lydon.test;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

@Controller
public class GreetingController {
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;
    
    /**
     * 接收前端消息。
     * @param message
     */
    @MessageMapping("/hello")
    public void hello(@Payload com.lydon.websocket.subscribe.Message message) {
        System.out.println(message);
    }
/**
 * 后台主动发送消息,所有订阅到/message/public的客户端都会受到此消息。
 * @param
 */
    @RequestMapping("/notifyHello")
    @ResponseBody
    public void notifyHello() {
        com.lydon.websocket.subscribe.Message message=new com.lydon.websocket.subscribe.Message();
        message.setContent("后台通知消息");
        message.setFrom("admin");
        System.out.println(message);
        simpMessagingTemplate.convertAndSend( "/notice", message);
    }
    /**
     * 后台主动发送消息,局部订阅收到此消息。
     * @param
     */
    @RequestMapping("/sendToUser")
    @ResponseBody
    public void sendToUser(String userName) {
        com.lydon.websocket.subscribe.Message message=new com.lydon.websocket.subscribe.Message();
        message.setContent("后台通知消息");
        message.setFrom("admin");
        message.setTo(userName);
        simpMessagingTemplate.convertAndSendToUser(message.getTo(), "/notice", message);
    }
    
/**
     * 使用注解的方式接收客户端信息后并返回消息
     * @param message
     * @return
     */
    @MessageMapping("/hello1")
    @SendTo("/message")
    public com.lydon.websocket.subscribe.Message hello1(@Payload com.lydon.websocket.subscribe.Message message) {
        System.out.println(message);
        com.lydon.websocket.subscribe.Message returnMessage = new com.lydon.websocket.subscribe.Message();
        returnMessage.setContent("转发2," + message.getContent());
        return returnMessage;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值