2026-10-13 22:53:52 +08:00
|
|
|
|
# Hera 后端
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-15 21:28:05 +08:00
|
|
|
|
Spring Boot 后端,提供微信小程序登录、手机号验证码绑定、用户资料、协议和关注我们接口。
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
命理计算使用 `cn.6tail:lunar` 根据公历生日和时辰生成四柱八字,再计算五行分布、日主、喜用和忌用。
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-15 21:28:05 +08:00
|
|
|
|
元宝页提供今日卡牌和每日生活小贴士接口。
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
## 本地启动
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
export WECHAT_APP_ID=wxa76a2ef9e8ba612e
|
2026-10-15 21:28:05 +08:00
|
|
|
|
export WECHAT_APP_SECRET='set-via-environment'
|
2026-10-14 22:12:06 +08:00
|
|
|
|
export DB_URL='jdbc:mysql://101.43.139.56:3306/hera?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true'
|
|
|
|
|
|
export DB_USERNAME=hera_user
|
|
|
|
|
|
export DB_PASSWORD='请通过部署环境配置'
|
2026-10-13 22:53:52 +08:00
|
|
|
|
mvn spring-boot:run
|
2026-08-12 20:00:49 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
默认地址:`http://localhost:8080`
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-15 21:28:05 +08:00
|
|
|
|
本机敏感配置可放在仓库根目录的 `.hera-local.yml`,使用与 `application.yml` 相同的 YAML
|
2026-10-18 00:20:53 +08:00
|
|
|
|
层级。默认启用 `local`,从当前启动目录读取该文件;此文件已加入 Git 忽略清单。
|
|
|
|
|
|
|
|
|
|
|
|
## 环境与部署
|
|
|
|
|
|
|
|
|
|
|
|
- `application.yml`:公共参数、上传限制与日志策略。
|
|
|
|
|
|
- `application-local.yml`:本地环境,MySQL/Redis 默认使用公网 `101.43.139.56`,允许创建缺失表。
|
|
|
|
|
|
- `application-prod.yml`:线上环境,MySQL/Redis 默认使用内网 `10.0.8.9`,不自动建表或改表。
|
|
|
|
|
|
- `.hera-local.yml`:本机私有配置,仅 `local` 环境加载。
|
|
|
|
|
|
- `.hera-prod.yml`:线上私有配置,仅 `prod` 环境加载,不会误读本地配置。
|
|
|
|
|
|
|
|
|
|
|
|
两套环境不能同时启用。地址和端口可通过 `DB_URL`、`REDIS_HOST`、`REDIS_PORT`、
|
|
|
|
|
|
`SERVER_PORT` 覆盖,其他参数仍使用现有环境变量。线上必须配置至少 32 字节、非开发默认值的
|
|
|
|
|
|
`hera.jwt-secret`(或 `HERA_JWT_SECRET`),不满足时拒绝启动。短信仍为 mock,正式上线前需接入厂商。
|
|
|
|
|
|
环境隔离只隔离配置文件,不会自动创建两套数据库;需要数据隔离时应分别指定数据库和 Redis 逻辑库。
|
|
|
|
|
|
|
|
|
|
|
|
服务器使用 Java 8,将 JAR 与私有 `.hera-prod.yml` 放在同一启动目录,执行:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
chmod 600 .hera-prod.yml
|
|
|
|
|
|
java -jar hera-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
私有文件字段结构参考 `deploy/hera-prod.yml.example`;可以直接填写真实值,也可以使用环境变量占位符。
|
|
|
|
|
|
本机已按现有密钥准备私有 `.hera-prod.yml`,未复制本地的公网连接地址覆盖线上内网地址。
|
|
|
|
|
|
这两个私有文件均不进入 Git 或 JAR,不应放在 Nginx 可下载目录中。
|
|
|
|
|
|
需要将私有文件置于其他目录时,可设置 `HERA_PROD_CONFIG=optional:file:/etc/hera/prod.yml`
|
|
|
|
|
|
或对应的 `HERA_LOCAL_CONFIG`,默认仍从启动目录查找。
|
|
|
|
|
|
环境变量占位符只在未被私有文件的同名直接值覆盖时生效;若要通过环境变量管理某字段,
|
|
|
|
|
|
请删除私有文件中的直接值或将该值改成对应占位符。
|
|
|
|
|
|
|
|
|
|
|
|
## 日志
|
|
|
|
|
|
|
|
|
|
|
|
控制台与文件同时输出,时间使用北京时间。默认路径为启动目录的 `logs/`,
|
|
|
|
|
|
可设置 `LOG_PATH=/var/log/hera`,启动用户必须具有目录写权限:
|
|
|
|
|
|
|
|
|
|
|
|
- `hera.log`:启动信息、请求摘要及异常等全部应用日志。
|
|
|
|
|
|
- `hera-error.log`:仅 ERROR 级别日志,错误同时保留在 `hera.log`。
|
|
|
|
|
|
- `archive/`:按日期和大小滚动后的 gzip 压缩日志。
|
|
|
|
|
|
|
|
|
|
|
|
默认每文件 20MB、保留 30 天,每个文件序列独立限制总量为 2GB(两个序列合计最高约 4GB,
|
|
|
|
|
|
不含当前活动文件);支持 `LOG_MAX_FILE_SIZE`、`LOG_MAX_HISTORY`、`LOG_TOTAL_SIZE_CAP` 覆盖。
|
|
|
|
|
|
应用日志不代替 Nginx 访问日志、指标和告警,磁盘仍需运维监控。
|
|
|
|
|
|
|
|
|
|
|
|
每个请求返回 `X-Request-Id`,对应日志中的 `requestId`。请求摘要记录方法、路由模板、
|
|
|
|
|
|
状态码和耗时,不记录查询串、请求或响应正文、手机号、验证码、Token、Cookie、文件凭证等。
|
|
|
|
|
|
未知路由只记 `<unmapped>`,不打印可能包含敏感信息的原始路径。异常日志保留类型、原因链类型和
|
|
|
|
|
|
堆栈位置,但不打印异常消息,以免泄露 SQL 参数或包含微信密钥的 URL。
|
|
|
|
|
|
默认不启用 SQL 参数与 HTTP wire DEBUG 日志,不建议在线上自行打开此类日志。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
tail -f logs/hera.log
|
|
|
|
|
|
tail -f logs/hera-error.log
|
|
|
|
|
|
```
|
2026-10-15 21:28:05 +08:00
|
|
|
|
|
2026-10-17 22:43:12 +08:00
|
|
|
|
## Redis
|
|
|
|
|
|
|
|
|
|
|
|
使用 Spring Data Redis 和 Lettuce,依赖版本由 Spring Boot 2.7.18 管理。
|
2026-10-18 00:20:53 +08:00
|
|
|
|
本地默认地址为 `101.43.139.56:6379`,线上为 `10.0.8.9:6379`,逻辑库为 `0`,连接与命令超时均为 3 秒。
|
2026-10-17 22:43:12 +08:00
|
|
|
|
支持 `REDIS_HOST`、`REDIS_PORT`、`REDIS_USERNAME`、`REDIS_PASSWORD`、`REDIS_DATABASE`、
|
|
|
|
|
|
`REDIS_SSL` 环境变量;本机密码配置在被 Git 忽略的 `.hera-local.yml` 中。
|
|
|
|
|
|
|
|
|
|
|
|
业务代码可注入 `StringRedisTemplate`。Key、Value 和 Hash 均采用字符串序列化;
|
|
|
|
|
|
结构化数据使用现有 `ObjectMapper` 显式转换为 JSON。建议 Key 使用 `hera:{业务}:` 前缀,
|
|
|
|
|
|
缓存和临时数据写入时必须指定合理的 TTL。当前接入连接能力,登录会话、mock 短信验证码
|
|
|
|
|
|
仍由现有 MySQL 链路保存,未启用用户资料自动缓存。
|
|
|
|
|
|
|
|
|
|
|
|
`mvn test` 包含不访问真实 Redis 的配置测试。
|
|
|
|
|
|
`mvn test -Dtest=RedisIntegrationTest -Dhera.redis.integration=true` 显式验证真实连接、
|
|
|
|
|
|
认证、PING、字符串读写与 TTL,使用 `hera:test:redis:{随机值}` 测试键并在结束后删除,
|
|
|
|
|
|
不清空 Redis。该测试独立于 MySQL,不执行用户表迁移。
|
|
|
|
|
|
|
2026-10-15 21:28:05 +08:00
|
|
|
|
## 腾讯云 COS 文件存储
|
|
|
|
|
|
|
|
|
|
|
|
存储桶为 `hera-1319913268`,地域为 `ap-beijing`,桶权限保持私有读。
|
|
|
|
|
|
运行环境必须配置 `TENCENT_COS_SECRET_ID`、`TENCENT_COS_SECRET_KEY`。
|
|
|
|
|
|
推荐仅授权该桶 `hera/avatar/*`、`hera/files/*` 路径的 `cos:PutObject`、`cos:GetObject` 权限。
|
2026-10-18 00:20:53 +08:00
|
|
|
|
密钥只通过环境变量或被忽略的私有配置提供,不进入受版本管理的配置或 Git。
|
|
|
|
|
|
未配置 COS 密钥时允许服务启动,文件操作会返回配置错误。
|
2026-10-15 21:28:05 +08:00
|
|
|
|
|
|
|
|
|
|
- `POST /api/user/avatar`:上传 JPG、PNG、WebP 头像,最大 5MB。
|
|
|
|
|
|
- `POST /api/files`:通过 multipart 字段 `file` 上传普通文件,最大 5MB。
|
|
|
|
|
|
- `GET /api/files/url?reference=cos%3A%2F%2Fhera%2Ffiles%2F...`:为本人文件续签。
|
|
|
|
|
|
|
|
|
|
|
|
所有上述接口需要 Bearer JWT。对象分别存储在 `hera/avatar/{userId}/`、
|
|
|
|
|
|
`hera/files/{userId}/`,数据库保存 `cos://` 对象标识;不要保存临时签名 URL。
|
|
|
|
|
|
资料查询返回的头像 URL 和文件上传返回的 URL 有效期为 900 秒;过期后重新获取。
|
|
|
|
|
|
历史 `/uploads/avatars/` 路径继续按原有本地静态资源配置访问,旧文件没有自动迁移。
|
|
|
|
|
|
|
|
|
|
|
|
访问入口默认使用 `http://101.43.139.56/file/access?token=...`,Nginx 保留路径和查询参数
|
|
|
|
|
|
转发至后端;参考 `deploy/nginx-file.conf.example`。后端校验文件专用短期凭证后,
|
|
|
|
|
|
302 跳转至 COS 官方 HTTPS 签名 URL。入口不要求登录头,必须携带有效文件凭证。
|
|
|
|
|
|
文件链接属于临时访问凭据,不应写入日志或分享给无权访问的人。
|
|
|
|
|
|
部署时通过 `HERA_JWT_SECRET` 配置随机签名密钥,并通过 `TENCENT_COS_PUBLIC_BASE_URL`
|
|
|
|
|
|
配置生产 HTTPS 域名下的 `/file/` 地址。小程序需配置入口和跳转目标的 HTTPS 合法域名。
|
|
|
|
|
|
当前 HTTP IP 地址供联调使用,不满足正式小程序的 HTTPS 域名要求。
|
|
|
|
|
|
|
|
|
|
|
|
### COS 验证
|
|
|
|
|
|
|
|
|
|
|
|
`mvn test` 执行本地签名、目录归属和模拟上传测试,不访问真实 COS。
|
|
|
|
|
|
`mvn test -Dhera.cos.integration=true` 额外启用真实 COS 联调:从运行配置读取密钥,
|
|
|
|
|
|
在 `hera/avatar/9223372036854775807/` 和 `hera/files/9223372036854775807/`
|
|
|
|
|
|
创建本次随机命名的测试对象,校验匿名访问为 403、签名下载内容一致,以及后端文件入口的跳转。
|
|
|
|
|
|
测试结束后删除本次创建的对象,因此联调账号还需要这两个测试目录的 `cos:DeleteObject` 权限。
|
|
|
|
|
|
此测试不会操作数据库,也不会验证远端 Nginx 是否已部署。
|
|
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
## 开发说明
|
2026-08-12 20:00:49 +08:00
|
|
|
|
|
2026-10-13 22:53:52 +08:00
|
|
|
|
- 当前已默认关闭微信 mock,并接入微信 `jscode2session`。
|
2026-10-18 00:20:53 +08:00
|
|
|
|
- 数据持久层使用 MyBatis Mapper XML,本地启动会执行 `schema.sql` 创建缺失的数据表,线上默认不执行。
|
|
|
|
|
|
- 本地数据库连接默认指向 `101.43.139.56:3306/hera`,线上默认内网 `10.0.8.9:3306/hera`,可通过环境参数覆盖。
|
2026-10-13 22:53:52 +08:00
|
|
|
|
- `WECHAT_APP_SECRET` 请优先使用服务器环境变量配置,不建议提交到公开仓库。
|
|
|
|
|
|
- `/api/auth/sms` 开发阶段返回 `mockCode`,接入短信厂商后移除返回值。
|
|
|
|
|
|
- 正式上线前需要替换 `hera.jwt-secret`、短信服务实现和协议正文。
|
2026-10-14 22:12:06 +08:00
|
|
|
|
|
|
|
|
|
|
## 数据表 CRUD
|
|
|
|
|
|
|
2026-10-15 21:28:05 +08:00
|
|
|
|
小程序用户业务已统一到 `user_account` 与 `user_profile`:微信身份、昵称和手机号
|
|
|
|
|
|
保存在账号表;性别、生日、出生时辰、头像、现居住地区与资料修改额度保存在资料表。
|
|
|
|
|
|
`User` 仅作为联合查询模型;业务接口不再读写 `hera_user`。
|
|
|
|
|
|
|
2026-10-17 22:43:12 +08:00
|
|
|
|
当前系统尚未上线,以当前数据库与 `schema.sql` 为准,不执行历史用户迁移、
|
|
|
|
|
|
启动时补列或修改旧表结构,也不读取或维护历史迁移版本表。
|
|
|
|
|
|
`schema.sql` 仅通过 `CREATE TABLE IF NOT EXISTS` 初始化缺失的当前业务表;
|
|
|
|
|
|
已有表结构若发生变化,应先更新代码与建表定义,不自动兼容历史结构。
|
|
|
|
|
|
纯微信账号的 `password_hash` 可空;资料修改周期为首次修改起六个月,最多五次。
|
|
|
|
|
|
历史迁移源码与对应测试已移除,但本次清理不会删除数据库中已有的表或记录。
|
2026-10-15 21:28:05 +08:00
|
|
|
|
|
|
|
|
|
|
`POST /api/auth/wx-login` 对已绑定手机号的用户额外返回 `token` 和 `user`;未绑定时,
|
|
|
|
|
|
继续通过 `sessionKey` 和 mock 短信验证码调用 `/api/auth/bind-phone` 完成注册或绑定。
|
|
|
|
|
|
绑定成功会核销会话与验证码。禁用账号不能登录或使用个人资料接口。
|
|
|
|
|
|
个人资料接口的字段名保持不变;资料尚未填写时,生日、时辰及五行报告可能为空,不填充虚构资料。
|
|
|
|
|
|
|
2026-10-17 22:43:12 +08:00
|
|
|
|
原 `/api/data/**` 通用 CRUD 控制器已撤下,避免普通登录用户改写设备归属、资产、
|
|
|
|
|
|
账号状态或他人资料。Mapper 与内部 CRUD Service 保留,不作为小程序 HTTP 接口。
|
|
|
|
|
|
账号注册和资料修改继续使用 `/api/auth/**` 与 `/api/user/profile`,尚未提供管理员接口。
|
|
|
|
|
|
|
|
|
|
|
|
## NFC 与虚拟物
|
|
|
|
|
|
|
|
|
|
|
|
全部接口需要 `Authorization: Bearer <token>`,用户身份取 JWT,不接收操作者用户 ID。
|
|
|
|
|
|
列表接受 `offset=0&limit=20`,单页最大 100。芯片和虚拟物字典由可信后台或数据库预先入库,
|
|
|
|
|
|
不允许小程序自行注册硬件、指定设备奖励或修改流水。
|
|
|
|
|
|
|
|
|
|
|
|
代码以现库结构为准:绑定流水通过 `nfc_uid` 关联设备,芯片不再使用 `last_login_at`。
|
|
|
|
|
|
`nfc_chip.sn` 为设备序列号,按现库定义使用 `VARCHAR(64) NOT NULL`,无默认值、无唯一索引。
|
|
|
|
|
|
硬件入库和更新时必须提供 SN;扫描、绑定及本人设备列表返回 `sn`,客户端不能通过绑定请求修改它。
|
|
|
|
|
|
设备归属和绑定历史仍以唯一 UID 关联,不将 SN 当作唯一标识或绑定凭证。
|
|
|
|
|
|
新库由 `schema.sql` 创建该字段;旧库若尚未新增,应使用真实序列号补录已有设备后再设置非空约束,
|
|
|
|
|
|
不自动生成序列号或用 UID 代填,本服务不在启动时自动修改已有表。
|
|
|
|
|
|
旧库如缺少芯片归属、解绑额度或绑定流水表,可先备份,再手工执行
|
|
|
|
|
|
`src/main/resources/db/nfc-schema-update.sql`;该脚本不由应用自动执行。新库由 `schema.sql` 建表。
|
|
|
|
|
|
若已有同名表但字段结构不同,部署前应核对,不会通过删表自动适配。
|
|
|
|
|
|
|
|
|
|
|
|
- `POST /api/nfc/scan`:`{"uid":"设备UID"}`,查看绑定状态,不返回他人身份或 NDEF。
|
|
|
|
|
|
- `POST /api/nfc/bind`:同上,绑定设备、写绑定流水、激活预置虚拟物,整体事务提交。
|
|
|
|
|
|
- `POST /api/nfc/unbind`:同上,解绑本人设备并写解绑时间。
|
|
|
|
|
|
- `GET /api/nfc/devices`:本人当前设备。
|
|
|
|
|
|
- `GET /api/nfc/bindings`:本人绑定与解绑历史。
|
|
|
|
|
|
- `GET /api/virtual-items`:启用的虚拟物字典,按字典排序。
|
|
|
|
|
|
- `GET /api/user/virtual-items`:本人资产,含失效与送神状态。
|
|
|
|
|
|
- `GET /api/user/virtual-items/{id}`:本人持有关系详情。
|
|
|
|
|
|
- `PUT /api/user/virtual-items/sort`:`{"ids":[持有关系ID,...]}`,按提交顺序设置排序值。
|
|
|
|
|
|
- `POST /api/user/virtual-items/offerings`:`{"userVirtualItemId":1,"offeringType":3,"content":"祈愿"}`。
|
|
|
|
|
|
- `GET /api/user/virtual-items/offerings?holdingId=1`:本人供奉记录,`holdingId` 可省略。
|
|
|
|
|
|
- `POST /api/user/virtual-items/transfers`:`{"userVirtualItemId":1,"toUserId":2,"content":"祝福"}`。
|
|
|
|
|
|
- `GET /api/user/virtual-items/transfers`:本人发出或收到的回向记录。
|
|
|
|
|
|
|
|
|
|
|
|
一个芯片仅允许一个当前用户,一个微信用户可以绑定多个芯片;要求有效账号已绑定微信和手机号。
|
|
|
|
|
|
重复绑定本人设备只刷新更新时间,不增加绑定次数,也不重复发放资产。
|
|
|
|
|
|
每台芯片按北京时间自然年最多解绑两次,次数跟随芯片,不因换用户而重置,跨年重新计算。
|
|
|
|
|
|
|
|
|
|
|
|
同类虚拟物在一个用户下只有一条资产记录,保留首次获得的 `nfc_uid` 和获得时间。
|
|
|
|
|
|
绑定新设备可恢复该类失效资产。解绑最后一台提供该类虚拟物的设备后,资产状态置为 `3`(失效),
|
|
|
|
|
|
不删除供奉和回向历史;仍有同类设备时保留资产。失效资产不能互动或直接请神,必须重新绑定。
|
|
|
|
|
|
供奉类型 `1` 请神、`2` 上香、`3` 祈愿、`4` 功德、`5` 送神。绑定激活自动记录请神;
|
|
|
|
|
|
送神置状态 `0`,保有对应设备时可通过请神恢复为 `1`。重复请神、重复送神会拒绝。
|
|
|
|
|
|
只有功德请求可填写 `meritValue`,要求 1 至 1000000,仅作互动记录,不代表积分、支付或余额。
|
|
|
|
|
|
|
|
|
|
|
|
回向只写记录,不创建接收方资产、不扣除发起方资产,也不把发起方状态改为已回向。
|
|
|
|
|
|
昵称快照从账号表生成;接收方原本有同类资产时保存其关系 ID,没有则为 `null`。
|
|
|
|
|
|
记录不开放通用修改和删除。UID 校验仅确认已入库设备,不具备防复制能力;
|
|
|
|
|
|
若产品需要防克隆,须增加硬件挑战响应或服务端签发的激活凭证,不能将普通 UID 当作秘密。
|
|
|
|
|
|
|
|
|
|
|
|
`NfcWorkflowTest` 在独立 H2 MySQL 模式测试库验证真实 Mapper XML、HTTP、事务与并发抢绑,
|
|
|
|
|
|
覆盖解绑上限、跨年、同类多设备、失效恢复、越权、供奉和只记账回向,不访问线上业务数据。
|
|
|
|
|
|
`mvn test -Dtest=NfcMySqlIntegrationTest -Dhera.nfc.mysql.integration=true` 显式检查现库列名,
|
|
|
|
|
|
通过只读、零行查询验证 XML 与现表兼容,再在七张连接级临时表中验证读写与回滚。
|
|
|
|
|
|
临时表创建成功并全部覆盖后才允许测试写入;结束时回滚并关闭连接自动清理,
|
|
|
|
|
|
不修改正式表结构和业务记录。测试账号需有 `CREATE TEMPORARY TABLES` 权限。
|