From 2fa61b350c9b055779a6470912b461188feb83e9 Mon Sep 17 00:00:00 2001
From: caozehui <2427765068@qq.com>
Date: Fri, 13 Mar 2026 08:49:45 +0800
Subject: [PATCH] =?UTF-8?q?=E9=BB=91=E5=90=8D=E5=8D=95=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E8=AE=BF=E9=97=AE=E5=B1=82=E3=80=81=E6=9C=8D=E5=8A=A1=E5=B1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../msgpush-module-push-server/pom.xml | 4 ++
.../push/checker/MsgPushGuardChain.java | 2 -
.../push/checker/impl/IdempotencyChecker.java | 16 -----
.../push/client/ClientConfiguration.java | 28 ++++----
.../module/push/constant/MsgPushConstant.java | 7 --
.../admin/blacklist/BlacklistController.java | 61 +++++++++++++++++
.../admin/blacklist/vo/BlacklistReqVO.java | 65 +++++++++++++++++++
.../ChannelProviderConfigController.java | 21 +++---
.../message/MessageRecordController.java | 3 +
.../dal/dataobject/blacklist/BlacklistDO.java | 60 +++++++++++++++++
.../dal/mysql/blacklist/BlacklistMapper.java | 13 ++++
.../ProviderErrorCodeMappingMappper.java | 2 +
.../push/enums/BlacklistSourceEnum.java | 35 ++++++++++
.../module/push/enums/ChannelTypeEnum.java | 38 +++++++++++
.../module/push/enums/ProviderTypeEnum.java | 36 ++++++++++
.../service/blacklist/BlacklistService.java | 14 ++++
.../blacklist/BlacklistServiceImpl.java | 25 +++++++
.../message/MessageRecordServiceImpl.java | 10 +--
.../retry/MessageRetryQueueServiceImpl.java | 10 +--
.../module/push/sms/MsgPushClientTest.java | 9 +--
20 files changed, 390 insertions(+), 69 deletions(-)
delete mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/impl/IdempotencyChecker.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/BlacklistController.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/vo/BlacklistReqVO.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/dataobject/blacklist/BlacklistDO.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/blacklist/BlacklistMapper.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/BlacklistSourceEnum.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ChannelTypeEnum.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ProviderTypeEnum.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistService.java
create mode 100644 msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistServiceImpl.java
diff --git a/msgpush-module-push/msgpush-module-push-server/pom.xml b/msgpush-module-push/msgpush-module-push-server/pom.xml
index cf1eea4..60f59b0 100644
--- a/msgpush-module-push/msgpush-module-push-server/pom.xml
+++ b/msgpush-module-push/msgpush-module-push-server/pom.xml
@@ -125,6 +125,10 @@
restful-sdk
1.0.0.1
+
+ com.njcn
+ msgpush-spring-boot-starter-protection
+
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/MsgPushGuardChain.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/MsgPushGuardChain.java
index 3ab56b7..f9c22cd 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/MsgPushGuardChain.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/MsgPushGuardChain.java
@@ -1,7 +1,6 @@
package com.njcn.msgpush.module.push.checker;
import com.njcn.msgpush.module.push.checker.impl.BlacklistChecker;
-import com.njcn.msgpush.module.push.checker.impl.IdempotencyChecker;
import com.njcn.msgpush.module.push.checker.impl.QuotaChecker;
import com.njcn.msgpush.module.push.checker.impl.RateLimitChecker;
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordReqVO;
@@ -19,7 +18,6 @@ public class MsgPushGuardChain {
public MsgPushGuardChain() {
this.checkers = new ArrayList<>();
- this.checkers.add(new IdempotencyChecker());
this.checkers.add(new BlacklistChecker());
this.checkers.add(new QuotaChecker());
this.checkers.add(new RateLimitChecker());
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/impl/IdempotencyChecker.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/impl/IdempotencyChecker.java
deleted file mode 100644
index b5937cf..0000000
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/checker/impl/IdempotencyChecker.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.njcn.msgpush.module.push.checker.impl;
-
-import com.njcn.msgpush.module.push.checker.IChecker;
-import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordReqVO;
-
-/**
- * @author caozehui
- * @data 2026-02-27
- * @description 接口幂等性检查器
- */
-public class IdempotencyChecker implements IChecker {
- @Override
- public boolean check(MessageRecordReqVO reqVO) {
- return true;
- }
-}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/client/ClientConfiguration.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/client/ClientConfiguration.java
index ee6b6ee..662224c 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/client/ClientConfiguration.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/client/ClientConfiguration.java
@@ -4,18 +4,12 @@ import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.AliyunProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.TelecomProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.UniPushProviderFactory;
-import com.njcn.msgpush.module.push.client.sender.Sender;
-import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
-import com.njcn.msgpush.module.push.dal.mysql.channel.ChannelProviderConfigMapper;
+import com.njcn.msgpush.module.push.enums.ProviderTypeEnum;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
-import com.njcn.msgpush.module.push.service.channel.ProviderErrorCodeMappingService;
-import com.njcn.msgpush.module.push.service.retry.MessageRetryQueueService;
-import com.njcn.msgpush.module.push.util.RestTemplateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
import java.util.HashMap;
import java.util.List;
@@ -37,20 +31,20 @@ public class ClientConfiguration {
Map messageProviderFactoryMap = new HashMap<>();
for (ChannelProviderConfigDO config : activeProviders) {
- switch (config.getProviderType()) {
- case MsgPushConstant.PROVIDER_TYPE_ALI_YUN: {
- MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_ALI_YUN, new AliyunProviderFactory());
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_ALI_YUN, orDefault);
+ switch (ProviderTypeEnum.getByCode(config.getProviderType())) {
+ case ALIYUN: {
+ MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(ProviderTypeEnum.ALIYUN.getCode(), new AliyunProviderFactory());
+ messageProviderFactoryMap.put(ProviderTypeEnum.ALIYUN.getCode(), orDefault);
}
break;
- case MsgPushConstant.PROVIDER_TYPE_TELECOM: {
- MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_TELECOM, new TelecomProviderFactory());
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_TELECOM, orDefault);
+ case TELECOM: {
+ MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(ProviderTypeEnum.TELECOM.getCode(), new TelecomProviderFactory());
+ messageProviderFactoryMap.put(ProviderTypeEnum.TELECOM.getCode(), orDefault);
}
break;
- case MsgPushConstant.PROVIDER_TYPE_UNI_PUSH: {
- MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(MsgPushConstant.PROVIDER_TYPE_UNI_PUSH, new UniPushProviderFactory());
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_UNI_PUSH, orDefault);
+ case UNIPUSH: {
+ MessageProviderFactory orDefault = messageProviderFactoryMap.getOrDefault(ProviderTypeEnum.UNIPUSH.getCode(), new UniPushProviderFactory());
+ messageProviderFactoryMap.put(ProviderTypeEnum.UNIPUSH.getCode(), orDefault);
}
break;
default:
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/constant/MsgPushConstant.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/constant/MsgPushConstant.java
index a0e7715..ad3fa00 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/constant/MsgPushConstant.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/constant/MsgPushConstant.java
@@ -5,13 +5,6 @@ package com.njcn.msgpush.module.push.constant;
* @data 2026-02-11
*/
public class MsgPushConstant {
- public static final String PROVIDER_TYPE_ALI_YUN = "aliyun";
- public static final String PROVIDER_TYPE_TELECOM = "telecom";
- public static final String PROVIDER_TYPE_UNI_PUSH = "uniPush";
-
- public static final String CHANNEL_SMS = "sms";
- public static final String CHANNEL_EMAIL = "email";
- public static final String CHANNEL_APP_PUSH = "app_push";
public static final String ERROR_MSG_UNKNOWN = "未知错误";
}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/BlacklistController.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/BlacklistController.java
new file mode 100644
index 0000000..04d8c1c
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/BlacklistController.java
@@ -0,0 +1,61 @@
+package com.njcn.msgpush.module.push.controller.admin.blacklist;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.njcn.msgpush.framework.common.pojo.CommonResult;
+import com.njcn.msgpush.module.push.controller.admin.blacklist.vo.BlacklistReqVO;
+import com.njcn.msgpush.module.push.dal.dataobject.blacklist.BlacklistDO;
+import com.njcn.msgpush.module.push.service.blacklist.BlacklistService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@RestController("/push/blacklist")
+public class BlacklistController {
+ @Autowired
+ private BlacklistService blacklistService;
+
+ @PostMapping("/page")
+ @Operation(summary = "分页查询黑名单列表")
+ @PreAuthorize("@ss.hasPermission('push:blacklist:page')")
+ public CommonResult> pageBlacklist(@Validated @RequestBody BlacklistReqVO reqVO) {
+ Page res = blacklistService.getPage(reqVO);
+ return success(res);
+ }
+
+ @PostMapping("/add")
+ @Operation(summary = "添加黑名单")
+ @PreAuthorize("@ss.hasPermission('push:blacklist:add')")
+ public CommonResult add(@RequestBody BlacklistReqVO reqVO) {
+ return CommonResult.success(blacklistService.save(BeanUtil.copyProperties(reqVO, BlacklistDO.class)));
+ }
+
+ @PostMapping("/update")
+ @Operation(summary = "更新黑名单")
+ @PreAuthorize("@ss.hasPermission('push:blacklist:update')")
+ public CommonResult update(@RequestBody BlacklistReqVO reqVO) {
+ return CommonResult.success(blacklistService.updateById(BeanUtil.copyProperties(reqVO, BlacklistDO.class)));
+ }
+
+ @PostMapping("/delete")
+ @Operation(summary = "删除黑名单")
+ @PreAuthorize("@ss.hasPermission('push:blacklist:delete')")
+ @Parameter(name = "ids", description = "id列表", required = true)
+ public CommonResult delete(@RequestParam("ids") List ids){
+ return CommonResult.success(blacklistService.removeByIds(ids));
+ }
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/vo/BlacklistReqVO.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/vo/BlacklistReqVO.java
new file mode 100644
index 0000000..dcbacbb
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/blacklist/vo/BlacklistReqVO.java
@@ -0,0 +1,65 @@
+package com.njcn.msgpush.module.push.controller.admin.blacklist.vo;
+
+import com.njcn.msgpush.framework.common.pojo.PageParam;
+import com.njcn.msgpush.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Data
+@Schema(description = "管理后台 - 黑名单 Request VO")
+public class BlacklistReqVO extends PageParam {
+
+ /**
+ * 主键 ID
+ */
+ @Schema(description = "主键 ID", example = "123444")
+ private Long id;
+
+ /**
+ * 渠道类型:sms/email/app_push
+ */
+ @Schema(description = "渠道类型:sms/email/app_push", example = "sms")
+ @InEnum(value = com.njcn.msgpush.module.push.enums.ChannelTypeEnum.class, message = "渠道类型必须是 {value}")
+ private String channel;
+
+ /**
+ * 黑名单目标:手机号/邮箱/设备 Token
+ */
+ @Schema(description = "黑名单目标:手机号/邮箱/设备 Token", example = "15601691000")
+ @NotBlank(message = "黑名单目标不能为空")
+ private String target;
+
+ /**
+ * 加入原因:用户投诉/无效号码/频繁退订等
+ */
+ @Schema(description = "加入原因:用户投诉/无效号码/频繁退订等", example = "用户投诉")
+ private String reason;
+
+ /**
+ * 操作来源:manual/auto/import
+ */
+ @Schema(description = "操作来源:manual/auto/import", example = "manual")
+ @InEnum(value = com.njcn.msgpush.module.push.enums.BlacklistSourceEnum.class, message = "操作来源必须是 {value}")
+ private String source;
+
+ /**
+ * 过期时间:-1=永久,时间戳=到期时间
+ */
+ @Schema(description = "过期时间:-1=永久,时间戳=到期时间", example = "15601691000")
+ @NotNull(message = "过期时间不能为空")
+ @Min(value = -1L, message = "过期时间不能小于 -1")
+ private Long expireTime;
+
+ /**
+ * 备注
+ */
+ @Schema(description = "备注", example = "备注信息")
+ private String remark;
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/channel/ChannelProviderConfigController.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/channel/ChannelProviderConfigController.java
index 8105e0f..3f84d87 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/channel/ChannelProviderConfigController.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/channel/ChannelProviderConfigController.java
@@ -7,15 +7,10 @@ import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.AliyunProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.TelecomProviderFactory;
import com.njcn.msgpush.module.push.client.factory.impl.UniPushProviderFactory;
-import com.njcn.msgpush.module.push.client.sender.Sender;
-import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.controller.admin.channel.vo.ChannelProviderConfigReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
+import com.njcn.msgpush.module.push.enums.ProviderTypeEnum;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
-import com.njcn.msgpush.module.push.service.channel.ProviderErrorCodeMappingService;
-import com.njcn.msgpush.module.push.service.message.MessageRecordService;
-import com.njcn.msgpush.module.push.service.retry.MessageRetryQueueService;
-import com.njcn.msgpush.module.push.util.RestTemplateUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -100,17 +95,17 @@ public class ChannelProviderConfigController {
* @param providerType 服务商类型,例如:aliyun\telecom\UniPush
*/
public void registerProviderBean(String providerType) {
- switch (providerType) {
- case MsgPushConstant.PROVIDER_TYPE_ALI_YUN: {
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_ALI_YUN, new AliyunProviderFactory());
+ switch (ProviderTypeEnum.getByCode(providerType)) {
+ case ALIYUN: {
+ messageProviderFactoryMap.put(ProviderTypeEnum.ALIYUN.getCode(), new AliyunProviderFactory());
}
break;
- case MsgPushConstant.PROVIDER_TYPE_TELECOM: {
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_TELECOM, new TelecomProviderFactory());
+ case TELECOM: {
+ messageProviderFactoryMap.put(ProviderTypeEnum.TELECOM.getCode(), new TelecomProviderFactory());
}
break;
- case MsgPushConstant.PROVIDER_TYPE_UNI_PUSH: {
- messageProviderFactoryMap.put(MsgPushConstant.PROVIDER_TYPE_UNI_PUSH, new UniPushProviderFactory());
+ case UNIPUSH: {
+ messageProviderFactoryMap.put(ProviderTypeEnum.UNIPUSH.getCode(), new UniPushProviderFactory());
}
break;
default:
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/message/MessageRecordController.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/message/MessageRecordController.java
index 0cd7325..7478d2a 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/message/MessageRecordController.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/controller/admin/message/MessageRecordController.java
@@ -2,6 +2,7 @@ package com.njcn.msgpush.module.push.controller.admin.message;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
+import com.njcn.msgpush.framework.idempotent.core.annotation.Idempotent;
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
@@ -18,6 +19,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
@@ -33,6 +35,7 @@ public class MessageRecordController {
@PermitAll
@PostMapping("/send")
@Operation(summary = "消息推送")
+ @Idempotent(timeout = 60)
public CommonResult send(@Valid @RequestBody List reqVOList) {
Boolean result = messageRecordService.send(reqVOList);
return CommonResult.success(result);
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/dataobject/blacklist/BlacklistDO.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/dataobject/blacklist/BlacklistDO.java
new file mode 100644
index 0000000..a95bb38
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/dataobject/blacklist/BlacklistDO.java
@@ -0,0 +1,60 @@
+package com.njcn.msgpush.module.push.dal.dataobject.blacklist;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.njcn.msgpush.framework.mybatis.core.dataobject.BaseDO;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Data
+@TableName("push_message_blacklist")
+public class BlacklistDO extends BaseDO {
+ /**
+ * 主键 ID
+ */
+ private Long id;
+
+ /**
+ * 渠道类型:sms/email/app_push
+ */
+ private String channel;
+
+ /**
+ * 黑名单目标:手机号/邮箱/设备 Token
+ */
+ private String target;
+
+ /**
+ * 加入原因:用户投诉/无效号码/频繁退订等
+ */
+ private String reason;
+
+ /**
+ * 操作来源:manual/auto/import
+ */
+ private String source;
+
+ /**
+ * 过期时间:-1=永久,时间戳=到期时间
+ */
+ private Long expireTime;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 命中次数
+ */
+ private Integer hitCount;
+
+ /**
+ * 最近命中时间
+ */
+ private LocalDateTime lastHitTime;
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/blacklist/BlacklistMapper.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/blacklist/BlacklistMapper.java
new file mode 100644
index 0000000..b359370
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/blacklist/BlacklistMapper.java
@@ -0,0 +1,13 @@
+package com.njcn.msgpush.module.push.dal.mysql.blacklist;
+
+import com.njcn.msgpush.framework.mybatis.core.mapper.BaseMapperX;
+import com.njcn.msgpush.module.push.dal.dataobject.blacklist.BlacklistDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Mapper
+public interface BlacklistMapper extends BaseMapperX {
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/channel/ProviderErrorCodeMappingMappper.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/channel/ProviderErrorCodeMappingMappper.java
index 92a0816..d8deb2c 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/channel/ProviderErrorCodeMappingMappper.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/dal/mysql/channel/ProviderErrorCodeMappingMappper.java
@@ -2,10 +2,12 @@ package com.njcn.msgpush.module.push.dal.mysql.channel;
import com.njcn.msgpush.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ProviderErrorCodeMappingDO;
+import org.apache.ibatis.annotations.Mapper;
/**
* @author caozehui
* @data 2026-03-02
*/
+@Mapper
public interface ProviderErrorCodeMappingMappper extends BaseMapperX {
}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/BlacklistSourceEnum.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/BlacklistSourceEnum.java
new file mode 100644
index 0000000..12e7b24
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/BlacklistSourceEnum.java
@@ -0,0 +1,35 @@
+package com.njcn.msgpush.module.push.enums;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.njcn.msgpush.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Getter
+@AllArgsConstructor
+public enum BlacklistSourceEnum implements ArrayValuable {
+ MANUAL("manual", "手动"),
+ AUTO("auto", "自动"),
+ IMPORT("import", "导入");
+
+ public static final String[] ARRAYS = Arrays.stream(values()).map(BlacklistSourceEnum::getCode).toArray(String[]::new);
+
+
+ private String code;
+ private String msg;
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ public static BlacklistSourceEnum getByCode(String code) {
+ return ArrayUtil.firstMatch(blacklistSourceEnum -> blacklistSourceEnum.getCode().equals(code), values());
+ }
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ChannelTypeEnum.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ChannelTypeEnum.java
new file mode 100644
index 0000000..f2281b1
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ChannelTypeEnum.java
@@ -0,0 +1,38 @@
+package com.njcn.msgpush.module.push.enums;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.njcn.msgpush.framework.common.core.ArrayValuable;
+import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
+import com.njcn.msgpush.framework.common.enums.UserTypeEnum;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Getter
+@AllArgsConstructor
+public enum ChannelTypeEnum implements ArrayValuable {
+ SMS("sms", "短信"),
+ EMAIL("email", "邮箱"),
+ APP_PUSH("app_push", "APP 推送"),;
+
+ public static final String[] ARRAYS = Arrays.stream(values()).map(ChannelTypeEnum::getCode).toArray(String[]::new);
+
+ private final String code;
+ private final String msg;
+
+
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ public static ChannelTypeEnum getByCode(String code) {
+ return ArrayUtil.firstMatch(channelTypeEnum -> channelTypeEnum.getCode().equals(code), values());
+ }
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ProviderTypeEnum.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ProviderTypeEnum.java
new file mode 100644
index 0000000..960eb72
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/enums/ProviderTypeEnum.java
@@ -0,0 +1,36 @@
+package com.njcn.msgpush.module.push.enums;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.njcn.msgpush.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Getter
+@AllArgsConstructor
+public enum ProviderTypeEnum implements ArrayValuable {
+
+ ALIYUN("aliyun", "阿里云"),
+ TELECOM("telecom", "电信"),
+ UNIPUSH("uniPush", "uniPush");
+
+ public static final String[] ARRAYS = Arrays.stream(values()).map(ProviderTypeEnum::getCode).toArray(String[]::new);
+
+
+ private String code;
+ private String msg;
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ public static ProviderTypeEnum getByCode(String code) {
+ return ArrayUtil.firstMatch(providerTypeEnum -> providerTypeEnum.getCode().equals(code), values());
+ }
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistService.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistService.java
new file mode 100644
index 0000000..eaf910e
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistService.java
@@ -0,0 +1,14 @@
+package com.njcn.msgpush.module.push.service.blacklist;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.njcn.msgpush.module.push.controller.admin.blacklist.vo.BlacklistReqVO;
+import com.njcn.msgpush.module.push.dal.dataobject.blacklist.BlacklistDO;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+public interface BlacklistService extends IService {
+ Page getPage(BlacklistReqVO reqVO);
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistServiceImpl.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistServiceImpl.java
new file mode 100644
index 0000000..e7c6af0
--- /dev/null
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/blacklist/BlacklistServiceImpl.java
@@ -0,0 +1,25 @@
+package com.njcn.msgpush.module.push.service.blacklist;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.njcn.msgpush.framework.common.util.object.PageUtils;
+import com.njcn.msgpush.module.push.controller.admin.blacklist.vo.BlacklistReqVO;
+import com.njcn.msgpush.module.push.dal.dataobject.blacklist.BlacklistDO;
+import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
+import com.njcn.msgpush.module.push.dal.mysql.blacklist.BlacklistMapper;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author caozehui
+ * @data 2026-03-12
+ */
+@Service
+public class BlacklistServiceImpl extends ServiceImpl implements BlacklistService {
+ @Override
+ public Page getPage(BlacklistReqVO reqVO) {
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(BlacklistDO::getChannel, reqVO.getChannel());
+ return this.page(new Page<>(PageUtils.getPageNum(reqVO), PageUtils.getPageSize(reqVO)), wrapper);
+ }
+}
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/message/MessageRecordServiceImpl.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/message/MessageRecordServiceImpl.java
index e9cc51b..a9cc965 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/message/MessageRecordServiceImpl.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/message/MessageRecordServiceImpl.java
@@ -11,12 +11,12 @@ import com.njcn.msgpush.framework.common.util.object.PageUtils;
import com.njcn.msgpush.module.push.client.factory.MessageProviderFactory;
import com.njcn.msgpush.module.push.client.sender.Sender;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
-import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.controller.admin.message.vo.MessageRecordReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.channel.ChannelProviderConfigDO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.dal.dataobject.retry.MessageRetryHistoryDO;
import com.njcn.msgpush.module.push.dal.mysql.message.MessageRecordMapper;
+import com.njcn.msgpush.module.push.enums.ChannelTypeEnum;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
import com.njcn.msgpush.module.push.service.retry.MessageRetryHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -70,13 +70,13 @@ public class MessageRecordServiceImpl extends ServiceImpl messageProviderFactory.createSmsSender(channelProviderConfigDO, sender).sendSms(messageRecordDO);
- case MsgPushConstant.CHANNEL_EMAIL -> {
+ boolean sendResult = switch (ChannelTypeEnum.getByCode(messageRecordDO.getChannel())) {
+ case SMS -> messageProviderFactory.createSmsSender(channelProviderConfigDO, sender).sendSms(messageRecordDO);
+ case EMAIL -> {
Map params = new HashMap<>();
yield messageProviderFactory.createEmailSender(channelProviderConfigDO, sender).sendEmail(messageRecordDO, params);
}
- case MsgPushConstant.CHANNEL_APP_PUSH -> messageProviderFactory.createAppPushSender(channelProviderConfigDO, sender).appPush(messageRecordDO);
+ case APP_PUSH -> messageProviderFactory.createAppPushSender(channelProviderConfigDO, sender).appPush(messageRecordDO);
default -> throw new RuntimeException("暂不支持该渠道:" + messageRecordDO.getChannel());
};
diff --git a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/retry/MessageRetryQueueServiceImpl.java b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/retry/MessageRetryQueueServiceImpl.java
index 36b5c3c..89e98f7 100644
--- a/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/retry/MessageRetryQueueServiceImpl.java
+++ b/msgpush-module-push/msgpush-module-push-server/src/main/java/com/njcn/msgpush/module/push/service/retry/MessageRetryQueueServiceImpl.java
@@ -6,13 +6,13 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.msgpush.framework.common.pojo.PageResult;
import com.njcn.msgpush.module.push.constant.MessageStatusConstant;
-import com.njcn.msgpush.module.push.constant.MsgPushConstant;
import com.njcn.msgpush.module.push.controller.admin.retry.vo.MessageRetryQueueReqVO;
import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import com.njcn.msgpush.module.push.dal.dataobject.retry.MessageRetryQueueDO;
import com.njcn.msgpush.module.push.dal.dataobject.retry.RetryStrategyConfigDO;
import com.njcn.msgpush.module.push.dal.mysql.retry.MessageRetryQueueMapper;
import com.njcn.msgpush.module.push.dal.redis.MessageRetryRedisDAO;
+import com.njcn.msgpush.module.push.enums.ChannelTypeEnum;
import com.njcn.msgpush.module.push.service.channel.ChannelProviderConfigService;
import com.njcn.msgpush.module.push.service.message.MessageRecordService;
import lombok.extern.slf4j.Slf4j;
@@ -126,8 +126,8 @@ public class MessageRetryQueueServiceImpl extends ServiceImpl