Qt 移动应用推送通知实现

推送通知是移动应用提升用户粘性的核心功能——无论是即时消息提醒、活动推送还是状态更新,都需要通过推送功能触达用户。Qt虽未直接提供跨平台推送API,但可通过集成原生服务(如Firebase Cloud Messaging、Apple Push Notification service)实现全平台推送。本文从原理到实战,详解Qt移动应用推送通知的完整实现方案,覆盖Android和iOS双平台。

一、推送通知核心原理与架构

移动应用的推送通知需要依托平台级服务,核心架构如下:

┌─────────────┐     ┌──────────────┐     ┌──────────────┐     ┌─────────────┐
│  你的服务器  │────▶│ 平台推送服务  │────▶│ 移动设备系统  │────▶│ 你的Qt应用  │
└─────────────┘     └──────────────┘     └──────────────┘     └─────────────┘(FCM/APNs等)        (系统通知托盘)

1. 关键概念

  • 设备令牌(Token):每个设备上的应用实例会生成唯一令牌,用于标识接收终端(如FCM的registration token、APNs的device token);
  • 推送服务
    • Android:依赖Firebase Cloud Messaging(FCM);
    • iOS:依赖Apple Push Notification service(APNs);
  • 通知类型
    • 显示通知:包含标题、内容、图标等,由系统托盘展示;
    • 数据通知:无UI展示,直接传递数据给应用(需应用运行)。

二、Android平台:基于FCM的推送实现

1. 环境准备

(1)配置Firebase项目
  1. 访问Firebase控制台,创建项目并添加Android应用;
  2. 下载配置文件google-services.json,复制到Qt项目的android目录下;
  3. 在Firebase控制台启用“Cloud Messaging”服务。
(2)Qt项目配置

.pro文件中添加Android权限和依赖:

QT += androidextras# 权限配置
android {ANDROID_PACKAGE_SOURCE_DIR = $$PWD/androidandroidPermissions += \android.permission.INTERNET \com.google.android.c2dm.permission.RECEIVE \android.permission.WAKE_LOCK
}

2. 核心代码实现

(1)获取设备令牌(Token)

通过JNI调用Android原生API获取FCM令牌:

// FCMHelper.h
#ifndef FCMHELPER_H
#define FCMHELPER_H#include <QObject>
#include <QAndroidJniObject>class FCMHelper : public QObject {Q_OBJECT
public:explicit FCMHelper(QObject *parent = nullptr);void getToken();signals:void tokenReceived(const QString &token); // 令牌获取成功void tokenError(const QString &error);    // 令牌获取失败private slots:void onTokenReceived(JNIEnv *env, jobject thiz, jstring token);void onTokenError(JNIEnv *env, jobject thiz, jstring error);
};#endif // FCMHELPER_H
// FCMHelper.cpp
#include "FCMHelper.h"
#include <QtAndroid>
#include <QDebug>// JNI回调函数注册
static JNINativeMethod methods[] = {{"onTokenReceived", "(Ljava/lang/String;)V", (void*)&FCMHelper::onTokenReceived},{"onTokenError", "(Ljava/lang/String;)V", (void*)&FCMHelper::onTokenError}
};jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env;if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)return JNI_ERR;jclass cls = env->FindClass("org/qtproject/example/FCMReceiver");env->RegisterNatives(cls, methods, sizeof(methods)/sizeof(methods[0]));return JNI_VERSION_1_6;
}FCMHelper::FCMHelper(QObject *parent) : QObject(parent) {// 初始化FCM服务QAndroidJniObject activity = QtAndroid::androidActivity();QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/FCMReceiver","initialize","(Landroid/app/Activity;)V",activity.object<jobject>());
}void FCMHelper::getToken() {// 调用Java方法获取令牌QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/FCMReceiver","getToken");
}// 令牌获取成功的JNI回调
void FCMHelper::onTokenReceived(JNIEnv *env, jobject thiz, jstring token) {QString tokenStr = env->GetStringUTFChars(token, nullptr);qDebug() << "FCM Token:" << tokenStr;emit tokenReceived(tokenStr);
}// 令牌获取失败的JNI回调
void FCMHelper::onTokenError(JNIEnv *env, jobject thiz, jstring error) {QString errorStr = env->GetStringUTFChars(error, nullptr);qDebug() << "FCM Error:" << errorStr;emit tokenError(errorStr);
}
(2)创建Android原生接收类

