UE5多人MOBA+GAS 54、用户登录和会话创建请求

文章目录

  • 创建主菜单需要的
    • 创建主菜单游戏模式
    • 创建主菜单游戏控制器
    • 创建主菜单界面UI
    • 实现登录游戏实例
  • 创建等待界面
  • 配置和获取协调器 URL
  • 撰写和发送会话创建请求


创建主菜单需要的

创建主菜单游戏模式

MainMenuGameMode
在这里插入图片描述

创建主菜单游戏控制器

MainMenuPlayerController
在这里插入图片描述

#pragma once#include "CoreMinimal.h"
#include "MenuPlayerController.h"
#include "MainMenuPlayerController.generated.h"/*** */
UCLASS()
class CRUNCH_API AMainMenuPlayerController : public AMenuPlayerController
{GENERATED_BODY()
public:	AMainMenuPlayerController();
};
#include "MainMenuPlayerController.h"AMainMenuPlayerController::AMainMenuPlayerController()
{// 禁用自动管理相机目标bAutoManageActiveCameraTarget = false;
}

分别创建两个的蓝图
在这里插入图片描述
在这里插入图片描述
创建一个摄像机,自动启用玩家0
在这里插入图片描述

创建主菜单界面UI

MainMenuWidget

#pragma once#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/WidgetSwitcher.h"
#include "Framework/MGameInstance.h"
#include "MainMenuWidget.generated.h"class UButton;
/*** */
UCLASS()
class CRUNCH_API UMainMenuWidget : public UUserWidget
{GENERATED_BODY()
public:virtual void NativeConstruct() override;/******************************/	/*           Main             *//******************************/	
private:UPROPERTY(meta = (BindWidget))TObjectPtr<UWidgetSwitcher> MainSwitcher;// 游戏实例UPROPERTY()TObjectPtr<UMGameInstance> MGameInstance;/******************************/	/*           Login            *//******************************/
private:// 登录界面的根组件UPROPERTY(meta = (BindWidget))TObjectPtr<UWidget> LoginWidgetRoot;// 登录按钮UPROPERTY(meta = (BindWidget))TObjectPtr<UButton> LoginButton;// 登录按钮点击事件UFUNCTION()void OnLoginButtonClicked();/*** 登录完成时的回调函数* @param bWasSuccessful 是否登录成功* @param PlayerNickname 登录成功时的玩家昵称* @param ErrorMsg 登录失败时的错误信息*/void LoginCompleted(bool bWasSuccessful, const FString& PlayerNickname, const FString& ErrorMsg);
};
#include "MainMenuWidget.h"#include "Components/Button.h"void UMainMenuWidget::NativeConstruct()
{Super::NativeConstruct();// 获取游戏实例MGameInstance = GetGameInstance<UMGameInstance>();if (MGameInstance){}// 绑定登录按钮点击事件LoginButton->OnClicked.AddDynamic(this, &UMainMenuWidget::OnLoginButtonClicked);
}void UMainMenuWidget::OnLoginButtonClicked()
{// 登录按钮点击时触发UE_LOG(LogTemp, Warning, TEXT("Longing In!"))
}void UMainMenuWidget::LoginCompleted(bool bWasSuccessful, const FString& PlayerNickname, const FString& ErrorMsg)
{if (bWasSuccessful){UE_LOG(LogTemp, Warning, TEXT("登录成功: %s"), *PlayerNickname)}else{UE_LOG(LogTemp, Warning, TEXT("登录失败: %s"), *ErrorMsg)}
}

创建蓝图版本
在这里插入图片描述
然后修改对应命名
在这里插入图片描述

设置切换器的锚点
在这里插入图片描述
在这里插入图片描述

设置一下登录
在这里插入图片描述
添加一个尺寸框包裹
在这里插入图片描述

添加一个背景模糊
在这里插入图片描述
把UI添加到主菜单玩家控制器中
在这里插入图片描述
在这里插入图片描述

实现登录游戏实例

UMGameInstance

