增加文件上传及下载
							parent
							
								
									d93041180a
								
							
						
					
					
						commit
						3baef6449e
					
				
							
								
								
									
										212
									
								
								README.md
								
								
								
								
							
							
						
						
									
										212
									
								
								README.md
								
								
								
								
							|  | @ -3,28 +3,28 @@ go web脚手架, [数据库及表结构](./resource/sql/weekly_report.sql) | |||
| 
 | ||||
| # [web框架gin](https://gin-gonic.com/zh-cn/docs/introduction/) | ||||
| ## 特性 | ||||
| #### 快速 | ||||
| - 快速 | ||||
| 基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。 | ||||
| 
 | ||||
| #### 支持中间件 | ||||
| - 支持中间件 | ||||
| 传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。 | ||||
| 
 | ||||
| #### Crash 处理 | ||||
| - Crash 处理 | ||||
| Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic! | ||||
| 
 | ||||
| #### JSON 验证 | ||||
| - JSON 验证 | ||||
| Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。 | ||||
| 
 | ||||
| #### 路由组 | ||||
| - 路由组 | ||||
| 更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。 | ||||
| 
 | ||||
| #### 错误管理 | ||||
| - 错误管理 | ||||
| Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。 | ||||
| 
 | ||||
| #### 内置渲染 | ||||
| - 内置渲染 | ||||
| Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。 | ||||
| 
 | ||||
