12 KiB
阅读机/听书机 接口测试数据手册
配套文件:
阅读机数据表+接口设计-v1.md、015_train_test_data.sql本文档中的「请求示例」全部使用015_train_test_data.sql已插入的真实数据,可直接照抄测试。基础地址:
http://localhost:8096/api/iot/v1(端口按你实际改) 数据前提:已执行015_train_test_data.sql,且sys_user中存在userId=10001、status='0'(正常)。
0. 鉴权与测试顺序
| 接口 | 鉴权 |
|---|---|
POST /device/login |
免鉴权(permitAll) |
GET /book/list |
免鉴权(已放开) |
GET /book/download |
免鉴权(已放开) |
| 其余 6 个接口 | 需 Authorization: Bearer <accessToken>(来自登录返回) |
登录接口有强制设备签名(
DeviceHmacFilter):必须带X-Signature+X-Nonce请求头,且 body 的timestamp距今 ≤5 分钟,否则报「缺少设备签名头 / 签名校验失败 / 时间戳超时」。 本地联调不想算签名时,把application.yml的iot.hmac.enabled改为false(重启后端)即可跳过验签;生产环境务必保持true。 其余接口(Bearer 鉴权)不受该 Filter 影响。
推荐顺序:登录 → 复制 data.accessToken → 在 Swagger 点 Authorize 填 Bearer <accessToken>(或 curl 带 -H 'Authorization: Bearer <accessToken>')→ 测其余接口。
1. 设备学员登录 POST /api/iot/v1/device/login
请求(取自 015 设备 READER-LIB-01 + 学员 10001):
curl -X POST 'http://localhost:8096/api/iot/v1/device/login' \
-H 'Content-Type: application/json' \
-d '{
"deviceId":"READER-LIB-01",
"userId":10001,
"firmware":"1.4.2",
"appVersion":"2.1.0",
"timestamp":1767620000000,
"nonce":"a1b2c3d4e5f6"
}'
预期响应:
{
"code": 200,
"msg": "操作成功",
"data": {
"accessToken": "<ruoyi生成的token>",
"sessionId": "<本次新建的业务会话ID>",
"heartbeatInterval": 60
}
}
2. 设备注销 POST /api/iot/v1/device/logout(需 token)
curl -X POST 'http://localhost:8096/api/iot/v1/device/logout' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <accessToken>' \
-d '{"deviceId":"READER-LIB-01","reason":"REBOOT","timestamp":1767621000000,"nonce":"f6e5d4c3b2a1"}'
预期:{"data":{"result":true,"tokenRevoked":true}}
3. 设备心跳 POST /api/iot/v1/device/heartbeat(需 token)
curl -X POST 'http://localhost:8096/api/iot/v1/device/heartbeat' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <accessToken>' \
-d '{"deviceId":"READER-LIB-01","status":"ONLINE","metrics":{"cpu":20,"mem":30,"diskFree":10240},"configVersion":"CV-17","personVersion":"PV-226118-7","timestamp":1767622000000,"nonce":"aa11bb22cc33"}'
预期:{"data":{"nextInterval":60,"commands":[]}}
4. 阅读记录单条上报 POST /api/iot/v1/reading/record(需 token)
新 recordId(正常 ACCEPTED) —— 用上架书 BK-00012/BV-3:
curl -X POST 'http://localhost:8096/api/iot/v1/reading/record' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <accessToken>' \
-d '{
"deviceId":"READER-LIB-01",
"recordId":"RD-TEST-0001",
"bookId":"BK-00012",
"bookVersion":"BV-3",
"mode":"read",
"recordType":"END",
"startTime":1767620000000,
"endTime":1767622400000,
"durationSec":1420,
"pageFrom":12,
"pageTo":46,
"progress":0.35
}'
预期:{"data":{"result":"ACCEPTED","studyMinutes":23,"totalMinutes":<累计/60>}}
重复发送同一个
recordId=RD-TEST-0001→ 返回{"result":"DUPLICATE",...}(幂等)。
5. 阅读记录批量上报 POST /api/iot/v1/reading/record/batch(需 token)
curl -X POST 'http://localhost:8096/api/iot/v1/reading/record/batch' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <accessToken>' \
-d '{
"deviceId":"READER-LIB-01",
"batchId":"BATCH-RD-001",
"timestamp":1767622500000,
"nonce":"b2b3c4d5e6f7",
"records":[
{"recordId":"RD-TEST-0002","bookId":"BK-00013","bookVersion":"BV-2","mode":"read","recordType":"END","startTime":1767620000000,"endTime":1767622400000,"durationSec":980,"pageFrom":5,"pageTo":22,"progress":0.18}
]
}'
预期:{"data":{"itemResults":[{"recordId":"RD-TEST-0002","result":"ACCEPTED"}]}}
6. 获取学员阅读汇总与续读进度 GET /api/iot/v1/reading/progress(需 token)
curl 'http://localhost:8096/api/iot/v1/reading/progress?deviceId=READER-LIB-01' \
-H 'Authorization: Bearer <accessToken>'
预期(基于 015 已插入的进度/上报数据;需存在一个 ACTIVE 会话,登录后即有):
{
"data": {
"userId": 10001,
"totalReadSeconds": 2400,
"totalAudioSeconds": 600,
"bookRecords": [
{
"bookId": "BK-00012", "bookVersion": "BV-3",
"mainProgress": {"mode":"read","pageNo":46,"sentenceIndex":null,"progress":0.35,"updateTime":1767622400000},
"alternateProgressList": [
{"mode":"read","bookVersion":"BV-2","pageNo":22,"sentenceIndex":null,"progress":0.18,"createTime":1767610000000}
]
},
{
"bookId": "BK-00012", "bookVersion": "BV-3",
"mainProgress": {"mode":"audio","pageNo":120,"sentenceIndex":88,"progress":0.50,"updateTime":1767622500000},
"alternateProgressList": []
},
{
"bookId": "BK-00013", "bookVersion": "BV-2",
"mainProgress": {"mode":"read","pageNo":30,"sentenceIndex":null,"progress":0.20,"updateTime":1767622500000},
"alternateProgressList": []
}
]
}
}
totalReadSeconds=1420+980(两条 read 上报累加);totalAudioSeconds=600(audio 上报)。
7. 获取可阅读书籍列表 GET /api/iot/v1/book/list(免鉴权)
# 全部上架书
curl 'http://localhost:8096/api/iot/v1/book/list?deviceId=READER-LIB-01'
# 按分类过滤(只返回上架)
curl 'http://localhost:8096/api/iot/v1/book/list?deviceId=READER-LIB-01&bookCategory=SAFETY'
预期(bookCategory 省略时 total=3,只返回 is_on_shelf=1 的书;下架的 BK-00012/BV-2、BK-00015 不返回):
{
"data": {
"total": 3,
"list": [
{"bookId":"BK-00012","bookTitle":"铁路房建施工安全手册","bookCategory":"SAFETY","bookVersion":"BV-3","fileSize":2048000,"fileMd5":"c4ca4238a0b923820dcc509a6f75849b","isOnShelf":true},
{"bookId":"BK-00013","bookTitle":"铁路电力安全工作规程","bookCategory":"REGULATION","bookVersion":"BV-2","fileSize":3072000,"fileMd5":"a1b2c3d4e5f60718293a4b5c6d7e8f90a","isOnShelf":true},
{"bookId":"BK-00014","bookTitle":"高铁客运服务英语","bookCategory":"LANGUAGE","bookVersion":"BV-1","fileSize":1536000,"fileMd5":"f0e1d2c3b4a5968778695a4b3c2d1e0f1","isOnShelf":true}
]
}
}
bookCategory=SAFETY时total=1(仅BK-00012/BV-3)。
8. PDF 书籍下载 GET /api/iot/v1/book/download(免鉴权)
# 上架书(正常)
curl -i 'http://localhost:8096/api/iot/v1/book/download?deviceId=READER-LIB-01&bookId=BK-00012&bookVersion=BV-3'
# 支持断点续传
curl -i -H 'Range: bytes=0-1023' 'http://localhost:8096/api/iot/v1/book/download?deviceId=READER-LIB-01&bookId=BK-00012&bookVersion=BV-3'
- 上架书:HTTP 200(或 Range 时 206),响应头带
Accept-Ranges: bytes、Content-MD5。 - 下架书:
bookId=BK-00012&bookVersion=BV-2(is_on_shelf=0)→ 业务报错{"code":500,"msg":"图书已下架,禁止下载"}。 - 不存在的版本:
bookId=BK-00015&bookVersion=BV-9→图书或版本不存在。
⚠️
download_url支持两种形态: ① 相对路径(如正式数据的/profile/upload/2026/10/21/铁路房建施工安全手册_20261021085854A001.pdf,或测试用的/books/BK-00012/BV-3.pdf)——后端自动在前面补上「后端 base URL(scheme+host+port,如http://localhost:8096)」转成可访问的 http(s) 绝对地址后再流式返回; ② 完整 http(s) 远程地址(如 OSS)——直接拉取。 两种都会自动加Content-Type: application/pdf与Content-Disposition(下载头),保证浏览器可访问。 相对路径由后端自身静态资源处理器提供文件:/profile/**指向 RuoYi 上传根目录(文件须真实存在于该磁盘目录),/books/**指向classpath:/static/books/(测试 PDF 已放此处)。文件不存在则返回「文件不存在」。
9. 下载完成回执上报 POST /api/iot/v1/book/download/ack(需 token)
curl -X POST 'http://localhost:8096/api/iot/v1/book/download/ack' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <accessToken>' \
-d '{
"deviceId":"READER-LIB-01",
"bookId":"BK-00012",
"bookVersion":"BV-3",
"fileMd5":"c4ca4238a0b923820dcc509a6f75849b",
"result":"SUCCESS",
"errMsg":"",
"timestamp":1767630000000,
"nonce":"cc55dd66ee77"
}'
预期:{"data":{"deviceReady":true,"recordId":<自增主键>}}
result可取SUCCESS/FAIL(缺省 SUCCESS);落库train_book_download_record。
10. 边界 / 异常用例矩阵(均基于 015 数据)
| 用例 | 操作 | 预期 |
|---|---|---|
| 禁用设备登录 | device/login 用 deviceId=READER-LIB-03(status=2) |
msg:"设备已禁用" |
| 重复上报幂等 | reading/record 用已存在的 recordId=RD-20261020-0001 |
result:"DUPLICATE" |
| 冲突进度(REPLACED 仅补交) | 用 deviceId=READER-LIB-02(其会话 SES-20261019-0001 是 REPLACED)发 reading/record 新 recordId |
result:"CONFLICT_SAVED",写入 train_reading_alternate_progress |
| 下架书被过滤 | book/list 不含 BK-00012/BV-2、BK-00015 |
total=3(仅上架) |
| 下架书禁止下载 | book/download?bookId=BK-00012&bookVersion=BV-2 |
业务错误「图书已下架,禁止下载」 |
| REPLACED 禁止进度查询 | reading/progress?deviceId=READER-LIB-02(需先有一个有效 token) |
msg:"当前会话状态不允许查询进度(被替换设备仅允许补交上报)" |
| 版本强绑定 | 进度查询中 BK-00012 的 read 主进度 BV-3 与备选 BV-2 不混用页码 |
各自返回对应版本页码 |
11. 已插入测试数据速查(源自 015)
设备 train_iot_device
READER-LIB-01status=1(正常)、READER-LIB-02status=1、READER-LIB-03status=2(禁用)
图书 train_book_snapshot(is_on_shelf)
BK-00012/BV-3SAFETY 上架 md5=c4ca4238a0b923820dcc509a6f75849bBK-00012/BV-2SAFETY 下架BK-00013/BV-2REGULATION 上架 md5=a1b2c3d4e5f60718293a4b5c6d7e8f90aBK-00014/BV-1LANGUAGE 上架 md5=f0e1d2c3b4a5968778695a4b3c2d1e0f1BK-00015/BV-1REGULATION 下架
会话 train_user_session
SES-20261020-0001user=10001 device=READER-LIB-01 status=1 ACTIVESES-20261019-0001user=10001 device=READER-LIB-02 status=2 REPLACED(用于冲突用例)
主进度 train_reading_current_progress:10001 的 BK-00012/read/BV-3(46,0.35)、BK-00012/audio/BV-3(120,88,0.50)、BK-00013/read/BV-2(30,0.20)
备选进度 train_reading_alternate_progress:10001 BK-00012/read/BV-2(22,0.18)
上报日志 train_reading_duration_log:RD-20261020-0001(ACCEPTED)、RD-20261020-0002(ACCEPTED)、RD-20261019-0001(CONFLICT_SAVED)
下载回执 train_book_download_record:BK-00012/BV-3 SUCCESS、BK-00013/BV-2 SUCCESS、BK-00014/BV-1 FAIL(errMsg=存储空间不足)