/*** 登录完成委托* 参数:*   - bWasSuccessful:登录是否成功*   - PlayerNickName:玩家昵称*   - ErrorMsg:错误信息*/
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnLoginCompleted, bool /*bWasSuccessful*/, const FString& /*PlayerNickName*/, const FString& /*ErrorMsg*/);
/*************************************//*             登录功能              *//*************************************/
public:// 检查是否已登录bool IsLoggedIn() const;// 检查是否正在登录中bool IsLoggingIn() const;// 客户端通过账户门户登录void ClientAccountPortalLogin();// 登录完成委托FOnLoginCompleted OnLoginCompleted;private:// 客户端登录实现void ClientLogin(const FString& Type, const FString& Id, const FString& Token);// 登录完成回调void LoginCompleted(int NumOfLocalPlayer, bool bWasSuccessful, const FUniqueNetId& UserId, const FString& Error);// 登录委托句柄FDelegateHandle LoggingInDelegateHandle;
bool UMGameInstance::IsLoggedIn() const
{if (IOnlineIdentityPtr IdentityPtr = UTNetStatics::GetIdentityPtr()){// 查询本地玩家0的登录状态,是否为已登录return IdentityPtr->GetLoginStatus(0) == ELoginStatus::LoggedIn;}// 如果IdentityPtr无效,则默认未登录return false;
}bool UMGameInstance::IsLoggingIn() const
{// 如果登录委托句柄有效,说明还在等待登录回调return LoggingInDelegateHandle.IsValid();
}void UMGameInstance::ClientAccountPortalLogin()
{// 调用统一的ClientLogin接口,使用AccountPortal方式ClientLogin("AccountPortal", "", "");
}void UMGameInstance::ClientLogin(const FString& Type, const FString& Id, const FString& Token)
{if (IOnlineIdentityPtr IdentityPtr = UTNetStatics::GetIdentityPtr()){// 如果已经有一个登录委托在监听,先移除它,避免重复绑定if (LoggingInDelegateHandle.IsValid()){IdentityPtr->OnLoginCompleteDelegates->Remove(LoggingInDelegateHandle);LoggingInDelegateHandle.Reset();}// 绑定登录完成回调LoggingInDelegateHandle = IdentityPtr->OnLoginCompleteDelegates->AddUObject(this, &UMGameInstance::LoginCompleted);// 调用OnlineSubsystem的登录函数(异步)if (!IdentityPtr->Login(0,FOnlineAccountCredentials(Type, Id, Token))){UE_LOG(LogTemp, Warning, TEXT("登录失败!"))if (LoggingInDelegateHandle.IsValid()){IdentityPtr->OnLoginCompleteDelegates->Remove(LoggingInDelegateHandle);LoggingInDelegateHandle.Reset();}// 通知外部,登录失败OnLoginCompleted.Broadcast(false, "", "登录失败!");}}
}void UMGameInstance::LoginCompleted(int32 NumOfLocalPlayer, bool bWasSuccessful, const FUniqueNetId& UserId,const FString& Error)
{if (IOnlineIdentityPtr IdentityPtr = UTNetStatics::GetIdentityPtr()){// 移除登录完成委托if (LoggingInDelegateHandle.IsValid()){IdentityPtr->OnLoginCompleteDelegates->Remove(LoggingInDelegateHandle);LoggingInDelegateHandle.Reset();}FString PlayerNickname = "";if (bWasSuccessful){// 获取玩家昵称PlayerNickname = IdentityPtr->GetPlayerNickname(UserId);UE_LOG(LogTemp, Warning, TEXT("登录成功: %s"), *(PlayerNickname))}else{UE_LOG(LogTemp, Warning, TEXT("登录失败: %s"), *(Error))}OnLoginCompleted.Broadcast(bWasSuccessful, PlayerNickname, Error);}else{OnLoginCompleted.Broadcast(false, "", "无法找到身份指针");}
}

UMainMenuWidget到主菜单UI中绑定委托


void UMainMenuWidget::NativeConstruct()
{Super::NativeConstruct();// 获取游戏实例MGameInstance = GetGameInstance<UMGameInstance>();if (MGameInstance){MGameInstance->OnLoginCompleted.AddUObject(this, &UMainMenuWidget::LoginCompleted);}// 绑定登录按钮点击事件LoginButton->OnClicked.AddDynamic(this, &UMainMenuWidget::OnLoginButtonClicked);
}void UMainMenuWidget::OnLoginButtonClicked()
{// 登录按钮点击时触发UE_LOG(LogTemp, Warning, TEXT("Longing In!"))if (MGameInstance && !MGameInstance->IsLoggedIn() && !MGameInstance->IsLoggingIn()){// 触发登录MGameInstance->ClientAccountPortalLogin();}
}

编译运行后点击登录会跳转到网页登录
在这里插入图片描述

创建等待界面

WaitingWidget
在这里插入图片描述

#pragma once#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Button.h"
#include "Components/TextBlock.h"
#include "WaitingWidget.generated.h"/*** 等待界面控件* 用于在需要玩家等待(如连接、加载、匹配)时显示提示信息,* 并可选提供“取消”按钮。*/
UCLASS()
class CRUNCH_API UWaitingWidget : public UUserWidget
{GENERATED_BODY()
public:virtual void NativeConstruct() override;// 获取 Cancel 按钮的点击事件引用,并清空之前绑定的所有回调。FOnButtonClickedEvent& ClearAndGetButtonClickedEvent();/*** 设置等待提示信息,并控制“取消”按钮是否可见。* @param WaitInfo   等待提示文本* @param bAllowCancel 是否允许取消(决定按钮显隐)*/void SetWaitInfo(const FText& WaitInfo, bool bAllowCancel = false);private:// 等待提示文本UPROPERTY(meta = (BindWidget))TObjectPtr<UTextBlock> WaitInfoText;// 取消按钮UPROPERTY(meta = (BindWidget))TObjectPtr<UButton> CancelButton;
};
#include "WaitingWidget.h"void UWaitingWidget::NativeConstruct()
{Super::NativeConstruct();
}FOnButtonClickedEvent& UWaitingWidget::ClearAndGetButtonClickedEvent()
{// 清空按钮已有的点击事件CancelButton->OnClicked.Clear();return CancelButton->OnClicked;
}void UWaitingWidget::SetWaitInfo(const FText& WaitInfo, bool bAllowCancel)
{// 设置取消按钮的可见性if (CancelButton){CancelButton->SetVisibility(bAllowCancel ? ESlateVisibility::Visible : ESlateVisibility::Hidden);}// 更新提示文字if (WaitInfoText){WaitInfoText->SetText(WaitInfo);}
}

回到主菜单界面UMainMenuWidget

	/******************************/	/*           Main             *//******************************/// 切换到主界面void SwitchToMainWidget();// 主界面的根组件UPROPERTY(meta = (BindWidget))TObjectPtr<UWidget> MainWidgetRoot;/******************************/	/*           等待			  *//******************************/
private:// 等待界面UPROPERTY(meta = (BindWidget))TObjectPtr<UWaitingWidget> WaitingWidget;// 切换到等待界面FOnButtonClickedEvent& SwitchToWaitingWidget(const FText& WaitInfo, bool bAllowCancel = false);
void UMainMenuWidget::NativeConstruct()
{Super::NativeConstruct();// 获取游戏实例MGameInstance = GetGameInstance<UMGameInstance>();if (MGameInstance){MGameInstance->OnLoginCompleted.AddUObject(this, &UMainMenuWidget::LoginCompleted);if (MGameInstance->IsLoggedIn()){SwitchToMainWidget();}}// 绑定登录按钮点击事件LoginButton->OnClicked.AddDynamic(this, &UMainMenuWidget::OnLoginButtonClicked);
}void UMainMenuWidget::SwitchToMainWidget()
{if (MainSwitcher){MainSwitcher->SetActiveWidget(MainWidgetRoot);}
}void UMainMenuWidget::OnLoginButtonClicked()
{// 登录按钮点击时触发UE_LOG(LogTemp, Warning, TEXT("Longing In!"))if (MGameInstance && !MGameInstance->IsLoggedIn() && !MGameInstance->IsLoggingIn()){// 触发登录MGameInstance->ClientAccountPortalLogin();// SwitchToWaitingWidget(FText::FromString("正在登录..."));SwitchToWaitingWidget(FText::FromString(FString(TEXT("正在登录..."))));}
}void UMainMenuWidget::LoginCompleted(bool bWasSuccessful, const FString& PlayerNickname, const FString& ErrorMsg)
{if (bWasSuccessful){UE_LOG(LogTemp, Warning, TEXT("登录成功: %s"), *PlayerNickname)}else{UE_LOG(LogTemp, Warning, TEXT("登录失败: %s"), *ErrorMsg)}SwitchToMainWidget();
}FOnButtonClickedEvent& UMainMenuWidget::SwitchToWaitingWidget(const FText& WaitInfo, bool bAllowCancel)
{// 切换到等待界面MainSwitcher->SetActiveWidget(WaitingWidget);// 设置等待信息WaitingWidget->SetWaitInfo(WaitInfo, bAllowCancel);return WaitingWidget->ClearAndGetButtonClickedEvent();
}

创建等待UI蓝图版本
在这里插入图片描述
设置按钮锚点和位置
在这里插入图片描述
可以添加等待动画
在这里插入图片描述
主界面菜单中添加该UI
在这里插入图片描述
在这里插入图片描述
主菜单界面UMainMenuWidget中创建用于创建会话的按钮已经输入

	/******************************/	/*           会话			  *//******************************/// 创建会话按钮UPROPERTY(meta=(BindWidget))TObjectPtr<UButton> CreateSessionButton;// 输入房间(会话)的名称的文本框UPROPERTY(meta=(BindWidget))TObjectPtr<UEditableText> NewSessionNameText;// 点击“创建会话”按钮时调用UFUNCTION()void CreateSessionBtnClicked();// 取消房间创建(如等待界面点击取消时触发)UFUNCTION()void CancelSessionCreation();// 房间(会话)名称输入框文字变更时调用(用于校验是否可创建)UFUNCTION()void NewSessionNameTextChanged(const FText& NewText);
void UMainMenuWidget::NativeConstruct()
{Super::NativeConstruct();// 获取游戏实例MGameInstance = GetGameInstance<UMGameInstance>();if (MGameInstance){MGameInstance->OnLoginCompleted.AddUObject(this, &UMainMenuWidget::LoginCompleted);if (MGameInstance->IsLoggedIn()){SwitchToMainWidget();}}// 绑定登录按钮点击事件LoginButton->OnClicked.AddDynamic(this, &UMainMenuWidget::OnLoginButtonClicked);// 绑定创建会话按钮点击事件CreateSessionButton->OnClicked.AddDynamic(this, &UMainMenuWidget::CreateSessionBtnClicked);// 绑定新会话名称输入框内容改变事件NewSessionNameText->OnTextChanged.AddDynamic(this, &UMainMenuWidget::NewSessionNameTextChanged);
}void UMainMenuWidget::CreateSessionBtnClicked()
{// 确保玩家已登录if (MGameInstance && MGameInstance->IsLoggedIn()){// 请求创建并加入一个新的房间(会话)MGameInstance->RequestCreateAndJoinSession(FName(NewSessionNameText->GetText().ToString()));// 切换到等待界面,提示“Creating Lobby”,并绑定取消操作SwitchToWaitingWidget(FText::FromString(FString(TEXT("创建大厅"))), true).AddDynamic(this, &UMainMenuWidget::CancelSessionCreation);}
}void UMainMenuWidget::CancelSessionCreation()
{if (MGameInstance){MGameInstance->CancelSessionCreation();}SwitchToMainWidget();
}void UMainMenuWidget::NewSessionNameTextChanged(const FText& NewText)
{// 创建按钮是否可用CreateSessionButton->SetIsEnabled(!NewText.IsEmpty());
}

游戏实例UMGameInstance中补充函数

	/*************************************//*      客户端会话创建和搜索			 *//*************************************/
public:// 请求创建并加入新会话void RequestCreateAndJoinSession(const FName& NewSessionName);// 取消会话创建void CancelSessionCreation();
void UMGameInstance::RequestCreateAndJoinSession(const FName& NewSessionName)
{UE_LOG(LogTemp, Warning, TEXT("请求创建并加入会话: %s"), *(NewSessionName.ToString()))
}void UMGameInstance::CancelSessionCreation()
{UE_LOG(LogTemp, Warning, TEXT("取消会话创建"))
}

添加控件
在这里插入图片描述
再修改一下
在这里插入图片描述
在这里插入图片描述

配置和获取协调器 URL

	/*** 获取协调器URL键值* @return 协调器服务URL的FName键*/static FName GetCoordinatorURLKey();/*** 获取协调器URL地址* @return 协调器服务地址字符串*/static FString GetCoordinatorURL();/*** 获取默认协调器URL* @return 默认的协调器服务地址*/static FString GetDefaultCoordinatorURL();
FName UTNetStatics::GetCoordinatorURLKey()
{// 返回用于解析命令行参数的键值(这里是固定字符串 "COORDINATOR_URL")return FName("COORDINATOR_URL");
}FString UTNetStatics::GetCoordinatorURL()
{// 优先从命令行中获取 Coordinator URLFString CoordinatorURL = GetCommandlineArgAsString(GetCoordinatorURLKey());if (CoordinatorURL != ""){// 如果命令行中有值,则直接返回return CoordinatorURL;}// 如果命令行参数为空,则使用配置文件中的默认值return GetDefaultCoordinatorURL();
}FString UTNetStatics::GetDefaultCoordinatorURL()
{FString CoordinatorURL = "";// 从配置文件 [Crunch.Net] 节点中读取键 "CoordinatorURL"// 目标配置文件为 DefaultGame.iniGConfig->GetString(TEXT("Crunch.Net"), TEXT("CoordinatorURL"), CoordinatorURL, GGameIni);// 打印日志,方便调试,输出获取到的默认 URLUE_LOG(LogTemp, Warning, TEXT("Getting Default Coordinator URL as: %s"), *CoordinatorURL)// 返回默认配置中的 URLreturn CoordinatorURL;
}

填写本地主机号,这里的 127.0.0.1表示 本机
在这里插入图片描述

[Crunch.Net]
CoordinatorURL="127.0.0.1"

撰写和发送会话创建请求

UMGameInstance

#include "Interfaces/IHttpResponse.h"
#include "Interfaces/IHttpRequest.h"/*************************************//*      客户端会话创建和搜索			 *//*************************************/private:// 会话创建请求完成回调void SessionCreationRequestCompleted(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully, FGuid SessionSearchId);
void UMGameInstance::RequestCreateAndJoinSession(const FName& NewSessionName)
{UE_LOG(LogTemp, Warning, TEXT("请求创建并加入会话: %s"), *(NewSessionName.ToString()))// 创建HTTP请求对象,准备向协调器发起会话创建请求FHttpRequestRef Request = FHttpModule::Get().CreateRequest();// 生成唯一会话搜索ID用于后续查询FGuid SessionSearchId = FGuid::NewGuid();// 获取协调器服务的基础URL地址FString CoordinatorURL  = UTNetStatics::GetCoordinatorURL();// 拼接目标 API 地址:<CoordinatorURL>/SessionsFString URL = FString::Printf(TEXT("%s/Sessions"), *CoordinatorURL);UE_LOG(LogTemp, Warning, TEXT("发送会话创建请求到 URL:%s"), *URL)// 配置 HTTP 请求:目标地址 + 请求方式 POSTRequest->SetURL(URL);Request->SetVerb("POST");// 设置 HTTP 请求头,指定请求体为 JSON 格式Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));// 构造 JSON 请求体,包含 SessionName 和 SessionSearchIdTSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);JsonObject->SetStringField(UTNetStatics::GetSessionNameKey().ToString(), NewSessionName.ToString());JsonObject->SetStringField(UTNetStatics::GetSessionSearchIdKey().ToString(), SessionSearchId.ToString());// 将 JSON 对象转换为字符串FString RequestBody;TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&RequestBody);FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);// 设置 HTTP 请求体Request->SetContentAsString(RequestBody);// 绑定会话创建完成回调Request->OnProcessRequestComplete().BindUObject(this, &UMGameInstance::SessionCreationRequestCompleted, SessionSearchId);// 发送 HTTP 请求,测试中在python中编写代码接收请求信息if (!Request->ProcessRequest()){UE_LOG(LogTemp, Warning, TEXT("会话创建请求失败"))}
}void UMGameInstance::SessionCreationRequestCompleted(FHttpRequestPtr Request, FHttpResponsePtr Response,bool bConnectedSuccessfully, FGuid SessionSearchId)
{if (!bConnectedSuccessfully){UE_LOG(LogTemp, Warning, TEXT("连接协调服务器失败,网络连接未成功!"))return;}UE_LOG(LogTemp, Warning, TEXT("连接协调服务器成功!"))
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/920119.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920119.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SCSS上传图片占位区域样式

_App.scss// 上传图片占位区域样式---------------------------------------- [theme"uploadImage"] {transition: 0.2s;position: relative;cursor: pointer;border-radius: 4px;/*居中填满*/background-repeat: no-repeat;background-position: center;background-…

Prometheus+Grafana监控mysql

1、简述 使用 Prometheus 结合 Grafana 监控 MySQL 是一套成熟且广泛应用的方案&#xff0c;能实现对 MySQL 性能、状态等指标的实时采集、存储、可视化及告警。 2、整体架构说明 Prometheus&#xff1a;负责定时从 MySQL 采集监控指标&#xff08;需借助 Exporter&#xff0…

网络流量分析——Tcpdump 数据包过滤

文章目录.PCAP 文件Tcpdump 数据包过滤过滤和高级语法选项有用的 TCPDump 过滤器主机过滤器源/目标过滤器使用源和端口作为过滤器将目标与网络过滤器结合使用协议过滤器 - 通用名称协议过滤器 - 编号端口过滤器端口范围过滤器小于/大于过滤器利用更大的AND 过滤器无滤镜的基本捕…

DeepSeek V3.1 横空出世:重新定义大语言模型的边界与可能

当大语言模型领域的竞争进入白热化阶段&#xff0c;一场静默的技术革命正在悄然酝酿。2025 年8月19日&#xff0c;DeepSeek 团队带着全新升级的 V3.1 版本强势登场&#xff0c;这个被业内称为 “智能体时代敲门砖” 的模型&#xff0c;究竟藏着多少颠覆认知的黑科技&#xff1f…

Unity Netcode for GameObjects(多人联机小Demo)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、安装 Netcode for GameObjects二、做个小Dome1.NetcodeManageNet2.创建UI3.创建预制体4.代码介绍UI代码随机位置代码总结前言 Netcode for GameObjects 是 …

Ant Design for UI 选择下拉框

1. 单选框 与多选框<template><div class"demo-page" style"padding: 40px; max-width: 1200px; margin: 0 auto; font-family: Microsoft YaHei, Arial, sans-serif;"><h1 style"color: #1890ff; text-align: center; margin-bottom…

动手学深度学习01-引言

动手学深度学习pytorch 参考地址&#xff1a;https://zh.d2l.ai/ 文章目录动手学深度学习pytorch1-第01章-引言1. 机器学习/深度学习基础1.1 什么是机器学习&#xff1f;1.2 深度学习与机器学习的关系&#xff1f;2. 数据&#xff08;Data&#xff09;2.1 什么是样本、特征、标…

大模型提示词工程背后的原理:深入理解Prompt Learning(提示学习)

“ 知其然也要知其所以然&#xff0c;为什么会有提示词工程&#xff1f;” 了解和使用过大模型的人应该都知道提示词工程&#xff0c;即使不了解提示词工程&#xff0c;至少也应该听说过&#xff0c;提示词工程说白了就是一种和大模型交流的方法&#xff0c;它的作用就是让大模…

AI 智能体安全设计模式:从三大“反模式”看如何构建可信的 AI 系统

摘要&#xff1a;当我们将 AI 智能体&#xff08;Agent&#xff09;从实验原型推向生产环境时&#xff0c;许多团队在不经意间重复着一些危险的错误实践。这些反复出现的错误&#xff0c;在软件工程中被称为“反模式”&#xff08;Anti-Patterns&#xff09;。本文基于 Curity …

【前端安全】前端安全第一课:防止 XSS 和 CSRF 攻击的常见手法

【前端安全】前端安全第一课&#xff1a;防止 XSS 和 CSRF 攻击的常见手法 所属专栏&#xff1a; 《前端小技巧集合&#xff1a;让你的代码更优雅高效》 上一篇&#xff1a; 【性能指标】决战性能之巅&#xff1a;深入理解核心 Web 指标&#xff08;Core Web Vitals&#xff0…

QT新建文件或者项目解释:那些模板分别是什么意思?

在 Qt Creator 的 “New File or Project” 界面中&#xff0c;不同分类下的模板有着不同的用途和适用场景&#xff0c;以下是对各部分的详细说明&#xff1a;一、“项目” 分类下1. Application&#xff08;应用程序&#xff09;用途&#xff1a;用于创建可直接运行的应用程序…

《支付回调状态异常的溯源与架构级修复》

在后端开发领域&#xff0c;能通过错误日志直接定位的问题&#xff0c;只能算作“基础挑战”&#xff1b;而那些依赖特定数据量、并发量或外部交互场景才会触发的隐性问题&#xff0c;往往像藏在电路中的虚焊点&#xff0c;平时看似正常&#xff0c;关键时刻却会导致整个系统断…

C语言 运算符 (2)

一、内容概要内容提neirong关系运算符 逻辑运算符 逗号运算符 位运算二、运算符2.1 关系运算符说明&#xff1a; >,<,>,<,,! &#xff08;都是双目的&#xff09;所有关系运算符都是双目运算符&#xff08;二元运算符&#xff09;&#xff0c;运算符左侧和右侧、可…

mac版SVN客户端: macSvn 下载、使用指南【保姆级教程】

做项目要用SVN&#xff0c;在Mac平台找顺手的客户端好难。Windows下的TortoiseSVN很赞&#xff0c;Mac却一直没对等工具。直到发现新发布的MacSVN&#xff0c;布局和操作深得我心&#xff0c;内置常用工具&#xff0c;还能无缝集成到OS与任务栏&#xff0c;便捷易上手&#xff…

MongoDB分片集群自动化部署

OS&#xff1a;CentOS Linux release 7.9.2009 (Core) 场景&#xff1a; 需要半自动化或者自动化部署MongoDB集群时&#xff0c;可用此脚本。提高交付效率。 脚本实现架构图&#xff1a;脚本&#xff1a; check_clear_host.sh #此脚本有2个功能及是检查 资源规格和清理资源上的…

go-redis库使用总结

文章目录1. 概述与特性2. 安装与初始化2.1 安装2.2 初始化3 基本使用模式3.1 单实例客户端3.2 连接池与自动重连4. 常用 Redis 数据结构操作4.1 字符串&#xff08;String&#xff09;4.2 哈希&#xff08;Hash&#xff09;4.3 列表&#xff08;List&#xff09;4.4 集合&#…

【软件设计模式】策略模式

1.概念策略&#xff08;Strategy&#xff09;模式定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以相互替换&#xff0c;且算法的变化不会影响使用算法的客户。策略模式属于行为型设计模式&#xff0c;它通过对算法进行封装&#xff0c;把使用算法的责…

Mac电脑英特尔版本最新系统15.6.1安装php环境

Mac电脑安装php环境 版本环境&#xff1a; 2025-08-22 14:09:19 安装 最新系统15.6.1系统&#xff1a; 新版本的mac不带php环境&#xff0c;需要自己 安装 brew install php8.3 启动说明 查看 . 使用官方方法安装 NVM curl -o- https://raw.githubusercontent.com/nvm-sh/…

Android焦点窗口变化导致遥控键值监听失效问题分析

最近在做语音全局控制Android系统功能&#xff0c;通过集成第三方语音识别sdk得到相关控制指令&#xff0c;然后将指令通过进程间通信传递给当前应用并作出响应。有很多通用指令&#xff0c;比如播放/暂停&#xff0c;Android系统本身就有全局控制指令&#xff1a;KeyEvent.KEY…

降本增效:基于 JavaScript 的 AI 编程 IDE 上下文压缩优化方案

降本增效&#xff1a;基于 JavaScript 的 AI 编程 IDE 上下文压缩优化方案 在当前 AI 辅助编程&#xff08;AI Pair Programming&#xff09;日益普及的背景下&#xff0c;开发者越来越依赖如 GitHub Copilot、Tabnine、CodeLlama 等智能编码工具。然而&#xff0c;一个普遍存在…