file.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package v1
  2. import (
  3. "context"
  4. "designs/app/common/request"
  5. "designs/global"
  6. "designs/model"
  7. "designs/response"
  8. "fmt"
  9. "github.com/gin-gonic/gin"
  10. "github.com/tencentyun/cos-go-sdk-v5"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "path/filepath"
  15. "strings"
  16. "time"
  17. )
  18. func FileList(c *gin.Context) {
  19. form := request.Check(c, &struct {
  20. Dir string `form:"dir" binding:"required"`
  21. Offset *int `form:"offset" binding:"required"`
  22. Limit *int `form:"limit" binding:"required"`
  23. Search string `form:"search" binding:""`
  24. }{})
  25. query := global.App.DB.Table("file").Where("dir", form.Dir)
  26. if form.Search != "" {
  27. query = query.Where("fileName", "like", "%"+form.Search+"%")
  28. }
  29. var count int64
  30. err := query.Count(&count).Error
  31. if err != nil {
  32. response.Fail(c, 1001, err.Error())
  33. return
  34. }
  35. var files []model.File
  36. err = query.Offset(*form.Offset).Limit(*form.Limit).Scan(&files).Error
  37. if err != nil {
  38. response.Fail(c, 1002, err.Error())
  39. return
  40. }
  41. response.Success(c, gin.H{
  42. "count": count,
  43. "data": files,
  44. })
  45. }
  46. func DirDownload(c *gin.Context) {
  47. form := request.Check(c, &struct {
  48. Dir string `form:"dir" binding:"required"`
  49. }{})
  50. data, err := DirExplode(form.Dir)
  51. if err != nil {
  52. response.Fail(c, 1001, err.Error())
  53. return
  54. }
  55. response.Success(c, gin.H{
  56. "data": data,
  57. })
  58. }
  59. func DirExplode(dir string) (map[string]interface{}, error) {
  60. data := make(map[string]interface{})
  61. var files []model.File
  62. err := global.App.DB.Table("file").Where("dir", dir).Scan(&files).Error
  63. if err != nil {
  64. return nil, err
  65. }
  66. for _, file := range files {
  67. if file.Type == 2 {
  68. data[file.FileName], _ = DirExplode(file.Dir)
  69. } else {
  70. data[file.FileName] = file.CosPath
  71. }
  72. }
  73. return data, nil
  74. }
  75. func FileDelete(c *gin.Context) {
  76. form := request.Check(c, &struct {
  77. FileId int `form:"fileId" json:"fileId" binding:"required"`
  78. }{})
  79. var file model.File
  80. global.App.DB.Table("file").Where("id", form.FileId).Find(&file)
  81. if file.Type == 1 {
  82. //删除本地文件和云端文件 (本地文件暂时不删除,作为备份)
  83. err := ServiceFileDelete(file.CosPath)
  84. if err != nil {
  85. response.Fail(c, 2001, "云端文件删除失败"+err.Error())
  86. return
  87. }
  88. }
  89. var d interface{}
  90. err := global.App.DB.Table("file").Where("id", form.FileId).Delete(d).Error
  91. if err != nil {
  92. response.Fail(c, 2001, err.Error())
  93. return
  94. }
  95. response.Success(c, gin.H{})
  96. }
  97. func LocalFileToService(c *gin.Context) {
  98. form := request.Check(c, &struct {
  99. Dir string `form:"dir" json:"dir" binding:"required"`
  100. FilePath string `form:"filePath" json:"filePath" binding:"required"`
  101. }{})
  102. path, err := FileToService(form.FilePath)
  103. if err != nil {
  104. response.Fail(c, 1004, err.Error())
  105. return
  106. }
  107. now := model.XTime{
  108. Time: time.Now(),
  109. }
  110. //存储到mysql
  111. err = global.App.DB.Table("file").Create(&model.File{
  112. CreatedAt: now,
  113. UpdatedAt: now,
  114. FileName: filepath.Base(form.FilePath),
  115. LocalPath: form.FilePath,
  116. Type: 1,
  117. Dir: form.Dir,
  118. CosPath: path,
  119. }).Error
  120. if err != nil {
  121. response.Fail(c, 2001, err.Error())
  122. return
  123. }
  124. response.Success(c, gin.H{
  125. "file_path": path,
  126. })
  127. }
  128. func UploadToCos(c *gin.Context) {
  129. // 获取文件
  130. file, err := c.FormFile("file")
  131. if err != nil {
  132. response.Fail(c, 400, "未选择文件")
  133. return
  134. }
  135. //获取dir
  136. dir := c.PostForm("dir")
  137. if dir == "" {
  138. dir = "/"
  139. } else if dir != "/" { //格式化
  140. dir = "/" + strings.Trim(dir, "/") + "/"
  141. }
  142. // 存储路径生成
  143. saveDir := fmt.Sprintf("uploads/%s", dir)
  144. os.MkdirAll(saveDir, 0755)
  145. savePath := filepath.Join(saveDir, file.Filename)
  146. // 保存文件
  147. if err := c.SaveUploadedFile(file, savePath); err != nil {
  148. response.Fail(c, 500, "文件保存失败")
  149. return
  150. }
  151. path, err := FileToService(savePath)
  152. if err != nil {
  153. response.Fail(c, 1004, err.Error())
  154. return
  155. }
  156. now := model.XTime{
  157. Time: time.Now(),
  158. }
  159. //存储文件夹
  160. var dirFile model.File
  161. base := filepath.Base(dir)
  162. dirPath := strings.TrimSuffix(dir, base+"/")
  163. fmt.Println("dirPath", dirPath)
  164. global.App.DB.Table("file").Where("type", 2).Where("fileName", base).Where("dir", dirPath).First(&dirFile)
  165. if dirFile.Id == 0 {
  166. err := global.App.DB.Table("file").Create(&model.File{
  167. CreatedAt: now,
  168. UpdatedAt: now,
  169. FileName: base,
  170. Dir: dirPath,
  171. LocalPath: "",
  172. Type: 2,
  173. CosPath: "",
  174. }).Error
  175. if err != nil {
  176. response.Fail(c, 2001, err.Error())
  177. return
  178. }
  179. }
  180. //存储到mysql
  181. var files model.File
  182. global.App.DB.Table("file").Where("fileName", filepath.Base(savePath)).Where("dir", dir).Find(&files)
  183. if files.Id != 0 {
  184. err = global.App.DB.Table("file").Where("id", files.Id).Updates(map[string]interface{}{
  185. "localPath": savePath,
  186. "updatedAt": now,
  187. "fileName": filepath.Base(savePath),
  188. "dir": dir,
  189. "cosPath": path,
  190. }).Error
  191. } else {
  192. err = global.App.DB.Table("file").Create(&model.File{
  193. CreatedAt: now,
  194. UpdatedAt: now,
  195. FileName: filepath.Base(savePath),
  196. LocalPath: savePath,
  197. Type: 1,
  198. Dir: dir,
  199. CosPath: path,
  200. }).Error
  201. }
  202. if err != nil {
  203. response.Fail(c, 2001, err.Error())
  204. return
  205. }
  206. response.Success(c, gin.H{
  207. "file_path": path,
  208. })
  209. }
  210. func CreateDir(c *gin.Context) {
  211. form := request.Check(c, &struct {
  212. Dir string `form:"dir" json:"dir" binding:"required"`
  213. DirName string `form:"dirName" json:"dirName" binding:"required"`
  214. }{})
  215. count := strings.Count(form.Dir, "/")
  216. if count >= 3 {
  217. response.Fail(c, 1002, "文件夹的层级不能超过三级")
  218. return
  219. }
  220. now := model.XTime{
  221. Time: time.Now(),
  222. }
  223. //存储到mysql
  224. err := global.App.DB.Table("file").Create(&model.File{
  225. CreatedAt: now,
  226. UpdatedAt: now,
  227. FileName: form.DirName,
  228. Dir: form.Dir,
  229. LocalPath: "",
  230. Type: 2,
  231. CosPath: "",
  232. }).Error
  233. if err != nil {
  234. response.Fail(c, 2001, err.Error())
  235. return
  236. }
  237. response.Success(c, gin.H{})
  238. }
  239. const CosUrl = "https://chunhao-1257323087.cos.ap-shanghai.myqcloud.com"
  240. const CosServiceUrl = "https://service.cos.myqcloud.com"
  241. const SecretID = "AKIDgQ2TzTq381nQrAJKBC8tSqCNM9lBQTQB"
  242. const SecretKey = "gBVWO4dzCD5qeKoy30phTBi7NXYYM2b0"
  243. func FileToService(filePath string) (string, error) {
  244. // 将 examplebucket-1250000000 和 COS_REGION 修改为用户真实的信息
  245. // 存储桶名称,由 bucketname-appid 组成,appid 必须填入,可以在 COS 控制台查看存储桶名称。https://console.cloud.tencent.com/cos5/bucket
  246. // COS_REGION 可以在控制台查看,https://console.cloud.tencent.com/cos5/bucket, 关于地域的详情见 https://cloud.tencent.com/document/product/436/6224
  247. u, _ := url.Parse(CosUrl)
  248. // 用于 Get Service 查询,默认全地域 service.cos.myqcloud.com
  249. su, _ := url.Parse(CosServiceUrl)
  250. b := &cos.BaseURL{BucketURL: u, ServiceURL: su}
  251. // 1.永久密钥
  252. client := cos.NewClient(b, &http.Client{
  253. Transport: &cos.AuthorizationTransport{
  254. SecretID: SecretID, // 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
  255. SecretKey: SecretKey, // 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
  256. },
  257. })
  258. key := filepath.Base(filePath)
  259. fmt.Println("key", key)
  260. fmt.Println("filePath", filePath)
  261. res, _, err := client.Object.Upload(
  262. context.Background(), filePath, filePath, nil,
  263. )
  264. fmt.Println(res)
  265. if err != nil {
  266. return "", err
  267. }
  268. //ourl := client.Object.GetObjectURL(key)
  269. return res.Location, nil
  270. }
  271. func ServiceFileDelete(cosPath string) error {
  272. u, _ := url.Parse(CosUrl)
  273. // 用于 Get Service 查询,默认全地域 service.cos.myqcloud.com
  274. su, _ := url.Parse(CosServiceUrl)
  275. b := &cos.BaseURL{BucketURL: u, ServiceURL: su}
  276. // 1.永久密钥
  277. client := cos.NewClient(b, &http.Client{
  278. Transport: &cos.AuthorizationTransport{
  279. SecretID: SecretID, // 用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
  280. SecretKey: SecretKey, // 用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。子账号密钥获取可参考 https://cloud.tencent.com/document/product/598/37140
  281. },
  282. })
  283. res, err := client.Object.Delete(
  284. context.Background(), cosPath,
  285. )
  286. fmt.Println(res)
  287. if err != nil {
  288. return err
  289. }
  290. return nil
  291. }