# Amour
**Repository Path**: codesensi/Amour
## Basic Information
- **Project Name**: Amour
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-09-30
- **Last Updated**: 2026-09-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Amour
`Amour`(法语中意为"爱")——爱慕情侣小站后端服务,提供门户站点与管理后台全部接口;配套前端工程:[AmourWeb](https://github.com/codesensi/AmourWeb)。
版本演进与各版本变更内容见 [CHANGELOG.md](CHANGELOG.md),版本号遵循语义化版本。
## 在线体验
演示站点:(已开启演示模式,仅开放只读操作,密码均为 `123456`)
| 账号 | 角色 |
| ------- | ---------- |
| `admin` | 超级管理员 |
| `li` | 男主 |
| `su` | 女主 |
## 技术栈
- Java 21 + Spring Boot 4 + MyBatis-Flex
- H2 文件数据库(`MODE=MySQL`,启动时自动执行幂等初始化脚本)
- Sa-Token(JWT 简单模式)+ Caffeine 本地缓存
## 本地开发
环境要求:JDK 21(Gradle 版本由 Wrapper 自管,无需单独安装 Gradle)。
```bash
# 启动(默认 dev 环境,http://localhost:9666)
./gradlew bootRun # Windows 为 gradlew.bat bootRun
# 编译 + 测试
./gradlew compileJava test
```
| 项 | 说明 |
| --------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 内置账号 | `admin`(超级管理员)/ `li`(男主)/ `su`(女主),密码均为 `123456` |
| H2 数据库 | 文件库位于 `./data/amour_dev`,首次启动自动建库;`init_ddl.sql` / `init_dml.sql` 每次启动执行且保持幂等(种子数据按唯一键防重入) |
| H2 控制台 | dev 环境开启:(JDBC URL 与用户名见 `application-dev.yml`,密码为空) |
| 生产配置 | `application-prod.yml`(H2 密码、JWT 密钥等),容器部署时的环境变量覆盖见下文 Docker 部署 |
## 功能特性
### 门户站点(免登录,`/portal/**`)
- **情侣主页**:首屏男女主展示信息与一言文案(随机下发、失败降级)
- **纪念日**:重要日期的展示与倒计时
- **点点滴滴**:生活动态记录
- **情侣日记**:双人日记
- **恋爱画册**:照片墙(仅下发「显示」状态的照片)
- **恋爱清单**:心愿清单与完成状态
- **足迹地图**:到访城市记录,前端以高德地图渲染
- **留言簿**:访客留言上墙与提交(提交防滥用依赖 `@RateLimit` 按 IP 限流)
- **时间胶囊**:写给未来的信
- **公共配置 / 数据字典**:站点名称、备案文案、验证码开关等展示配置与枚举项下发(敏感配置服务端剔除)
- **访问统计**:访问量上报与累计查询
### 管理后台(登录态 + 权限码,`/sys/**`、`/admin/**`)
- **系统管理**:用户、角色(含角色数据权限分配)、路由菜单(RBAC 权限)、参数配置、数据字典、文件管理、登录与操作日志、通知中心(业务事件触发写入)、缓存管理
- **业务管理**:仪表盘数据聚合、纪念日、点点滴滴、情侣日记、恋爱画册、恋爱清单、足迹地图、留言簿、时间胶囊
### 基础能力
- **登录态**:Sa-Token JWT 简单模式 + 图形验证码
- **权限模型**:RBAC,接口按 `@SaCheckPermission` 权限码鉴权,未登录请求由拦截器统一拒绝
- **行级数据权限**:按「角色 × 业务模块」配置可见/可改范围档位(`all`-全部数据 / `self`-仅本人,如主角角色初始为「全可读 + 仅本人可改」),无配置按 `self` 兜底、超管角色判定层硬编码 `all/all`;判定结果回填到分页行的 `canEdit`,前端操作列按钮与状态开关联动禁用,后端 `assertEditable` 写保护兜底
- **接口限流**:`@RateLimit` 按 IP 限流,阈值由参数配置动态管理(高德代理、留言提交等免登录接口防滥用)
- **演示模式**:开关开启后拦截全部数据写操作,供演示环境只读体验
- **操作日志**:AOP 切面采集,专用线程池异步落库,绝不反压业务线程
- **文件管理**:上传/预览/下载,按业务类型限额,本地存储 `{bizType}/{yyyyMM}/{fileId}.{ext}` 组织
- **高德服务代理**:`/_AMapService` 转发高德 Web 服务并在服务端附加 jscode,避免前端暴露安全密钥
- **QQ 信息查询**:按 QQ 号查询头像与昵称,供留言、资料展示等免登录场景复用
## 项目架构
```
Amour/src/main/java/cn/codesensi/amour
├── AmourApplication.java # 启动类
├── advice/ # 统一响应包装(Result{success, code, msg, data, timestamp, traceId})
├── aspect/ # AOP 切面(操作日志、接口限流)
├── common/ # 通用常量、异常定义(如 RbacConst 公开路径清单)
├── config/ # 配置类(WebMvc 拦截链、线程池、缓存、Logbook 等)
├── controller/ # 控制层(薄壳,只做参数校验与响应组织)
│ ├── portal/ # 门户接口(免登录,/portal/**)
│ ├── system/ # 系统管理(/sys/**)
│ ├── admin/ # 业务管理(/admin/**)
│ └── *.java # 登录/验证码/文件/QQ 信息/高德代理等根路径接口
├── filter/ # Servlet 过滤器
├── handler/ # 全局异常处理
├── interceptor/ # 拦截器(演示模式拦截)
├── mapper/ # MyBatis-Flex 数据访问层
├── model/
│ ├── entity/ # 数据库实体(雪花 ID 主键)
│ ├── request/ # 入参模型(jakarta validation 校验注解)
│ ├── response/ # 响应模型
│ ├── dto/ # 服务层数据传输对象
│ └── converter/ # MapStruct 实体转换器
├── security/ # 安全相关
└── service/ # 业务层(接口 + impl 实现,业务逻辑承载)
```
## 接口约定
- 统一响应 `Result{ success, code, msg, data, timestamp, traceId? }`
- 分页五字段:`records / pageNumber / pageSize / totalRow / totalPage`
- 雪花 ID 防精度丢失:所有标识类 `Long` 字段序列化为字符串,前端一律按 `string` 消费
- 时间格式:`LocalDateTime` 为 `yyyy-MM-dd HH:mm:ss`,`LocalDate` 为 `yyyy-MM-dd`
- 接口前缀:`/portal/**` 免登录;`/sys/**`、`/admin/**` 需登录并校验权限码;`/file/view/**`、`/qq-info`、`/_AMapService/**` 等免登录场景在拦截器单独放行
## 第三方服务
第三方接口的密钥统一在 **管理后台-参数配置**(sys_config `security` 分组)维护,修改即热更新,无需重启:
| 配置键 | 用途 |
| -------------------- | ------------------------------------------------------------- |
| `security.amap-key` | 高德 Web 端 JS API Key,前端地图 JS SDK 消费 |
| `security.amap-code` | 高德安全密钥 jscode,仅服务端 `/_AMapService` 代理转发时附加 |
| `security.uapi-key` | UApiPro 接口密钥,一言 / QQ 信息查询以 `X-API-KEY` 请求头携带 |
- `security.amap-code` 未配置时,`/_AMapService` 按高德错误语义返回「密钥未配置」
- `security.uapi-key` 未配置时,一言 / QQ 信息查询自动降级(官方头像拼接、空数据),不影响页面访问
- 接口地址与超时等非密钥项在 `application.yml` 的 `app` 段配置,改动需重启生效
## 分支与发版
- **分支模型**:单主干——`main` 为长期分支,功能以短生命周期分支开发,合入后删除
- **提交校验**:推送的提交信息遵循 Conventional Commits,由 CI(`Commit Lint`)自动校验
- **发版流程**:`CHANGELOG.md` 定稿版本段 → 在 `main` 上创建 `v*` 附注标签并推送 → Actions 自动创建 GitHub Release(正文为对应版本段落,tag 含 `-` 的预发布标识会自动标记为 pre-release)
## Docker 部署
镜像发布在 Docker Hub(`codesensi/amour`),部署命令:
```bash
docker run -dp 9666:9666 --name amour \
--restart unless-stopped \
-v /docker/amour/data:/app/data \
-v /docker/amour/logs:/app/logs \
-e SPRING_DATASOURCE_PASSWORD='H2密码' \
-e SATOKEN_JWTSECRETKEY='JWT密钥' \
codesensi/amour:latest
```
| 参数 | 说明 |
| --------------------------------- | -------------------------------------------------------------------------------- |
| `-d` | 后台运行,容器在后台守护 |
| `-p 9666:9666` | 端口映射(宿主机端口:容器端口);9666 为服务端口,单体部署时浏览器直接访问该端口 |
| `--name amour` | 容器名,供 `docker ps`、`docker logs` 等后续操作引用 |
| `--restart unless-stopped` | 重启策略:容器崩溃或 Docker 守护进程重启后自动拉起,手动停止后不复活 |
| `-v /docker/amour/data:/app/data` | 持久化 H2 数据库与上传文件,不挂载则数据随容器删除而丢失 |
| `-v /docker/amour/logs:/app/logs` | 持久化应用日志与 GC 日志 |
| `-e SPRING_DATASOURCE_PASSWORD` | H2 连接密码,覆盖内置默认值(生产务必修改;密码在首次建库时写入库文件) |
| `-e SATOKEN_JWTSECRETKEY` | JWT 签名密钥,覆盖内置默认值(生产务必修改;更换后所有已登录 token 失效) |
| `codesensi/amour:latest` | 镜像标签:`latest` 为最新版本,替换为具体版本号(如 `1.0.0`)可用于回滚 |
### 注意事项
- **H2 密码与库文件绑定**:密码在首次建库时写入 `.mv.db` 文件。挂载已用旧密码初始化过的数据卷时,`SPRING_DATASOURCE_PASSWORD` 必须与原库一致,否则连接失败(`Wrong user name or password`);换密码需挂**全新数据卷**(首次启动按新密码初始化),或用旧密码连接后执行 `ALTER USER sa SET PASSWORD '新密码'`。