|
|
|
|
# 语音数据FTP同步服务
|
|
|
|
|
|
|
|
|
|
> 基于淮南 yydc-tb-server 老代码改造的 Spring Boot 服务
|
|
|
|
|
> 用于从FTP服务器读取录音数据,上传至OSS并入库到人大金仓数据库
|
|
|
|
|
|
|
|
|
|
## 项目简介
|
|
|
|
|
|
|
|
|
|
本服务定时从FTP服务器读取通话记录txt文件,下载对应的mp3录音文件,上传到OSS对象存储,并将通话记录保存到人大金仓数据库。**每个地市单独部署一份服务**。
|
|
|
|
|
|
|
|
|
|
参考老代码(淮南):`src/main/java/淮南/MineService.java`(已废弃,新代码基于其重写)
|
|
|
|
|
|
|
|
|
|
## 技术栈
|
|
|
|
|
|
|
|
|
|
| 技术 | 版本 |
|
|
|
|
|
|-----|------|
|
|
|
|
|
| Spring Boot | 2.6.13 |
|
|
|
|
|
| MyBatis | 2.3.1 |
|
|
|
|
|
| 数据库 | 人大金仓 (KingbaseES) |
|
|
|
|
|
| 工具库 | Apache Commons Net (FTP) |
|
|
|
|
|
| JDK | 1.8+ |
|
|
|
|
|
|
|
|
|
|
## 目录结构
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
dataservice-yy/
|
|
|
|
|
├── src/main/java/com/threecloud/dataserviceyy/
|
|
|
|
|
│ ├── DataserviceYyApplication.java # 启动类
|
|
|
|
|
│ ├── config/
|
|
|
|
|
│ │ ├── DataSourceConfig.java # 数据源配置
|
|
|
|
|
│ │ └── FtpSyncProperties.java # FTP配置
|
|
|
|
|
│ ├── entity/
|
|
|
|
|
│ │ └── MidVoiceCallRecord.java # 通话记录实体
|
|
|
|
|
│ ├── mapper/
|
|
|
|
|
│ │ └── MidVoiceCallRecordMapper.java # MyBatis Mapper
|
|
|
|
|
│ ├── service/
|
|
|
|
|
│ │ └── FtpSyncService.java # 核心同步服务
|
|
|
|
|
│ └── util/
|
|
|
|
|
│ ├── FilePathUtil.java # 路径工具
|
|
|
|
|
│ ├── FileUploadUtil.java # OSS上传工具
|
|
|
|
|
│ ├── FtpUtil.java # FTP工具
|
|
|
|
|
│ └── DateUtil.java # 日期工具
|
|
|
|
|
├── src/main/resources/
|
|
|
|
|
│ ├── application.yml # 内部配置
|
|
|
|
|
│ ├── logback-spring.xml # 日志配置
|
|
|
|
|
│ └── mapper/
|
|
|
|
|
│ └── MidVoiceCallRecordMapper.xml # SQL映射
|
|
|
|
|
├── config/
|
|
|
|
|
│ └── application-external.yml # 外部配置(部署时修改)
|
|
|
|
|
├── sql/
|
|
|
|
|
│ └── mid_voice_call_record.sql # 建表SQL
|
|
|
|
|
├── pom.xml # Maven配置
|
|
|
|
|
└── README.md # 本文档
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 数据流程
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
┌──────────────┐ 1.连接 ┌──────────────┐
|
|
|
|
|
│ 本服务 │◀───────────▶│ FTP服务器 │
|
|
|
|
|
│ │ 2.下载txt │ (录音盒) │
|
|
|
|
|
│ │ 3.下载mp3 │ │
|
|
|
|
|
└──────┬───────┘ └──────────────┘
|
|
|
|
|
│
|
|
|
|
|
│ 4.上传
|
|
|
|
|
▼
|
|
|
|
|
┌──────────────┐
|
|
|
|
|
│ OSS存储 │ http://oss地址/voice/合肥/340100/20240101/xxx.mp3
|
|
|
|
|
└──────────────┘
|
|
|
|
|
│
|
|
|
|
|
│ 5.入库
|
|
|
|
|
▼
|
|
|
|
|
┌──────────────┐
|
|
|
|
|
│ 人大金仓 │ mid_voice_call_record 表
|
|
|
|
|
└──────────────┘
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 数据库表
|
|
|
|
|
|
|
|
|
|
### mid_voice_call_record(通话记录表)
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
CREATE TABLE "mid_voice"."mid_voice_call_record" (
|
|
|
|
|
"id" int8 NOT NULL GENERATED ALWAYS AS IDENTITY,
|
|
|
|
|
"city_code" varchar(20),
|
|
|
|
|
"city_name" varchar(100),
|
|
|
|
|
"call_record_id" varchar(100) NOT NULL, -- 唯一标识,建议加唯一索引
|
|
|
|
|
"call_tel" varchar(50) NOT NULL, -- 主叫
|
|
|
|
|
"called_tel" varchar(200) NOT NULL, -- 被叫
|
|
|
|
|
"call_start_time" timestamp(6) NOT NULL,
|
|
|
|
|
"call_end_time" timestamp(6) NOT NULL,
|
|
|
|
|
"call_duration" int4 NOT NULL, -- 秒
|
|
|
|
|
"call_direction" varchar(50) NOT NULL, -- 1呼入/2呼出
|
|
|
|
|
"device_no" varchar(100) NOT NULL, -- 设备编码(FTP_地市编码)
|
|
|
|
|
"business_scenario" varchar(100),
|
|
|
|
|
"recording_file_name" varchar(200) NOT NULL,
|
|
|
|
|
"recording_file_path" varchar(500) NOT NULL, -- OSS URL
|
|
|
|
|
"recording_file_size" int4,
|
|
|
|
|
"call_status" varchar(20), -- 1正常/2未接通
|
|
|
|
|
"fail_reason" text,
|
|
|
|
|
"remarks" text,
|
|
|
|
|
"sync_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
"create_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
"org_code" varchar(64),
|
|
|
|
|
PRIMARY KEY ("id")
|
|
|
|
|
)
|
|
|
|
|
PARTITION BY LIST ("city_code");
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**建议加唯一索引**(防重最后一道防线):
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
CREATE UNIQUE INDEX idx_call_record_id_unique
|
|
|
|
|
ON mid_voice.mid_voice_call_record (call_record_id);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 部署说明
|
|
|
|
|
|
|
|
|
|
### 1. 准备JAR包
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /Users/wang/sanduoyun/developspace/dataservice-yy
|
|
|
|
|
mvn clean package -DskipTests
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
产物:`target/dataservice-yy-0.0.1-SNAPSHOT.jar`
|
|
|
|
|
|
|
|
|
|
### 2. 部署目录结构
|
|
|
|
|
|
|
|
|
|
每台服务器(每地市):
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
/opt/dataservice-yy/
|
|
|
|
|
├── dataservice-yy-0.0.1-SNAPSHOT.jar
|
|
|
|
|
├── config/
|
|
|
|
|
│ └── application-external.yml # 修改此文件配置FTP
|
|
|
|
|
├── vaa-ftp-temp/ # 自动创建(临时文件)
|
|
|
|
|
└── logs/ # 自动创建(运行日志)
|
|
|
|
|
└── app.log
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3. 修改外部配置
|
|
|
|
|
|
|
|
|
|
编辑 `config/application-external.yml`:
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
spring:
|
|
|
|
|
datasource:
|
|
|
|
|
url: jdbc:kingbase8://你的数据库IP:54321/kingbase?currentSchema=mid_voice
|
|
|
|
|
username: dcms_dev
|
|
|
|
|
password: 你的密码
|
|
|
|
|
|
|
|
|
|
ftp-sync:
|
|
|
|
|
cities:
|
|
|
|
|
- city-code: "340100" # 你的地市编码
|
|
|
|
|
city-name: "合肥"
|
|
|
|
|
ftp-host: 10.126.129.7 # FTP服务器
|
|
|
|
|
ftp-port: 9979
|
|
|
|
|
ftp-username: ftpuser
|
|
|
|
|
ftp-password: ftppass
|
|
|
|
|
ftp-source-dir: /340100/record/ # txt目录
|
|
|
|
|
ftp-record-dir: /340100/recordfile/ # mp3目录
|
|
|
|
|
ftp-archive-dir: /340100/processed/ # 归档目录
|
|
|
|
|
|
|
|
|
|
vaa-sync:
|
|
|
|
|
oss:
|
|
|
|
|
base-url: http://你的OSS地址:9090
|
|
|
|
|
upload-url: http://你的OSS地址:9090/apiOss/oss/fileUpload
|
|
|
|
|
appcode: dataservice-yy
|
|
|
|
|
appid: 你的appid
|
|
|
|
|
appsecret: 你的appsecret
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4. 启动服务
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cd /opt/dataservice-yy
|
|
|
|
|
nohup java -jar dataservice-yy-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 &
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5. 验证启动
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
tail -f logs/app.log
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
看到如下日志说明启动成功:
|
|
|
|
|
```
|
|
|
|
|
【项目启动】开始执行首次FTP录音同步
|
|
|
|
|
【项目启动】首次同步完成,后续将在每2小时自动执行
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 配置项说明
|
|
|
|
|
|
|
|
|
|
### 数据库配置(spring.datasource)
|
|
|
|
|
|
|
|
|
|
| 配置项 | 必填 | 说明 |
|
|
|
|
|
|-------|-----|------|
|
|
|
|
|
| `url` | ✓ | JDBC URL(人大金仓:jdbc:kingbase8://IP:port/db) |
|
|
|
|
|
| `username` | ✓ | 数据库用户 |
|
|
|
|
|
| `password` | ✓ | 数据库密码 |
|
|
|
|
|
| `driver-class-name` | ✓ | com.kingbase8.Driver |
|
|
|
|
|
|
|
|
|
|
### FTP配置(ftp-sync.cities[])
|
|
|
|
|
|
|
|
|
|
| 配置项 | 必填 | 说明 |
|
|
|
|
|
|-------|-----|------|
|
|
|
|
|
| `city-code` | ✓ | 地市编码(如340100),与数据库分区对应 |
|
|
|
|
|
| `city-name` | ✓ | 地市名称(用于OSS路径) |
|
|
|
|
|
| `ftp-host` | ✓ | FTP服务器IP |
|
|
|
|
|
| `ftp-port` | ✓ | FTP端口 |
|
|
|
|
|
| `ftp-username` | ✓ | FTP用户名 |
|
|
|
|
|
| `ftp-password` | ✓ | FTP密码 |
|
|
|
|
|
| `ftp-source-dir` | ✓ | txt源目录(处理后归档) |
|
|
|
|
|
| `ftp-record-dir` | ✓ | mp3/wav文件目录 |
|
|
|
|
|
| `ftp-archive-dir` | ✓ | 处理完的txt移动到此目录 |
|
|
|
|
|
|
|
|
|
|
### FTP全局配置(ftp-sync.*)
|
|
|
|
|
|
|
|
|
|
| 配置项 | 默认值 | 说明 |
|
|
|
|
|
|-------|-------|------|
|
|
|
|
|
| `enabled` | true | 是否启用FTP同步 |
|
|
|
|
|
| `sync-interval-cron` | 0 0 0/2 * * ? | 定时任务(每2小时) |
|
|
|
|
|
| `temp-path` | ./vaa-ftp-temp | 本地临时文件目录 |
|
|
|
|
|
| `retain-days` | 10 | 临时文件保留天数 |
|
|
|
|
|
| `txt-encoding` | GBK | txt文件编码(老系统用GBK) |
|
|
|
|
|
| `field-separator` | ※ | 字段分隔符(老系统用※) |
|
|
|
|
|
|
|
|
|
|
### OSS配置(vaa-sync.oss)
|
|
|
|
|
|
|
|
|
|
| 配置项 | 必填 | 说明 |
|
|
|
|
|
|-------|-----|------|
|
|
|
|
|
| `base-url` | ✓ | OSS访问基础URL |
|
|
|
|
|
| `upload-url` | ✓ | OSS上传接口URL |
|
|
|
|
|
| `appcode` | ✓ | 应用编码 |
|
|
|
|
|
| `appid` | ✓ | 应用ID |
|
|
|
|
|
| `appsecret` | ✓ | 应用密钥 |
|
|
|
|
|
|
|
|
|
|
## txt文件格式
|
|
|
|
|
|
|
|
|
|
**编码**:GBK
|
|
|
|
|
**分隔符**:※
|
|
|
|
|
**字段顺序**:
|
|
|
|
|
```
|
|
|
|
|
kssj※jssj※hjls※hjzls※zjhm※bjhm※thsc※...※thfx
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| 序号 | 字段 | 说明 | 示例 |
|
|
|
|
|
|-----|------|------|------|
|
|
|
|
|
| 1 | kssj | 开始时间 | 20240101120000 |
|
|
|
|
|
| 2 | jssj | 结束时间 | 20240101120030 |
|
|
|
|
|
| 3 | hjls | 呼叫流水 | 12345 |
|
|
|
|
|
| 4 | hjzls | 呼叫主/被叫流水 | 67890 |
|
|
|
|
|
| 5 | zjhm | 主叫号码 | 055312345678 |
|
|
|
|
|
| 6 | bjhm | 被叫号码 | 12345678 |
|
|
|
|
|
| 7 | thsc | 通话时长(秒) | 30 |
|
|
|
|
|
| ... | ... | 中间字段 | ... |
|
|
|
|
|
| 10 | thfx | 通话方向 | 1=呼入/0=呼出 |
|
|
|
|
|
|
|
|
|
|
**录音文件**:`{ftpRecordDir}/{yyyyMMdd}/{hjls}_{hjzls}.mp3`
|
|
|
|
|
|
|
|
|
|
## 防重复机制
|
|
|
|
|
|
|
|
|
|
| 层级 | 方式 | 说明 |
|
|
|
|
|
|-----|------|------|
|
|
|
|
|
| 1 | FTP归档 | 处理完的txt移到 `archive/` |
|
|
|
|
|
| 2 | 数据库前缀查重 | `call_record_id LIKE '340100_FTP_%'` |
|
|
|
|
|
| 3 | 内存Set去重 | 同批内不重复 |
|
|
|
|
|
| 4 | 数据库唯一索引 | 建议在 `call_record_id` 上加 |
|
|
|
|
|
|
|
|
|
|
## 定时任务
|
|
|
|
|
|
|
|
|
|
默认 `0 0 0/2 * * ?`(每2小时执行一次)。
|
|
|
|
|
|
|
|
|
|
可在 `application-external.yml` 中修改:
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
ftp-sync:
|
|
|
|
|
sync-interval-cron: "0 0 0/2 * * ?"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**常用 Cron 表达式**:
|
|
|
|
|
- 每分钟:`0 0/1 * * * ?`
|
|
|
|
|
- 每30分钟:`0 0/30 * * * ?`
|
|
|
|
|
- 每小时:`0 0 * * * ?`
|
|
|
|
|
- 每2小时:`0 0 0/2 * * ?`
|
|
|
|
|
- 每天凌晨2点:`0 0 2 * * ?`
|
|
|
|
|
|
|
|
|
|
## 日志
|
|
|
|
|
|
|
|
|
|
### 日志位置
|
|
|
|
|
|
|
|
|
|
`logs/app.log`(按天滚动,保留30天)
|
|
|
|
|
|
|
|
|
|
### 日志前缀
|
|
|
|
|
|
|
|
|
|
| 前缀 | 含义 |
|
|
|
|
|
|------|------|
|
|
|
|
|
| 【FTP定时】 | 定时任务开始/结束 |
|
|
|
|
|
| 【FTP主流程】 | 同步主流程 |
|
|
|
|
|
| 【FTP地市】 | 单地市处理 |
|
|
|
|
|
| 【FTP文件】 | 单txt文件处理 |
|
|
|
|
|
| 【FTP行】 | 单行记录处理 |
|
|
|
|
|
| 【FTP防重】 | 数据库防重查询 |
|
|
|
|
|
| 【异常】 | 错误信息 |
|
|
|
|
|
|
|
|
|
|
### 常用查看命令
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# 实时日志
|
|
|
|
|
tail -f logs/app.log
|
|
|
|
|
|
|
|
|
|
# 只看错误
|
|
|
|
|
grep "【异常】" logs/app.log
|
|
|
|
|
|
|
|
|
|
# 只看单地市
|
|
|
|
|
grep "【FTP地市】" logs/app.log | grep "合肥"
|
|
|
|
|
|
|
|
|
|
# 同步成功数
|
|
|
|
|
grep "保存成功" logs/app.log | wc -l
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 常见问题
|
|
|
|
|
|
|
|
|
|
### Q1: 数据库连接失败
|
|
|
|
|
|
|
|
|
|
检查 `application-external.yml` 的 `spring.datasource.*` 配置,确保:
|
|
|
|
|
- IP和端口正确
|
|
|
|
|
- 用户名密码正确
|
|
|
|
|
- 数据库服务已启动
|
|
|
|
|
|
|
|
|
|
### Q2: FTP连接失败
|
|
|
|
|
|
|
|
|
|
检查 `ftp-sync.cities[0].ftp-*` 配置:
|
|
|
|
|
- FTP服务可达:`telnet 10.126.129.7 9979`
|
|
|
|
|
- 用户名密码正确
|
|
|
|
|
- 目录路径有读写权限
|
|
|
|
|
|
|
|
|
|
### Q3: 录音文件下载失败
|
|
|
|
|
|
|
|
|
|
检查 FTP 上是否存在对应路径的文件:
|
|
|
|
|
- 路径格式:`{ftp-record-dir}/{yyyyMMdd}/{hjls}_{hjzls}.mp3`
|
|
|
|
|
- 文件名大小写是否一致
|
|
|
|
|
|
|
|
|
|
### Q4: OSS上传失败
|
|
|
|
|
|
|
|
|
|
检查 `vaa-sync.oss.*` 配置:
|
|
|
|
|
- `upload-url` 接口是否可达
|
|
|
|
|
- `appid` / `appsecret` 是否正确
|
|
|
|
|
|
|
|
|
|
### Q5: 数据没有入库
|
|
|
|
|
|
|
|
|
|
检查:
|
|
|
|
|
- 数据库 `mid_voice_call_record` 表是否存在
|
|
|
|
|
- 日志中是否有 `保存成功` 字样
|
|
|
|
|
- 数据库表分区是否覆盖了该地市编码
|
|
|
|
|
|
|
|
|
|
## 与老代码(淮南 yydc-tb-server)的差异
|
|
|
|
|
|
|
|
|
|
| 项 | 老代码 | 新代码 |
|
|
|
|
|
|---|-------|-------|
|
|
|
|
|
| 数据源 | Oracle | 人大金仓 |
|
|
|
|
|
| 配置 | Spring XML | application.yml |
|
|
|
|
|
| 同步方式 | 手动运行 | 定时任务 |
|
|
|
|
|
| mp3处理 | 只存URL | 下载+上传OSS |
|
|
|
|
|
| 防重 | 不防重 | 数据库+FTP双层防重 |
|
|
|
|
|
| 部署 | 单机单实例 | 多地市独立部署 |
|
|
|
|
|
| 状态 | 已废弃 | 当前生产 |
|
|
|
|
|
|
|
|
|
|
## 维护
|
|
|
|
|
|
|
|
|
|
| 项 | 频率 |
|
|
|
|
|
|---|------|
|
|
|
|
|
| 检查日志 | 每天 |
|
|
|
|
|
| 清理磁盘 | 自动(保留10天) |
|
|
|
|
|
| 数据库备份 | 由DBA负责 |
|
|
|
|
|
| 配置文件变更 | 部署时修改外部配置 |
|
|
|
|
|
|
|
|
|
|
## 联系
|
|
|
|
|
|
|
|
|
|
- 项目维护:xxx
|
|
|
|
|
- 内部文档:xxx
|