当前位置: 首页 > news >正文

【家政平台开发(16)】消息通知系统设计:搭建高效沟通桥梁

本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析,剖析家政行业现状、挖掘用户需求与梳理功能要点,到系统设计阶段的架构选型、数据库构建,再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化,测试阶段多维度保障平台质量,部署发布阶段确保平稳上线。还深入探讨运营策略、技术创新应用及未来发展方向,为家政平台开发提供全面且实用的知识体系与实践指南。

目录

  • 一、通知渠道设计
    • 1.1 短信通知服务集成设计
      • 1.1.1 短信服务商的选择
      • 1.1.2 短信发送接口的接入
      • 1.1.3 短信通知的优化策略
    • 1.2 站内信与推送通知设计
      • 1.2.1 站内信系统设计
      • 1.2.2 推送通知技术选型
      • 1.2.3 推送通知的实现与优化
  • 二、通知内容与模板设计
    • 2.1 不同业务场景通知内容规划
      • 2.1.1 服务流程通知
      • 2.1.2 异常情况通知
      • 2.1.3 平台资讯通知
    • 2.2 通知模板引擎选择与设计
      • 2.2.1 模板引擎对比与选择
      • 2.2.2 通知模板设计原则
      • 2.2.3 模板管理与更新
  • 三、通知发送与管理机制设计
    • 3.1 通知队列与异步发送设计
      • 3.1.1 消息队列选型
      • 3.1.2 通知队列的实现
      • 3.1.3 异步发送的优势与实现细节
    • 3.2 通知记录与状态管理设计
      • 3.2.1 通知记录表结构设计
      • 3.2.2 通知状态管理机制
      • 3.2.3 通知查询与统计功能实现


一、通知渠道设计

1.1 短信通知服务集成设计

在消息通知系统里,短信通知是非常关键的一环。它能够直接触达用户的手机,确保用户及时收到重要信息。对于家政平台而言,像订单确认、服务提醒、密码找回等场景,短信通知都发挥着不可或缺的作用。选择合适的短信服务提供商,是保障短信通知质量的基础,这其中价格、稳定性、发送速度等因素都是需要重点考量的。价格直接关系到平台的运营成本,如果短信发送单价过高,长期下来会是一笔不小的开支;稳定性则决定了短信能否准确无误地发送到用户手中,不稳定的服务可能导致部分用户收不到短信,影响用户体验;发送速度也至关重要,比如在订单紧急提醒的场景下,快速的短信发送能让用户第一时间做出响应。

1.1.1 短信服务商的选择

目前市面上主流的短信服务商有阿里云短信服务、腾讯云短信服务等。

  • 阿里云短信服务依托阿里云强大的云计算基础设施,稳定性极高,并且在全球范围内都有广泛的节点覆盖,这使得短信的发送速度非常快。其价格套餐也较为灵活,根据短信发送量的不同,提供了多种优惠方案,适合不同规模的平台使用。
  • 腾讯云短信服务则在接口易用性方面表现出色,提供了详细的开发文档和示例代码,即使是开发经验较少的团队也能快速上手。在到达率方面,腾讯云通过与各大运营商的深度合作,保证了短信能够高概率地送达用户手机。

若平台对成本较为敏感,且短信发送量不是特别大,可以优先考虑腾讯云短信服务,其较低的价格门槛能有效控制成本;若平台更注重稳定性和全球覆盖能力,阿里云短信服务会是更好的选择。

1.1.2 短信发送接口的接入

以 Spring Boot 整合短信服务商 SDK 为例,首先需要在项目的 pom.xml 文件中添加相应的依赖。比如使用阿里云短信服务,就需要添加阿里云短信服务 SDK 的依赖:

<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.6.0</version>
</dependency>
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>2.1.0</version>
</dependency>

接着在 application.yml 或 application.properties 中配置相关参数,如 API 密钥、签名等:

sms:aliyun:accessKeyId: your-access-key-idaccessKeySecret: your-access-key-secretsignName: 你的签名

在发送短信的核心代码中,首先要创建阿里云短信服务的客户端对象:

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;public class SmsService {public SendSmsResponse sendSms(String phoneNumbers, String templateCode, String templateParam) throws Exception {Config config = new Config().setAccessKeyId("your-access-key-id").setAccessKeySecret("your-access-key-secret");config.endpoint = "dysmsapi.aliyuncs.com";Client client = new Client(config);SendSmsRequest sendSmsRequest = new SendSmsRequest().setPhoneNumbers(phoneNumbers).setSignName("你的签名").setTemplateCode(templateCode).setTemplateParam(templateParam);return client.sendSms(sendSmsRequest);}
}

上述代码中,通过创建Client对象并设置相关参数,然后构建SendSmsRequest对象,填充手机号、签名、模板代码和模板参数等信息,最后调用client.sendSms(sendSmsRequest)方法发送短信,并返回发送结果。

1.1.3 短信通知的优化策略

为了避免短信发送过于频繁导致用户反感,可以根据用户的操作行为和业务场景,合理设置短信发送的频率限制。比如对于订单状态变更通知,在订单创建、服务开始、服务结束等关键节点发送短信,而不是在订单处理过程中的每一个小步骤都发送。当短信发送失败时,要及时进行重试机制的处理。可以设置重试次数和重试间隔时间,例如初始重试间隔为 1 分钟,每次重试间隔翻倍,最多重试 3 次。同时,要记录详细的短信发送日志,包括发送时间、发送内容、接收手机号、发送结果等信息,便于后续的问题排查和数据分析。根据用户行为数据,如用户的活跃时间、历史订单时间等,合理调整短信发送时机,提高短信的阅读率 。比如对于经常在晚上下单的用户,将订单相关的短信通知安排在晚上发送,这样更符合用户的使用习惯。

1.2 站内信与推送通知设计