android/src/org/qtproject/example/目录下创建FCMReceiver.java

package org.qtproject.example;import android.app.Activity;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;public class FCMReceiver extends FirebaseMessagingService {private static Activity m_activity;private static native void onTokenReceived(String token);private static native void onTokenError(String error);public static void initialize(Activity activity) {m_activity = activity;}public static void getToken() {FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> {if (!task.isSuccessful()) {onTokenError("获取令牌失败: " + task.getException().getMessage());return;}String token = task.getResult();onTokenReceived(token);});}// 接收推送消息@Overridepublic void onMessageReceived(RemoteMessage remoteMessage) {Log.d("FCM", "收到推送消息");if (remoteMessage.getNotification() != null) {// 处理显示通知String title = remoteMessage.getNotification().getTitle();String body = remoteMessage.getNotification().getBody();showNotification(title, body);}if (remoteMessage.getData().size() > 0) {// 处理数据通知(可发送到Qt应用)String data = remoteMessage.getData().toString();// 调用Qt方法传递数据(需通过JNI)}}// 显示系统通知private void showNotification(String title, String body) {// Android通知栏显示逻辑(需创建通知渠道)// ...}
}
(3)在Qt应用中使用
// 主窗口中初始化FCM
FCMHelper *fcmHelper = new FCMHelper(this);
connect(fcmHelper, &FCMHelper::tokenReceived, this, [this](const QString &token) {// 将令牌发送到你的服务器sendTokenToServer(token);
});
fcmHelper->getToken();

三、iOS平台:基于APNs的推送实现

1. 环境准备

(1)配置Apple开发者账号
  1. 在Apple开发者中心创建推送证书(APNs SSL Certificate);
  2. 在Xcode中配置项目:开启“Push Notifications”能力,导入推送证书。
(2)Qt项目配置

.pro文件中添加iOS配置:

ios {QMAKE_INFO_PLIST = Info.plistiosDeploymentTarget = 12.0
}

Info.plist中添加推送权限描述:

<key>NSRemoteNotificationUsageDescription</key>
<string>需要推送通知权限以接收消息提醒</string>

2. 核心代码实现

(1)请求推送权限并获取设备令牌

通过Objective-C++调用iOS原生API:

