需求:

当用户进行某个操作,需要通知其他用户时,其他用户可以实时接收消息。

工程为 Spring cloud + VUE 。

技术实现:

Spring Cloud、Spring boot、vue、webSocket等。

流程

用户登录系统→连接到socket服务进行监听→页面用户操作某业务→调用socket服务传递json消息→socket服务推送消息到其他用户页面→收到消息解析json进行其他业务处理

通讯json

目前推送的有:业务的ID、业务的类型、推送的简约内容

============================新建服务====================================================

一:新建socket服务,聚合到父工程里(不会的去复习下spring boot)

1:配置socket属性文件application.yml,兼容后面文章的离线通讯

#eureka注册中心地址
eureka:instance:prefer-ip-address: trueclient:service-url:defaultZone: http://XXX.XXX.XXX.XXX:8060/eureka/register-with-eureka: truefetch-registry: trueserver:port: 9002servlet:context-path: /
spring:application:name: api-webSocketdatasource:driver-class-name: oracle.jdbc.OracleDriverurl: jdbc:oracle:thin:@XXX.XXX.XXX:8098:XEusername: XXXpassword: XXXtype: com.alibaba.druid.pool.DruidDataSource#最大活跃数maxActive: 20#初始化数量initialSize: 5#最大连接等待超时时间maxWait: 60000redis:host: XXX.XXX.XXX.XXX# 端口port: 6379# 超时时间timeout: 5000jedis:pool:#连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: 3000#连接池最大连接数(使用负值表示没有限制)max-active: 200#连接池中的最大空闲连接max-idle: 20#连接池中最小空闲连接min-idle: 2# MyBatis
mybatis:# 搜索指定包别名typeAliasesPackage:  com.fencer.rcdd# 配置mapper的扫描,找到所有的mapper.xml映射文件mapperLocations: classpath*:mapper/**/*Mapper.xml# 日志配置
logging:level:com.fencer: debugorg.springframework: WARNorg.spring.springboot.dao: debug

2:父工程添加相关依赖pom.xml

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.0.4.RELEASE</version></dependency>

3:新建socket配置类