站内信和推送通知是增强用户与平台互动的重要手段。站内信就像是平台内的私人信件,用户可以随时查看历史消息,适合用于一些不需要即时提醒,但需要用户留存查看的信息,如平台政策更新、服务评价反馈等。推送通知则能在第一时间将重要消息推送到用户的设备上,吸引用户的注意力,适用于订单状态变更、优惠活动提醒等需要用户立即知晓的场景。

1.2.1 站内信系统设计

站内信的数据表结构设计如下:

CREATE TABLE `message` (`id` bigint AUTO_INCREMENT PRIMARY KEY,`sender_id` bigint NOT NULL,`receiver_id` bigint NOT NULL,`message_content` text NOT NULL,`send_time` datetime DEFAULT CURRENT_TIMESTAMP,`is_read` tinyint DEFAULT 0
);

在上述表结构中,id是主键,用于唯一标识每一条站内信;sender_id表示发件人的用户 ID;receiver_id表示收件人的用户 ID;message_content存储消息的具体内容;send_time记录消息的发送时间;is_read字段表示消息是否已读,0 表示未读,1 表示已读。

实现站内信的发送功能时,后端代码可以通过 MyBatis-Plus 提供的BaseMapper进行数据库操作:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Message;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface MessageMapper extends BaseMapper<Message> {
}import com.example.demo.entity.Message;
import com.example.demo.mapper.MessageMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class MessageService {@Autowiredprivate MessageMapper messageMapper;public void sendMessage(Message message) {messageMapper.insert(message);}
}

在前端展示站内信列表时,使用 Element plus 搭建界面,通过调用后端接口获取站内信数据,并进行展示:

<template><div><el-table :data="messageList"><el-table-column prop="send_time" label="发送时间"></el-table-column><el-table-column prop="message_content" label="消息内容"></el-table-column><el-table-column prop="is_read" label="是否已读"><template #default="scope"><span v-if="scope.row.is_read === 0">未读</span><span v-else>已读</span></template></el-table-column></el-table></div>
</template><script setup>
import { ref } from 'vue';
import axios from 'axios';const messageList = ref([]);axios.get('/api/messages').then(response => {messageList.value = response.data;
});
</script>

1.2.2 推送通知技术选型

常见的推送通知技术方案有极光推送、个推等。

  • 极光推送支持多种平台,包括 iOS、Android 等,并且提供了丰富的推送功能,如单推、群推、广播等。在数据统计方面,极光推送能详细统计推送的到达率、点击率等数据,方便平台对推送效果进行分析。
  • 个推则在推送稳定性和大数据处理方面表现突出,能够支持海量用户的推送需求,并且提供了智能推送功能,根据用户的行为和属性进行精准推送。

对于家政平台来说,由于用户群体主要集中在移动端,且需要对不同用户进行个性化的推送,极光推送更适合,其丰富的功能和详细的数据统计能满足平台的运营需求。

1.2.3 推送通知的实现与优化

在后端集成极光推送 SDK 时,首先需要在项目中添加极光推送的依赖:

<dependency><groupId>cn.jiguang</groupId><artifactId>jpush-client</artifactId><version>3.4.6</version>
</dependency>

然后配置极光推送的相关参数,如 AppKey、MasterSecret 等。在根据不同业务场景构造推送消息时,例如订单状态变更通知:

import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;public class PushService {private static final String APP_KEY = "your-app-key";private static final String MASTER_SECRET = "your-master-secret";public void sendOrderStatusPush(String userId, String orderStatus) throws APIConnectionException, APIRequestException {JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance());PushPayload payload = PushPayload.newBuilder().setPlatform(Platform.android_ios()).setAudience(Audience.alias(userId)).setMessage(Message.content("您的订单状态已变更为:" + orderStatus)).setOptions(Options.newBuilder().setApnsProduction(false).build()).build();PushResult result = jPushClient.sendPush(payload);}
}

在优化推送通知的展示样式方面,可以根据不同的推送内容设置不同的图标和提示音,吸引用户的注意力。同时,在推送消息中添加一些引导性的文字,如 “点击查看详情”,提高用户的点击率和参与度。

二、通知内容与模板设计

2.1 不同业务场景通知内容规划

在家政平台的日常运营中,不同的业务场景需要有针对性的通知内容,这样才能确保用户能够准确理解通知的含义,及时做出相应的反应。合理规划通知内容,不仅能提升用户体验,还能增强用户对平台的信任度。

2.1.1 服务流程通知

  1. 在服务接单环节,通知内容应清晰地告知用户接单的家政人员信息,包括姓名、照片、服务评分等,让用户对服务人员有初步的了解和信任。同时,明确上门时间也至关重要,精确到具体的日期和时间段,方便用户做好准备。例如:“尊敬的用户,您预约的 [服务项目] 已被家政人员 [姓名] 接单,其服务评分高达 [X] 分。[姓名] 将于 [上门日期][上门时间段] 上门为您服务,请您提前做好准备。”

  2. 当服务即将开始时,提前一定时间提醒用户,比如提前 1 - 2 小时,让用户有足够的时间安排自己的事务。在通知中再次确认服务信息,避免出现误解。可以这样表述:“您好,距离您预约的 [服务项目] 开始时间还有 1 小时,家政人员 [姓名] 将按时上门服务。服务信息如下:[服务项目详情],请您保持电话畅通,以便服务人员与您联系。”

  3. 服务完成后,通知用户及时进行评价,这不仅有助于平台了解服务质量,也能为其他用户提供参考。可以设置一些激励措施,如评价送积分、优惠券等,提高用户评价的积极性。通知内容可以是:“您的 [服务项目] 已完成,感谢您使用我们的平台。为了帮助我们提升服务质量,请您对本次服务进行评价。评价后您将获得 [X] 积分,可用于兑换平台优惠券哦。点击 [评价链接] 即可进行评价。”