// APNsHelper.h
#ifndef APNHELPER_H
#define APNHELPER_H#include <QObject>
#include <QString>#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
#endifclass APNsHelper : public QObject {Q_OBJECT
public:explicit APNsHelper(QObject *parent = nullptr);void requestPermission();signals:void tokenReceived(const QString &token);void permissionDenied();private:
#ifdef __OBJC__void registerForRemoteNotifications();
#endif
};#endif // APNHELPER_H
// APNsHelper.mm(注意文件后缀为.mm以支持Objective-C++)
#include "APNsHelper.h"
#include <QDebug>#ifdef __OBJC__
// 通知代理类
@interface QtAPNsDelegate : NSObject <UNUserNotificationCenterDelegate>
@property (nonatomic, assign) APNsHelper *helper;
@end@implementation QtAPNsDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)centerwillPresentNotification:(UNNotification *)notificationwithCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {// 应用前台时显示通知completionHandler(UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionSound);
}- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)responsewithCompletionHandler:(void(^)(void))completionHandler {// 处理通知点击事件completionHandler();
}
@end
#endifAPNsHelper::APNsHelper(QObject *parent) : QObject(parent) {
#ifdef __OBJC__// 设置通知代理QtAPNsDelegate *delegate = [[QtAPNsDelegate alloc] init];delegate.helper = this;UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];center.delegate = delegate;
#endif
}void APNsHelper::requestPermission() {
#ifdef __OBJC__UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert |UNAuthorizationOptionSound |UNAuthorizationOptionBadge)completionHandler:^(BOOL granted, NSError *error) {if (granted) {[self registerForRemoteNotifications];} else {emit permissionDenied();}}];
#endif
}#ifdef __OBJC__
void APNsHelper::registerForRemoteNotifications() {dispatch_async(dispatch_get_main_queue(), ^{[[UIApplication sharedApplication] registerForRemoteNotifications];});
}
#endif// 重写UIApplicationDelegate的方法获取令牌(需在main.m中实现)
#ifdef __OBJC__
extern "C" void applicationDidRegisterForRemoteNotificationsWithDeviceToken(UIApplication *application, NSData *deviceToken) {// 转换token为字符串const unsigned char *dataBuffer = (const unsigned char *)[deviceToken bytes];NSMutableString *tokenString = [NSMutableString stringWithCapacity:[deviceToken length] * 2];for (int i = 0; i < [deviceToken length]; ++i) {[tokenString appendFormat:@"%02.2hhx", dataBuffer[i]];}// 发送令牌到Qt信号APNsHelper *helper = ...; // 获取APNsHelper实例emit helper->tokenReceived([tokenString UTF8String]);
}
#endif
(2)在Qt应用中使用
// 初始化APNs
#ifdef Q_OS_IOS
APNsHelper *apnsHelper = new APNsHelper(this);
connect(apnsHelper, &APNsHelper::tokenReceived, this, [this](const QString &token) {sendTokenToServer(token); // 发送令牌到服务器
});
apnsHelper->requestPermission();
#endif

四、跨平台封装与统一接口

为简化双平台开发,可封装统一的推送管理类:

// PushManager.h
#ifndef PUSHMANAGER_H
#define PUSHMANAGER_H#include <QObject>
#include <QString>class PushManager : public QObject {Q_OBJECT
public:static PushManager *instance();void initialize(); // 初始化推送服务void sendTokenToServer(const QString &token); // 上传令牌到服务器signals:void notificationReceived(const QString &title, const QString &content); // 收到通知void tokenReady(const QString &token); // 令牌就绪private:PushManager(QObject *parent = nullptr);
};#endif // PUSHMANAGER_H
// PushManager.cpp
#include "PushManager.h"
#ifdef Q_OS_ANDROID
#include "FCMHelper.h"
#endif
#ifdef Q_OS_IOS
#include "APNsHelper.h"
#endif
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>PushManager *PushManager::instance() {static PushManager instance;return &instance;
}PushManager::PushManager(QObject *parent) : QObject(parent) {}void PushManager::initialize() {
#ifdef Q_OS_ANDROIDFCMHelper *fcm = new FCMHelper(this);connect(fcm, &FCMHelper::tokenReceived, this, &PushManager::tokenReady);fcm->getToken();
#endif
#ifdef Q_OS_IOSAPNsHelper *apns = new APNsHelper(this);connect(apns, &APNsHelper::tokenReceived, this, &PushManager::tokenReady);apns->requestPermission();
#endif
}void PushManager::sendTokenToServer(const QString &token) {// 发送POST请求到你的服务器,注册令牌QNetworkAccessManager *manager = new QNetworkAccessManager(this);QNetworkRequest request(QUrl("https://你的服务器地址/register_token"));request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");QByteArray data = QString("{\"token\":\"%1\"}").arg(token).toUtf8();QNetworkReply *reply = manager->post(request, data);connect(reply, &QNetworkReply::finished, [reply]() {if (reply->error() == QNetworkReply::NoError) {qDebug() << "令牌注册成功";} else {qDebug() << "令牌注册失败:" << reply->errorString();}reply->deleteLater();});
}

main.cpp中初始化:

#include "PushManager.h"int main(int argc, char *argv[]) {QGuiApplication app(argc, argv);// 初始化推送服务PushManager::instance()->initialize();// ... 其他初始化代码 ...return app.exec();
}

五、通知点击处理与应用跳转

当用户点击通知时,需打开应用并跳转到对应页面,实现方式如下:

1. Android处理

FCMReceiver.java中重写通知点击逻辑:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {// ... 其他代码 ...Intent intent = new Intent(this, org.qtproject.qt5.android.bindings.QtActivity.class);intent.putExtra("page", "detail"); // 传递页面参数intent.putExtra("id", "123");      // 传递数据PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);// 构建通知时关联PendingIntentNotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id").setContentIntent(pendingIntent);
}

在Qt中获取参数:

// 从Android intent中获取参数
#ifdef Q_OS_ANDROID
QAndroidJniObject activity = QtAndroid::androidActivity();
QAndroidJniObject intent = activity.callObjectMethod("getIntent", "()Landroid/content/Intent;");
QAndroidJniObject page = intent.callObjectMethod("getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;", QAndroidJniObject::fromString("page").object<jstring>());
if (page.isValid()) {QString pageStr = page.toString();qDebug() << "跳转页面:" << pageStr;// 执行页面跳转逻辑
}
#endif

2. iOS处理

QtAPNsDelegate中处理点击事件:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)responsewithCompletionHandler:(void(^)(void))completionHandler {NSDictionary *userInfo = response.notification.request.content.userInfo;NSString *page = userInfo[@"page"];// 传递参数到Qt(可通过全局变量或信号)completionHandler();
}

六、最佳实践与注意事项

1. 权限与用户体验

  • 权限申请时机:在用户完成关键操作(如登录)后再请求推送权限,提高授权率;
  • 频率控制:避免频繁推送,提供“设置→通知”开关允许用户关闭;
  • 内容相关性:推送内容与用户行为相关(如购物应用推送降价提醒)。

2. 技术优化

  • 令牌刷新处理:设备令牌可能会变化(如应用重装、系统更新),需定期重新获取并同步到服务器;
  • 通知渠道:Android 8.0+必须创建通知渠道,否则通知无法显示:
    // Android创建通知渠道
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel("default", "默认通知", NotificationManager.IMPORTANCE_DEFAULT);NotificationManager manager = getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);
    }
    
  • 后台数据处理:数据通知(无UI)需在Service(Android)或AppDelegate(iOS)中处理,避免阻塞UI。

3. 测试工具

  • FCM测试:使用Firebase控制台的“发送测试消息”功能;
  • APNs测试:使用curl命令发送测试通知:
    curl -v -d '{"aps":{"alert":"测试通知","sound":"default"}}' \
    -H "apns-topic: 你的应用Bundle ID" \
    -H "apns-push-type: alert" \
    --http2 \
    --cert 你的推送证书.pem:证书密码 \
    https://api.sandbox.push.apple.com/3/device/设备令牌
    

七、总结

Qt移动应用的推送通知实现需针对Android和iOS平台分别集成FCM和APNs服务,核心步骤包括:

  1. 配置平台推送服务并获取设备令牌;
  2. 将令牌同步到你的服务器,用于定向推送;
  3. 处理接收的通知并展示到系统托盘;
  4. 实现通知点击跳转逻辑。

通过封装跨平台接口,可显著降低双平台开发的复杂度。实际开发中需重点关注令牌刷新、权限管理和用户体验,避免过度推送导致用户反感。

掌握这套方案后,你的Qt移动应用将具备完善的推送能力,有效提升用户活跃度和留存率。

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

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

相关文章

Word和WPS文字如何制作分栏试卷?想分几栏分几栏

使用Word和WPS文字制作试卷的时候&#xff0c;通常会使用A3大小的纸张&#xff0c;横向布局。但是如果题目的题干、问题、选项文字太少&#xff0c;会带来试卷上有较大的空白&#xff0c;既不美观又浪费纸&#xff0c;解决办法就是将试卷分栏&#xff0c;根据需要分成多栏&…

ubuntu 安装vmware tools