package com.XXX.io.ws;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/*** 类描述:** @author :carry* @version: 1.0  CreatedDate in  2019年09月24日* <p>* 修订历史: 日期          修订者     修订描述*/
@Configuration
public class WebSocketConfig {/** * @方法描述: 注入ServerEndpointExporter,*      * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint* @return: org.springframework.web.socket.server.standard.ServerEndpointExporter* @Author: carry*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

 4:新建服务类

package com.fencer.io.ws;import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;/*** 类描述:** @author :carry* @version: 1.0  CreatedDate in  2019年09月24日* <p>* 修订历史: 日期          修订者     修订描述*/
@Component
@ServerEndpoint(value = "/websocket/{userId}")//设置访问URL
public class WebSocket {//静态变量,用来记录当前在线连接数。private static int onlineCount = 0;private Session session;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();//与某个客户端的连接会话,需要通过它来给客户端发送数据private static Map<String, Session> sessionPool = new HashMap<String, Session>();/*** @方法描述: 开启socket* @return: void* @Author: carry*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId) {this.session = session;webSockets.add(this);//加入set中addOnlineCount();           //在线数加1sessionPool.put(userId, session);//把对应用户id的session放到sessionPool中,用于单点信息发送System.out.println("【websocket消息】 有新连接加入!用户id" + userId + ",当前在线人数为" + getOnlineCount());}/*** @方法描述: 关闭socket* @return: void* @Author: carry*/@OnClosepublic void onClose() {webSockets.remove(this);subOnlineCount();           //在线数减1System.out.println("【websocket消息】 连接断开!当前在线人数为" + getOnlineCount());}/*** @方法描述: 收到客户端消息* @return: void* @Author: carry*/@OnMessagepublic void onMessage(String message) {System.out.println("【websocket消息】收到客户端消息:" + message);}/*** @方法描述: 广播消息全体发送* @return: void* @Author: carry*/public void sendAllMessage(String message) {for (WebSocket webSocket : webSockets) {System.out.println("【websocket消息】广播消息:" + message);try {webSocket.session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}/*** @方法描述: 一对一单点消息* @return: void* @Author: carry*/public  void  sendOneMessage(String userId, String message) {try {// 防止推送到客户端的信息太多导致弹窗太快Thread.sleep(500);System.out.println("用户"+userId+"【websocket消息】单点消息:" + message);Session session = sessionPool.get(userId);if (session != null) {// getAsyncRemote是异步发送,加锁防止上一个消息还未发完下一个消息又进入了此方法// 也就是防止多线程中同一个session多次被调用报错,虽然上面睡了0.5秒,为了保险最好加锁synchronized (session) {session.getAsyncRemote().sendText(message);}}} catch (Exception e) {e.printStackTrace();}}/*** @方法描述: 发生错误时调用* @return: void* @Author: carry*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("发生错误");error.printStackTrace();}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocket.onlineCount++;}public static synchronized void subOnlineCount() {WebSocket.onlineCount--;}
}

5:对外暴露接口

package com.XX.io.ws;import com.XX.common.base.AjaxResult;
import com.XX.common.base.BaseController;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 类描述:** @author :carry* @version: 1.0  CreatedDate in  2019年09月24日* <p>* 修订历史: 日期         修订者     修订描述*/
@RestController
@RequestMapping("/websocket")
public class SocketController extends BaseController {@Autowiredprivate WebSocket webSocket;/** * @方法描述: 向所有用户发送消息(一人对所有人发布同一个消息)* @return: com.XX.common.base.AjaxResult* @Author: carry*/@PostMapping("/sendAllWebSocket")public AjaxResult sendAllWebSocket(@RequestParam String jsonMsg) {try {webSocket.sendAllMessage(jsonMsg);} catch (Exception e) {return error(e.getMessage());}return success();}/** * @方法描述: 一对一发送消息(一人对一人发布同一个消息)* @return: com.XX.common.base.AjaxResult* @Author: carry*/@PostMapping("/sendOneWebSocketOneToOne")public AjaxResult sendOneWebSocketOneToOne(@RequestParam("userId") String userId, @RequestParam String jsonMsg) {try {webSocket.sendOneMessage(userId, jsonMsg);} catch (Exception e) {return error(e.getMessage());}return success();}/*** @方法描述: 一对一发送多消息(一人对一人发布多个消息)*         此方法会出现多线程问题,需要在sendOneMessage进行处理* @return: com.XX.common.base.AjaxResult* @Author: carry*/@PostMapping("/sendManayWebSocketOneToOne")public AjaxResult sendManayWebSocketOneToOne(@RequestParam("userId") String userId, @RequestParam String jsonString) {try {JSONArray jsonArray = JSONArray.fromObject(jsonString);for(int i=0;i<jsonArray.size();i++){JSONObject jsonObject= JSONObject.fromObject(jsonArray.get(i));webSocket.sendOneMessage(userId, jsonObject.toString());}} catch (Exception e) {return error(e.getMessage());}return success();}/** * @方法描述: 一对多发送消息(一人对多人发布同一个消息)* @return: com.fencer.common.base.AjaxResult* @Author: carry*/@PostMapping("/sendUserListWebSocket")public AjaxResult sendUserListWebSocket(@RequestParam List<String> userList, @RequestParam String jsonMsg) {try {for (String userId : userList) {webSocket.sendOneMessage(userId, jsonMsg);}} catch (Exception e) {return error(e.getMessage());}return success();}}

6:入口类也贴上吧

package XXX.XXX;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;@EnableEurekaClient
@EnableHystrix
@MapperScan(basePackages = { "com.XX.XX.mapper" })
@ComponentScan(basePackages = "com.XXX.*")
@SpringBootApplication
public class WebSocketApplication implements CommandLineRunner {public static void main(String[] args) {SpringApplication.run(WebSocketApplication.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("######################WebSocket服务启动完成!######################");}@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}

============================其他服务的调用====================================================

二:其他服务的调用,使用rest+template调用(不会的可以复习一下spring colud 服务之间的调用)

