Files
xiaotutongxue/backend/xt-server/pom.xml
T
lovife 65ebf8de90 feat(storage): 对象存储接七牛云 —— 解除"不能上多副本"
文件以前直接写本地磁盘:两个实例各存各的,学生这次传到 A、下次请求落到 B,
文件就"不见了"。这不是性能问题,是正确性问题 —— 它一直卡着不上多副本。

新增:
  · module/file/storage/{StorageService,LocalStorageService,QiniuStorageService}
  · config/StorageConfig(装配 + 可选启动自检)
  · FillProperties 新增 fill.storage
  · MaterialFileController 新增 GET /{id}/url(签名链接)与 GET /{id}/content
  · scripts/e2e-m1-storage.py(存储自检,没配七牛时跳过而非失败)

关键设计:
  ① 业务只认 path(std/1/17/张同学-…-身份证.jpg),各实现自己映射成真实位置:
     本地 ./data/uploads/std/...、七牛 xiaotutongxue/std/...
     **换存储不用改数据库、不用改业务代码**
  ② 空间私有 → 下载必须签名。GET /{id}/url 每次现签(默认 30 分钟),
     所以这个 URL 绝不能长期保存:写进库、塞进导出的 Excel、发给学生明天再打开,都是 403
  ③ 对象键里有中文,拼 URL **必须逐段编码** —— 整串 encode 会把 / 编成 %2F,
     那在七牛那边是另一个键,表现是"传上去了却打不开",且报错什么都没有
  ④ 区域默认 auto:华东-浙江在新旧控制台对应 z0 与 cn-east-2,
     写错了的症状是**上传超时**——一个从报错完全看不出原因的失败
  ⑤ AK/SK 不进仓库也不进 jar:dev.yml 只放占位符;
     真密钥在 backend/application-local.yml(已 gitignore),
     用 spring.config.import: optional:**file**:./application-local.yml
     —— 刻意用 file: 而不是 classpath:,后者会被打进 jar,密钥就跟着构建产物走了
  ⑥ 配了 qiniu 却没密钥 → 启动就炸(fail-fast):起得来的话第一个受害的是
     正在填材料的学生,而排查要从"文件保存失败"一路追到环境变量

已验证:存储抽象改造没破坏任何现有链路 —— 本地磁盘路径下
  e2e-m3-file 29/29、m3-submit 31/31、m1-materials 68/68、m3-draft 27/27 全绿;
  启动日志打出「本地磁盘(多副本部署下会丢文件)」;git check-ignore 确认
  application-local.yml 被忽略而 .example 不被忽略。

⏳ 未验证:**七牛的真实链路没跑过** —— 用户给了域名/空间/区域/私有/目录前缀,
   但没给 AccessKey/SecretKey,没有它生成不了上传凭证。
   补上后跑 python scripts/e2e-m1-storage.py 即可(它会验:配置齐全 →
   上传处理落进七牛 → 取签名链接 → 真的下载回来比字节 → 不带签名被拒
   → 对象键带前缀 → 原始件一字不差)。没配时脚本跳过并 exit 0,不误报失败。
2026-09-29 14:09:13 +08:00

140 lines
4.7 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.tianbaotong</groupId>
<artifactId>fill-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>xt-server</artifactId>
<name>xt-server · 主应用</name>
<description>Web 层与业务模块。图片处理服务在 M2 拆出,不在这里。</description>
<dependencies>
<dependency>
<groupId>cn.tianbaotong</groupId>
<artifactId>xt-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- ⚠️ Boot 4 改名:原来的 spring-boot-starter-aop 现在是 spring-boot-starter-aspectj -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Redis:验证码 / 登录锁定 / Token 黑名单 / 限流 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Lettuce 连接池需要 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- ORM(Boot 4 专用 starter) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
</dependency>
<!-- 分页 / 多租户 / 防全表更新插件(MP 3.5.9+ 独立模块,见父 POM 注释) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-jsqlparser</artifactId>
</dependency>
<!-- 数据库驱动 + 迁移 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!--
⚠️ Boot 4 + Flyway 的双重坑,两个都踩了才跑得起来:
1) 自动配置被拆成独立模块(spring-boot-flyway)。
只加 org.flywaydb:flyway-core 会「依赖在、但迁移不跑」,且不报任何错。
2) Flyway 10+ 把「数据库支持」也拆成了独立模块。
只加 starter(内含 flyway-core)会在启动时报 Unsupported Database: PostgreSQL。
所以 starter + flyway-database-postgresql 两个都要。
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-flyway</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<!-- Excel 导入导出(用户/组织/名单) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!-- 对象存储(材料原图与规范件)—— provider=qiniu 时用,本地开发可退回磁盘 -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
</dependency>
<!-- OpenAPI 文档(dev/test 环境启用) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>