Files
monisuo/PUSH_IMPLEMENTATION_GUIDE.md

412 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
<dependency>
<groupId>cn.jpush</groupId>
<artifactId>jpush-client</artifactId>
<version>3.5.8</version>
</dependency>
```
#### 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<String, String> 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<Void> sendDepositApproval(
@RequestParam String userId,
@RequestParam String orderNo,
@RequestParam String amount,
@RequestParam boolean approved) {
String title = approved ? "充值审批通过" : "充值审批驳回";
String content = approved
? "您的充值订单已审批通过,金额: " + amount + " USDT"
: "您的充值订单已被驳回,金额: " + amount + " USDT";
Map<String, String> 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<Void> sendWithdrawApproval(
@RequestParam String userId,
@RequestParam String orderNo,
@RequestParam String amount,
@RequestParam boolean approved) {
String title = approved ? "提现审批通过" : "提现审批驳回";
String content = approved
? "您的提现申请已处理,金额: " + amount + " USDT"
: "您的提现申请已被驳回,金额: " + amount + " USDT";
Map<String, String> 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开发团队