 1:为了方便服务里面其他功能的方便,封装单独的调用公共类

SocketService.java
package com.xxx.rcdd.io.ws;import com.xxx.common.base.AjaxResult;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import net.sf.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;import java.util.List;import static com.fencer.common.base.AjaxResult.error;
import static com.fencer.common.base.AjaxResult.success;/*** 类描述:** @author :carry* @version: 1.0  CreatedDate in  2019年09月26日* <p>* 修订历史: 日期          修订者     修订描述*/
@Service
public class SocketService {@AutowiredRestTemplate restTemplate;/*** @方法描述: 向全部用户广播消息* @return: void* @Author: carry*/public void sedMsgAll(String jsonMsg) {try {//发送消息Thread thread = new Thread(new Runnable() {@Overridepublic void run() {SocketService.this.sendAllWebSocket(jsonMsg);}});thread.start();} catch (Exception e) {throw new RuntimeException(e.getMessage());}}/*** @方法描述:一对一发送消息(一人对一人发布同一个消息)* @return: void* @Author: carry*/public void sendOneMsgToOneToOne(String userId, String jsonMsg) {try {//发送消息Thread thread = new Thread(new Runnable() {@Overridepublic void run() {SocketService.this.sendOneWebSocketOneToOne(userId, jsonMsg);}});thread.start();} catch (Exception e) {throw new RuntimeException(e.getMessage());}}/*** @方法描述:一对一发送多消息(一人对一人发布多个消息)* @return: void* @Author: carry*/public void sendManayToOneToOne(String userId,JSONArray jsonArray) {try {//发送消息Thread thread = new Thread(new Runnable() {@Overridepublic void run() {SocketService.this.sendManayWebSocketOneToOne(userId, jsonArray);}});thread.start();} catch (Exception e) {throw new RuntimeException(e.getMessage());}}/*** @方法描述:一对多发送消息(一人对多人发布同一个消息)* @return: void* @Author: carry*/public void sendUserList(List<String> userList, String jsonMsg) {try {//发送消息Thread thread = new Thread(new Runnable() {@Overridepublic void run() {SocketService.this.sendUserListWebSocket(userList, jsonMsg);}});thread.start();} catch (Exception e) {throw new RuntimeException(e.getMessage());}}/*** @方法描述: 消息发送失败回调* @return: com.fencer.rcdd.domain.util.SysUser* @Author: carry*/private AjaxResult fallbackOfMessage() {System.out.println("error fallbackOfMessage.... ");return error();}/*** @方法描述: 向全部用户广播消息* @return: com.fencer.rcdd.domain.util.SysUser* @Author: carry*/@HystrixCommand(fallbackMethod = "fallbackOfMessage")private AjaxResult sendAllWebSocket(String jsonMsg) {try {String url = "http://API-WEBSOCKET/websocket/sendAllWebSocket";MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();map.add("jsonMsg", jsonMsg);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);restTemplate.postForEntity(url, request, AjaxResult.class);} catch (Exception e) {e.printStackTrace();return error(e.getMessage());}return success();}/*** @方法描述:一对一发送消息(一人对一人发布同一个消息)* @return: com.fencer.rcdd.domain.util.SysUser* @Author: carry*/@HystrixCommand(fallbackMethod = "fallbackOfMessage")private AjaxResult sendOneWebSocketOneToOne(String userId, String jsonMsg) {try {String url = "http://API-WEBSOCKET/websocket/sendOneWebSocketOneToOne";MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();map.add("userId", userId);map.add("jsonMsg", jsonMsg);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);restTemplate.postForEntity(url, request, AjaxResult.class);} catch (Exception e) {e.printStackTrace();return error(e.getMessage());}return success();}/*** @方法描述:一对一发送多消息(一人对一人发布多个消息)* @return: com.fencer.rcdd.domain.util.SysUser* @Author: carry*/@HystrixCommand(fallbackMethod = "fallbackOfMessage")private AjaxResult sendManayWebSocketOneToOne(String userId,JSONArray jsonArray) {try {String jsonString = jsonArray.toString();String url = "http://API-WEBSOCKET/websocket/sendManayWebSocketOneToOne";MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();map.add("userId", userId);map.add("jsonString", jsonString);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);restTemplate.postForEntity(url, request, AjaxResult.class);} catch (Exception e) {e.printStackTrace();return error(e.getMessage());}return success();}/*** @方法描述:一对多发送消息(一人对多人发布同一个消息)* @return: com.fencer.rcdd.domain.util.SysUser* @Author: carry*/@HystrixCommand(fallbackMethod = "fallbackOfMessage")private AjaxResult sendUserListWebSocket(List<String> userList, String jsonMsg) {try {String url = "http://API-WEBSOCKET/websocket/sendUserListWebSocket";MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();map.add("userList", userList);map.add("jsonMsg", jsonMsg);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);restTemplate.postForEntity(url, request, AjaxResult.class);} catch (Exception e) {e.printStackTrace();return error(e.getMessage());}return success();}
}

2:具体业务的调用

省略业务代码List<Map<String, Object>> infoList = new ArrayList<Map<String, Object>>();Map<String, Object> msgMap = new HashMap<String, Object>();msgMap.put("id", uuid);msgMap.put("type", "shift");msgMap.put("title", "通知内容");infoList.add(msgMap);infoList.add(msgMap);JSONArray jsonArray =JSONArray.fromObject(infoList);JSONObject  jsonObject=JSONObject.fromObject(msgMap);//发送消息socketService.sedMsgAll(jsonObject.toString());//socketService.sendOneMsgToOneToOne("3001",jsonObject.toString());// socketService.sendManayToOneToOne("3001", jsonArray);

=================================前端VUE部分====================================================

因为推送可能是在不同的页面,本人是在不变的页面比如导航组件里链接的socket服务进行监听,然后调用element的notic组件进行前台展示,前台可以根据消息的类型或者id,进行自己的处理,比如进入到业务的具体页面之类。