2.1.2 异常情况通知

  • 如果服务时间发生变更,要详细说明变更原因,如家政人员突发疾病、交通拥堵等,让用户了解情况。同时,提供新的服务时间,并表达歉意。例如:“非常抱歉地通知您,由于家政人员 [姓名] 突发疾病,无法按时为您提供 [服务项目]。我们已紧急安排其他家政人员 [新姓名] 为您服务,新的上门时间为 [新上门日期][新上门时间段],给您带来的不便,我们深表歉意。”

  • 当服务人员发生变更时,除了告知用户新的服务人员信息外,还可以简要说明变更原因,如原服务人员临时有事无法出勤。强调新服务人员的专业能力和经验,让用户放心。通知可以写成:“您好,由于原家政人员 [姓名] 临时有事无法出勤,我们为您更换了服务人员 [新姓名]。[新姓名] 具有丰富的家政服务经验,服务评分也非常高,相信能为您提供优质的服务。服务时间不变,仍为 [上门日期][上门时间段]。”

  • 在订单取消场景下,明确取消原因是用户主动取消还是平台因某些原因取消。如果是平台取消,提供相应的补偿措施,如优惠券、积分等,以弥补用户的损失。比如:“您的 [订单编号] 订单已取消,取消原因是 [具体原因]。为了表达我们的歉意,我们将为您发放一张 [X] 元的优惠券,下次使用平台服务时可直接抵扣。优惠券将在 24 小时内发放到您的账户,请注意查收。”

2.1.3 平台资讯通知

  • 在优惠活动通知中,突出活动的优惠力度,如 “全场 8 折”“满减优惠” 等,让用户一眼就能看到实惠。明确活动的起止时间,避免用户错过。详细说明参与方式,是自动享受优惠还是需要输入优惠码等。通知内容可以是:“平台限时优惠活动来袭!即日起至 [活动结束日期],所有服务项目全场 8 折。下单时无需输入优惠码,系统将自动为您计算折扣后的价格。抓住机会,享受超值家政服务吧!”

  • 新服务项目通知则重点介绍新服务的特点、优势和适用人群。可以通过案例或用户评价来增强说服力,吸引用户尝试。例如:“我们平台新推出了‘智能家居清洁服务’,该服务采用先进的清洁设备和专业的清洁技术,能够深入清洁各种智能家居设备,确保设备的正常运行和使用寿命。特别适合家中拥有较多智能家居设备的用户。已有用户反馈,使用后设备运行更加流畅,清洁效果非常满意。快来体验吧!”

2.2 通知模板引擎选择与设计

通知模板引擎在消息通知系统中起着至关重要的作用,它能够将动态数据与固定的模板结构相结合,生成个性化的通知内容,大大提高了通知生成的效率和灵活性。

2.2.1 模板引擎对比与选择

  • Velocity 是一个基于 Java 的模板引擎,它的语法相对简单,类似于 Java 的语法结构,易于学习和使用。在性能方面,Velocity 表现较为出色,能够快速地解析和渲染模板。然而,Velocity 在与 Spring Boot 的集成度上相对较低,需要进行一些额外的配置和开发工作。

  • Freemarker 是另一个广泛使用的模板引擎,它具有强大的表达式语言和丰富的内置函数,能够实现复杂的逻辑处理。Freemarker 的语法相对复杂一些,但它提供了更高的灵活性。在性能方面,Freemarker 也有不错的表现。与 Spring Boot 的集成度较高,通过简单的配置即可在 Spring Boot 项目中使用。

  • Thymeleaf 是一个现代的模板引擎,它以其简洁的语法和良好的可读性而受到青睐。Thymeleaf 支持 HTML5、XHTML 和 XML,可以直接在 HTML 文件中嵌入模板表达式,这使得前端开发人员能够更方便地进行模板的编写和维护。在性能方面,虽然 Thymeleaf 略逊于 Velocity 和 Freemarker,但随着版本的不断更新,其性能也在逐步提升。Thymeleaf 与 Spring Boot 的集成非常紧密,是 Spring Boot 默认推荐的模板引擎,这使得在 Spring Boot 项目中使用 Thymeleaf 变得非常便捷。

综合考虑家政平台消息通知系统的需求,Thymeleaf 更适合。其简洁的语法和与 Spring Boot 的紧密集成,能够降低开发成本,提高开发效率。同时,虽然性能略逊一筹,但在消息通知系统的应用场景下,其性能表现能够满足需求。

2.2.2 通知模板设计原则

通知模板应简洁明了,避免使用过于复杂的语言和结构。模板中的文字应通俗易懂,让用户能够快速理解通知的核心内容。在服务流程通知中,避免使用过多的专业术语,用简洁的语言描述服务的状态和相关信息。

模板的结构和代码应易于维护,方便开发人员在后期进行修改和扩展。将不同的通知内容模块化,每个模块负责生成特定类型的通知。这样,当业务需求发生变化时,只需修改相应的模块,而不会影响到整个通知系统。

通知模板要能够支持动态数据的填充,根据不同的业务场景和用户信息,生成个性化的通知内容。在服务流程通知模板中,设置模板变量如servicePersonName、{serviceTime} 等,在生成通知时,通过传入实际的业务数据,如家政人员姓名、服务时间等,实现通知内容的动态生成。以服务即将开始的通知模板为例:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>服务即将开始通知</title>
</head>
<body><p>您好,距离您预约的[[${serviceItem}]]开始时间还有1小时,家政人员[[${servicePersonName}]]将按时上门服务。</p><p>服务信息如下:[[${serviceDetails}]],请您保持电话畅通,以便服务人员与您联系。</p>
</body>
</html>

在上述模板中,通过[[${serviceItem}]]、[[${servicePersonName}]]、[[${serviceDetails}]]等模板变量,实现了服务项目、家政人员姓名、服务详情等动态数据的填充。

2.2.3 模板管理与更新

