From d473d5d04ac64c6f33962587100c1859bc074903 Mon Sep 17 00:00:00 2001
From: zhoupeng <812968653@qq.com>
Date: Fri, 14 Aug 2026 18:39:06 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../yudao-module-member-biz/pom.xml | 7 ++
.../app/chat/AppChatController.java | 9 +-
.../framework/web/config/JPushProperties.java | 20 ++++
.../service/push/MemberPushService.java | 12 ++
.../service/push/MemberPushServiceImpl.java | 105 ++++++++++++++++++
.../src/main/resources/application.yaml | 6 +
6 files changed, 158 insertions(+), 1 deletion(-)
create mode 100644 yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/JPushProperties.java
create mode 100644 yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushService.java
create mode 100644 yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushServiceImpl.java
diff --git a/yudao-module-member/yudao-module-member-biz/pom.xml b/yudao-module-member/yudao-module-member-biz/pom.xml
index cf95191..3a2f7a0 100644
--- a/yudao-module-member/yudao-module-member-biz/pom.xml
+++ b/yudao-module-member/yudao-module-member-biz/pom.xml
@@ -106,6 +106,13 @@
yudao-spring-boot-starter-biz-ip
+
+
+ cn.jpush.api
+ jpush-client
+ 3.7.7
+
+
com.aliyun
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/chat/AppChatController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/chat/AppChatController.java
index eefd935..38f8952 100644
--- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/chat/AppChatController.java
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/chat/AppChatController.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.member.client.vo.chat.friend.ChatAddFriendReqVO;
import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatPrivateMessageSendReqVO;
import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatPrivateMessageSendResVO;
import cn.iocoder.yudao.module.member.service.opentype.OpenTypeService;
+import cn.iocoder.yudao.module.member.service.push.MemberPushService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
@@ -27,6 +28,8 @@ public class AppChatController {
@Resource
private ChatApi chatApi;
+ @Resource
+ private MemberPushService memberPushService;
@PostMapping("/send-private-msg")
@Operation(summary = "发送私聊消息(有会员限制)")
@@ -35,7 +38,11 @@ public class AppChatController {
openTypeService.isUserCanSendMessage(sendId, body.getRecvId());
body.setSendId(sendId);
body.setTerminal(1);
- return success(chatApi.send(body));
+ ChatPrivateMessageSendResVO result = chatApi.send(body);
+ if (result != null) {
+ memberPushService.pushPrivateMessage(body);
+ }
+ return success(result);
}
@GetMapping("/add-friend")
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/JPushProperties.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/JPushProperties.java
new file mode 100644
index 0000000..9299192
--- /dev/null
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/framework/web/config/JPushProperties.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.member.framework.web.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties("jpush")
+@Data
+public class JPushProperties {
+
+ private boolean enabled;
+
+ private String appKey;
+
+ private String masterSecret;
+
+ private boolean apnsProduction;
+
+}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushService.java
new file mode 100644
index 0000000..c28a2a5
--- /dev/null
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushService.java
@@ -0,0 +1,12 @@
+package cn.iocoder.yudao.module.member.service.push;
+
+import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatPrivateMessageSendReqVO;
+
+public interface MemberPushService {
+
+ /**
+ * 推送私聊消息通知
+ */
+ void pushPrivateMessage(ChatPrivateMessageSendReqVO message);
+
+}
diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushServiceImpl.java
new file mode 100644
index 0000000..1d3a3b1
--- /dev/null
+++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/push/MemberPushServiceImpl.java
@@ -0,0 +1,105 @@
+package cn.iocoder.yudao.module.member.service.push;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.member.client.vo.chat.user.ChatPrivateMessageSendReqVO;
+import cn.iocoder.yudao.module.member.dal.dataobject.push.MemberPushDeviceDO;
+import cn.iocoder.yudao.module.member.framework.web.config.JPushProperties;
+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;
+import cn.jpush.api.push.model.notification.AndroidNotification;
+import cn.jpush.api.push.model.notification.IosNotification;
+import cn.jpush.api.push.model.notification.Notification;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class MemberPushServiceImpl implements MemberPushService {
+
+ private static final int MAX_ALERT_LENGTH = 100;
+
+ @Resource
+ private MemberPushDeviceService pushDeviceService;
+ @Resource
+ private MemberUserApi memberUserApi;
+ @Resource
+ private JPushProperties jPushProperties;
+
+ @Override
+ public void pushPrivateMessage(ChatPrivateMessageSendReqVO message) {
+ if (!jPushProperties.isEnabled() || StrUtil.isBlank(jPushProperties.getAppKey())
+ || StrUtil.isBlank(jPushProperties.getMasterSecret())) {
+ return;
+ }
+ List devices = pushDeviceService.getByMemberId(message.getRecvId());
+ List registrationIds = devices.stream()
+ .filter(device -> StrUtil.equalsIgnoreCase(device.getProvider(), "jpush"))
+ .map(MemberPushDeviceDO::getRegistrationId)
+ .filter(StrUtil::isNotBlank)
+ .distinct()
+ .collect(Collectors.toList());
+ if (CollUtil.isEmpty(registrationIds)) {
+ return;
+ }
+
+ MemberUserRespDTO sender = memberUserApi.getUser(message.getSendId());
+ String title = sender != null && StrUtil.isNotBlank(sender.getNickname()) ? sender.getNickname() : "新消息";
+ String alert = buildAlert(message);
+ PushPayload payload = PushPayload.newBuilder()
+ .setPlatform(Platform.android_ios())
+ .setAudience(Audience.registrationId(registrationIds))
+ .setNotification(Notification.newBuilder()
+ .setAlert(alert)
+ .addPlatformNotification(AndroidNotification.newBuilder().setTitle(title).build())
+ .addPlatformNotification(IosNotification.newBuilder().incrBadge(1).build())
+ .build())
+ .setMessage(Message.newBuilder().setTitle(title).setMsgContent(alert)
+ .addExtra("type", "private_message")
+ .addExtra("senderId", String.valueOf(message.getSendId()))
+ .addExtra("receiverId", String.valueOf(message.getRecvId()))
+ .addExtra("messageType", String.valueOf(message.getType()))
+ .build())
+ .setOptions(Options.newBuilder().setApnsProduction(jPushProperties.isApnsProduction()).build())
+ .build();
+ try {
+ JPushClient client = new JPushClient(jPushProperties.getMasterSecret(), jPushProperties.getAppKey());
+ PushResult result = client.sendPush(payload);
+ log.info("[pushPrivateMessage][sendId({}) recvId({}) registrationIds({}) msgId({}) 推送成功]",
+ message.getSendId(), message.getRecvId(), registrationIds.size(), result.msg_id);
+ } catch (Exception e) {
+ log.error("[pushPrivateMessage][sendId({}) recvId({}) 极光推送失败]",
+ message.getSendId(), message.getRecvId(), e);
+ }
+ }
+
+ private String buildAlert(ChatPrivateMessageSendReqVO message) {
+ if (message.getType() == null || message.getType() == 0) {
+ return StrUtil.maxLength(message.getContent(), MAX_ALERT_LENGTH);
+ }
+ switch (message.getType()) {
+ case 1:
+ return "[图片]";
+ case 2:
+ return "[文件]";
+ case 3:
+ return "[语音]";
+ case 4:
+ return "[视频]";
+ default:
+ return "您收到一条新消息";
+ }
+ }
+
+}
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index c160025..422a064 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -366,6 +366,12 @@ yudao:
key: pLXUGAwK5305
customer: E77DF18BE109F454A5CD319E44BF5177
+jpush:
+ enabled: ${JPUSH_ENABLED:true}
+ app-key: ${JPUSH_APP_KEY:d7773439aa8c579dc31a552f}
+ master-secret: ${JPUSH_MASTER_SECRET:a2ea6bb666a26ff1dd246ffa}
+ apns-production: ${JPUSH_APNS_PRODUCTION:true}
+
debug: false
# 插件配置 TODO 芋艿:【IOT】需要处理下
pf4j: