Files
railwaysystem/RuoYi-Vue/sql/train/v2/016_api_test_data.md
T

12 KiB
Raw Blame History

阅读机/听书机 接口测试数据手册

配套文件:阅读机数据表+接口设计-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-01 status=1(正常)、READER-LIB-02 status=1、READER-LIB-03 status=2(禁用)

图书 train_book_snapshot(is_on_shelf)

  • BK-00012/BV-3 SAFETY 上架 md5=c4ca4238a0b923820dcc509a6f75849b
  • BK-00012/BV-2 SAFETY 下架
  • BK-00013/BV-2 REGULATION 上架 md5=a1b2c3d4e5f60718293a4b5c6d7e8f90a
  • BK-00014/BV-1 LANGUAGE 上架 md5=f0e1d2c3b4a5968778695a4b3c2d1e0f1
  • BK-00015/BV-1 REGULATION 下架

会话 train_user_session

  • SES-20261020-0001 user=10001 device=READER-LIB-01 status=1 ACTIVE
  • SES-20261019-0001 user=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=存储空间不足)