- 前端
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index2</title>
<link href="~/js/element-plus/index.css" rel="stylesheet" />
@* 顺序不能错*@
<script src="~/js/vue/vue.js"></script>
<script src="~/js/element-plus/index.js"></script>
<script src="~/js/element-plus/zh-cn.js"></script>
<script src="~/lib/jquery/dist/jquery.js"></script>
<style lang="less">
.loginContainer {
position: relative;
padding: 50px;
}
.title {
display: flex;
justify-content: center;
position: absolute;
color: #fff;
text-align: center;
z-index: 999;
}
:root {
--card-height: 65vh;
--card-width: calc(var(--card-height) / 1.5);
}
body {
min-height: 100vh;
background: #212534;
display: flex;
align-items: center;
flex-direction: column;
padding-top: 2rem;
padding-bottom: 2rem;
box-sizing: border-box;
}
.card {
background: #191c29;
width: var(--card-width);
height: var(--card-height);
padding: 3px;
position: relative;
border-radius: 6px;
justify-content: center;
align-items: center;
text-align: center;
display: flex;
font-size: 1.5em;
color: rgb(88 199 250 / 0%);
cursor: pointer;
font-family: cursive;
}
.card:hover {
color: rgb(88 199 250 / 100%);
transition: color 1s;
color: #fff;
}
.card:hover:before,
.card:hover:after {
animation: none;
opacity: 0;
}
.card::before {
content: '';
width: 104%;
height: 102%;
border-radius: 8px;
background-image: linear-gradient(
var(--rotate),
#5ddcff,
#3c67e3 43%,
#4e00c2
);
position: absolute;
z-index: -1;
top: -1%;
left: -2%;
animation: spin 2.5s linear infinite;
}
.card::after {
position: absolute;
content: '';
top: calc(var(--card-height) / 6);
left: 0;
right: 0;
z-index: -1;
height: 100%;
width: 100%;
margin: 0 auto;
transform: scale(0.8);
filter: blur(calc(var(--card-height) / 6));
background-image: linear-gradient(
var(--rotate),
#5ddcff,
#3c67e3 43%,
#4e00c2
);
opacity: 1;
transition: opacity 0.5s;
animation: spin 2.5s linear infinite;
}
a {
color: #212534;
text-decoration: none;
font-family: sans-serif;
font-weight: bold;
margin-top: 2rem;
}
</style>
</head>
<body>
<div id="app">
<div class="flex gap-2">
<el-tag type="primary">Tag 1</el-tag>
<el-tag type="success">Tag 2</el-tag>
<el-tag type="info">Tag 3</el-tag>
<el-tag type="warning">Tag 4</el-tag>
<el-tag type="danger">Tag 5</el-tag>
</div>
<div>
<el-input v-model="input" style="width: 240px" placeholder="Please input" />
</div>
<el-row>
<el-button type="primary" @@click="SeletTo">查询</el-button>
<el-table :data="renderDynamic"
ref="product"
row-key="id"
size="mini"
@@select="selectRow"
default-expand-all
@@select-all="selectAllRow"
@@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column type="index" label="序号" width="50"> </el-table-column>
<el-table-column prop="createUser" label="创建人"> </el-table-column>
<el-table-column prop="fileName" label="文件名"> </el-table-column>
<el-table-column prop="createTime" label="时间"> </el-table-column>
</el-table>
</el-row>
</div>
<script>
const { createApp, reactive, ref, toRefs, onMounted, nextTick, onUnmounted, getCurrentInstance } = Vue
const { ElMessageBox, ElMessage, ElLoading, ElNotification } = ElementPlus
const setup = {
setup() {
const { proxy } = getCurrentInstance()
const input = ref('12412 ')
const chat_cont = ref(null)
const Data = reactive({
renderDynamic: [
{
id: "1589546710706933760",
pid: "-1111",
fullName: "zhangping",
isDirectory: 1,
description: "12",
fileName: "12",
size: 109881,
createUser: "admin",
createTime: "2022-11-06 00:14:03",
updateUser: "admin",
updateTime: "2022-11-06 00:14:03",
sensitivity: null,
standardNumber: null,
sort: "",
children: [
{
id: "1598583904029212672",
pid: "1589546710706933760",
fullName:
"hdfs://hdp01:8020/dmp/meta/script/XX项目演示-孟/12/3.png",
isDirectory: 0,
description: null,
fileName: "3.png",
size: 36627,
createUser: "admin",
createTime: "2022-12-02 01:44:38",
updateUser: "admin",
updateTime: "2022-12-06 15:18:44",
sensitivity: 1,
standardNumber: "",
sort: "文件类型1",
children: [
{
id: "1589546834929635328",
pid: "-1",
fullName:
"hdfs://hdp01:8020/dmp/meta/script/XX项目演示-孟/12/1.jpg",
isDirectory: 0,
description: null,
fileName: "1.jpg",
size: 98316,
createUser: "admin",
createTime: "2022-11-07 17:14:32",
updateUser: "admin",
updateTime: "2022-11-07 17:14:32",
sensitivity: null,
standardNumber: null,
sort: "",
children: [
{
id: "1656206644327051264",
pid: "-1",
fullName:
"hdfs://mycluster:8020/dataStandard/file/教育行业数融平台/JYT 0633—2022:教育基础数据.pdf",
isDirectory: 0,
description: null,
fileName: "JYT 0633—2022:教育基础数据.pdf",
size: 266646,
createUser: "admin",
createTime: "2023-05-10 15:56:49",
updateUser: "admin",
updateTime: "2023-05-10 15:56:49",
sensitivity: null,
standardNumber: "",
sort: "",
children: [],
},
],
},
],
},
{
id: "1656206805937778688",
pid: "-1",
fullName:
"hdfs://mycluster:8020/dataStandard/file/教育行业数融平台/JYT 0637—2022:教育系统人员基础数据.pdf",
isDirectory: 0,
description: null,
fileName: "JYT 0637—2022:教育系统人员基础数据.pdf",
size: 227038,
createUser: "admin",
createTime: "2023-05-10 15:57:28",
updateUser: "admin",
updateTime: "2023-05-10 15:57:28",
sensitivity: null,
standardNumber: "",
sort: "",
children: [],
}
],
}
]
})
const methods = {
// 勾选父节点时,子层级一起勾选或一起取消勾选
selectRow(selection, row) {
console.log(selection);
let data = selection.some((item) => {
return row.id === item.id;
});
if (data) {
let pid = row.pid;
// 勾选节点时 父节点
if (row.pid > 0) {
// 获取当前行的父亲行的信息(直接改变原来的树)
Data.renderDynamic.forEach((element) => {
if (pid == element.id) {
console.log(element);
this.toggleSelection(element,true);
this.$refs.product.toggleRowSelection(element, true);
}
});
}
// 勾选节点时
if (row.children) {
this.setChildren(row.children, true);
}
} else {
// 取消勾选节点时
if (row.children) {
this.setChildren(row.children, false);
}
}
},
// 全选按钮
selectAllRow(selection) {
// 全选
let isSelect = selection.some((item) => {
let tableDataIds = Data.renderDynamic.map((data) => data.id);
if (tableDataIds.indexOf(item.id) !== -1) {
return true;
} else {
return false;
}
});
// 全不选
let isCancel = !Data.renderDynamic.every((item) => {
let selectIds = selection.map((data) => data.id);
if (selectIds.indexOf(item.id) !== -1) {
return true;
} else {
return false;
}
});
if (isSelect) {
selection.map((item) => {
if (item.children) {
this.setChildren(item.children, true);
}
});
}
if (isCancel) {
Data.renderDynamic.map((item) => {
if (item.children) {
this.setChildren(item.children, false);
}
});
}
},
// 父节点含多个子层级
setChildren(children, type) {
children.map((item) => {
this.toggleSelection(item, type);
if (item.children) {
this.setChildren(item.children, type);
}
});
},
toggleSelection(row, select) {
if (row) {
this.$nextTick(() => {
this.$refs.product.toggleRowSelection(row, select);
});
}
},
handleSelectionChange(val) {
console.log(val, "选中的值");
},
}
// 初始化
onMounted(async () => {
})
return {
...toRefs(Data),
...methods,
}
}
}
createApp(setup).use(ElementPlus, { locale: ElementPlusLocaleZhCn }).mount("#app")
</script>
</body>
</html>
2 Socket类
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace EFCoreTest.socket
{
//注入扩展
public static class SocketsExtension
{
public static IServiceCollection AddWebSocketManager(this IServiceCollection services)
{
services.AddTransient<SocketsManager>();
var exportedTypes = Assembly.GetEntryAssembly()?.ExportedTypes;
if (exportedTypes == null) return services;
foreach (var type in exportedTypes)
if (type.GetTypeInfo().BaseType == typeof(SocketsHandler))
services.AddSingleton(type);
return services;
}
public static IApplicationBuilder MapSockets(this IApplicationBuilder app, PathString path,SocketsHandler socket)
{
return app.Map(path, x => x.UseMiddleware<SocketsMiddleware>(socket));
}
}
}
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace EFCoreTest.socket
{
public abstract class SocketsHandler
{
protected SocketsHandler(SocketsManager sockets)
{
Sockets = sockets;
}
public SocketsManager Sockets { get; set; }
/// <summary>
/// 连接一个 socket
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public virtual async Task OnConnected(WebSocket socket)
{
await Task.Run(() => { Sockets.AddSocket(socket); });
}
/// <summary>
/// 断开指定 socket
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public virtual async Task OnDisconnected(WebSocket socket)
{
await Sockets.RemoveSocketAsync(Sockets.GetId(socket));
}
/// <summary>
/// 发送消息给指定 socket
/// </summary>
/// <param name="socket"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessage(WebSocket socket, string message)
{
if (socket.State != WebSocketState.Open) return;
await socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(message)),WebSocketMessageType.Text, true, CancellationToken.None);
}
/// <summary>
/// 发送消息给指定 id 的 socket
/// </summary>
/// <param name="id"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessage(string id, string message)
{
await SendMessage(Sockets.GetSocketById(id), message);
}
/// <summary>
/// 给所有 sockets 发送消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendMessageToAll(string message)
{
foreach (var connection in Sockets.GetAllConnections()) await SendMessage(connection.Value, message);
}
/// <summary>
/// 接收到消息
/// </summary>
/// <param name="socket"></param>
/// <param name="result"></param>
/// <param name="buffer"></param>
/// <returns></returns>
///ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken
public abstract Task Receive(WebSocket socket, WebSocketReceiveResult result, byte[] buffer);
}
}
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
namespace EFCoreTest.socket
{
public class SocketsManager
{
private readonly ConcurrentDictionary<string, WebSocket> _connections = new ConcurrentDictionary<string, WebSocket>();
/// <summary>
/// 获取所有 sockets 的字典集合
/// </summary>
/// <returns></returns>
public ConcurrentDictionary<string, WebSocket> GetAllConnections()
{
return _connections;
}
/// <summary>
/// 获取指定 id 的 socket
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public WebSocket GetSocketById(string id)
{
return _connections.FirstOrDefault(x => x.Key == id).Value;
}
/// <summary>
/// 根据 socket 获取其 id
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public string GetId(WebSocket socket)
{
return _connections.FirstOrDefault(x => x.Value == socket).Key;
}
/// <summary>
/// 删除指定 id 的 socket,并关闭该链接
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task RemoveSocketAsync(string id)
{
_connections.TryRemove(id, out var socket);
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "socket connection closed",
CancellationToken.None);
}
/// <summary>
/// 添加一个 socket
/// </summary>
/// <param name="socket"></param>
public void AddSocket(WebSocket socket)
{
_connections.TryAdd(CreateId(), socket);
}
//todo 橙色的高亮注释
/// <summary>
/// 创建 id
/// </summary>
/// <returns></returns>
private string CreateId()
{
return Guid.NewGuid().ToString("N");
}
}
}
using Microsoft.AspNetCore.Http;
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
namespace EFCoreTest.socket
{
/// <summary>
/// WebSocket 的中间件
/// </summary>
public class SocketsMiddleware
{
private readonly RequestDelegate _next;
public SocketsMiddleware(RequestDelegate next, SocketsHandler handler)
{
_next = next;
Handler = handler;
}
private SocketsHandler Handler { get; }
public async Task InvokeAsync(HttpContext context)
{
if (context.WebSockets.IsWebSocketRequest)
{
// 转换当前连接为一个 ws 连接
var socket = await context.WebSockets.AcceptWebSocketAsync();
await Handler.OnConnected(socket);
// 接收消息的 buffer
var buffer = new byte[1024 * 4];
// 判断连接类型,并执行相应操作
while (socket.State == WebSocketState.Open)
{
// 这句执行之后,buffer 就是接收到的消息体,可以根据需要进行转换。
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
switch (result.MessageType)
{
case WebSocketMessageType.Text:
await Handler.Receive(socket, result, buffer);
break;
case WebSocketMessageType.Close:
await Handler.OnDisconnected(socket);
break;
case WebSocketMessageType.Binary:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
else
{
await _next(context);
}
}
}
}
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;
namespace EFCoreTest.socket
{
public class WebSocketMessageHandler : SocketsHandler
{
public WebSocketMessageHandler(SocketsManager sockets) : base(sockets)
{
}
//连接
public override async Task OnConnected(WebSocket socket)
{
await base.OnConnected(socket);
var socketId = Sockets.GetId(socket);
// await SendMessageToAll($"{socketId}已加入");
}
//释放
public override async Task OnDisconnected(WebSocket socket)
{
await base.OnDisconnected(socket);
var socketId = Sockets.GetId(socket);
//await SendMessageToAll($"{socketId}离开了");
}
//接受
public override async Task Receive(WebSocket socket, WebSocketReceiveResult result, byte[] buffer)
{
var socketId = Sockets.GetId(socket);
var msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
var message = $"{socketId} 发送了消息:{msg}";
await SendMessageToAll(message);
}
public async Task SendMessageAll(string message)
{
await SendMessageToAll(message);
}
}
}
using EFCoreTest.socket;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
namespace Net6Test.socket
{
public class WSocketClientHelp
{
ClientWebSocket ws = null;
Uri uri = null;
bool isUserClose = false;//是否最后由用户手动关闭
/// <summary>
/// WebSocket状态
/// </summary>
public WebSocketState? State { get => ws?.State; }
/// <summary>
/// 包含一个数据的事件
/// </summary>
public delegate void MessageEventHandler(object sender, string data);
public delegate void ErrorEventHandler(object sender, Exception ex);
/// <summary>
/// 连接建立时触发
/// </summary>
public event EventHandler OnOpen;
/// <summary>
/// 客户端接收服务端数据时触发
/// </summary>
public event MessageEventHandler OnMessage;
/// <summary>
/// 通信发生错误时触发
/// </summary>
public event ErrorEventHandler OnError;
/// <summary>
/// 连接关闭时触发
/// </summary>
public event EventHandler OnClose;
public SocketsManager Sockets { get; set; }
public WSocketClientHelp(string wsUrl)
{
uri = new Uri(wsUrl);
ws = new ClientWebSocket();
}
/// <summary>
/// 打开链接
/// </summary>
public void Open(string msg)
{
Task.Run(async () =>
{
if (ws.State == WebSocketState.Connecting || ws.State == WebSocketState.Open)
return;
string netErr = string.Empty;
try
{
//初始化链接
isUserClose = false;
ws = new ClientWebSocket();
await ws.ConnectAsync(uri, CancellationToken.None);
if (OnOpen != null)
OnOpen(ws, new EventArgs());
Send(msg);
//全部消息容器
List<byte> bs = new List<byte>();
//缓冲区
var buffer = new byte[1024 * 4];
//监听Socket信息
WebSocketReceiveResult result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
//是否关闭
while (!result.CloseStatus.HasValue)
{
//文本消息
if (result.MessageType == WebSocketMessageType.Text)
{
bs.AddRange(buffer.Take(result.Count));
//消息是否已接收完全
if (result.EndOfMessage)
{
//发送过来的消息
string userMsg = Encoding.UTF8.GetString(bs.ToArray(), 0, bs.Count);
if (OnMessage != null)
OnMessage(ws, userMsg);
//清空消息容器
bs = new List<byte>();
}
}
//继续监听Socket信息
result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
}
////关闭WebSocket(服务端发起)
// await ws.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
catch (Exception ex)
{
netErr = " .Net发生错误" + ex.Message;
if (OnError != null)
OnError(ws, ex);
//if (ws != null && ws.State == WebSocketState.Open)
// //关闭WebSocket(客户端发起)
// await ws.CloseAsync(WebSocketCloseStatus.Empty, ex.Message, CancellationToken.None);
}
finally
{
if (!isUserClose)
Close(ws.CloseStatus.Value, ws.CloseStatusDescription + netErr);
}
});
}
/// <summary>
/// 使用连接发送文本消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否尝试了发送</returns>
public bool Send(string mess)
{
if (ws.State != WebSocketState.Open)
return false;
Task.Run(async () =>
{
var replyMess = Encoding.UTF8.GetBytes(mess);
//发送消息
await ws.SendAsync(new ArraySegment<byte>(replyMess), WebSocketMessageType.Text, true, CancellationToken.None);
});
return true;
}
/// <summary>
/// 使用连接发送字节消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否尝试了发送</returns>
public bool Send(byte[] bytes)
{
if (ws.State != WebSocketState.Open)
return false;
Task.Run(async () =>
{
//发送消息
await ws.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Binary, true, CancellationToken.None);
});
return true;
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
isUserClose = true;
Close(WebSocketCloseStatus.NormalClosure, "用户手动关闭");
}
public void Close(WebSocketCloseStatus closeStatus, string statusDescription)
{
Task.Run(async () =>
{
try
{
//关闭WebSocket(客户端发起)
await ws.CloseAsync(closeStatus, statusDescription, CancellationToken.None);
}
catch (Exception ex)
{
}
ws.Abort();
ws.Dispose();
if (OnClose != null)
OnClose(ws, new EventArgs());
});
}
}
}
3测试调用
WSocketClientHelp wSocketClient = new WSocketClientHelp("ws://localhost:60232/ws");
wSocketClient.Open(msg);