# Monisuo 推送功能实现指南 ## 概述 本文档详细说明如何在Monisuo虚拟货币交易平台中实现推送通知功能。 ## 架构设计 ### 1. 推送服务选择 **推荐方案**: 极光推送 (JPush) **理由**: - 国内推送到达率高(>95%) - 支持iOS和Android双平台 - 提供完整的Flutter SDK - 免费版支持100万条/月 - 提供REST API和SDK两种方式 **备选方案**: 个推 (Getui) ## 2. 系统架构 ``` [管理员审批] → [后端服务] → [JPush服务器] → [用户手机] ↓ ↓ ↓ ↓ 创建推送任务 调用JPush API 推送消息 显示通知 ``` ## 3. 实现步骤 ### 步骤1: 注册极光推送 1. 访问 https://www.jiguang.cn/ 2. 注册账号并登录 3. 创建应用 4. 获取AppKey和Master Secret ### 步骤2: 后端集成 #### 2.1 添加依赖 ```xml cn.jpush jpush-client 3.5.8 ``` #### 2.2 配置文件 ```yaml # application.yml jpush: app-key: your-app-key master-secret: your-master-secret production: false # 开发环境使用false ``` #### 2.3 推送服务类 ```java package com.it.rattan.monisuo.service; import cn.jiguang.common.resp.DefaultResult; import cn.jpush.api.JPushClient; import cn.jpush.api.push.PushResult; import cn.jpush.api.push.model.Message; import cn.jpush.api.push.model.Notification; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.push.model.audience.Audience; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.Map; @Service public class JPushService { @Value("${jpush.app-key}") private String appKey; @Value("${jpush.master-secret}") private String masterSecret; @Value("${jpush.production}") private boolean production; private JPushClient jPushClient; public JPushService() { jPushClient = new JPushClient(masterSecret, appKey); } /** * 向指定用户发送推送 */ public void sendToUser(String userId, String title, String content, Map extras) { try { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.alias(userId)) .setNotification(Notification.alert(content)) .setMessage(Message.content(content).setExtras(extras)) .setOptions(cn.jpush.api.push.model.Options.newBuilder() .setApnsProduction(production) .build()) .build(); PushResult result = jPushClient.sendPush(payload); if (result.statusCode == 200) { System.out.println("推送成功: " + result.msgId); } else { System.err.println("推送失败: " + result.statusCode); } } catch (Exception e) { e.printStackTrace(); } } /** * 向所有用户发送推送 */ public void sendToAll(String title, String content) { try { PushPayload payload = PushPayload.newBuilder() .setPlatform(Platform.all()) .setAudience(Audience.all()) .setNotification(Notification.alert(content)) .build(); jPushClient.sendPush(payload); } catch (Exception e) { e.printStackTrace(); } } } ``` #### 2.4 推送控制器 ```java package com.it.rattan.monisuo.controller; import com.it.rattan.monisuo.common.Result; import com.it.rattan.monisuo.service.JPushService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api/push") public class PushController { @Autowired private JPushService jPushService; /** * 发送充值审批通知 */ @PostMapping("/deposit/approval") public Result sendDepositApproval( @RequestParam String userId, @RequestParam String orderNo, @RequestParam String amount, @RequestParam boolean approved) { String title = approved ? "充值审批通过" : "充值审批驳回"; String content = approved ? "您的充值订单已审批通过,金额: " + amount + " USDT" : "您的充值订单已被驳回,金额: " + amount + " USDT"; Map extras = new HashMap<>(); extras.put("type", "order"); extras.put("orderNo", orderNo); extras.put("approved", String.valueOf(approved)); jPushService.sendToUser(userId, title, content, extras); return Result.success("推送成功"); } /** * 发送提现审批通知 */ @PostMapping("/withdraw/approval") public Result sendWithdrawApproval( @RequestParam String userId, @RequestParam String orderNo, @RequestParam String amount, @RequestParam boolean approved) { String title = approved ? "提现审批通过" : "提现审批驳回"; String content = approved ? "您的提现申请已处理,金额: " + amount + " USDT" : "您的提现申请已被驳回,金额: " + amount + " USDT"; Map extras = new HashMap<>(); extras.put("type", "order"); extras.put("orderNo", orderNo); extras.put("approved", String.valueOf(approved)); jPushService.sendToUser(userId, title, content, extras); return Result.success("推送成功"); } } ``` ### 步骤3: 在审批流程中集成推送 修改 `FundService.approve()` 方法: ```java @Transactional public void approve(...) { // ... 原有审批逻辑 ... // 审批成功后发送推送 if (order.getType() == 1) { // 充值审批 jPushService.sendToUser( order.getUserId().toString(), status == 2 ? "充值审批通过" : "充值审批驳回", "订单号: " + orderNo + ", 金额: " + order.getAmount() + " USDT", Map.of("type", "order", "orderNo", orderNo) ); } else { // 提现审批 jPushService.sendToUser( order.getUserId().toString(), status == 2 ? "提现审批通过" : "提现审批驳回", "订单号: " + orderNo + ", 金额: " + order.getAmount() + " USDT", Map.of("type", "order", "orderNo", orderNo) ); } } ``` ## 4. 推送场景设计 ### 场景1: 充值审批通过 ```json { "userId": "5", "title": "充值审批通过", "content": "您的充值订单已审批通过,金额: 100 USDT", "extras": { "type": "order", "orderNo": "F20260324001", "approved": "true" } } ``` **触发时机**: 管理员点击"审批通过"按钮后 ### 场景2: 提现审批驳回 ```json { "userId": "5", "title": "提现审批驳回", "content": "您的提现申请已被驳回,金额: 50 USDT", "extras": { "type": "order", "orderNo": "F20260324002", "approved": "false", "reason": "余额不足" } } ``` **触发时机**: 管理员点击"审批驳回"按钮后 ### 场景3: 系统公告 ```json { "title": "系统维护通知", "content": "系统将于今晚22:00-23:00进行维护,届时暂停服务", "extras": { "type": "announcement" } } ``` **触发时机**: 后台管理页面发布系统公告 ## 5. 测试方法 ### 5.1 本地测试 1. **启动后端服务** ```bash cd ~/Desktop/projects/monisuo mvn spring-boot:run ``` 2. **发送测试推送** ```bash curl -X POST http://localhost:5010/api/push/deposit/approval \ -H "Content-Type: application/json" \ -d "userId=5&orderNo=F20260324001&amount=100&approved=true" ``` 3. **检查推送日志** ```bash tail -f logs/app.log | grep "推送" ``` ### 5.2 极光推送控制台测试 1. 登录极光推送控制台 2. 选择应用 3. 点击"推送" -> "发送通知" 4. 选择"别名"推送 5. 输入用户别名(userId) 6. 填写标题和内容 7. 点击"立即发送" ## 6. 监控与统计 ### 6.1 推送统计 在极光推送控制台可以查看: - 推送到达率 - 推送打开率 - 推送失败原因 - 用户活跃度 ### 6.2 日志记录 在 `application.yml` 中添加: ```yaml logging: level: com.it.rattan.monisuo.service.JPushService: DEBUG ``` ## 7. 费用估算 ### 7.1 免费版 - 100万条推送/月 - 适用于中小规模应用 - 基本统计功能 ### 7.2 付费版 - 无限制推送 - 高级统计功能 - 优先技术支持 **推荐**: 初期使用免费版,用户量增长后再考虑升级 ## 8. 安全性考虑 ### 8.1 API密钥保护 - AppKey和Master Secret不要提交到Git - 使用环境变量或配置中心管理 ### 8.2 推送内容审核 - 敏感词过滤 - 内容长度限制 ### 8.3 推送频率限制 - 避免频繁推送打扰用户 - 设置推送间隔(如1分钟内不重复推送) ## 9. 最佳实践 ### 9.1 推送时机 - 充值/提现审批:立即推送 - 系统公告:定时推送 - 资产变动:延迟推送(汇总后推送) ### 9.2 推送内容 - 标题简洁明了(<20字) - 内容包含关键信息(订单号、金额等) - 避免过度营销 ### 9.3 错误处理 - 推送失败时记录日志 - 重大通知支持重试 - 提供站内信作为备选 ## 10. 后续优化 ### 10.1 站内信系统 - 推送失败时存入数据库 - 用户可以在应用内查看历史消息 ### 10.2 推送模板 - 使用模板管理推送内容 - 支持多语言推送 ### 10.3 推送策略 - 根据用户活跃度调整推送频率 - 支持用户自定义推送设置 --- **文档版本**: V1.0 **最后更新**: 2026-03-24 **作者**: Monisuo开发团队