设计一个通知模板管理界面,运营人员可以在该界面中创建新的通知模板。在创建过程中,提供可视化的编辑工具,让运营人员能够方便地编辑模板的内容、结构和样式。同时,设置模板类型、模板名称等属性,便于对模板进行分类管理。

当业务需求发生变化或需要优化通知内容时,运营人员可以在管理界面中对已有的通知模板进行编辑。编辑完成后,保存模板并进行版本控制,记录每次编辑的时间、编辑人员和编辑内容。这样,在需要时可以追溯模板的历史版本,查看模板的变更记录。

采用版本控制机制,为每个通知模板分配唯一的版本号。当模板发生变更时,版本号自动递增。在生成通知时,根据模板的版本号选择最新的模板进行渲染。同时,提供模板版本对比功能,让运营人员能够直观地查看不同版本模板之间的差异,便于进行模板的管理和维护。

三、通知发送与管理机制设计

3.1 通知队列与异步发送设计

在消息通知系统中,通知发送的效率和稳定性至关重要。引入通知队列和异步发送机制,可以有效提高系统的响应速度,避免因发送通知导致业务阻塞,从而提升用户体验。

3.1.1 消息队列选型

常见的消息队列有 RabbitMQ、Kafka、ActiveMQ 等,它们在可靠性、性能、功能特性等方面各有优劣,适用于不同的场景。

  • RabbitMQ 遵循 AMQP 标准,提供了可靠的消息传输。它支持多种消息模式,如路由、主题、扇出、RPC 等,灵活性极高。通过镜像队列等方式,RabbitMQ 能够实现集群部署,保障消息不丢失,具有高可用性。在需要复杂消息路由逻辑的场景,如家政平台中不同类型通知的分发,RabbitMQ 能很好地满足需求。它也常用于微服务架构中,作为微服务间通信的桥梁,实现服务解耦。

  • Kafka 具有高吞吐量的特点,特别适合处理大规模数据流,如日志收集、实时数据处理等场景。它天然支持分布式部署,易于水平扩展,并且消息持久化能力强,支持长时间存储。基于发布 / 订阅模式,Kafka 支持主题和分区的概念,适合一对多的消息发布。对于大数据处理场景,Kafka 常与 Hadoop、Spark 集成,进行离线分析或实时流处理 。但在处理少量、频繁的通知消息时,Kafka 的优势并不明显。

  • ActiveMQ 是 JMS 规范的实现,成熟稳定,历史悠久,适合 Java 生态。它支持多种协议,除了 JMS,还支持 AMQP、STOMP 等。ActiveMQ 功能丰富,提供消息持久化、事务支持、多种消息模式。在传统企业应用中,特别是需要遵循 JMS 标准的 Java 应用,ActiveMQ 应用广泛。在金融、电信等对稳定性要求高的行业,因其成熟稳定,也常用于这些领域的消息传输。

综合考虑家政平台通知系统的需求,RabbitMQ 更适合。家政平台的通知消息量相对不是特别巨大,但对消息的可靠性和路由灵活性要求较高。RabbitMQ 的高可用性和丰富的消息模式,能够确保通知消息准确无误地发送到目标用户,并且可以根据不同的业务场景进行灵活的路由。

3.1.2 通知队列的实现

以 RabbitMQ 为例,在 Spring Boot 项目中实现通知队列,首先需要在 pom.xml 文件中添加 Spring Boot Starter AMQP 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

然后在 application.yml 文件中配置 RabbitMQ 的连接信息:

spring:rabbitmq:host: your-rabbitmq-hostport: 5672username: your-usernamepassword: your-password

接下来创建配置类,用于声明交换机、队列和绑定关系:

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {@Beanpublic TopicExchange notificationExchange() {return new TopicExchange("notification-exchange");}@Beanpublic Queue notificationQueue() {return new Queue("notification-queue");}@Beanpublic Binding binding() {return BindingBuilder.bind(notificationQueue()).to(notificationExchange()).with("notification.#");}
}

在上述代码中,创建了一个主题交换机notification-exchange和一个队列notification-queue,并通过BindingBuilder将队列绑定到交换机上,路由键为notification.#,表示匹配以notification.开头的所有路由键。

在发送通知消息时,通过RabbitTemplate将消息发送到队列中:

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class NotificationSender {@Autowiredprivate RabbitTemplate rabbitTemplate;public void send(String message) {rabbitTemplate.convertAndSend("notification-exchange", "notification.message", message);}
}