VMware Workstation菜单栏->虚拟机->安装VMware Tools 打开ubuntu内加载的光盘&#xff0c;复制VMwareTools-10.3.26-22085142.tar.gz&#xff0c;解压出来 sudo ./vmware-install.pl #执行安装软件 VMware Tools 安装完成以后重启Ubuntu&#xff0c;重启以后就可以直…

【实时Linux实战系列】在实时应用中进行负载均衡

在实时应用中&#xff0c;负载均衡是确保系统能够高效处理多个任务的关键技术。通过合理调度任务到不同的处理单元&#xff0c;负载均衡可以提高系统的整体性能&#xff0c;减少延迟&#xff0c;并提高资源利用率。在实时 Linux 系统中&#xff0c;负载均衡尤为重要&#xff0c…

bash的特性-命令和文件自动补全

一、前言在 Linux Shell 编程和日常使用中&#xff0c;Bash 的自动补全功能 是一个非常强大且实用的特性。它不仅可以节省输入时间&#xff0c;还能有效减少拼写错误&#xff0c;提升命令执行效率。本文将带你全面了解 Bash 的自动补全机制&#xff0c;包括&#xff1a;✅ 命令…

Ubuntu系统 系统盘和数据盘扩容具体操作

Linux磁盘配置和需求&#xff0c;以下是完整的操作方案&#xff1a; 可以看到系统盘vda3 还有48GB 数据盘则是还有512GB没有挂载使用&#xff0c;下面是完成数据扩容的具体操作 一、完成系统盘扩容&#xff08;使用98GB空间&#xff09; # 1. 扩展逻辑卷&#xff08;LVM架构&am…

从0到1学Pandas(七):Pandas 在机器学习中的应用

目录一、数据预处理1.1 特征提取1.2 数据标准化与归一化1.3 特征编码二、特征工程2.1 特征选择​2.2 特征组合与衍生​2.3 缺失值处理策略​三、模型训练与评估3.1 数据集划分3.2 模型训练与预测3.3 模型评估与调优四、Pipeline 构建4.1 自动化工作流4.2 模型部署与应用4.3 模型…

LangChain和LangGraph 里面的 `create_react_agent`有什么不同

这两个函数虽然名称相同&#xff0c;但来自不同的库&#xff08;LangChain 和 LangGraph&#xff09;&#xff0c;它们在实现和使用上有一些关键区别&#xff1a; 主要区别特性LangChain 的 create_react_agentLangGraph 的 create_react_agent所属库LangChainLangGraph设计目的…

PostgreSQL 与 Oracle 数据库字段类型的详细对比

一、数值类型对比数据类型OraclePostgreSQL说明整数NUMBER(p,0)SMALLINT/INT/BIGINTOracle 统一用 NUMBER&#xff0c;PG 区分精度范围浮点数BINARY_FLOATREAL单精度浮点双精度浮点BINARY_DOUBLEDOUBLE PRECISION双精度浮点高精度小数NUMBER(p,s)NUMERIC(p,s)精确数值存储自增序…

JVM 性能调优实战:让系统性能 “飞” 起来的核心策略

在 Java 应用的生命周期中&#xff0c;性能问题如同隐藏的 “暗礁”—— 初期可能不显眼&#xff0c;但随着用户量增长和业务复杂度提升&#xff0c;微小的性能损耗会被无限放大&#xff0c;最终导致系统响应迟缓、频繁卡顿甚至崩溃。JVM 性能调优的目标&#xff0c;就是通过优…

Android Handler 完全指南

在 Android 开发中&#xff0c;Handler 是线程通信的核心工具 —— 当你在子线程下载图片后需要更新 UI&#xff0c;当你在 TCP 连接中收到数据需要通知界面&#xff0c;当你需要延迟执行某个任务时&#xff0c;都会用到 Handler。这个看似简单的类&#xff0c;却蕴含着 Androi…

梳理Ego-Planner模式下5通道、6通道与无人机模式的关系

