docs: 修正「导入必须用独立前缀」的错误论断

实测 gin v1.9.1 允许静态段与 :id 在同一层级共存:探针测了 POST/GET 的单级与
两级共 5 种组合,把 /materials/import 放进现成的 materials 组全都不会 panic。

路由本身保持 /material-import 不变——独立成前缀是命名与分组上的选择(导入是
含模板下载与上传入库的一条链路,也避免 /materials/import 被读成物料 id),
不是 gin 的路由限制。计划文档同步更正。

顺带把计划 Task 6 Step 7 的验证方式从 go build 改成跑路由测试:go build 只做
编译、不执行 RegisterRoutes,注册期的 panic 它兜不住。
This commit is contained in:
文睿 张 2026-10-10 16:18:02 +08:00
parent 8a61186cfd
commit f5e9029c46
2 changed files with 13 additions and 9 deletions

View File

@ -56,7 +56,7 @@
| GET | `/api/material-import/template` | 下载 xlsx 模板,返回文件流 |
| POST | `/api/material-import` | `multipart/form-data`,字段名 `file`,上传即入库 |
**路由必须挂在独立前缀 `/material-import`**:`materials` 组下已有 `GET /:id`,gin 的路由树不允许同一段既有静态前缀又有 `:id` 通配,把 `/materials/import/...` 加进该组会直接 panic。
**路由挂在独立前缀 `/material-import`**:这**不是** gin 的限制——实测 gin v1.9.1 允许静态段与 `:id` 在同一层级共存,把 `/materials/import/...` 加进 `materials` 组并不会 panic。独立成前缀是因为「导入」是含模板下载与上传入库的一条完整链路,两个端点归在一个前缀下,也避免 `/materials/import` 被读成某个物料的 id。
成功响应 `201 Created`:
@ -1952,11 +1952,13 @@ func (h *Handler) ImportMaterials(c *gin.Context) {
materialImportSvc: service.NewMaterialImportService(),
```
3. 在 `materials` 路由组之后加(**必须是独立前缀**):
3. 在 `materials` 路由组之后加(独立前缀,但**不是** gin 的路由限制,理由见「设计约定 3」):
```go
// 物料批量导入单独挂前缀:materials 组已有 GET /:id,
// gin 的路由树不允许同段既有静态前缀又有通配参数。
// 物料批量导入单独挂前缀。这不是 gin 的限制——实测 v1.9.1 允许静态段与
// :id 同层共存,把它放进上面的 materials 组并不会冲突;独立成前缀是因为
// 「导入」是含模板下载与上传入库的一条完整链路,两个端点归在一处,
// 也避免 /materials/import 被读成某个物料的 id。
materialImport := api.Group("/material-import")
materialImport.Use(middleware.AuthMiddleware(), middleware.OrganizationMiddleware())
{
@ -1970,10 +1972,10 @@ func (h *Handler) ImportMaterials(c *gin.Context) {
Run: `go test ./internal/handler/ -v -run 'ErrorWithData|Routes'`
Expected: PASS
- [ ] **Step 7: 起服务验证路由不 panic**
- [ ] **Step 7: 验证路由注册不 panic**
Run: `go build -o server.exe ./cmd/server && echo BUILD_OK`
Expected: `BUILD_OK`(gin 路由冲突会在注册时 panic,构建通过后由下一步的路由测试兜住)
Run: `go test ./internal/handler/ -run TestPhaseOneAndLegacyRoutesAreRegistered -v`
Expected: PASS(路由注册发生在 `NewHandler().RegisterRoutes` 内,这条用例会真正走完注册,真有冲突会在注册时 panic。注意 `go build` 只做编译、不注册路由,兜不住这类问题)
- [ ] **Step 8: Commit**

View File

@ -95,8 +95,10 @@ func (h *Handler) RegisterRoutes(r *gin.Engine) {
materials.POST("/:id/restore", h.RestoreMaterial)
}
// 物料批量导入单独挂前缀:materials 组已有 GET /:id,
// gin 的路由树不允许同段既有静态前缀又有通配参数。
// 物料批量导入单独挂前缀。这不是 gin 的限制——实测 v1.9.1 允许静态段与
// :id 同层共存,把它放进上面的 materials 组并不会冲突;独立成前缀是因为
// 「导入」是含模板下载与上传入库的一条完整链路,两个端点归在一处,
// 也避免 /materials/import 被读成某个物料的 id。
materialImport := api.Group("/material-import")
materialImport.Use(middleware.AuthMiddleware(), middleware.OrganizationMiddleware())
{