在消费者端,通过@RabbitListener注解监听队列中的消息,并进行发送处理:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class NotificationReceiver {@RabbitListener(queues = "notification-queue")public void receive(String message) {// 处理通知消息,调用短信发送、推送通知等方法System.out.println("Received message: " + message);}
}

3.1.3 异步发送的优势与实现细节

异步发送通知能够显著提升系统性能。在传统的同步发送方式下,当系统处理一个业务请求并需要发送通知时,业务线程需要等待通知发送完成后才能继续执行后续操作。如果通知发送过程中出现网络延迟、服务响应慢等问题,业务线程将被长时间阻塞,导致系统响应速度变慢,用户等待时间过长。而异步发送通知,业务线程只需将通知消息发送到队列中,即可立即返回继续执行其他任务,无需等待通知的实际发送结果。这样可以大大提高系统的并发处理能力,使系统能够快速响应用户的请求,提升用户体验。

在异步发送过程中,可能会出现消息丢失的问题。比如,当消息发送到队列后,队列所在的服务器突然崩溃,且消息尚未持久化到磁盘,就可能导致消息丢失。为了解决这个问题,可以开启 RabbitMQ 的消息持久化功能。在声明队列和交换机时,将它们的durable属性设置为true,表示持久化。这样,当服务器重启后,队列和交换机依然存在,消息也不会丢失。同时,在发送消息时,将消息的deliveryMode属性设置为2,表示消息持久化到磁盘。

消息重复发送也是异步发送中可能出现的问题。这可能是由于网络波动、消费者处理消息失败后重试等原因导致的。为了解决消息重复发送的问题,可以采用幂等性处理。在消费者端,对每个通知消息进行唯一标识,例如使用 UUID。在处理消息前,先检查该消息是否已经被处理过,如果已经处理过,则直接返回,不再重复处理。可以通过数据库或缓存来记录已处理的消息标识。

3.2 通知记录与状态管理设计

通知记录和状态管理是消息通知系统的重要组成部分,它能够帮助平台对通知发送情况进行全面的跟踪、查询和统计分析,及时发现问题并采取相应的措施,确保通知的有效送达。

3.2.1 通知记录表结构设计

设计通知记录表,用于存储通知的相关信息。表结构如下:

CREATE TABLE `notification_record` (`id` bigint AUTO_INCREMENT PRIMARY KEY,`receiver_id` bigint NOT NULL,`notification_content` text NOT NULL,`send_time` datetime DEFAULT CURRENT_TIMESTAMP,`send_status` tinyint DEFAULT 0,`failure_reason` text,`notification_type` tinyint NOT NULL
);

在上述表结构中,id是主键,用于唯一标识每一条通知记录;receiver_id表示通知的接收者用户 ID;notification_content存储通知的具体内容;send_time记录通知的发送时间;send_status字段表示通知的发送状态,0 表示待发送,1 表示发送中,2 表示发送成功,3 表示发送失败;failure_reason字段用于记录发送失败的原因;notification_type表示通知的类型,如 1 表示短信通知,2 表示站内信通知,3 表示推送通知等。

3.2.2 通知状态管理机制

定义通知的各种状态,如待发送、发送中、发送成功、发送失败等。在通知发送过程中,实时更新通知状态。当通知消息被放入队列中时,将通知状态更新为 “发送中”;当通知成功发送后,将状态更新为 “发送成功”;如果发送失败,将状态更新为 “发送失败”,并记录失败原因。

对于发送失败的通知,根据失败原因和业务需求进行相应的处理。如果是网络问题导致的临时失败,可以设置重试机制,在一定时间间隔后重新发送通知。例如,设置最大重试次数为 3 次,每次重试间隔 1 分钟。当重试次数达到上限后,如果仍然发送失败,则发送告警通知给系统管理员,以便及时排查问题。

3.2.3 通知查询与统计功能实现

实现通知的查询功能,支持根据接收者、时间范围、通知类型等条件进行查询。在后端代码中,通过 MyBatis-Plus 的QueryWrapper构建查询条件,实现灵活的查询操作。例如,根据接收者 ID 和通知类型查询通知记录:

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.NotificationRecord;
import com.example.demo.mapper.NotificationRecordMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class NotificationRecordService {@Autowiredprivate NotificationRecordMapper notificationRecordMapper;public List<NotificationRecord> queryNotifications(long receiverId, int notificationType) {QueryWrapper<NotificationRecord> wrapper = new QueryWrapper<>();wrapper.eq("receiver_id", receiverId);wrapper.eq("notification_type", notificationType);return notificationRecordMapper.selectList(wrapper);}
}

对通知发送数据进行统计分析,能够为系统优化提供有力的数据支持。统计发送成功率,通过计算发送成功的通知数量与总通知数量的比例,了解通知发送的整体效果。分析失败原因分布,统计不同失败原因的通知数量,找出导致通知发送失败的主要因素,针对性地进行优化。可以使用柱状图、饼图等可视化工具,将统计结果直观地展示给系统管理员和运营人员,方便他们进行数据分析和决策。

相关文章:

【家政平台开发(16)】消息通知系统设计:搭建高效沟通桥梁

本【家政平台开发】专栏聚焦家政平台从 0 到 1 的全流程打造。从前期需求分析&#xff0c;剖析家政行业现状、挖掘用户需求与梳理功能要点&#xff0c;到系统设计阶段的架构选型、数据库构建&#xff0c;再到开发阶段各模块逐一实现。涵盖移动与 PC 端设计、接口开发及性能优化…...

AI比人脑更强,因为被植入思维模型【44】成长破圈思维

giszz的理解&#xff1a;芒格说&#xff0c;不懂不投。我们一生都在追求破圈&#xff0c;突破本我&#xff0c;突破舒适圈、恐惧圈、学习圈、成长圈、自在圈&#xff0c;可是我们真正能懂的知识有实际真的太少了。这个思维模型给我的启迪&#xff0c;一是要破圈&#xff0c;二是…...

【JavaWeb-Spring boot】学习笔记

目录 <<回到导览Spring boot1. http协议1.1.请求协议1.2.响应协议 2.Tomcat2.1.请求2.1.1.apifox2.1.2.简单参数2.1.3.实体参数2.1.4.数组集合参数2.1.5.日期参数2.1.6.(重点)JSON参数2.1.7.路径参数 2.2.响应2.3.综合练习 3.三层架构3.1.三层拆分3.2.分层解耦3.3.补充 &…...

基于GitLab+Jenkins的持续集成实践指南

架构设计原则 分层自动化策略 基础层: 代码提交触发自动构建(100%自动化)中间层: 制品生成与验证(自动化+人工审核)发布层: 环境部署(受控手动触发)工具定位矩阵 工具核心职责关键优势GitLab源码管理+MR流程精细的权限控制Jenkins流水线编排+任务调度插件生态丰富Nexus制…...

用HTML.CSS.JavaScript实现一个贪吃蛇小游戏

目录 一、引言二、实现思路1. HTML 结构2. CSS 样式3. JavaScript 逻辑 三、代码实现四、效果展示 一、引言 贪吃蛇是一款经典的小游戏&#xff0c;曾经风靡一时。今天&#xff0c;我们将使用 HTML、CSS 和 JavaScript 来实现一个简单的贪吃蛇小游戏。通过这个项目&#xff0c…...

医疗思维图与数智云融合:从私有云到思维图的AI架构迭代(代码版)

医疗思维图作为AI架构演进的重要方向,其发展路径从传统云计算向融合时空智能、大模型及生态开放的“思维图”架构迭代,体现了技术与场景深度融合的趋势。 以下是其架构迭代的核心路径与关键特征分析: 一、从“智慧云”到“思维图”的架构演进逻辑 以下是针对医疗信息化领域…...

Kafka 中,为什么同一个分区只能由消费者组中的一个消费者消费?

在 Kafka 中&#xff0c;同一个分区只能由消费者组中的一个消费者消费&#xff0c;这是 Kafka 的设计决策之一&#xff0c;目的是保证消息的顺序性和避免重复消费。这背后有几个关键的原因&#xff1a; 1. 保证消息顺序性 Kafka 中的每个 分区&#xff08;Partition&#xff…...

Kafka 中的批次

在 Kafka 中&#xff0c;批次&#xff08;Batch&#xff09; 是生产者发送消息的一个重要概念。它对 Kafka 的性能、吞吐量、延迟等有很大影响。批量处理可以使消息发送更高效&#xff0c;减少网络往返和磁盘写入的开销。 下面我将详细解释 Kafka 中的批次机制&#xff0c;包括…...

《UNIX网络编程卷1:套接字联网API》第7章:套接字选项深度解析

《UNIX网络编程卷1&#xff1a;套接字联网API》第7章&#xff1a;套接字选项深度解析 一、套接字选项核心原理 1.1 选项层级体系 套接字选项按协议层级划分&#xff08;图1&#xff09;&#xff1a; SOL_SOCKET&#xff1a;通用套接字层选项IPPROTO_IP&#xff1a;IPv4协议层…...

使用 pytest-xdist 进行高效并行自化测试

pytest-xdist 是 pytest 的一个扩展插件&#xff0c;主要用于实现测试用例的并行执行和分布式测试。通过利用多进程或者多机分布式的方式&#xff0c;pytest-xdist 能够显著缩短测试执行时间&#xff0c;提升持续集成&#xff08;CI&#xff09;流程的效率。 在自动化测试中&a…...

谈谈策略模式,策略模式的适用场景是什么?

一、什么是策略模式&#xff1f;​​ 策略模式&#xff08;Strategy Pattern&#xff09;属于​​行为型设计模式​​。核心思路是将一组​​可替换的算法​​封装在独立的类中&#xff0c;使它们可以在运行时动态切换&#xff0c;同时使客户端代码与具体算法解耦。它包含三个…...

网络安全防御核心原则与实践指南

一、四大核心防御原则 A. 纵深防御原则&#xff08;Defense in Depth&#xff09; 定义&#xff1a;通过在多个层次&#xff08;如网络、系统、应用、数据&#xff09;设置互补的安全措施&#xff0c;形成多层次防护体系。 目的&#xff1a;防止单一漏洞导致整体安全失效&…...

动态规划2——斐波那契数列模型——三步问题

1.题目 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有 n 阶台阶&#xff0c;小孩一次可以上 1 阶、2 阶或 3 阶。实现一种方法&#xff0c;计算小孩有多少种上楼梯的方式。结果可能很大&#xff0c;你需要对结果模 1000000007。 示例 1&#xff1a; 输入&#xff1a;n 3 …...

周末总结(2024/04/05)

工作 人际关系核心实践&#xff1a; 要学会随时回应别人的善意&#xff0c;执行时间控制在5分钟以内 坚持每天早会打招呼 遇到接不住的话题时拉低自己&#xff0c;抬高别人(无阴阳气息) 朋友圈点赞控制在5min以内&#xff0c;职场社交不要放在5min以外 职场的人际关系在面对利…...

常见的图像生成算法

综合技术原理、优化方向和应用场景&#xff0c;结合经典模型与前沿进展进行分述&#xff1a; 一、经典生成模型 1. 生成对抗网络&#xff08;GAN&#xff09; 原理&#xff1a;由生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;通过…...

PE结构(十五)系统调用与函数地址动态寻找

双机调试 当需要分析一个程序时&#xff0c;这个程序一定是可以调试的&#xff0c;操作系统也不例外。在调试过程中下断点是很重要的 当我们对一个应用程序下断点时&#xff0c;应用程序是挂起的。但当我们对操作系统的内核程序下断点时&#xff0c;被挂起的不是内核程序而是…...

verilog状态机思想编程流水灯

目录 一、状态机1. 状态机基本概念2. 状态机类型3. Verilog 状态机设计要点 二、状态机实现一个1s流水灯三、DE2-115实物演示 一、状态机 1. 状态机基本概念 状态机&#xff08;Finite State Machine, FSM&#xff09;是数字电路设计中用于描述系统状态转换的核心组件&#x…...

Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解

N皇后问题要求在NN的棋盘上放置N个皇后&#xff0c;使得她们无法互相攻击。本文提供递归和循环迭代两种解法&#xff0c;并通过图示解释核心逻辑。 一、算法核心思想 使用回溯法逐行放置皇后&#xff0c;通过冲突检测保证每行、每列、对角线上只有一个皇后。发现无效路径时回退…...

#SVA语法滴水穿石# (000)断言基本概念和背景

一、前言 随着数字电路规模越来越大、设计越来越复杂,使得对设计的功能验证越来越重要。首先,我们要明白为什么要对设计进行验证?验证有什么作用?例如,在用FPGA进行设计时,我们并不能确保设计出来的东西没有功能上的漏洞,因此在设计后我们都会对其进行验证仿真。换句话说…...

【Android Studio 下载 Gradle 失败】

路虽远行则将至&#xff0c;事虽难做则必成 一、事故现场 下载Gradle下载不下来&#xff0c;没有Gradle就无法把项目编译为Android应用。 二、问题分析 观察发现下载时长三分钟&#xff0c;进度条半天没动&#xff0c;说明这个是国外的东西&#xff0c;被墙住了&#xff0c;需…...

贪心算法之Huffman编码

1. 算法推理 Huffman 编码的目标是为给定字符构造一种前缀码&#xff0c;使得整体编码长度最短。基本思想是&#xff1a; 贪心选择&#xff1a;每次选择频率最小的两个节点合并。合并后的节点的权值为两个子节点权值之和&#xff0c;代表这部分子树出现的总频率。 局部最优导…...

Flask学习笔记 - 表单

表单处理 基本表单处理&#xff1a;使用 request.form 获取表单数据。使用 Flask-WTF&#xff1a;结合 WTForms 进行表单处理和验证&#xff0c;简化表单操作。表单验证&#xff1a;使用验证器确保表单数据的有效性。文件上传&#xff1a;处理文件上传和保存文件。CSRF 保护&a…...

指针的补充(用于学习笔记的记录)

1.指针基础知识 1.1 指针变量的定义和使用 指针也是一种数据类型&#xff0c;指针变量也是一种变量 指针变量指向谁&#xff0c;就把谁的地址赋值给指针变量 #include<stdio.h>int main() {int a 0;char b 100;printf("%p,%p \n", &a,&b); // …...

【mongodb】mongodb的字段类型

目录 1. 基本数据类型1.1 String1.2 Number1.3 Boolean1.4 Date1.5 Null1.6 ObjectId1.7 Array1.8 Binary Data1.9 Object 2. 特殊数据类型2.1 Regular Expression2.2 JavaScript2.3 Symbol2.4 Decimal1282.5 Timestamp2.6 MinKey/MaxKey2.7 DBPointer 3. 常用字段类型示例4. 注…...

计算机视觉图像处理基础系列:滤波、边缘检测与形态学操作

计算机视觉图像处理基础系列&#xff1a;滤波、边缘检测与形态学操作 一、前言二、滤波&#xff1a;图像的精细化处理​2.1 滤波基础概念​2.1.1 滤波的本质​2.1.2 图像噪声来源与类型​ 2.2 线性滤波​2.2.1 均值滤波​2.2.2 高斯滤波​ 2.3 非线性滤波​2.3.1 中值滤波​ 三…...

实用的alias别名命令——比2=1+1简单的基础命令

目录 alias命令的用处alias命令的写法让alias别名永久存在的办法下篇预告 alias命令的用处 别名&#xff0c;就是linux系统中的命令的别称&#xff0c;而alias命令&#xff0c;可以显示linux系统当前设定的全部别名&#xff0c;当然&#xff0c;也可以自己定义一个别名。 ali…...

JAVA单例模式

目录 一、什么是单例模式&#xff1a; 二、饿汉模式&#xff1a; 代码示例&#xff1a; 饿汉模式的特点&#xff1a; 三、懒汉模式&#xff1a; 正确代码示例&#xff08;双重检查锁&#xff09;&#xff1a; 一、什么是单例模式&#xff1a; 一个类&#xff0c;在语法角度…...

k8s安装cri驱动创建storageclass动态类

部署nfs服务器 #所有k8s节点安装nfs客户端 yum install -y nfs-utils mkdir -p /nfs/share echo "/nfs/share *(rw,sync,no_root_squash)" >> /etc/exports systemctl enable --now nfs-serverhelm部署nfs的provisioner&sc 所有k8s节点安装客户端 yu…...

嵌入式Linux驱动—— 1 GPIO配置

目录 1.GPIO操作 1.1 IO命名 1.2 GPIO 时钟使能&#xff08;CCM&#xff09; 1.3 IO 复用&#xff08;IOMUXC&#xff09; 1.4 IO 配置 1.5 GPIO 配置 1.GPIO操作 GPIO操作主要是以下流程&#xff1a; 使能某组GPIO模块&#xff08;GPIO1、2、...&#xff09;&#…...

【C++11】lambda

lambda lambda表达式语法 lambda表达式本质是一个匿名函数对象&#xff0c;跟普通函数不同的是它可以定义在函数内部。lambda表达式语法使用层而言没有类型&#xff0c;所以一般是用auto或者模板参数定义的对象去接收lambda对象。 lambda表达式的格式&#xff1a;[capture-l…...

自旋锁(C++实现)

1 简介 自旋锁是一种典型的无锁算法&#xff0c;在任何时刻&#xff0c;它都最多只能有一个保持者。当有一个线程试图获得一个已经被占用的锁时&#xff0c;该线程就会一直进行循环等待&#xff0c;直到该锁被释放。自旋锁的优点是不会使线程状态发生切换&#xff0c;一直处于用…...

python基础-11-调试程序

文章目录 【README】【11】调试【11.1】抛出异常【11.1.1】抛出异常代码块 【11.2】获取回溯字符串【11.2.1】traceback获取异常回溯信息 【11.3】断言【11.3.1】断言代码示例 【11.4】日志&#xff08;使用logging模块&#xff09;【11.4.1】使用logging模块操作日志【11.4.3】…...

我的创作历程:从不情愿到主动分享的成长

&#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 二、转变&#xff1a;从被动到主动的心路历程 三、挑战&#xff1a;时间的压力与写作的坚持 四、收获&#xff1a;分享与成长 五、展望…...

uniapp地图导航及后台百度地图回显(v2/v3版本)

百度地图申请地址&#xff1a;控制台 | 百度地图开放平台 效果&#xff1a; 1.后台 1.1申请百度地图APi 1.2 引入百度地图 <script type"text/javascript" src"//api.map.baidu.com/api?v3.0&ak自己百度生气apikey"></script> 1.3 v2组…...

多layout 布局适配

安卓多布局文件适配方案操作流程 以下为通过多套布局文件适配不同屏幕尺寸/密度的详细步骤&#xff0c;结合主流适配策略及最佳实践总结&#xff1a; 一、‌创建多套布局资源目录‌ ‌按屏幕尺寸划分‌ 在 res 目录下创建以下文件夹&#xff08;根据设备特性自动匹配&#xff…...

马斯克 AI 超算

超算建设情况&#xff1a;马斯克旗下人工智能初创公司 xAI 正在田纳西州孟菲斯市建造世界上最大的超级计算机2。自 2024 年 6 月首次宣布这笔工程以来&#xff0c;xAI 已向当地规划和发展机构提交了 14 份施工许可申请&#xff0c;合计代表了 4.059 亿美元的预计项目成本2。该超…...

大模型学习四:‌DeepSeek Janus-Pro 多模态理解和生成模型 本地部署指南(折腾版)

一、说明简介 ‌DeepSeek Janus-Pro‌是一款先进的多模态理解和生成模型&#xff0c;旨在实现高质量的文本-图像生成与多模态理解。它是由DeepSeek团队研发的&#xff0c;是之前Janus模型的升级版&#xff0c;能够同时处理文本和图像&#xff0c;即可以理解图片内容&#xff0c…...

《AI大模型应知应会100篇》第3篇:大模型的能力边界:它能做什么,不能做什么

第3篇&#xff1a;大模型的能力边界&#xff1a;它能做什么&#xff0c;不能做什么 摘要 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;LLM&#xff09;已经成为许多领域的核心技术。然而&#xff0c;尽管它们展现出了惊人的能力&#xff0c;但也有明显的局限性…...

MySQL 面试知识点详解(索引、存储引擎、事务与隔离级别、MVCC、锁机制、优化)

一、索引基础概念 1 索引是什么&#xff1f; 定义&#xff1a;索引是帮助MySQL高效获取数据的有序数据结构&#xff0c;类似书籍的目录。核心作用&#xff1a;减少磁盘I/O次数&#xff0c;提升查询速度&#xff08;以空间换时间&#xff09;。 2 索引的优缺点 优点缺点加速…...

JS API

const变量优先 即对象、数组等引用类型数据可以用const声明 API作用和分类 DOM (ducument object model) 操作网页内容即HTML标签的 树状模型 HTML中标签 JS中对象 最大对象 document 其次大 html 以此类推 获取DOM对象 CSS 中 使用选择器 JS 中 选多个 时代的眼泪 修…...

hackmyvm-Principle

近况: 很难受、 也很累。 但是庆幸靶机很好 正值清明时节 清明时节雨纷纷 &#x1f327;️&#xff0c;路上行人欲断魂 &#x1f622;。 靶机地址 信息收集 主机发现 端口扫描 80端口仅仅是一个nginx 的欢迎界面而已 robots.txt的内容 hi.html的内容 hackme不存在 investigat…...

小刚说C语言刷题——第14讲 逻辑运算符

当我们需要将一个表达式取反&#xff0c;或者要判断两个表达式组成的大的表达式的结果时&#xff0c;要用到逻辑运算符。 1.逻辑运算符的分类 (1)逻辑非(!) &#xff01;a&#xff0c;当a为真时&#xff0c;&#xff01;a为假。当a为假时&#xff0c;&#xff01;a为真。 例…...

池化技术的深度解析与实践指南【大模型总结】

池化技术的深度解析与实践指南 池化技术作为计算机系统中的核心优化手段&#xff0c;通过资源复用和预分配机制显著提升系统性能。本文将从原理、实现到最佳实践&#xff0c;全方位剖析池化技术的核心要点&#xff0c;并结合实际案例说明其应用场景与调优策略。 一、池化技术的…...

基于Java的区域化智慧养老系统(源码+lw+部署文档+讲解),源码可白嫖!

摘 要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;区域化智慧养老系统当然不能排除在外。区域化智慧养老系统是在实际应用和软件工程的开发原理之上&#xff0c;运用Java语言、JSP技术以及…...

2025年3月 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试

2025.03 Scratch图形化编程等级考试一级真题试卷 一、选择题 第 1 题 气球初始位置如下图所示&#xff0c;scratch运行下列程序&#xff0c;气球会朝哪个方向移动&#xff1f;&#xff08; &#xff09; A.水平向右 B.垂直向下 C.水平向左 D.垂直向上 答案&#xff1a…...

Docker 命令简写配置

alias dpsdocker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" 配置好后&#xff0c;需要输入&#xff1a; source ~/.bashrc 后生效...

linux signal up/down/down_interruptiable\down_uninterruptiable使用

在Linux内核中&#xff0c;down, down_interruptible, down_killable, 和 up 是用于操作信号量&#xff08;semap hores&#xff09;的函数&#xff0c;它们用于进程同步和互斥。以下是对这些函数的简要说明。 1&#xff0c;down(&sem): 这个函数用于获取信号量。如果信号…...

【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】

嵌入式-stm32电位器控制LED亮暗 任务1代码1Key.cKey.hTimer.cTimer.hPWM.cPWM.hmain.c 实验现象1任务2代码2Key.cKey.hmain.c 实验现象2问题与解决总结 源码框架取自江协科技&#xff0c;在此基础上做扩展开发。 任务1 本文主要介绍利用stm32f103C8T6实现电位器控制PWM的占空比…...

Mysql 中 ACID 背后的原理

在 MySQL 中&#xff0c;ACID 是事务处理的核心原则&#xff0c;用于保证数据库在执行事务时的可靠性、数据一致性和稳定性。ACID 是四个关键特性的首字母缩写&#xff0c;分别是&#xff1a;Atomicity&#xff08;原子性&#xff09;、Consistency&#xff08;一致性&#xff…...

【算法】简单数论

模运算 a m o d b a − ⌊ a / b ⌋ b a\ mod \ b a - \lfloor a / b \rfloor \times b a mod ba−⌊a/b⌋b n m o d p n \ mod\ p n mod p得到的结果的正负至于被除数 n n n有关 模运算的性质&#xff1a; ( a b ) m o d m ( ( a m o d m ) ( b m o d m ) ) m o d m …...