| #### 可扩展性 | ||||
| - 可扩展性 | ||||
| 新建一个中间件非常简单,去查看 [示例代码](https://gin-gonic.com/zh-cn/docs/examples/) 吧。 | ||||
| 
 | ||||
| ## 服务创建及启动 | ||||
|  | @ -72,8 +72,153 @@ func main() { | |||
| } | ||||
| ``` | ||||
| 
 | ||||
| # [gorm](https://gorm.io/zh_CN/docs/index.html)    | ||||
| ## 概述 | ||||
| - 全功能 ORM | ||||
| - 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)属于、多对多、多态、单表继承) | ||||
| - Create,Save,Update,Delete,Find 中钩子方法保存/更新/删除/查找) | ||||
| - 支持 Preload、Joins 的预加载,Joins | ||||
| - 事务,嵌套事务,Save Point,Rollback To Saved Point、回滚到保存点 | ||||
| - Context、预编译模式、DryRun 模式DryRun 模式 | ||||
| - 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUDBatches、使用 Map 查找/创建、使用 SQL Expr 和 Context Valuer 进行 CRUD | ||||
| - SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询、Upsert、锁定、优化器/索引/注释提示、命名参数、子查询 | ||||
| - 复合主键,索引,约束 | ||||
| - Auto Migration | ||||
| - 自定义 Logger | ||||
| - 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…PI:数据库解析器(多个数据库,读/写拆分)/ Prometheus... | ||||
| - 每个特性都经过了测试的重重考验 | ||||
| - 开发者友好 | ||||
|    | ||||
| ## 模型定义  | ||||
| ``` | ||||
| type User struct { | ||||
|   ID           uint | ||||
|   Name         string | ||||
|   Email        *string | ||||
|   Age          uint8 | ||||
|   Birthday     *time.Time | ||||
|   MemberNumber sql.NullString | ||||
|   ActivatedAt  sql.NullTime | ||||
|   CreatedAt    time.Time | ||||
|   UpdatedAt    time.Time | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| # 通过Swagger测试接口 | ||||
| GORM 使用结构体名的 蛇形命名 作为表名。对于结构体 User,根据约定,其表名为 users   | ||||
| 您可以实现 Tabler 接口来更改默认表名,例如:   | ||||
| ``` | ||||
| type Tabler interface { | ||||
|     TableName() string | ||||
| } | ||||
| 
 | ||||
| // TableName 会将 User 的表名重写为 `profiles` | ||||
| func (User) TableName() string { | ||||
|   return "profiles" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 您可以使用 Table 方法临时指定表名,例如: | ||||
| ``` | ||||
| // 根据 User 的字段创建 `deleted_users` 表 | ||||
| db.Table("deleted_users").AutoMigrate(&User{}) | ||||
| 
 | ||||
| // 从另一张表查询数据 | ||||
| var deletedUsers []User | ||||
| db.Table("deleted_users").Find(&deletedUsers) | ||||
| // SELECT * FROM deleted_users; | ||||
| 
 | ||||
| db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{}) | ||||
| // DELETE FROM deleted_users WHERE name = 'jinzhu'; | ||||
| ``` | ||||
| 
 | ||||
| ## 连接数据库   | ||||
| ``` | ||||
| import ( | ||||
|   "gorm.io/driver/mysql" | ||||
|   "gorm.io/gorm" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
|   // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情 | ||||
|   dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local" | ||||
|   db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### 连接池 | ||||
| GORM 使用 database/sql 维护连接池 | ||||
| ``` | ||||
| sqlDB, err := db.DB() | ||||
| 
 | ||||
| // SetMaxIdleConns 设置空闲连接池中连接的最大数量 | ||||
| sqlDB.SetMaxIdleConns(10) | ||||
| 
 | ||||
| // SetMaxOpenConns 设置打开数据库连接的最大数量。 | ||||
| sqlDB.SetMaxOpenConns(100) | ||||
| 
 | ||||
| // SetConnMaxLifetime 设置了连接可复用的最大时间。 | ||||
| sqlDB.SetConnMaxLifetime(time.Hour) | ||||
| ``` | ||||
| 
 | ||||
| ## CRUD  | ||||
| ### 基本操作 | ||||
| ``` | ||||
| #  创建记录 | ||||
| user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()} | ||||
| 
 | ||||
| result := db.Create(&user) // 通过数据的指针来创建 | ||||
| 
 | ||||
| user.ID             // 返回插入数据的主键 | ||||
| result.Error        // 返回 error | ||||
| result.RowsAffected // 返回插入记录的条数 | ||||
| ---------------------------------------------------------------------- | ||||
| 
 | ||||
| #  查询 | ||||
| // 获取第一条记录(主键升序) | ||||
| db.First(&user) | ||||
| // SELECT * FROM users ORDER BY id LIMIT 1; | ||||
| 
 | ||||
| // 获取一条记录,没有指定排序字段 | ||||
| db.Take(&user) | ||||
| // SELECT * FROM users LIMIT 1; | ||||
| 
 | ||||
| // 获取最后一条记录(主键降序) | ||||
| db.Last(&user) | ||||
| // SELECT * FROM users ORDER BY id DESC LIMIT 1; | ||||
| ---------------------------------------------------------------------- | ||||
| 
 | ||||
| #  更新 | ||||
| user.Name = "jinzhu 2" | ||||
| user.Age = 100 | ||||
| db.Save(&user) | ||||
| // UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111 | ||||
| ---------------------------------------------------------------------- | ||||
| 
 | ||||
| # 删除 | ||||
| // Email 的 ID 是 `10` | ||||
| db.Delete(&email) | ||||
| // DELETE from emails where id = 10; | ||||
| 
 | ||||
| // 带额外条件的删除 | ||||
| db.Where("name = ?", "jinzhu").Delete(&email) | ||||
| // DELETE from emails where id = 10 AND name = "jinzhu"; | ||||
| ---------------------------------------------------------------------- | ||||
| ``` | ||||
| ### 创建钩子   | ||||
| GORM 允许用户定义的钩子有 BeforeSave, BeforeCreate, AfterSave, AfterCreate 创建记录时将调用这些钩子方法,请参考 Hooks 中关于生命周期的详细信息 | ||||
| ``` | ||||
| func (u *User) BeforeCreate(tx *gorm.DB) (err error) { | ||||
|   u.UUID = uuid.New() | ||||
| 
 | ||||
|     if u.Role == "admin" { | ||||
|         return errors.New("invalid role") | ||||
|     } | ||||
|     return | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| # 通过Swagger测试接口, [中文文档](https://github.com/swaggo/swag/blob/master/README_zh-CN.md)   | ||||
| [官方地址](https://github.com/swaggo) ,其中包含`swag`可执行程序和`gin-swagger`go web模块, [使用手册](https://github.com/swaggo/gin-swagger)   | ||||
| 查看地址为: **http://IP:8888/swagger/index.html**   | ||||
| 
 | ||||
|  | @ -211,7 +356,7 @@ jwt token | |||
| **用户-角色权限-菜单项|API|资源对应关系图**    | ||||
| <br> | ||||
|     | ||||
|    | ||||
|    | ||||
| 
 | ||||
| 
 | ||||
| # 获取菜单项 | ||||
|  | @ -480,7 +625,7 @@ x-user-id: 1 | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ## 使用[casbin](https://github.com/casbin/casbin) 控制权限 | ||||
| # 使用[casbin](https://github.com/casbin/casbin) 控制权限 | ||||
| Casbin is a powerful and efficient open-source access control library. It provides support for enforcing authorization based on various access control models.   | ||||
| 
 | ||||
| 可以 [在线](https://casbin.org/editor/) 书写规则:     | ||||
|  | @ -521,6 +666,37 @@ results, err := e.BatchEnforce([][]interface{}{{"alice", "data1", "read"}, {"bob | |||
| 
 | ||||
| # 文件上传及下载   | ||||
| 
 | ||||
| 文件上传成功返回:   | ||||
| ``` | ||||
| { | ||||
|     "code": 0, | ||||
|     "data": { | ||||
|         "file": { | ||||
|             "ID": 0, | ||||
|             "CreatedAt": "0001-01-01T00:00:00Z", | ||||
|             "UpdatedAt": "0001-01-01T00:00:00Z", | ||||
|             "name": "demo.c", | ||||
|             "url": "/Users/zero/Documents/uploads/file/fe01ce2a7fbac8fafaed7c982a04e229_20211102170427.c", | ||||
|             "tag": "c", | ||||
|             "key": "fe01ce2a7fbac8fafaed7c982a04e229_20211102170427.c" | ||||
|         } | ||||
|     }, | ||||
|     "msg": "上传成功" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| 数据库信息:   | ||||
| ``` | ||||
| mysql> select * from file_upload_and_downloads; | ||||
| +----+---------------------+---------------------+------------+--------+--------------------------------------------------------------------------------------+------+---------------------------------------------------+ | ||||
| | id | created_at          | updated_at          | deleted_at | name   | url                                                                                  | tag  | key                                               | | ||||
| +----+---------------------+---------------------+------------+--------+--------------------------------------------------------------------------------------+------+---------------------------------------------------+ | ||||
| |  3 | 2021-11-02 09:04:27 | 2021-11-02 09:04:27 | NULL       | demo.c | /Users/zero/Documents/uploads/file/fe01ce2a7fbac8fafaed7c982a04e229_20211102170427.c | c    | fe01ce2a7fbac8fafaed7c982a04e229_20211102170427.c | | ||||
| +----+---------------------+---------------------+------------+--------+--------------------------------------------------------------------------------------+------+---------------------------------------------------+ | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| # 反射reflect  | ||||
| [官方文档](https://pkg.go.dev/reflect)   | ||||
| 
 | ||||
|  | @ -585,6 +761,20 @@ Sets the location for time.Time values (when using parseTime=true). "Local" sets | |||
| 	github.com/casbin/gorm-adapter/v3 v3.0.2   | ||||
| 	 | ||||
| 
 | ||||
| #### 查看http请求详情 | ||||
| 
 | ||||
| 通过查看gin.Context>>Request>>(Body io.ReadCloser)>>src>>R>>buf=>点击view就能看到http详情。   | ||||
| 
 | ||||
| <br> | ||||
| <div align=center> | ||||
| <img src="./resource/md_res/gin-http-res.jpg" width="70%" height="70%" title="Go Http请求"></img> | ||||
| </div> | ||||
| <br>   | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
|    | ||||
|  |  | |||
|  | @ -0,0 +1,140 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"mime/multipart" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"go.uber.org/zap" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/common/response" | ||||
| 	webRes "goweb-gin-demo/model/web/response" | ||||
| 	"goweb-gin-demo/utils" | ||||
| ) | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 断点续传到服务器
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept multipart/form-data
 | ||||
| // @Produce  application/json
 | ||||
| // @Param file formData file true "an example for breakpoint resume, 断点续传示例"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"切片创建成功"}"
 | ||||
| // @Router /fileUploadAndDownload/breakpointContinue [post]
 | ||||
| func (u *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) { | ||||
| 	fileMd5 := c.Request.FormValue("fileMd5") | ||||
| 	fileName := c.Request.FormValue("fileName") | ||||
| 	chunkMd5 := c.Request.FormValue("chunkMd5") | ||||
| 	chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber")) | ||||
| 	chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal")) | ||||
| 	_, FileHeader, err := c.Request.FormFile("file") | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("接收文件失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("接收文件失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	f, err := FileHeader.Open() | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("文件读取失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("文件读取失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	defer func(f multipart.File) { | ||||
| 		err := f.Close() | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 	}(f) | ||||
| 	cen, _ := ioutil.ReadAll(f) | ||||
| 	if !utils.CheckMd5(cen, chunkMd5) { | ||||
| 		global.GLOBAL_LOG.Error("检查md5失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("检查md5失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	err, file := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("查找或创建记录失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("查找或创建记录失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	err, pathc := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("断点续传失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("断点续传失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathc, chunkNumber); err != nil { | ||||
| 		global.GLOBAL_LOG.Error("创建文件记录失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("创建文件记录失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	response.OkWithMessage("切片创建成功", c) | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 查找文件
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept multipart/form-data
 | ||||
| // @Produce  application/json
 | ||||
| // @Param file formData file true "Find the file, 查找文件"qqq
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"查找成功"}"
 | ||||
| // @Router /fileUploadAndDownload/findFile [post]
 | ||||
| func (u *FileUploadAndDownloadApi) FindFile(c *gin.Context) { | ||||
| 	fileMd5 := c.Query("fileMd5") | ||||
| 	fileName := c.Query("fileName") | ||||
| 	chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal")) | ||||
| 	err, file := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("查找失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("查找失败", c) | ||||
| 	} else { | ||||
| 		response.OkWithDetailed(webRes.FileResponse{File: file}, "查找成功", c) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 创建文件
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept multipart/form-data
 | ||||
| // @Produce  application/json
 | ||||
| // @Param file formData file true "上传文件完成"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"file uploaded, 文件创建成功"}"
 | ||||
| // @Router /fileUploadAndDownload/breakpointContinueFinish [post]
 | ||||
| func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) { | ||||
| 	fileMd5 := c.Query("fileMd5") | ||||
| 	fileName := c.Query("fileName") | ||||
| 	err, filePath := utils.MakeFile(fileName, fileMd5) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("文件创建失败!", zap.Any("err", err)) | ||||
| 		response.FailWithDetailed(webRes.FilePathResponse{FilePath: filePath}, "文件创建失败", c) | ||||
| 	} else { | ||||
| 		response.OkWithDetailed(webRes.FilePathResponse{FilePath: filePath}, "文件创建成功", c) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 删除切片
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept multipart/form-data
 | ||||
| // @Produce  application/json
 | ||||
| // @Param file formData file true "删除缓存切片"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"缓存切片删除成功"}"
 | ||||
| // @Router /fileUploadAndDownload/removeChunk [post]
 | ||||
| func (u *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) { | ||||
| 	fileMd5 := c.Query("fileMd5") | ||||
| 	fileName := c.Query("fileName") | ||||
| 	filePath := c.Query("filePath") | ||||
| 	err := utils.RemoveChunk(fileMd5) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = fileUploadAndDownloadService.DeleteFileChunk(fileMd5, fileName, filePath) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("缓存切片删除失败!", zap.Any("err", err)) | ||||
| 		response.FailWithDetailed(webRes.FilePathResponse{FilePath: filePath}, "缓存切片删除失败", c) | ||||
| 	} else { | ||||
| 		response.OkWithDetailed(webRes.FilePathResponse{FilePath: filePath}, "缓存切片删除成功", c) | ||||
| 	} | ||||
| } | ||||
|  | @ -3,10 +3,10 @@ package web | |||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"github.com/mojocn/base64Captcha" | ||||
| 	"go.uber.org/zap" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/common/response" | ||||
| 	webRes "goweb-gin-demo/model/web/response" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| 
 | ||||
| // 当开启多服务器部署时,替换下面的配置,使用redis共享存储验证码
 | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ type ApiGroup struct { | |||
| 	BaseApi | ||||
| 	JwtApi | ||||
| 	AuthorityMenuApi | ||||
| 	FileUploadAndDownloadApi | ||||
| 	SystemApi | ||||
| } | ||||
| 
 | ||||
| var userService = service.ServiceGroupApp.UserService | ||||
|  | @ -15,4 +17,5 @@ var jwtService =  service.ServiceGroupApp.JwtService | |||
| var menuService = service.ServiceGroupApp.MenuService | ||||
| var baseMenuService = service.ServiceGroupApp.BaseMenuService | ||||
| var systemConfigService = service.ServiceGroupApp.SystemConfigService | ||||
| var fileUploadAndDownloadService = service.ServiceGroupApp.FileUploadAndDownloadService | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,113 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"go.uber.org/zap" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/common/request" | ||||
| 	"goweb-gin-demo/model/common/response" | ||||
| 	"goweb-gin-demo/model/web" | ||||
| 	webRes "goweb-gin-demo/model/web/response" | ||||
| 	"net/http" | ||||
| ) | ||||
| 
 | ||||
| type FileUploadAndDownloadApi struct { | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 上传文件示例
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept multipart/form-data
 | ||||
| // @Produce  application/json
 | ||||
| // @Param file formData file true "上传文件示例"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"上传成功"}"
 | ||||
| // @Router /fileUploadAndDownload/upload [post]
 | ||||
| func (u *FileUploadAndDownloadApi) UploadFile(c *gin.Context) { | ||||
| 	var file web.FileUploadAndDownload | ||||
| 	noSave := c.DefaultQuery("noSave", "0") | ||||
| 	_, header, err := c.Request.FormFile("file") | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("接收文件失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("接收文件失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	err, file = fileUploadAndDownloadService.UploadFile(header, noSave) // 文件上传后拿到文件路径
 | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("修改数据库链接失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("修改数据库链接失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	response.OkWithDetailed(webRes.ExaFileResponse{File: file}, "上传成功", c) | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 文件下载
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept application/json
 | ||||
| // @Produce application/json
 | ||||
| // @Param fileName query string true "待下载的文件名"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"文件下载成功"}"
 | ||||
| // @Router /fileUploadAndDownload/download [get]
 | ||||
| func (u *FileUploadAndDownloadApi) DownloadFile(c *gin.Context) { | ||||
| 	fileName := c.Query("fileName") | ||||
| 
 | ||||
| 	//待下载的文件是存储本地的,如果存储在云盘,直接访问链接即可
 | ||||
| 	//如果没有记录,也会报错,record not found
 | ||||
| 	err, fileInfo := fileUploadAndDownloadService.FindFile(fileName) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("文件未找到!", zap.Any("err", err)) | ||||
| 		c.Redirect(http.StatusFound, "/404") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	c.Header("Content-Type", "application/octet-stream") | ||||
| 	c.Header("Content-Disposition", "attachment; filename="+fileInfo.Name) | ||||
| 	c.Header("Content-Transfer-Encoding", "binary") | ||||
| 
 | ||||
| 	c.File(fileInfo.Url) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 删除文件
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @Produce  application/json
 | ||||
| // @Param data body web.FileUploadAndDownload true "传入文件里面id即可"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
 | ||||
| // @Router /fileUploadAndDownload/deleteFile [post]
 | ||||
| func (u *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) { | ||||
| 	var file web.FileUploadAndDownload | ||||
| 	_ = c.ShouldBindJSON(&file) | ||||
| 	if err := fileUploadAndDownloadService.DeleteFile(file); err != nil { | ||||
| 		global.GLOBAL_LOG.Error("删除失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("删除失败", c) | ||||
| 		return | ||||
| 	} | ||||
| 	response.OkWithMessage("删除成功", c) | ||||
| } | ||||
| 
 | ||||
| // @Tags FileUploadAndDownload
 | ||||
| // @Summary 分页文件列表
 | ||||
| // @Security ApiKeyAuth
 | ||||
| // @accept application/json
 | ||||
| // @Produce application/json
 | ||||
| // @Param data body request.PageInfo true "页码, 每页大小"
 | ||||
| // @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
 | ||||
| // @Router /fileUploadAndDownload/getFileList [post]
 | ||||
| func (u *FileUploadAndDownloadApi) GetFileList(c *gin.Context) { | ||||
| 	var pageInfo request.PageInfo | ||||
| 	_ = c.ShouldBindJSON(&pageInfo) | ||||
| 	err, list, total := fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("获取失败!", zap.Any("err", err)) | ||||
| 		response.FailWithMessage("获取失败", c) | ||||
| 	} else { | ||||
| 		response.OkWithDetailed(response.PageResult{ | ||||
| 			List:     list, | ||||
| 			Total:    total, | ||||
| 			Page:     pageInfo.Page, | ||||
| 			PageSize: pageInfo.PageSize, | ||||
| 		}, "获取成功", c) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,11 +1,11 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"go.uber.org/zap" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/common/response" | ||||
| 	"goweb-gin-demo/model/web" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| 
 | ||||
| type JwtApi struct { | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ redis: | |||
|   addr: '127.0.0.1:6379' | ||||
|   password: '' | ||||
| 
 | ||||
| 
 | ||||
| # casbin configuration | ||||
| casbin: | ||||
|   model-path: './resource/rbac_model.conf' | ||||
|  | @ -29,7 +30,7 @@ casbin: | |||
| # system configuration | ||||
| system: | ||||
|   env: 'develop'  # Change to "develop" to skip authentication for development mode # public | ||||
|   addr: 8888 | ||||
|   addr: 8889 | ||||
|   db-type: 'mysql' | ||||
|   oss-type: 'local'    # 控制oss选择走本期还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置 | ||||
|   use-multipoint: false | ||||
|  | @ -52,6 +53,10 @@ mysql: | |||
|   log-mode: false | ||||
|   log-zap: false | ||||
| 
 | ||||
| # 本地下载文件路径 | ||||
| local: | ||||
|   path: '/Users/zero/Documents/uploads/file' | ||||
| 
 | ||||
| # timer task db clear table | ||||
| Timer: | ||||
|   start: true | ||||
|  |  | |||
							
								
								
									
										322
									
								
								docs/docs.go
								
								
								
								
							
							
						
						
									
										322
									
								
								docs/docs.go
								
								
								
								
							|  | @ -80,6 +80,295 @@ var doc = `{ | |||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/breakpointContinue": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "断点续传到服务器", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "an example for breakpoint resume, 断点续传示例", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"切片创建成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/breakpointContinueFinish": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "创建文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "上传文件完成", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"file uploaded, 文件创建成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/deleteFile": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "删除文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "description": "传入文件里面id即可", | ||||
|                         "name": "data", | ||||
|                         "in": "body", | ||||
|                         "required": true, | ||||
|                         "schema": { | ||||
|                             "$ref": "#/definitions/web.FileUploadAndDownload" | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"删除成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/download": { | ||||
|             "get": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "文件下载", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "string", | ||||
|                         "description": "待下载的文件名", | ||||
|                         "name": "fileName", | ||||
|                         "in": "query", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"文件下载成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/findFile": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "查找文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "Find the file, 查找文件", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"查找成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/getFileList": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "分页文件列表", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "description": "页码, 每页大小", | ||||
|                         "name": "data", | ||||
|                         "in": "body", | ||||
|                         "required": true, | ||||
|                         "schema": { | ||||
|                             "$ref": "#/definitions/request.PageInfo" | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/removeChunk": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "删除切片", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "删除缓存切片", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"缓存切片删除成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/upload": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "上传文件示例", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "上传文件示例", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"上传成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/jwt/jsonInBlacklist": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|  | @ -1400,6 +1689,39 @@ var doc = `{ | |||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "web.FileUploadAndDownload": { | ||||
|             "type": "object", | ||||
|             "properties": { | ||||
|                 "createdAt": { | ||||
|                     "description": "创建时间", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "id": { | ||||
|                     "description": "主键ID", | ||||
|                     "type": "integer" | ||||
|                 }, | ||||
|                 "key": { | ||||
|                     "description": "编号", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "name": { | ||||
|                     "description": "文件名", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "tag": { | ||||
|                     "description": "文件标签", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "updatedAt": { | ||||
|                     "description": "更新时间", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "url": { | ||||
|                     "description": "文件地址", | ||||
|                     "type": "string" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "web.SysAuthority": { | ||||
|             "type": "object", | ||||
|             "properties": { | ||||
|  |  | |||
|  | @ -61,6 +61,295 @@ | |||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/breakpointContinue": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "断点续传到服务器", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "an example for breakpoint resume, 断点续传示例", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"切片创建成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/breakpointContinueFinish": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "创建文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "上传文件完成", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"file uploaded, 文件创建成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/deleteFile": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "删除文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "description": "传入文件里面id即可", | ||||
|                         "name": "data", | ||||
|                         "in": "body", | ||||
|                         "required": true, | ||||
|                         "schema": { | ||||
|                             "$ref": "#/definitions/web.FileUploadAndDownload" | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"删除成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/download": { | ||||
|             "get": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "文件下载", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "string", | ||||
|                         "description": "待下载的文件名", | ||||
|                         "name": "fileName", | ||||
|                         "in": "query", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"文件下载成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/findFile": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "查找文件", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "Find the file, 查找文件", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"查找成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/getFileList": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "分页文件列表", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "description": "页码, 每页大小", | ||||
|                         "name": "data", | ||||
|                         "in": "body", | ||||
|                         "required": true, | ||||
|                         "schema": { | ||||
|                             "$ref": "#/definitions/request.PageInfo" | ||||
|                         } | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/removeChunk": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "删除切片", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "删除缓存切片", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"缓存切片删除成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/fileUploadAndDownload/upload": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|                     { | ||||
|                         "ApiKeyAuth": [] | ||||
|                     } | ||||
|                 ], | ||||
|                 "consumes": [ | ||||
|                     "multipart/form-data" | ||||
|                 ], | ||||
|                 "produces": [ | ||||
|                     "application/json" | ||||
|                 ], | ||||
|                 "tags": [ | ||||
|                     "FileUploadAndDownload" | ||||
|                 ], | ||||
|                 "summary": "上传文件示例", | ||||
|                 "parameters": [ | ||||
|                     { | ||||
|                         "type": "file", | ||||
|                         "description": "上传文件示例", | ||||
|                         "name": "file", | ||||
|                         "in": "formData", | ||||
|                         "required": true | ||||
|                     } | ||||
|                 ], | ||||
|                 "responses": { | ||||
|                     "200": { | ||||
|                         "description": "{\"success\":true,\"data\":{},\"msg\":\"上传成功\"}", | ||||
|                         "schema": { | ||||
|                             "type": "string" | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "/jwt/jsonInBlacklist": { | ||||
|             "post": { | ||||
|                 "security": [ | ||||
|  | @ -1381,6 +1670,39 @@ | |||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "web.FileUploadAndDownload": { | ||||
|             "type": "object", | ||||
|             "properties": { | ||||
|                 "createdAt": { | ||||
|                     "description": "创建时间", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "id": { | ||||
|                     "description": "主键ID", | ||||
|                     "type": "integer" | ||||
|                 }, | ||||
|                 "key": { | ||||
|                     "description": "编号", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "name": { | ||||
|                     "description": "文件名", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "tag": { | ||||
|                     "description": "文件标签", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "updatedAt": { | ||||
|                     "description": "更新时间", | ||||
|                     "type": "string" | ||||
|                 }, | ||||
|                 "url": { | ||||
|                     "description": "文件地址", | ||||
|                     "type": "string" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "web.SysAuthority": { | ||||
|             "type": "object", | ||||
|             "properties": { | ||||
|  |  | |||
|  | @ -391,6 +391,30 @@ definitions: | |||
|       id: | ||||
|         type: integer | ||||
|     type: object | ||||
|   web.FileUploadAndDownload: | ||||
|     properties: | ||||
|       createdAt: | ||||
|         description: 创建时间 | ||||
|         type: string | ||||
|       id: | ||||
|         description: 主键ID | ||||
|         type: integer | ||||
|       key: | ||||
|         description: 编号 | ||||
|         type: string | ||||
|       name: | ||||
|         description: 文件名 | ||||
|         type: string | ||||
|       tag: | ||||
|         description: 文件标签 | ||||
|         type: string | ||||
|       updatedAt: | ||||
|         description: 更新时间 | ||||
|         type: string | ||||
|       url: | ||||
|         description: 文件地址 | ||||
|         type: string | ||||
|     type: object | ||||
|   web.SysAuthority: | ||||
|     properties: | ||||
|       authorityId: | ||||
|  | @ -591,6 +615,182 @@ paths: | |||
|       summary: 用户登录 | ||||
|       tags: | ||||
|       - Base | ||||
|   /fileUploadAndDownload/breakpointContinue: | ||||
|     post: | ||||
|       consumes: | ||||
|       - multipart/form-data | ||||
|       parameters: | ||||
|       - description: an example for breakpoint resume, 断点续传示例 | ||||
|         in: formData | ||||
|         name: file | ||||
|         required: true | ||||
|         type: file | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"切片创建成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 断点续传到服务器 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/breakpointContinueFinish: | ||||
|     post: | ||||
|       consumes: | ||||
|       - multipart/form-data | ||||
|       parameters: | ||||
|       - description: 上传文件完成 | ||||
|         in: formData | ||||
|         name: file | ||||
|         required: true | ||||
|         type: file | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"file uploaded, 文件创建成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 创建文件 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/deleteFile: | ||||
|     post: | ||||
|       parameters: | ||||
|       - description: 传入文件里面id即可 | ||||
|         in: body | ||||
|         name: data | ||||
|         required: true | ||||
|         schema: | ||||
|           $ref: '#/definitions/web.FileUploadAndDownload' | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"删除成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 删除文件 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/download: | ||||
|     get: | ||||
|       consumes: | ||||
|       - application/json | ||||
|       parameters: | ||||
|       - description: 待下载的文件名 | ||||
|         in: query | ||||
|         name: fileName | ||||
|         required: true | ||||
|         type: string | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"文件下载成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 文件下载 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/findFile: | ||||
|     post: | ||||
|       consumes: | ||||
|       - multipart/form-data | ||||
|       parameters: | ||||
|       - description: Find the file, 查找文件 | ||||
|         in: formData | ||||
|         name: file | ||||
|         required: true | ||||
|         type: file | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"查找成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 查找文件 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/getFileList: | ||||
|     post: | ||||
|       consumes: | ||||
|       - application/json | ||||
|       parameters: | ||||
|       - description: 页码, 每页大小 | ||||
|         in: body | ||||
|         name: data | ||||
|         required: true | ||||
|         schema: | ||||
|           $ref: '#/definitions/request.PageInfo' | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"获取成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 分页文件列表 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/removeChunk: | ||||
|     post: | ||||
|       consumes: | ||||
|       - multipart/form-data | ||||
|       parameters: | ||||
|       - description: 删除缓存切片 | ||||
|         in: formData | ||||
|         name: file | ||||
|         required: true | ||||
|         type: file | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"缓存切片删除成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 删除切片 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /fileUploadAndDownload/upload: | ||||
|     post: | ||||
|       consumes: | ||||
|       - multipart/form-data | ||||
|       parameters: | ||||
|       - description: 上传文件示例 | ||||
|         in: formData | ||||
|         name: file | ||||
|         required: true | ||||
|         type: file | ||||
|       produces: | ||||
|       - application/json | ||||
|       responses: | ||||
|         "200": | ||||
|           description: '{"success":true,"data":{},"msg":"上传成功"}' | ||||
|           schema: | ||||
|             type: string | ||||
|       security: | ||||
|       - ApiKeyAuth: [] | ||||
|       summary: 上传文件示例 | ||||
|       tags: | ||||
|       - FileUploadAndDownload | ||||
|   /jwt/jsonInBlacklist: | ||||
|     post: | ||||
|       consumes: | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										4
									
								
								go.mod
								
								
								
								
							|  | @ -3,6 +3,8 @@ module goweb-gin-demo | |||
| go 1.16 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible | ||||
| 	github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect | ||||
| 	github.com/casbin/casbin/v2 v2.11.0 | ||||
| 	github.com/casbin/gorm-adapter/v3 v3.0.2 | ||||
| 	github.com/dgrijalva/jwt-go v3.2.0+incompatible | ||||
|  | @ -16,6 +18,7 @@ require ( | |||
| 	github.com/lestrrat-go/strftime v1.0.5 // indirect | ||||
| 	github.com/mailru/easyjson v0.7.7 // indirect | ||||
| 	github.com/mojocn/base64Captcha v1.3.1 | ||||
| 	github.com/qiniu/api.v7/v7 v7.8.2 | ||||
| 	github.com/robfig/cron/v3 v3.0.1 | ||||
| 	github.com/satori/go.uuid v1.2.0 | ||||
| 	github.com/shirou/gopsutil v3.20.11+incompatible | ||||
|  | @ -24,6 +27,7 @@ require ( | |||
| 	github.com/stretchr/testify v1.7.0 | ||||
| 	github.com/swaggo/gin-swagger v1.3.2 | ||||
| 	github.com/swaggo/swag v1.7.4 | ||||
| 	github.com/tencentyun/cos-go-sdk-v5 v0.7.31 | ||||
| 	go.uber.org/zap v1.16.0 | ||||
| 	golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect | ||||
| 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | ||||
|  |  | |||
							
								
								
									
										20
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										20
									
								
								go.sum
								
								
								
								
							|  | @ -24,14 +24,19 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN | |||
| github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= | ||||
| github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= | ||||
| github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= | ||||
| github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= | ||||
| github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= | ||||
| github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= | ||||
| github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= | ||||
| github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||
| github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||||
| github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible h1:D3gwOr9qUUmyyBRDbpnATqu+EkqqmigFd3Od6xO1QUU= | ||||
| github.com/aliyun/aliyun-oss-go-sdk v2.1.10+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= | ||||
| github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= | ||||
| github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= | ||||
| github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= | ||||
| github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA= | ||||
| github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= | ||||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||||
| github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | ||||
| github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= | ||||
|  | @ -166,14 +171,20 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ | |||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= | ||||
| github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= | ||||
| github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= | ||||
| github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||
| github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||
| github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= | ||||
| github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= | ||||
| github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | ||||
| github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | ||||
| github.com/gookit/color v1.3.6 h1:Rgbazd4JO5AgSTVGS3o0nvaSdwdrS8bzvIXwtK6OiMk= | ||||
| github.com/gookit/color v1.3.6/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||
|  | @ -332,6 +343,8 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 | |||
| github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||
| github.com/mojocn/base64Captcha v1.3.1 h1:2Wbkt8Oc8qjmNJ5GyOfSo4tgVQPsbKMftqASnq8GlT0= | ||||
| github.com/mojocn/base64Captcha v1.3.1/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY= | ||||
| github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= | ||||
| github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | ||||
|  | @ -366,6 +379,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 | |||
| github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||
| github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= | ||||
| github.com/qiniu/api.v7/v7 v7.8.2 h1:f08kI0MmsJNzK4sUS8bG3HDH67ktwd/ji23Gkiy2ra4= | ||||
| github.com/qiniu/api.v7/v7 v7.8.2/go.mod h1:FPsIqxh1Ym3X01sANE5ZwXfLZSWoCUp5+jNI8cLo3l0= | ||||
| github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= | ||||
| github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= | ||||
| github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||||
|  | @ -424,6 +439,10 @@ github.com/swaggo/gin-swagger v1.3.2/go.mod h1:8GN8KIlwgjawtEvE+B8sx3q9SPJuX/ZPx | |||
| github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= | ||||
| github.com/swaggo/swag v1.7.4 h1:up+ixy8yOqJKiFcuhMgkuYuF4xnevuhnFAXXF8OSfNg= | ||||
| github.com/swaggo/swag v1.7.4/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI= | ||||
| github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= | ||||
| github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= | ||||
| github.com/tencentyun/cos-go-sdk-v5 v0.7.31 h1:NujkkOKMJ3IFs1+trCwXOKRCIPQ8qI5Lxul9JkhTg6M= | ||||
| github.com/tencentyun/cos-go-sdk-v5 v0.7.31/go.mod h1:4E4+bQ2gBVJcgEC9Cufwylio4mXOct2iu05WjgEBx1o= | ||||
| github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | ||||
| github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= | ||||
| github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= | ||||
|  | @ -578,6 +597,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | |||
| golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= | ||||
| golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								goweb-gin-demo
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								goweb-gin-demo
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -38,6 +38,8 @@ func Routers() *gin.Engine { | |||
| 		RouterGroup.InitJwtRouter(PrivateGroup) | ||||
| 		RouterGroup.InitUserRouter(PrivateGroup) | ||||
| 		RouterGroup.InitMenuRouter(PrivateGroup) | ||||
| 		RouterGroup.InitSystemRouter(PrivateGroup) | ||||
| 		RouterGroup.InitFileUploadAndDownloadRouter(PrivateGroup) | ||||
| 	} | ||||
| 
 | ||||
| 	global.GLOBAL_LOG.Info("router register success") | ||||
|  |  | |||
|  | @ -4,3 +4,71 @@ | |||
| [goweb-demo]2021/11/02 - 11:30:42.979	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:43	router register success | ||||
| [goweb-demo]2021/11/02 - 11:30:42.982	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8888"} | ||||
| [goweb-demo]2021/11/02 - 11:30:44.819	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8888: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 14:32:20.344	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:43	router register success | ||||
| [goweb-demo]2021/11/02 - 14:32:20.346	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8888"} | ||||
| [goweb-demo]2021/11/02 - 14:32:20.347	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	net.Listen error: listen tcp :8888: bind: address already in use | ||||
| [goweb-demo]2021/11/02 - 14:32:42.358	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:43	router register success | ||||
| [goweb-demo]2021/11/02 - 14:32:42.359	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8888"} | ||||
| [goweb-demo]2021/11/02 - 14:59:57.739	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 14:59:57.742	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 15:00:08.777	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 15:00:15.664	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 15:00:15.666	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 15:07:51.456	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 15:08:07.925	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 15:08:07.927	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8888"} | ||||
| [goweb-demo]2021/11/02 - 15:17:02.625	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 15:17:02.628	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8888"} | ||||
| [goweb-demo]2021/11/02 - 15:34:46.466	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/api/web/user.go:36	登陆失败! 用户名不存在或者密码错误!	{"err": "invalid connection"} | ||||
| [goweb-demo]2021/11/02 - 15:37:39.579	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 15:37:39.582	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 15:54:23.350	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 15:54:32.834	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 15:54:32.836	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 16:06:12.308	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 16:06:12.309	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 16:09:47.266	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 16:09:54.752	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 16:09:54.755	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 16:20:39.040	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/utils/upload/local.go:39	function os.MkdirAll() Filed	{"err": "mkdir : no such file or directory"} | ||||
| [goweb-demo]2021/11/02 - 16:21:07.385	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/utils/upload/local.go:39	function os.MkdirAll() Filed	{"err": "mkdir : no such file or directory"} | ||||
| [goweb-demo]2021/11/02 - 16:26:23.159	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 16:26:31.302	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 16:26:31.306	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 16:35:48.848	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/utils/upload/local.go:39	function os.MkdirAll() Filed	{"err": "mkdir : no such file or directory"} | ||||
| [goweb-demo]2021/11/02 - 16:37:09.761	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 16:37:09.764	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 16:37:17.352	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/api/web/file_upload_download.go:35	修改数据库链接失败!	{"err": "Error 1146: Table 'weekly_report.exa_file_upload_and_downloads' doesn't exist"} | ||||
| [goweb-demo]2021/11/02 - 17:03:38.349	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 17:03:38.353	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 17:14:21.779	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 17:14:21.782	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 17:29:03.543	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 17:29:11.545	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 17:29:11.552	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 17:56:09.792	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 17:56:20.437	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 17:56:20.440	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:52:46.120	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:52:46.124	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:53:04.183	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 19:53:13.557	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:53:13.559	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:54:22.978	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:38	accept tcp [::]:8889: use of closed network connection | ||||
| [goweb-demo]2021/11/02 - 19:54:31.396	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:54:31.399	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:56:09.819	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:56:09.822	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:57:48.713	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:57:48.717	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 19:58:18.069	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 19:58:18.070	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 20:01:23.356	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/api/web/file_upload_download.go:58	文件未找到!	{"err": "Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key = ? AND `file_upload_and_downloads`.`deleted_at` IS NULL ORDER BY `file_uplo' at line 1"} | ||||
| [goweb-demo]2021/11/02 - 20:01:38.751	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/api/web/file_upload_download.go:58	文件未找到!	{"err": "Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key = ? AND `file_upload_and_downloads`.`deleted_at` IS NULL ORDER BY `file_uplo' at line 1"} | ||||
| [goweb-demo]2021/11/02 - 20:04:10.155	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 20:04:10.159	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 20:07:53.705	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 20:07:53.709	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 20:09:04.558	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/initialize/router.go:45	router register success | ||||
| [goweb-demo]2021/11/02 - 20:09:04.562	[34minfo[0m	/Users/zero/work/mygithub/goweb-gin-demo/core/server.go:31	server run success on 	{"address": ":8889"} | ||||
| [goweb-demo]2021/11/02 - 20:09:44.609	[31merror[0m	/Users/zero/work/mygithub/goweb-gin-demo/api/web/file_upload_download.go:59	文件未找到!	{"err": "record not found"} | ||||
|  |  | |||
|  | @ -0,0 +1,24 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"goweb-gin-demo/global" | ||||
| ) | ||||
| 
 | ||||
| // file struct, 文件结构体
 | ||||
| type File struct { | ||||
| 	global.GLOBAL_MODEL | ||||
| 	FileName     string | ||||
| 	FileMd5      string | ||||
| 	FilePath     string | ||||
| 	ExaFileChunk []FileChunk | ||||
| 	ChunkTotal   int | ||||
| 	IsFinish     bool | ||||
| } | ||||
| 
 | ||||
| // file chunk struct, 切片结构体
 | ||||
| type FileChunk struct { | ||||
| 	global.GLOBAL_MODEL | ||||
| 	ExaFileID       uint | ||||
| 	FileChunkNumber int | ||||
| 	FileChunkPath   string | ||||
| } | ||||
|  | @ -0,0 +1,13 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"goweb-gin-demo/global" | ||||
| ) | ||||
| 
 | ||||
| type FileUploadAndDownload struct { | ||||
| 	global.GLOBAL_MODEL | ||||
| 	Name string `json:"name" gorm:"comment:文件名"` // 文件名
 | ||||
| 	Url  string `json:"url" gorm:"comment:文件地址"` // 文件地址
 | ||||
| 	Tag  string `json:"tag" gorm:"comment:文件标签"` // 文件标签
 | ||||
| 	Key  string `json:"key" gorm:"comment:编号"`   // 编号
 | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| package response | ||||
| 
 | ||||
| import "goweb-gin-demo/model/web" | ||||
| 
 | ||||
| type FilePathResponse struct { | ||||
| 	FilePath string `json:"filePath"` | ||||
| } | ||||
| 
 | ||||
| type FileResponse struct { | ||||
| 	File web.File `json:"file"` | ||||
| } | ||||
|  | @ -0,0 +1,7 @@ | |||
| package response | ||||
| 
 | ||||
| import "goweb-gin-demo/model/web" | ||||
| 
 | ||||
| type ExaFileResponse struct { | ||||
| 	File web.FileUploadAndDownload `json:"file"` | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 292 KiB | 
|  | @ -7,6 +7,8 @@ type RouterGroup struct { | |||
| 	web.JwtRouter | ||||
| 	web.UserRouter | ||||
| 	web.MenuRouter | ||||
| 	web.SysRouter | ||||
| 	web.FileUploadAndDownloadRouter | ||||
| } | ||||
| 
 | ||||
| var RouterGroupApp = new(RouterGroup) | ||||
|  |  | |||
|  | @ -0,0 +1,24 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"goweb-gin-demo/api" | ||||
| ) | ||||
| 
 | ||||
| type FileUploadAndDownloadRouter struct { | ||||
| } | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadRouter) InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) { | ||||
| 	fileUploadAndDownloadRouter := Router.Group("fileUploadAndDownload") | ||||
| 	var fileUploadAndDownloadApi = api.ApiGroupApp.ApiGroup.FileUploadAndDownloadApi | ||||
| 	{ | ||||
| 		fileUploadAndDownloadRouter.POST("upload", fileUploadAndDownloadApi.UploadFile)                                 // 上传文件
 | ||||
| 		fileUploadAndDownloadRouter.GET("download", fileUploadAndDownloadApi.DownloadFile)                              // 文件下载
 | ||||
| 		fileUploadAndDownloadRouter.POST("getFileList", fileUploadAndDownloadApi.GetFileList)                           // 获取上传文件列表
 | ||||
| 		fileUploadAndDownloadRouter.POST("deleteFile", fileUploadAndDownloadApi.DeleteFile)                             // 删除指定文件
 | ||||
| 		fileUploadAndDownloadRouter.POST("breakpointContinue", fileUploadAndDownloadApi.BreakpointContinue)             // 断点续传
 | ||||
| 		fileUploadAndDownloadRouter.GET("findFile", fileUploadAndDownloadApi.FindFile)                                  // 查询当前文件成功的切片
 | ||||
| 		fileUploadAndDownloadRouter.POST("breakpointContinueFinish", fileUploadAndDownloadApi.BreakpointContinueFinish) // 查询当前文件成功的切片
 | ||||
| 		fileUploadAndDownloadRouter.POST("removeChunk", fileUploadAndDownloadApi.RemoveChunk)                           // 查询当前文件成功的切片
 | ||||
| 	} | ||||
| } | ||||
|  | @ -2,7 +2,7 @@ package web | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	v1 "goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/api" | ||||
| ) | ||||
| 
 | ||||
| type JwtRouter struct { | ||||
|  | @ -10,7 +10,7 @@ type JwtRouter struct { | |||
| 
 | ||||
| func (s *JwtRouter) InitJwtRouter(Router *gin.RouterGroup) { | ||||
| 	jwtRouter := Router.Group("jwt") | ||||
| 	var jwtApi = v1.ApiGroupApp.ApiGroup.JwtApi | ||||
| 	var jwtApi = api.ApiGroupApp.ApiGroup.JwtApi | ||||
| 	{ | ||||
| 		jwtRouter.POST("jsonInBlacklist", jwtApi.JsonInBlacklist) // jwt加入黑名单
 | ||||
| 	} | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ package web | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	v1 "goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/middleware" | ||||
| ) | ||||
| 
 | ||||
|  | @ -12,7 +12,7 @@ type MenuRouter struct { | |||
| func (s *MenuRouter) InitMenuRouter(Router *gin.RouterGroup) (R gin.IRoutes) { | ||||
| 	menuRouter := Router.Group("menu").Use(middleware.OperationRecord()) | ||||
| 	menuRouterWithoutRecord := Router.Group("menu") | ||||
| 	var authorityMenuApi = v1.ApiGroupApp.ApiGroup.AuthorityMenuApi | ||||
| 	var authorityMenuApi = api.ApiGroupApp.ApiGroup.AuthorityMenuApi | ||||
| 	{ | ||||
| 		menuRouter.POST("addBaseMenu", authorityMenuApi.AddBaseMenu)           // 新增菜单
 | ||||
| 		menuRouter.POST("addMenuAuthority", authorityMenuApi.AddMenuAuthority) //	增加menu和角色关联关系
 | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| package web | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/middleware" | ||||
| ) | ||||
| 
 | ||||
| type SysRouter struct { | ||||
| } | ||||
| 
 | ||||
| func (s *SysRouter) InitSystemRouter(Router *gin.RouterGroup) { | ||||
| 	sysRouter := Router.Group("system").Use(middleware.OperationRecord()) | ||||
| 	var systemApi = api.ApiGroupApp.ApiGroup.SystemApi | ||||
| 	{ | ||||
| 		sysRouter.POST("getSystemConfig", systemApi.GetSystemConfig) // 获取配置文件内容
 | ||||
| 		sysRouter.POST("setSystemConfig", systemApi.SetSystemConfig) // 设置配置文件内容
 | ||||
| 		sysRouter.POST("getServerInfo", systemApi.GetServerInfo)     // 获取服务器信息
 | ||||
| 		sysRouter.POST("reloadSystem", systemApi.ReloadSystem)       // 重启服务
 | ||||
| 	} | ||||
| } | ||||
|  | @ -2,7 +2,7 @@ package web | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	v1 "goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/api" | ||||
| 	"goweb-gin-demo/middleware" | ||||
| ) | ||||
| 
 | ||||
|  | @ -12,7 +12,7 @@ type UserRouter struct { | |||
| func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) { | ||||
| 	userRouter := Router.Group("user").Use(middleware.OperationRecord()) | ||||
| 	userRouterWithoutRecord := Router.Group("user") | ||||
| 	var baseApi = v1.ApiGroupApp.ApiGroup.BaseApi | ||||
| 	var baseApi = api.ApiGroupApp.ApiGroup.BaseApi | ||||
| 	{ | ||||
| 		userRouter.POST("register", baseApi.Register)                     // 用户注册账号
 | ||||
| 		userRouter.POST("changePassword", baseApi.ChangePassword)         // 用户修改密码
 | ||||
|  |  | |||
|  | @ -0,0 +1,66 @@ | |||
| package service | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 
 | ||||
| 	"gorm.io/gorm" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/web" | ||||
| ) | ||||
| 
 | ||||
| type FileUploadAndDownloadService struct { | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: FindOrCreateFile
 | ||||
| //@description: 上传文件时检测当前文件属性,如果没有文件则创建,有则返回文件的当前切片
 | ||||
| //@param: fileMd5 string, fileName string, chunkTotal int
 | ||||
| //@return: err error, file model.File
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) FindOrCreateFile(fileMd5 string, fileName string, chunkTotal int) (err error, file web.File) { | ||||
| 	var cfile web.File | ||||
| 	cfile.FileMd5 = fileMd5 | ||||
| 	cfile.FileName = fileName | ||||
| 	cfile.ChunkTotal = chunkTotal | ||||
| 
 | ||||
| 	if errors.Is(global.GLOBAL_DB.Where("file_md5 = ? AND is_finish = ?", fileMd5, true).First(&file).Error, gorm.ErrRecordNotFound) { | ||||
| 		err = global.GLOBAL_DB.Where("file_md5 = ? AND file_name = ?", fileMd5, fileName).Preload("FileChunk").FirstOrCreate(&file, cfile).Error | ||||
| 		return err, file | ||||
| 	} | ||||
| 	cfile.IsFinish = true | ||||
| 	cfile.FilePath = file.FilePath | ||||
| 	err = global.GLOBAL_DB.Create(&cfile).Error | ||||
| 	return err, cfile | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: CreateFileChunk
 | ||||
| //@description: 创建文件切片记录
 | ||||
| //@param: id uint, fileChunkPath string, fileChunkNumber int
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) CreateFileChunk(id uint, fileChunkPath string, fileChunkNumber int) error { | ||||
| 	var chunk web.FileChunk | ||||
| 	chunk.FileChunkPath = fileChunkPath | ||||
| 	chunk.ExaFileID = id | ||||
| 	chunk.FileChunkNumber = fileChunkNumber | ||||
| 	err := global.GLOBAL_DB.Create(&chunk).Error | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: DeleteFileChunk
 | ||||
| //@description: 删除文件切片记录
 | ||||
| //@param: fileMd5 string, fileName string, filePath string
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) DeleteFileChunk(fileMd5 string, fileName string, filePath string) error { | ||||
| 	var chunks []web.FileChunk | ||||
| 	var file web.File | ||||
| 	err := global.GLOBAL_DB.Where("file_md5 = ? AND file_name = ?", fileMd5, fileName).First(&file).Update("IsFinish", true).Update("file_path", filePath).Error | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = global.GLOBAL_DB.Where("exa_file_id = ?", file.ID).Delete(&chunks).Unscoped().Error | ||||
| 	return err | ||||
| } | ||||
|  | @ -8,6 +8,7 @@ type ServiceGroup struct { | |||
| 	MenuService | ||||
| 	BaseMenuService | ||||
| 	SystemConfigService | ||||
| 	FileUploadAndDownloadService | ||||
| } | ||||
| 
 | ||||
| var ServiceGroupApp = new(ServiceGroup) | ||||
|  |  | |||
|  | @ -0,0 +1,98 @@ | |||
| package service | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"mime/multipart" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/model/common/request" | ||||
| 	"goweb-gin-demo/model/web" | ||||
| 	"goweb-gin-demo/utils/upload" | ||||
| ) | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: Upload
 | ||||
| //@description: 创建文件上传记录
 | ||||
| //@param: file model.FileUploadAndDownload
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) Upload(file web.FileUploadAndDownload) error { | ||||
| 	return global.GLOBAL_DB.Create(&file).Error | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: FindFile
 | ||||
| //@description: 查找文件
 | ||||
| //@param: id uint
 | ||||
| //@return: error, model.FileUploadAndDownload
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) FindFile(key string) (error, web.FileUploadAndDownload) { | ||||
| 	var file web.FileUploadAndDownload | ||||
| 	err := global.GLOBAL_DB.Where("`key` = ?", key).First(&file).Error | ||||
| 	return err, file | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: DeleteFile
 | ||||
| //@description: 删除文件记录
 | ||||
| //@param: file model.FileUploadAndDownload
 | ||||
| //@return: err error
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) DeleteFile(file web.FileUploadAndDownload) (err error) { | ||||
| 	var fileFromDb web.FileUploadAndDownload | ||||
| 	err, fileFromDb = e.FindFile(file.Key) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	oss := upload.NewOss() | ||||
| 	if err = oss.DeleteFile(fileFromDb.Key); err != nil { | ||||
| 		return errors.New("文件删除失败") | ||||
| 	} | ||||
| 	err = global.GLOBAL_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: GetFileRecordInfoList
 | ||||
| //@description: 分页获取数据
 | ||||
| //@param: info request.PageInfo
 | ||||
| //@return: err error, list interface{}, total int64
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) GetFileRecordInfoList(info request.PageInfo) (err error, list interface{}, total int64) { | ||||
| 	limit := info.PageSize | ||||
| 	offset := info.PageSize * (info.Page - 1) | ||||
| 	db := global.GLOBAL_DB.Model(&web.FileUploadAndDownload{}) | ||||
| 	var fileLists []web.FileUploadAndDownload | ||||
| 	err = db.Count(&total).Error | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&fileLists).Error | ||||
| 	return err, fileLists, total | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: UploadFile
 | ||||
| //@description: 根据配置文件判断是文件上传到本地或者七牛云
 | ||||
| //@param: header *multipart.FileHeader, noSave string
 | ||||
| //@return: err error, file model.FileUploadAndDownload
 | ||||
| 
 | ||||
| func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader, noSave string) (err error, file web.FileUploadAndDownload) { | ||||
| 	oss := upload.NewOss() | ||||
| 	filePath, key, uploadErr := oss.UploadFile(header) | ||||
| 	if uploadErr != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	if noSave == "0" { | ||||
| 		s := strings.Split(header.Filename, ".") | ||||
| 		f := web.FileUploadAndDownload{ | ||||
| 			Url:  filePath, | ||||
| 			Name: header.Filename, | ||||
| 			Tag:  s[len(s)-1], | ||||
| 			Key:  key, | ||||
| 		} | ||||
| 		return e.Upload(f), f | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | @ -0,0 +1,107 @@ | |||
| package utils | ||||
| 
 | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| ) | ||||
| 
 | ||||
| // 前端传来文件片与当前片为什么文件的第几片
 | ||||
| // 后端拿到以后比较次分片是否上传 或者是否为不完全片
 | ||||
| // 前端发送每片多大
 | ||||
| // 前端告知是否为最后一片且是否完成
 | ||||
| 
 | ||||
| const breakpointDir = "./breakpointDir/" | ||||
| const finishDir = "./fileDir/" | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: BreakPointContinue
 | ||||
| //@description: 断点续传
 | ||||
| //@param: content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string
 | ||||
| //@return: error, string
 | ||||
| 
 | ||||
| func BreakPointContinue(content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string) (error, string) { | ||||
| 	path := breakpointDir + fileMd5 + "/" | ||||
| 	err := os.MkdirAll(path, os.ModePerm) | ||||
| 	if err != nil { | ||||
| 		return err, path | ||||
| 	} | ||||
| 	err, pathc := makeFileContent(content, fileName, path, contentNumber) | ||||
| 	return err, pathc | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: CheckMd5
 | ||||
| //@description: 检查Md5
 | ||||
| //@param: content []byte, chunkMd5 string
 | ||||
| //@return: CanUpload bool
 | ||||
| 
 | ||||
| func CheckMd5(content []byte, chunkMd5 string) (CanUpload bool) { | ||||
| 	fileMd5 := MD5V(content) | ||||
| 	if fileMd5 == chunkMd5 { | ||||
| 		return true // 可以继续上传
 | ||||
| 	} else { | ||||
| 		return false // 切片不完整,废弃
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: makeFileContent
 | ||||
| //@description: 创建切片内容
 | ||||
| //@param: content []byte, fileName string, FileDir string, contentNumber int
 | ||||
| //@return: error, string
 | ||||
| 
 | ||||
| func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (error, string) { | ||||
| 	path := FileDir + fileName + "_" + strconv.Itoa(contentNumber) | ||||
| 	f, err := os.Create(path) | ||||
| 	if err != nil { | ||||
| 		return err, path | ||||
| 	} else { | ||||
| 		_, err = f.Write(content) | ||||
| 		if err != nil { | ||||
| 			return err, path | ||||
| 		} | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	return nil, path | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: makeFileContent
 | ||||
| //@description: 创建切片文件
 | ||||
| //@param: fileName string, FileMd5 string
 | ||||
| //@return: error, string
 | ||||
| 
 | ||||
| func MakeFile(fileName string, FileMd5 string) (error, string) { | ||||
| 	rd, err := ioutil.ReadDir(breakpointDir + FileMd5) | ||||
| 	if err != nil { | ||||
| 		return err, finishDir + fileName | ||||
| 	} | ||||
| 	_ = os.MkdirAll(finishDir, os.ModePerm) | ||||
| 	fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) | ||||
| 	if err != nil { | ||||
| 		return err, finishDir + fileName | ||||
| 	} | ||||
| 	defer fd.Close() | ||||
| 	for k := range rd { | ||||
| 		content, _ := ioutil.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k)) | ||||
| 		_, err = fd.Write(content) | ||||
| 		if err != nil { | ||||
| 			_ = os.Remove(finishDir + fileName) | ||||
| 			return err, finishDir + fileName | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, finishDir + fileName | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@function: RemoveChunk
 | ||||
| //@description: 移除切片
 | ||||
| //@param: FileMd5 string
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func RemoveChunk(FileMd5 string) error { | ||||
| 	err := os.RemoveAll(breakpointDir + FileMd5) | ||||
| 	return err | ||||
| } | ||||
|  | @ -0,0 +1,75 @@ | |||
| package upload | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"mime/multipart" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/aliyun/aliyun-oss-go-sdk/oss" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| 
 | ||||
| type AliyunOSS struct{} | ||||
| 
 | ||||
| func (*AliyunOSS) UploadFile(file *multipart.FileHeader) (string, string, error) { | ||||
| 	bucket, err := NewBucket() | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error())) | ||||
| 		return "", "", errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// 读取本地文件。
 | ||||
| 	f, openError := file.Open() | ||||
| 	if openError != nil { | ||||
| 		global.GLOBAL_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error())) | ||||
| 		return "", "", errors.New("function file.Open() Failed, err:" + openError.Error()) | ||||
| 	} | ||||
| 	defer f.Close() // 创建文件 defer 关闭
 | ||||
| 	// 上传阿里云路径 文件名格式 自己可以改 建议保证唯一性
 | ||||
| 	//yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename
 | ||||
| 	yunFileTmpPath := global.GLOBAL_CONFIG.AliyunOSS.BasePath + "/" + "uploads" + "/" + time.Now().Format("2006-01-02") + "/" + file.Filename | ||||
| 
 | ||||
| 	// 上传文件流。
 | ||||
| 	err = bucket.PutObject(yunFileTmpPath, f) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function formUploader.Put() Failed", zap.Any("err", err.Error())) | ||||
| 		return "", "", errors.New("function formUploader.Put() Failed, err:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	return global.GLOBAL_CONFIG.AliyunOSS.BucketUrl + "/" + yunFileTmpPath, yunFileTmpPath, nil | ||||
| } | ||||
| 
 | ||||
| func (*AliyunOSS) DeleteFile(key string) error { | ||||
| 	bucket, err := NewBucket() | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error())) | ||||
| 		return errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// 删除单个文件。objectName表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
 | ||||
| 	// 如需删除文件夹,请将objectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
 | ||||
| 	err = bucket.DeleteObject(key) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error())) | ||||
| 		return errors.New("function bucketManager.Delete() Filed, err:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func NewBucket() (*oss.Bucket, error) { | ||||
| 	// 创建OSSClient实例。
 | ||||
| 	client, err := oss.New(global.GLOBAL_CONFIG.AliyunOSS.Endpoint, global.GLOBAL_CONFIG.AliyunOSS.AccessKeyId, global.GLOBAL_CONFIG.AliyunOSS.AccessKeySecret) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// 获取存储空间。
 | ||||
| 	bucket, err := client.Bucket(global.GLOBAL_CONFIG.AliyunOSS.BucketName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return bucket, nil | ||||
| } | ||||
|  | @ -0,0 +1,85 @@ | |||
| package upload | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"mime/multipart" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"goweb-gin-demo/utils" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| 
 | ||||
| type Local struct{} | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@object: *Local
 | ||||
| //@function: UploadFile
 | ||||
| //@description: 上传文件
 | ||||
| //@param: file *multipart.FileHeader
 | ||||
| //@return: string, string, error
 | ||||
| 
 | ||||
| func (*Local) UploadFile(file *multipart.FileHeader) (string, string, error) { | ||||
| 	// 读取文件后缀
 | ||||
| 	ext := path.Ext(file.Filename) | ||||
| 	// 读取文件名并加密
 | ||||
| 	name := strings.TrimSuffix(file.Filename, ext) | ||||
| 	name = utils.MD5V([]byte(name)) | ||||
| 	// 拼接新文件名
 | ||||
| 	filename := name + "_" + time.Now().Format("20060102150405") + ext | ||||
| 	// 尝试创建此路径
 | ||||
| 	mkdirErr := os.MkdirAll(global.GLOBAL_CONFIG.Local.Path, os.ModePerm) | ||||
| 	if mkdirErr != nil { | ||||
| 		global.GLOBAL_LOG.Error("function os.MkdirAll() Filed", zap.Any("err", mkdirErr.Error())) | ||||
| 		return "", "", errors.New("function os.MkdirAll() Filed, err:" + mkdirErr.Error()) | ||||
| 	} | ||||
| 	// 拼接路径和文件名
 | ||||
| 	p := global.GLOBAL_CONFIG.Local.Path + "/" + filename | ||||
| 
 | ||||
| 	f, openError := file.Open() // 读取文件
 | ||||
| 	if openError != nil { | ||||
| 		global.GLOBAL_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error())) | ||||
| 		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error()) | ||||
| 	} | ||||
| 	defer f.Close() // 创建文件 defer 关闭
 | ||||
| 
 | ||||
| 	out, createErr := os.Create(p) | ||||
| 	if createErr != nil { | ||||
| 		global.GLOBAL_LOG.Error("function os.Create() Filed", zap.Any("err", createErr.Error())) | ||||
| 
 | ||||
| 		return "", "", errors.New("function os.Create() Filed, err:" + createErr.Error()) | ||||
| 	} | ||||
| 	defer out.Close() // 创建文件 defer 关闭
 | ||||
| 
 | ||||
| 	_, copyErr := io.Copy(out, f) // 传输(拷贝)文件
 | ||||
| 	if copyErr != nil { | ||||
| 		global.GLOBAL_LOG.Error("function io.Copy() Filed", zap.Any("err", copyErr.Error())) | ||||
| 		return "", "", errors.New("function io.Copy() Filed, err:" + copyErr.Error()) | ||||
| 	} | ||||
| 	return p, filename, nil | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@object: *Local
 | ||||
| //@function: DeleteFile
 | ||||
| //@description: 删除文件
 | ||||
| //@param: key string
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func (*Local) DeleteFile(key string) error { | ||||
| 	p := global.GLOBAL_CONFIG.Local.Path + "/" + key | ||||
| 	if strings.Contains(p, global.GLOBAL_CONFIG.Local.Path) { | ||||
| 		if err := os.Remove(p); err != nil { | ||||
| 			return errors.New("本地文件删除失败, err:" + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | @ -0,0 +1,96 @@ | |||
| package upload | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"mime/multipart" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"github.com/qiniu/api.v7/v7/auth/qbox" | ||||
| 	"github.com/qiniu/api.v7/v7/storage" | ||||
| 	"go.uber.org/zap" | ||||
| ) | ||||
| 
 | ||||
| type Qiniu struct{} | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@object: *Qiniu
 | ||||
| //@function: UploadFile
 | ||||
| //@description: 上传文件
 | ||||
| //@param: file *multipart.FileHeader
 | ||||
| //@return: string, string, error
 | ||||
| 
 | ||||
| func (*Qiniu) UploadFile(file *multipart.FileHeader) (string, string, error) { | ||||
| 	putPolicy := storage.PutPolicy{Scope: global.GLOBAL_CONFIG.Qiniu.Bucket} | ||||
| 	mac := qbox.NewMac(global.GLOBAL_CONFIG.Qiniu.AccessKey, global.GLOBAL_CONFIG.Qiniu.SecretKey) | ||||
| 	upToken := putPolicy.UploadToken(mac) | ||||
| 	cfg := qiniuConfig() | ||||
| 	formUploader := storage.NewFormUploader(cfg) | ||||
| 	ret := storage.PutRet{} | ||||
| 	putExtra := storage.PutExtra{Params: map[string]string{"x:name": "github logo"}} | ||||
| 
 | ||||
| 	f, openError := file.Open() | ||||
| 	if openError != nil { | ||||
| 		global.GLOBAL_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error())) | ||||
| 
 | ||||
| 		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error()) | ||||
| 	} | ||||
| 	defer f.Close()                                                  // 创建文件 defer 关闭
 | ||||
| 	fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) // 文件名格式 自己可以改 建议保证唯一性
 | ||||
| 	putErr := formUploader.Put(context.Background(), &ret, upToken, fileKey, f, file.Size, &putExtra) | ||||
| 	if putErr != nil { | ||||
| 		global.GLOBAL_LOG.Error("function formUploader.Put() Filed", zap.Any("err", putErr.Error())) | ||||
| 		return "", "", errors.New("function formUploader.Put() Filed, err:" + putErr.Error()) | ||||
| 	} | ||||
| 	return global.GLOBAL_CONFIG.Qiniu.ImgPath + "/" + ret.Key, ret.Key, nil | ||||
| } | ||||
| 
 | ||||
| //@author: [piexlmax](https://github.com/piexlmax)
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@object: *Qiniu
 | ||||
| //@function: DeleteFile
 | ||||
| //@description: 删除文件
 | ||||
| //@param: key string
 | ||||
| //@return: error
 | ||||
| 
 | ||||
| func (*Qiniu) DeleteFile(key string) error { | ||||
| 	mac := qbox.NewMac(global.GLOBAL_CONFIG.Qiniu.AccessKey, global.GLOBAL_CONFIG.Qiniu.SecretKey) | ||||
| 	cfg := qiniuConfig() | ||||
| 	bucketManager := storage.NewBucketManager(mac, cfg) | ||||
| 	if err := bucketManager.Delete(global.GLOBAL_CONFIG.Qiniu.Bucket, key); err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error())) | ||||
| 		return errors.New("function bucketManager.Delete() Filed, err:" + err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@object: *Qiniu
 | ||||
| //@function: qiniuConfig
 | ||||
| //@description: 根据配置文件进行返回七牛云的配置
 | ||||
| //@return: *storage.Config
 | ||||
| 
 | ||||
| func qiniuConfig() *storage.Config { | ||||
| 	cfg := storage.Config{ | ||||
| 		UseHTTPS:      global.GLOBAL_CONFIG.Qiniu.UseHTTPS, | ||||
| 		UseCdnDomains: global.GLOBAL_CONFIG.Qiniu.UseCdnDomains, | ||||
| 	} | ||||
| 	switch global.GLOBAL_CONFIG.Qiniu.Zone { // 根据配置文件进行初始化空间对应的机房
 | ||||
| 	case "ZoneHuadong": | ||||
| 		cfg.Zone = &storage.ZoneHuadong | ||||
| 	case "ZoneHuabei": | ||||
| 		cfg.Zone = &storage.ZoneHuabei | ||||
| 	case "ZoneHuanan": | ||||
| 		cfg.Zone = &storage.ZoneHuanan | ||||
| 	case "ZoneBeimei": | ||||
| 		cfg.Zone = &storage.ZoneBeimei | ||||
| 	case "ZoneXinjiapo": | ||||
| 		cfg.Zone = &storage.ZoneXinjiapo | ||||
| 	} | ||||
| 	return &cfg | ||||
| } | ||||
|  | @ -0,0 +1,59 @@ | |||
| package upload | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/tencentyun/cos-go-sdk-v5" | ||||
| 	"go.uber.org/zap" | ||||
| 	"goweb-gin-demo/global" | ||||
| 	"mime/multipart" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type TencentCOS struct{} | ||||
| 
 | ||||
| // UploadFile upload file to COS
 | ||||
| func (*TencentCOS) UploadFile(file *multipart.FileHeader) (string, string, error) { | ||||
| 	client := NewClient() | ||||
| 	f, openError := file.Open() | ||||
| 	if openError != nil { | ||||
| 		global.GLOBAL_LOG.Error("function file.Open() Filed", zap.Any("err", openError.Error())) | ||||
| 		return "", "", errors.New("function file.Open() Filed, err:" + openError.Error()) | ||||
| 	} | ||||
| 	defer f.Close() // 创建文件 defer 关闭
 | ||||
| 	fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) | ||||
| 
 | ||||
| 	_, err := client.Object.Put(context.Background(), global.GLOBAL_CONFIG.TencentCOS.PathPrefix+"/"+fileKey, f, nil) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return global.GLOBAL_CONFIG.TencentCOS.BaseURL + "/" + global.GLOBAL_CONFIG.TencentCOS.PathPrefix + "/" + fileKey, fileKey, nil | ||||
| } | ||||
| 
 | ||||
| // DeleteFile delete file form COS
 | ||||
| func (*TencentCOS) DeleteFile(key string) error { | ||||
| 	client := NewClient() | ||||
| 	name := global.GLOBAL_CONFIG.TencentCOS.PathPrefix + "/" + key | ||||
| 	_, err := client.Object.Delete(context.Background(), name) | ||||
| 	if err != nil { | ||||
| 		global.GLOBAL_LOG.Error("function bucketManager.Delete() Filed", zap.Any("err", err.Error())) | ||||
| 		return errors.New("function bucketManager.Delete() Filed, err:" + err.Error()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // NewClient init COS client
 | ||||
| func NewClient() *cos.Client { | ||||
| 	urlStr, _ := url.Parse("https://" + global.GLOBAL_CONFIG.TencentCOS.Bucket + ".cos." + global.GLOBAL_CONFIG.TencentCOS.Region + ".myqcloud.com") | ||||
| 	baseURL := &cos.BaseURL{BucketURL: urlStr} | ||||
| 	client := cos.NewClient(baseURL, &http.Client{ | ||||
| 		Transport: &cos.AuthorizationTransport{ | ||||
| 			SecretID:  global.GLOBAL_CONFIG.TencentCOS.SecretID, | ||||
| 			SecretKey: global.GLOBAL_CONFIG.TencentCOS.SecretKey, | ||||
| 		}, | ||||
| 	}) | ||||
| 	return client | ||||
| } | ||||
|  | @ -0,0 +1,39 @@ | |||
| package upload | ||||
| 
 | ||||
| import ( | ||||
| 	"mime/multipart" | ||||
| 
 | ||||
| 	"goweb-gin-demo/global" | ||||
| ) | ||||
| 
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@interface_name: OSS
 | ||||
| //@description: OSS接口
 | ||||
| 
 | ||||
| type OSS interface { | ||||
| 	UploadFile(file *multipart.FileHeader) (string, string, error) | ||||
| 	DeleteFile(key string) error | ||||
| } | ||||
| 
 | ||||
| //@author: [ccfish86](https://github.com/ccfish86)
 | ||||
| //@author: [SliverHorn](https://github.com/SliverHorn)
 | ||||
| //@function: NewOss
 | ||||
| //@description: OSS接口
 | ||||
| //@description: OSS的实例化方法
 | ||||
| //@return: OSS
 | ||||
| 
 | ||||
| func NewOss() OSS { | ||||
| 	switch global.GLOBAL_CONFIG.System.OssType { | ||||
| 	case "local": | ||||
| 		return &Local{} | ||||
| 	case "qiniu": | ||||
| 		return &Qiniu{} | ||||
| 	case "tencent-cos": | ||||
| 		return &TencentCOS{} | ||||
| 	case "aliyun-oss": | ||||
| 		return &AliyunOSS{} | ||||
| 	default: | ||||
| 		return &Local{} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue