string(7723) "{"docs":[{"id":"158579","text":"\u3010Python\u3011Tkinter\u56fe\u5f62\u754c\u9762\u8bbe\u8ba1\uff08GUI\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"HGNET","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183196","_id":"158579"},{"id":"158620","text":"python\u4e4bgui-tkinter\u53ef\u89c6\u5316\u7f16\u8f91\u754c\u9762 \u81ea\u52a8\u751f\u6210\u4ee3\u7801","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"darkspr","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183190","_id":"158620"},{"id":"158603","text":"python3.6 +tkinter GUI\u7f16\u7a0b \u5b9e\u73b0\u754c\u9762\u5316\u7684\u6587\u672c\u5904\u7406\u5de5\u5177","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"chenyuebai","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183187","_id":"158603"},{"id":"27850","text":"Python GUI\u4e4btkinter\u7a97\u53e3\u89c6\u7a97\u6559\u7a0b\u5927\u96c6\u5408\uff08\u770b\u8fd9\u7bc7\u5c31\u591f\u4e86\uff09 - \u6d2a\u536b","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"shwee","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183186","_id":"27850"},{"id":"158605","text":"Python GUI\u7f16\u7a0b(Tkinter) windows\u754c\u9762\u5f00\u53d1","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"itfat","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183184","_id":"158605"},{"id":"28228","text":"tkinter python\uff08\u56fe\u5f62\u5f00\u53d1\u754c\u9762\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"yudanqu","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183159","_id":"28228"},{"id":"158613","text":"Tkinter\u56fe\u5f62\u754c\u9762\u8bbe\u8ba1\uff08GUI\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"pywjh","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183158","_id":"158613"},{"id":"341361","text":"\u91cf\u5316\u5206\u6790\u83b7\u53d6\u6570\u636e\u76843\u79cd\u59ff\u52bf\uff08\u538b\u7bb1\u5e95\u7684\u795e\u5668Tushare\uff09","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"casual","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183069","_id":"341361"},{"id":"238879","text":"\u9762\u5411\u4ea4\u6613\u7684\u65e5\u5185\u9ad8\u9891\u91cf\u5316\u4ea4\u6613\u5e73\u53f0\u7b14\u8bb0","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"TaiYangXiManYouZhe","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183067","_id":"238879"},{"id":"238890","text":"2021 \u6700\u65b0\u91cf\u5316\u6295\u8d44\u4ea4\u6613\u8d44\u6e90\u6c47\u603b","intro":"\u76ee\u5f55\n\nECharts\n\u5f02\u6b65\u52a0\u8f7d\n\n\n\nECharts\r\n\u6570\u636e\u53ef\u89c6\u5316\u5728\u8fc7\u53bb\u51e0\u5e74\u4e2d\u53d6\u5f97\u4e86\u5de8\u5927\u8fdb\u5c55\u3002\u5f00\u53d1\u4eba\u5458\u5bf9\u53ef\u89c6\u5316\u4ea7\u54c1\u7684\u671f\u671b\u4e0d\u518d\u662f\u7b80\u5355\u7684\u56fe\u8868\u521b\u5efa\u5de5\u5177\uff0c\u800c\u662f\u5728\u4ea4\u4e92\u3001\u6027\u80fd\u3001\u6570\u636e\u5904\u7406\u7b49\u65b9\u9762\u6709\u66f4\u9ad8\u7684\u8981\u6c42\u3002\r\nchart.setOption({\r\n color: [\r\n ","username":"xgqfrms","tagsname":"","tagsid":"","catesname":"","catesid":"","createtime":"1641183063","_id":"238890"}],"count":535118}"
array(2) {
["docs"]=>
array(10) {
[0]=>
array(10) {
["id"]=>
string(6) "158579"
["text"]=>
string(46) "【Python】Tkinter图形界面设计(GUI)"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(5) "HGNET"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183196"
["_id"]=>
string(6) "158579"
}
[1]=>
array(10) {
["id"]=>
string(6) "158620"
["text"]=>
string(60) "python之gui-tkinter可视化编辑界面 自动生成代码"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(7) "darkspr"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183190"
["_id"]=>
string(6) "158620"
}
[2]=>
array(10) {
["id"]=>
string(6) "158603"
["text"]=>
string(66) "python3.6 +tkinter GUI编程 实现界面化的文本处理工具"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(10) "chenyuebai"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183187"
["_id"]=>
string(6) "158603"
}
[3]=>
array(10) {
["id"]=>
string(5) "27850"
["text"]=>
string(80) "Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) - 洪卫"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(5) "shwee"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183186"
["_id"]=>
string(5) "27850"
}
[4]=>
array(10) {
["id"]=>
string(6) "158605"
["text"]=>
string(45) "Python GUI编程(Tkinter) windows界面开发"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(5) "itfat"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183184"
["_id"]=>
string(6) "158605"
}
[5]=>
array(10) {
["id"]=>
string(5) "28228"
["text"]=>
string(39) "tkinter python(图形开发界面)"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(7) "yudanqu"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183159"
["_id"]=>
string(5) "28228"
}
[6]=>
array(10) {
["id"]=>
string(6) "158613"
["text"]=>
string(34) "Tkinter图形界面设计(GUI)"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(5) "pywjh"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183158"
["_id"]=>
string(6) "158613"
}
[7]=>
array(10) {
["id"]=>
string(6) "341361"
["text"]=>
string(68) "量化分析获取数据的3种姿势(压箱底的神器Tushare)"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(6) "casual"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183069"
["_id"]=>
string(6) "341361"
}
[8]=>
array(10) {
["id"]=>
string(6) "238879"
["text"]=>
string(51) "面向交易的日内高频量化交易平台笔记"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(18) "TaiYangXiManYouZhe"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183067"
["_id"]=>
string(6) "238879"
}
[9]=>
array(10) {
["id"]=>
string(6) "238890"
["text"]=>
string(41) "2021 最新量化投资交易资源汇总"
["intro"]=>
string(288) "目录
ECharts
异步加载
ECharts
数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。
chart.setOption({
color: [
"
["username"]=>
string(7) "xgqfrms"
["tagsname"]=>
string(0) ""
["tagsid"]=>
string(0) ""
["catesname"]=>
string(0) ""
["catesid"]=>
string(0) ""
["createtime"]=>
string(10) "1641183063"
["_id"]=>
string(6) "238890"
}
}
["count"]=>
int(535118)
}
Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码 - 爱码网
功能介绍
- 客户端给所有在线用户发送消息
- 客户端给指定在线用户发送消息
- 服务器给客户端发送消息(轮询方式)
项目搭建
项目结构图

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cyb</groupId>
<artifactId>socket_test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>socket_test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- springboot websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--guava依赖-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<!--fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
appliccation.properties

SocketTestApplication.java(Spring Boot启动类)

WebSocketStompConfig.java

package com.cyb.socket.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketStompConfig {
//这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件
@Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
}
WebSocket.java(Socket核心类)

package com.cyb.socket.websocket;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @Author:陈彦斌
* @Description:Socket核心类
* @Date: 2020-07-26
*/
@Component
@ServerEndpoint(value = "/connectWebSocket/{userId}")
public class WebSocket {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 在线人数
*/
public static int onlineNumber = 0;
/**
* 以用户的姓名为key,WebSocket为对象保存起来
*/
private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
/**
* 会话
*/
private Session session;
/**
* 用户名称
*/
private String userId;
/**
* 建立连接
*
* @param session
*/
@OnOpen
public void onOpen(@PathParam("userId") String userId, Session session) {
onlineNumber++;
System.out.println("现在来连接的客户id:" + session.getId() + "用户名:" + userId);
//logger.info("现在来连接的客户id:"+session.getId()+"用户名:"+userId);
this.userId = userId;
this.session = session;
System.out.println("有新连接加入! 当前在线人数" + onlineNumber);
// logger.info("有新连接加入! 当前在线人数" + onlineNumber);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
//先给所有人发送通知,说我上线了
Map<String, Object> map1 = Maps.newHashMap();
map1.put("messageType", 1);
map1.put("userId", userId);
sendMessageAll(JSON.toJSONString(map1), userId);
//把自己的信息加入到map当中去
clients.put(userId, this);
System.out.println("有连接关闭! 当前在线人数" + onlineNumber);
//logger.info("有连接关闭! 当前在线人数" + clients.size());
//给自己发一条消息:告诉自己现在都有谁在线
Map<String, Object> map2 = Maps.newHashMap();
map2.put("messageType", 3);
//移除掉自己
Set<String> set = clients.keySet();
map2.put("onlineUsers", set);
sendMessageTo(JSON.toJSONString(map2), userId);
} catch (IOException e) {
System.out.println(userId + "上线的时候通知所有人发生了错误");
//logger.info(userId+"上线的时候通知所有人发生了错误");
}
}
@OnError
public void onError(Session session, Throwable error) {
//logger.info("服务端发生了错误"+error.getMessage());
//error.printStackTrace();
System.out.println("服务端发生了错误:" + error.getMessage());
}
/**
* 连接关闭
*/
@OnClose
public void onClose() {
onlineNumber--;
//webSockets.remove(this);
clients.remove(userId);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
Map<String, Object> map1 = Maps.newHashMap();
map1.put("messageType", 2);
map1.put("onlineUsers", clients.keySet());
map1.put("userId", userId);
sendMessageAll(JSON.toJSONString(map1), userId);
} catch (IOException e) {
System.out.println(userId + "下线的时候通知所有人发生了错误");
//logger.info(userId+"下线的时候通知所有人发生了错误");
}
//logger.info("有连接关闭! 当前在线人数" + onlineNumber);
//logger.info("有连接关闭! 当前在线人数" + clients.size());
System.out.println("有连接关闭! 当前在线人数" + onlineNumber);
}
/**
* 收到客户端的消息
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session) {
try {
//logger.info("来自客户端消息:" + message+"客户端的id是:"+session.getId());
System.out.println("来自客户端消息:" + message + " | 客户端的id是:" + session.getId());
JSONObject jsonObject = JSON.parseObject(message);
String textMessage = jsonObject.getString("message");
String fromuserId = jsonObject.getString("userId");
String touserId = jsonObject.getString("to");
//如果不是发给所有,那么就发给某一个人
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
Map<String, Object> map1 = Maps.newHashMap();
map1.put("messageType", 4);
map1.put("textMessage", textMessage);
map1.put("fromuserId", fromuserId);
if (touserId.equals("All")) {
map1.put("touserId", "所有人");
sendMessageAll(JSON.toJSONString(map1), fromuserId);
} else {
map1.put("touserId", touserId);
System.out.println("开始推送消息给" + touserId);
sendMessageTo(JSON.toJSONString(map1), touserId);
}
} catch (Exception e) {
e.printStackTrace();
//logger.info("发生了错误了");
}
}
/**
* 给指定的用户发送消息
*
* @param message
* @param TouserId
* @throws IOException
*/
public void sendMessageTo(String message, String TouserId) throws IOException {
for (WebSocket item : clients.values()) {
System.out.println("给指定的在线用户发送消息,在线人员名单:【" + item.userId.toString() + "】发送消息:" + message);
if (item.userId.equals(TouserId)) {
item.session.getAsyncRemote().sendText(message);
break;
}
}
}
/**
* 给所有用户发送消息
*
* @param message 数据
* @param FromuserId
* @throws IOException
*/
public void sendMessageAll(String message, String FromuserId) throws IOException {
for (WebSocket item : clients.values()) {
System.out.println("给所有在线用户发送给消息,在线人员名单:【" + item.userId.toString() + "】发送消息:" + message);
item.session.getAsyncRemote().sendText(message);
}
}
/**
* 给所有在线用户发送消息
*
* @param message 数据
* @throws IOException
*/
public void sendMessageAll(String message) throws IOException {
for (WebSocket item : clients.values()) {
System.out.println("服务器给所有在线用户发送消息,当前在线人员为【" + item.userId.toString() + "】发送消息:" + message);
item.session.getAsyncRemote().sendText(message);
}
}
/**
* 获取在线用户数
*
* @return
*/
public static synchronized int getOnlineCount() {
return onlineNumber;
}
}
TestController.java(前端控制器)

package com.cyb.socket.websocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
@Controller
@RequestMapping("testMethod")
public class TestController {
@Autowired
private WebSocket webSocket;
/**
* 给指定的在线用户发送消息
* @param userId
* @param msg
* @return
* @throws IOException
*/
@ResponseBody
@GetMapping("/sendTo")
public String sendTo(@RequestParam("userId") String userId,@RequestParam("msg") String msg) throws IOException {
webSocket.sendMessageTo(msg,userId);
return "推送成功";
}
/**
* 给所有在线用户发送消息
* @param msg
* @return
* @throws IOException
* @throws IOException
*/
@ResponseBody
@PostMapping("/sendAll")
public String sendAll(@RequestBody String msg) throws IOException, IOException {
webSocket.sendMessageAll(msg);
return "推送成功";
}
}
SocketTask.java(轮询调度往客户端推送消息)

package com.cyb.socket.schedule;
import com.cyb.socket.websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class SocketTask {
@Autowired
private WebSocket webSocket;
private SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS" );
//5秒轮询一次
@Scheduled(fixedRate = 5000)
public void sendClientData() throws IOException {
String msg="{\"message\":\"你好\",\"userId\":\"002\",\"to\":\"All\"}";
webSocket.sendMessageAll(msg);
System.out.println("消息推送时间:"+ sdf.format(new Date()));
}
}
测试网页
index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Test My WebSocket</title>
</head>
<body>
TestWebSocket
<input id="text" type="text" style="width:500px"/>
<button onclick="send()">SEND MESSAGE</button>
<button onclick="closeWebSocket()">CLOSE</button>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
//连接WebSocket节点
websocket = new WebSocket("ws://localhost:8083/connectWebSocket/001");
}
else{
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭连接
function closeWebSocket(){
websocket.close();
}
//发送消息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
index2.html
<!DOCTYPE HTML>
<html>
<head>
<title>Test My WebSocket</title>
</head>
<body>
TestWebSocket
<input id="text" type="text" style="width:500px" />
<button onclick="send()">SEND MESSAGE</button>
<button onclick="closeWebSocket()">CLOSE</button>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
//连接WebSocket节点
websocket = new WebSocket("ws://localhost:8083/connectWebSocket/002");
}
else{
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭连接
function closeWebSocket(){
websocket.close();
}
//发送消息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
项目地址
链接:https://pan.baidu.com/s/1yiAXTkCjHac-F3S1HFyNJQ
提取码:53tp
功能演示
客户端给所有在线用户发消息

客户端给指定在线用户发送消息

服务器给客户端发送消息(轮询方式)
注意需要加上这些注解

演示

通过前端控制器给指定用户发送消息

演示

相关文章:
-
2021-11-07
-
2021-08-27
-
2021-08-05
-
2021-08-05
-
2021-11-18
-
2021-11-07
-
2021-12-10
猜你喜欢
-
2021-09-08
-
2021-11-07
-
2021-12-15
-
2021-08-05
-
2021-08-05
-
2021-10-17
-
2019-05-23
相关资源
-
下载
2023-01-29
-
下载
2022-12-06
-
下载
2021-06-06