springboot2.0 WebSocket uniapp 前后端代码 两套

(声明:我这是给我自己看的, 代码实在是懒得整理了, 全都是复制出来的, 如果大家看不懂也别喷我.......我只是写代码不行,不代表喷人不行啊,,有问题的可以随时私信我或者加我qq952288306问我,)

一: 后端:


    org.springframework.boot
    spring-boot-starter-websocket
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket支持
 */
@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter getServerEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;


/**
 * WebSocketServer
 *
 */
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {

    static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 接收userId
     */
    private String userId = "";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
            //加入set中
        } else {
            webSocketMap.put(userId, this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }

        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());

        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + userId + ",报文:" + message);
        //可以群发消息
        //消息保存到数据库、redis
        if (StringUtils.isNotBlank(message)) {
            if ("ping".equals(message.toLowerCase())) {
                try {
                    webSocketMap.get(this.userId).sendMessage("pong");
                    return;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

//            try {
//                //解析发送的报文
//                JSONObject jsonObject = JSONObject.parseObject(message);
//                //追加发送人(防止串改)
//                jsonObject.put("fromUserId", this.userId);
//                String toUserId = jsonObject.getString("toUserId");
//                //传送给对应toUserId用户的websocket
//                if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
//                    webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
//                } else {
//                    log.error("请求的userId:" + toUserId + "不在该服务器上");
//                    //否则不在这个服务器上,发送到mysql或者redis
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
        }
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 发送自定义消息
     */
    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
        log.info("发送消息到:" + userId + ",报文:" + message);
        if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
            webSocketMap.get(userId).sendMessage(message);
        } else {
            log.error("用户" + userId + ",不在线!");
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}
import com.example.didi.demo.config.WebSocketServer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;


@RestController
public class WebSocketController {

    @GetMapping("index")
    public ResponseEntity index(){
        return ResponseEntity.ok("请求成功");
    }

    @GetMapping("page")
    public ModelAndView page(){
        return new ModelAndView("socket");
    }

    @RequestMapping("/push/{toUserId}")
    public ResponseEntity pushToWeb(String message, @PathVariable String toUserId) throws IOException {
        WebSocketServer.sendInfo(message,toUserId);
        return ResponseEntity.ok("MSG SEND SUCCESS");
    }

uniapp端:

this.socketTask1 = uni.connectSocket({
					// 【非常重要】必须确保你的服务器是成功的,如果是手机测试千万别使用ws://127.0.0.1:8080【特别容易犯的错误】


				url: "ws://域名:端口号/imserver/" + userId",

					success(data) {
						console.log("websocket创建成功", data);
					},
				});


				//消息的发送和接收必须在正常连接打开中,才能发送或接收【否则会失败】
				this.socketTask1.onOpen((res) => {
					console.log("socketTask1连接正常打开中...!", res);
					this.is_open_socket = true;
					// 注:只有连接正常打开中 ,才能正常成功发送消息
					this.socketTask1.send({
						data: 'socketTask1我再给你发送消息啦!',
						success() {
							console.log("socketTask1消息发送成功");
						},
					});
					// 注:只有连接正常打开中 ,才能正常收到消息
					this.socketTask1.onMessage((res) => {
						console.log("socketTask1收到服务器内容:" + JSON.stringify(res));
					});
				})
				// 这里仅是事件监听【如果socket关闭了会执行】
				this.socketTask1.onClose((err) => {
					console.log("socketTask1已经被关闭了", err) //在此进行重连
				})

				//先确保清除了之前的心跳定时器
				clearInterval(this.pingpangTimes1)
				//每过一段时间发送一次心跳,发送Ping,服务器会反馈pong,这样操作以保持socket一直是连接状态,防止断开连接,心跳停止
				this.pingpangTimes1 = setInterval(() => {
					this.socketTask1.send({
						data: "ping",
						success: () => {},
						fail: () => {
						}
					});
				}, 5000)

*************************************************************************************************************************************************************************************************************************************************************

第二套;后端使用了模版


import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig2 implements WebSocketMessageBrokerConfigurer {


    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {

        registry.addEndpoint("/websocket").setAllowedOrigins("*");
        registry.addEndpoint("/sockjs").setAllowedOrigins("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
        te.setPoolSize(1);
        te.setThreadNamePrefix("wss-heartbeat-thread-");
        te.initialize();
        // 广播和独播 的路径 广播的话是stomp.subscribe("/queue/all/message",{})  独播在下面
        registry.enableSimpleBroker("/queue/all", "/topic/user").setHeartbeatValue(new long[]{15000, 15000}).setTaskScheduler(te);
        //  独播应该是 /topic/user/{id}/message
        registry.setUserDestinationPrefix("/topic/user");
        // 如果给服务端发消息应该是 /send/toServer......
        //registry.setApplicationDestinationPrefixes("/send");
    }
}

 

package com.example.didi.demo.web;

import com.example.didi.demo.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * WebSocketController
 */
@RestController
public class WebSocket2Controller {

    @Autowired
    private SimpMessagingTemplate template;

    @RequestMapping("pushToOne")
    public void push(String id, Student entity) {
        entity.setAge(12);
        entity.setName("wbb");
        template.convertAndSendToUser(id, "/message", entity);
    }
    @RequestMapping("pushToAll")
    public void pushToAll(String id, Student entity) {
        entity.setAge(12);
        entity.setName("wbbb");
        template.convertAndSend( "/queue/all/message", entity);
    }

}

这里我们使用stomp.js  来实现 订阅和 广播, 因为uniapp的API实际上是不支持这个广播和订阅的, 除非使用第一套的代码, 鉴定userId 可以用原生API实现(不想整理代码了, 实在是太懒了)

	//广播消息(一对多),同步拍卖发广播消息
			subscribeAllMessage() {
				let that = this
				//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(广播接收信息)
				that.stompClient.subscribe("/subscribe/all/message", function(response) {
					console.log(response);
					that.$u.toast(response.body);

				});
			},
			subscribeUserMessage(clientId) {
				//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(队列接收信息)
				let that = this
				that.stompClient.subscribe("subscribe/user/" + clientId + "/message", function(response) {
					var message = response.body;
					if (message) {
						var result = JSON.parse(message);
						that.$u.toast(result);
					}
				});
			},

			//连接ws
			connectWS() {
				//var socket = new SockJS("ws://域名:端口号/websocket");
				//var socket = new SockJS("wss://域名:端口号/websocket");// APP 端使用会报错 Cannot read property 'prototype' of undefined
				//this.stompClient = Stomp.over(socket);
				//或者用下面的写法
				this.stompClient = Stomp.client("wss://域名:端口号/websocket");
				
				
				this.stompClient.heartbeat.outgoing = 5000;
				this.stompClient.heartbeat.incoming = 5000;
				//连接WebSocket服务端
				let header={}
				let that = this
				this.stompClient.connect(header, function(frame) {
					console.log("Stomp连接成功");
					this.isSocketOpen = true;
					uni.setStorageSync("isSocketOpen", true)
					// 订阅消息
					that.subscribeAllMessage();
					//独播  这里写死 id是 10
					that.subscribeUserMessage(10);
				}, function(err) {
					//自动重连接WebSocket服务端
					uni.setStorageSync("isSocketOpen", false);
					if (that.isSocketOpen == false) {
						setTimeout(() => {
							console.log("Stomp连接中断,正在重新连接……");
							that.connectWS();
						}, 2000);
					}
				});
			},

提供一下 stomp.js的下载链接  

开源中国

github   https://github.com/jmesnil/stomp-websocket  lib目录下

你可能感兴趣的:(订阅消息,java,springboot)