Copilot said: 你需要梳理Ego-Planner模式下5通道、6通道与无人机模式的关系&#xff0c;以及轨迹跟随、紧急情况和人工接管的流程。下面结合你的描述和三张图片&#xff0c;对核心逻辑进行总结和整理&#xff1a; --- ## 一、状态组合与对应模式&#xff08;见图1&#xff09;…

odbc和jdbc什么区别

ODBC 和 JDBC 都是用于连接和操作数据库的标准接口&#xff0c;但它们分别面向不同的编程语言和平台。下面是它们的区别与对比&#xff0c;帮助你理解它们的用途和适用场景。&#x1f4ca; 一、基本概念对比特性ODBC&#xff08;Open Database Connectivity&#xff09;JDBC&am…

境外期货Level2高频Tick历史行情数据获取与应用指南

在金融量化分析中&#xff0c;本地数据的高效使用是提升策略效果的重要基础。本文以CSV格式的本地数据为核心&#xff0c;以外盘期货分钟数据、CME/COMEX/CBOT历史行情为例&#xff0c;阐述专业化的数据处理与应用方法&#xff0c;为研究者提供可行性方案。一、数据预处理标准化…

迅为RK3588开发板安卓GPIO调用-APP运行测试

将网盘上的安卓工程文件复制到 Windows 电脑上。确保工程路径中使用英文字符&#xff0c;不包含中文。接着&#xff0c;启动 Android Studio&#xff0c;点击“Open”按钮选择应用工程文件夹&#xff0c;然后点击“OK”。由于下载 Gradle 和各种 Jar 包可能需要一段时间&#x…

以太坊下一阶段的关键——隐私

1. 引言 随着以太坊庆祝其十周年纪念&#xff0c;Aztec Labs 联合创始人兼 CEO Zac Williamson 和以太坊基金会 PSE 负责人 Sam Richards 表示&#xff0c;以太坊必须加强其对隐私的原始承诺。 以太坊庆祝十周年纪念&#xff0c;标志着智能合约、去中心化金融&#xff08;DeF…

CTFpwn学习笔记1-栈溢出

栈溢出通过写入超出数组定义范围的字符长度达到溢出&#xff0c;从而覆盖栈上其余数据&#xff0c;覆盖返回地址约等于控制程序执行流例如&#xff1a;经过ida反编译后&#xff0c;发现这里要将v2的值修改为11.28125才能获得flag&#xff0c;同时我们可以发现这里使用了gets这个…

使用 Android Studio 中的 Gemini,让 Flutter 开发更便捷

作者 / Flutter 产品经理 Ander Dobo 及 Gemini in Android Studio 产品经理 Sandhya Mohan在 Android Studio 中创建 Android 应用的 Flutter 开发者将迎来一次重大的飞跃: Android Studio 中的 Gemini 已全面支持 Dart 和 Flutter 开发&#xff01;这意味着您可以直接在您青睐…

Deep Learning_ Foundations and Concepts-Springer (2024)【拜读】前向编码器20章

Diffusion Models 扩散模型 我们已经了解到&#xff0c;构建强大的生成模型的一种有效方法是&#xff1a;先引入一个关于潜在变量z的分布p(z)&#xff0c;然后使用深度神经网络将z变换到数据空间x。由于神经网络具有通用性&#xff0c;能够将简单固定的分布转化为关于x的高度灵…

Spring全局异常处理最佳实践

全局异常处理器详解 什么是全局异常处理器&#xff1f; 全局异常处理器是Spring框架提供的统一异常处理机制&#xff0c;用于集中处理应用程序中所有控制器&#xff08;Controller&#xff09;层抛出的异常。它的核心价值在于&#xff1a; 统一异常处理&#xff1a;避免在每个C…

STL学习(十一、常用的算数算法和集合算法)

目录 一、常用的算数算法 1.accmulate 2.fill 二、常用的集合算法 1.set_intersection 2.set_union 3.set_difference 一、常用的算数算法 包含头文件为<numeric> 1.accmulate 函数原型 accmulate(iterator beg, iterator end, value) // 计算元素累计和 // …