如何使用 GoFrame 规范路由实现上传一个压缩包(例如 zip 格式)并解压出其中的图片文件进行处理。示例分为两个部分:路由注册和处理函数代码。
1. 路由注册
假设项目结构中有一个 router 包,用于统一注册路由。在这里,我们注册一个 POST 请求路由 /upload/zip,指向处理上传的控制器方法。例如:
// router/router.go
package router
import (
"myproject/app/api" // 替换为你自己的包路径
"github.com/gogf/gf/v2/net/ghttp"
)
func init() {
// 获取默认服务对象
s := ghttp.GetServer()
// 这里可以使用分组路由,方便后续扩展
s.Group("/", func(group *ghttp.RouterGroup) {
// 定义 POST 路由,处理压缩包上传
group.POST("/upload/zip", api.Upload.UploadZip)
})
}2. 上传处理函数
在处理函数中,我们需要:
从请求中获取上传的文件(假设表单字段名称为
file)。将上传文件保存到临时目录。
使用 Go 内置的
archive/zip包打开压缩包。遍历压缩包内的所有文件,筛选出图片文件(通过后缀名判断),并保存到指定目录或进行进一步处理。
下面是示例代码:
// app/api/upload/upload.go
package upload
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
// Upload 对象,可以在此处添加更多相关方法
var Upload = new(uploadApi)
type uploadApi struct{}
// UploadZip 处理上传压缩包并解压出图片
func (a *uploadApi) UploadZip(r *ghttp.Request) {
// 1. 从请求中获取上传的文件,字段名称为 "file"
uploadFile := r.GetUploadFile("file")
if uploadFile == nil {
r.Response.WriteJson(g.Map{"code": 400, "msg": "未获取到上传文件"})
return
}
// 2. 保存上传文件到临时目录
tempDir := "./uploads/temp"
if err := os.MkdirAll(tempDir, os.ModePerm); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "创建临时目录失败:" + err.Error()})
return
}
tempFilePath := filepath.Join(tempDir, uploadFile.Filename)
if err := uploadFile.Save(tempFilePath); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "保存上传文件失败:" + err.Error()})
return
}
// 3. 打开压缩包
zipReader, err := zip.OpenReader(tempFilePath)
if err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "打开压缩包失败:" + err.Error()})
return
}
defer zipReader.Close()
// 4. 创建存放图片的目标目录
imgDir := "./uploads/images"
if err := os.MkdirAll(imgDir, os.ModePerm); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "创建图片目录失败:" + err.Error()})
return
}
// 5. 遍历压缩包内的所有文件
for _, f := range zipReader.File {
// 判断文件后缀是否为图片(可根据需求扩展)
if !isImage(f.Name) {
continue
}
// 打开压缩包内的文件
rc, err := f.Open()
if err != nil {
g.Log().Errorf(r.Context(), "打开文件[%s]失败:%v", f.Name, err)
continue
}
// 拼接目标文件路径,取文件名部分(防止目录穿越)
targetPath := filepath.Join(imgDir, filepath.Base(f.Name))
outFile, err := os.Create(targetPath)
if err != nil {
g.Log().Errorf(r.Context(), "创建目标文件[%s]失败:%v", targetPath, err)
rc.Close()
continue
}
// 拷贝文件内容到目标文件
if _, err := io.Copy(outFile, rc); err != nil {
g.Log().Errorf(r.Context(), "保存文件[%s]失败:%v", targetPath, err)
outFile.Close()
rc.Close()
continue
}
outFile.Close()
rc.Close()
}
// 6. 返回成功响应
r.Response.WriteJson(g.Map{"code": 200, "msg": "上传并处理成功"})
}
// isImage 判断文件是否为图片,根据扩展名判断
func isImage(filename string) bool {
ext := strings.ToLower(filepath.Ext(filename))
switch ext {
case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp":
return true
}
return false
}3.使用规范路由
(1). 路由绑定(规范路由)
在项目的路由注册文件中,我们使用 BindObject 绑定控制器对象到指定路由。例如:
// router/router.go
package router
import (
"myproject/app/api/upload" // 请根据实际项目路径调整
"github.com/gogf/gf/v2/net/ghttp"
)
func init() {
// 获取默认的 HTTP 服务对象
s := ghttp.GetServer()
// 将 Upload 控制器绑定到 /upload 路径
// 这样,当请求 /upload/zip 时,将自动调用 Upload 对象中的 Zip 方法
s.BindObject("/upload", new(upload.Upload))
}(2). 控制器方法实现
在控制器对象中定义一个 Zip 方法,该方法将会自动映射到路由 /upload/zip。实现步骤如下:
获取上传文件:从请求中取出上传的文件(表单字段名称为
file)。保存上传文件到临时目录:用于后续打开解压。
使用
archive/zip包打开压缩包。遍历压缩包中文件:筛选出图片文件(通过后缀判断),并保存到指定目录中。
返回处理结果。
示例代码如下:
// app/api/upload/upload.go
package upload
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
// Upload 控制器对象,通过规范路由绑定后自动映射 URL 请求
type Upload struct{}
// Zip 方法处理 /upload/zip 请求,实现压缩包上传及图片处理
func (u *Upload) Zip(r *ghttp.Request) {
// 1. 从请求中获取上传文件,字段名称为 "file"
uploadFile := r.GetUploadFile("file")
if uploadFile == nil {
r.Response.WriteJson(g.Map{"code": 400, "msg": "未获取到上传文件"})
return
}
// 2. 保存上传文件到临时目录
tempDir := "./uploads/temp"
if err := os.MkdirAll(tempDir, os.ModePerm); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "创建临时目录失败:" + err.Error()})
return
}
tempFilePath := filepath.Join(tempDir, uploadFile.Filename)
if err := uploadFile.Save(tempFilePath); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "保存上传文件失败:" + err.Error()})
return
}
// 3. 打开上传的 zip 压缩包
zipReader, err := zip.OpenReader(tempFilePath)
if err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "打开压缩包失败:" + err.Error()})
return
}
defer zipReader.Close()
// 4. 创建存放图片的目标目录
imgDir := "./uploads/images"
if err := os.MkdirAll(imgDir, os.ModePerm); err != nil {
r.Response.WriteJson(g.Map{"code": 500, "msg": "创建图片目录失败:" + err.Error()})
return
}
// 5. 遍历压缩包内的所有文件
for _, f := range zipReader.File {
// 根据扩展名判断是否为图片文件
if !isImage(f.Name) {
continue
}
// 打开压缩包内的文件
rc, err := f.Open()
if err != nil {
g.Log().Errorf(r.Context(), "打开文件[%s]失败:%v", f.Name, err)
continue
}
// 防止目录穿越:只取文件名部分
targetPath := filepath.Join(imgDir, filepath.Base(f.Name))
outFile, err := os.Create(targetPath)
if err != nil {
g.Log().Errorf(r.Context(), "创建目标文件[%s]失败:%v", targetPath, err)
rc.Close()
continue
}
// 将压缩包中文件内容拷贝到目标文件
if _, err := io.Copy(outFile, rc); err != nil {
g.Log().Errorf(r.Context(), "保存文件[%s]失败:%v", targetPath, err)
outFile.Close()
rc.Close()
continue
}
outFile.Close()
rc.Close()
}
// 6. 返回成功响应
r.Response.WriteJson(g.Map{"code": 200, "msg": "上传并处理成功"})
}
// isImage 判断文件是否为图片文件(可根据需求扩展判断规则)
func isImage(filename string) bool {
ext := strings.ToLower(filepath.Ext(filename))
switch ext {
case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp":
return true
}
return false
}(3). 说明
规范路由:使用
s.BindObject("/upload", new(upload.Upload))后,框架会自动将请求/upload/zip映射到Upload对象的Zip方法,无需手动编写路由分组或具体路由映射。安全性:
文件保存时使用
filepath.Base只获取文件名,避免目录穿越风险。可根据实际需要增加对文件大小、MIME 类型等校验。
扩展:除了基础的图片文件保存,实际项目中还可以对图片做缩略图处理、水印添加、上传到云存储等操作。
以上示例展示了如何使用 GoFrame 规范路由实现图片压缩包的上传与处理。根据项目实际需求,你可以进一步完善错误处理和业务逻辑。
最后
以上就是岁月静好最近收集整理的关于使用 goframe 框架的规范路由进行图片文件压缩包的上传与处理的全部内容,更多相关使用内容请搜索靠谱客的其他文章。
发表评论 取消回复