 mounted() {//链接socketthis.connWebSocket();},beforeDestroy() {// 监听窗口关闭事件,vue生命周期销毁之前关闭socket当窗口关闭时,防止连接还没断开就关闭窗口。this.onbeforeunload();},methods: {connWebSocket() {let userInfo = JSON.parse(localStorage.getItem("userInfos"));let userId = userInfo.userId;// WebSocketif ("WebSocket" in window) {this.websocket = new WebSocket("ws://localhost:9002/websocket/" + userId //userId 传此id主要后端java用来保存session信息,用于给特定的人发送消息,广播类消息可以不用此参数);//初始化socketthis.initWebSocket();} else {ctx.$message.error("次浏览器不支持websocket");}},initWebSocket() {// 连接错误this.websocket.onerror = this.setErrorMessage;// 连接成功this.websocket.onopen = this.setOnopenMessage;// 收到消息的回调this.websocket.onmessage = this.setOnmessageMessage;// 连接关闭的回调this.websocket.onclose = this.setOncloseMessage;// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = this.onbeforeunload;},setErrorMessage() {console.log("WebSocket连接发生错误   状态码:" + this.websocket.readyState);},setOnopenMessage() {console.log("WebSocket连接成功    状态码:" + this.websocket.readyState);},setOnmessageMessage(result) {console.log("服务端返回:" + result.data);let msgMap = JSON.parse(result.data);let id = msgMap.id;let title = msgMap.title;let type = msgMap.type;// 根据服务器推送的消息做自己的业务处理this.$notify({title: "你有一条新信息",type: "info",duration: 0,dangerouslyUseHTMLString: true,message:'<div style="height:100px;width:100px">' +title,position: "bottom-right"});},setOncloseMessage() {console.log("WebSocket连接关闭    状态码:" + this.websocket.readyState);},onbeforeunload() {this.closeWebSocket();},closeWebSocket() {this.websocket.close();}},

基本上面的代码复制到你们自己的工程里就能运行,有些涉及数据库、地址、或者公司隐私之类的,大部分用XXX去掉了,换成你们自己的即可。

======================================正式环境配合nginx使用=======================================

因为服务器对外只开通了8077端口,所以只能通过Nginx来反向代理

1:修改前台文件

connWebSocket() {let userInfo = JSON.parse(localStorage.getItem("userInfos"));let userId = userInfo.userId;if ("WebSocket" in window) {this.websocket = new WebSocket("ws://xxx.xxx.xxx.xxx:8077/websocket/" + userId);this.initWebSocket();} else {ctx.$message.error("次浏览器不支持websocket");}},

2:修改Nginx配置文件

主要的2点

1: map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
   }

2: websocket 服务的端口是9002,需要代理到此端口

location /websocket {
        proxy_pass http://127.0.0.1:9002;  
        proxy_redirect off; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_read_timeout 3600s; #超时时间
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header Upgrade $http_upgrade; #开启websocket支持
        proxy_set_header Connection $connection_upgrade; #开启websocket支持
    }

完整代码:


#user  nobody;
worker_processes  1;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;events {worker_connections  65555;
}http {map $http_upgrade $connection_upgrade {default upgrade;'' close;}include       mime.types;default_type  application/octet-stream;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#access_log  logs/access.log  main;sendfile        on;autoindex       on;tcp_nopush      on;tcp_nodelay     on; keepalive_timeout 120; fastcgi_connect_timeout 300;fastcgi_send_timeout 300;fastcgi_read_timeout 300;fastcgi_buffer_size 64k;fastcgi_buffers 4 64k;    fastcgi_busy_buffers_size 128k;fastcgi_temp_file_write_size 128k;client_header_buffer_size 100m; #上传文件大小限制    gzip on;gzip_min_length   1k;gzip_buffers     4 16k;gzip_http_version 1.0;gzip_comp_level 9;gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/gif image/png;#gzip_types       text/plain application/x-javascript text/css application/xml;gzip_vary on;server {listen       8077;server_name  localhost;#charset koi8-r;#access_log  logs/host.access.log  main;location / {root   D:/dist;  index  index.html index.htm;}location /iserver {proxy_pass http://127.0.0.1:8090/iserver;}location ^~/api {proxy_pass http://127.0.0.1:8088;}location /websocket {proxy_pass http://127.0.0.1:9002;  proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 3600s; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; }error_page  404              /index.html;location /index.html {root   D:/dist; index  index.html index.htm;}}

==============================添加 消息提示音====================================================

1:vue页面修改,添加代码

<!-- 语音播放功能 --><audio ref="audio" controls v-show="false"><source id="tts_source_id" src="../assets/mp3/messageToYou.mp3" type="audio/mpeg"></audio>

2:添加一个调用的方法

methods: {myplay(){this.$refs.audio.play();},
}

3:推送完消息后调用

setOnmessageMessage(result) {this.myplay();//调用播放方法console.log("服务端返回:" + result.data);let msgMap = JSON.parse(result.data);let id = msgMap.id;let business_Id = msgMap.business_Id;let title = msgMap.title;let type = msgMap.type; //主要
.........省略其他代码
}

Spring clound+VUE+WebSocket实现消息推送 一(即时通讯)相关推荐

  1. 消息推送和即时通讯项目简单实现

    使用Netty实现的服务端消息推送,Android端消息接收功能 各子项目功能说明如下: 1.IMClient:Android客户端工程 2.IMServer:服务端Web工程,负责监控连接和推送消息 ...

  2. springboot定时发送短信_springboot 整合websocket实现消息推送(主动推送,具体用户推送,群发,定时推送)...

    websocket springboot 整合websocket实现消息推送(主动推送,具体用户推送,群发,定时推送) 使用WebSocket构建交互式Web应用程序 本指南将引导您完成创建" ...

  3. Vue-全局websocket 实现消息推送

    在上一篇文章 WebSocket 消息推送https://blog.csdn.net/qq_63312957/article/details/125375122?spm=1001.2014.3001. ...

  4. vue-admin websocket接收消息推送+语音提示(详细代码)

    websocket接收消息推送+语音提示 这个是同事的代码,我拿来记录一下,希望以后可以看得懂-- utils/websocket.js const audioUrl = require('@/ass ...

  5. php通知websocket,php实现websocket实时消息推送

    php实现websocket实时消息推送,供大家参考,具体内容如下 SocketService.php /** * Created by xwx * Date: 2017/10/18 * Time: ...

  6. python websocket实现消息推送_python Django websocket 实时消息推送

    [实例简介] Django websocket 实时消息推送 服务端主动推送 调用 send(username, title, data, url) username:用户名 title:消息标题 d ...

  7. python websocket实时消息推送

    python websocket实时消息推送 十分想念顺店杂可... 本人写的渣,大神勿喷. 转载请附带本文链接,谢谢. 服务端代码 # -*- coding: utf-8 -*- # @Time : ...

  8. java整合消息推送_SpringMVC整合websocket实现消息推送及触发功能

    本文为大家分享了SpringMVC整合websocket实现消息推送,供大家参考,具体内容如下 1.创建websocket握手协议的后台 (1)HandShake的实现类 /** *Project N ...

  9. spring boot 集成socketIo 做消息推送

    spring boot 集成socketIo 做消息推送 项目需求 代码展示 客户端代码 服务端代码 项目需求 后台管理系统用户小铃铛,消息推送功能并展示有多少条消息或者小红点 代码展示 客户端代码 ...

最新文章

  1. Mac下显示隐藏文件
  2. SOL注入——HTTP头部注入(六)
  3. 【音视频安卓开发 (三)】OpenGL ES 直接绘制YUV
  4. 从微信浏览器,调起本地应用,最简单的解决方案
  5. php mysql rpm包_MYSQL RPM包安装
  6. 定义域可以写成不等式吗_证单变量不等式(一)
  7. mysql union 不同字段_mysql中union和union all的区别和注意点
  8. ssm集成mysql_idea+SSM+Mysql框架整合
  9. ios中UIWebview和asiHttprequest的用法
  10. office如何快速批量地压缩PPT内的全部图片
  11. 电脑操作技巧:如何抓图
  12. zbox的测试例——selectAll+selectInverse
  13. Linux网卡up但是没有running,eth0 up但是没有running的小问题
  14. Delphi文件正文提取开发组件--文件内容搜索的高效工具
  15. 正则表达式中的方法、检测、特殊字符、敏感词替换等等
  16. NASA丨登陆火星六大前沿技术
  17. 通过DataEase行列权限设置实现数据权限管控
  18. matlab handles结构体
  19. 新世纪福音战士剧场版破
  20. 极品家丁最新章节列表

热门文章

  1. 视频教程-Linux shell脚本习题-Linux
  2. 贪心算法(局部最优)
  3. 关于ASO与ASM的结合
  4. 解锁一个新技能,如何在Python代码中使用表情包...
  5. 人脑是怎样认知图像的?——结构描述模式(传统模式识别之五)
  6. 马蜂窝推荐系统容灾缓存服务的设计与实现
  7. 在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径
  8. 2021年12月国产数据库排行榜: openGauss节节攀升拿下榜眼,GaussDB与TDSQL你争我夺各进一位...
  9. SQL Based on practice
  10. 计蒜客——Nise-Anti-AK Problem