• 【Go】gin框架生成压缩包与下载文件


    在没有加入下面这串代码之前,下载的压缩包一直为空。遂debug了两个小时。。。
    可以在服务端本地创建压缩包。单独将服务端本地的压缩包发送给客户端也是没问题的。但是两个合起来,客户端接收到的压缩包内容就为空了。
    期间也尝试了
    zipFile.Close()
    zipWriter.Close()
    但是zipFile不能立刻关

    	// 关闭 ZIP 归档,确保所有数据都被写入压缩包文件
    	err = zipWriter.Close()
    	if err != nil {
    		fmt.Println("无法关闭 ZIP 归档:", err)
    		return
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将缓冲区中的数据刷新到磁盘上的压缩包文件。
    在创建 ZIP 归档后,需要调用 zipWriter.Close() 来确保所有的数据都被写入压缩包文件。在 zipWriter.Close() 被调用之前,压缩包文件可能仍然处于打开状态,并且尚未完全写入磁盘。

    func download(c *gin.Context) {
    	tmpData := make(map[string]interface{})
    	if err := c.ShouldBindJSON(&tmpData); err != nil {
    		log.Println(err)
    		c.JSON(http.StatusBadRequest, gin.H{"msg": "请求参数错误"})
    		return
    	}
    	// 获取要下载的文件列表
    	filePaths := tmpData["selectedIds"].([]interface{})
    	// 获取当前时间
    	currentTime := time.Now()
    	// 格式化为特定格式
    	formattedTime := currentTime.Format("2006-01-02-15-04")
    	zipFilename := formattedTime + ".zip"
    	tempZipPath := filepath.Join(zipFilename)
    	// 创建压缩包文件
    	zipFile, err := os.Create(tempZipPath)
    	if err != nil {
    		fmt.Println("无法创建压缩包文件:", err)
    		return
    	}
    	defer zipFile.Close()
    
    	// 创建 ZIP 归档
    	zipWriter := zip.NewWriter(zipFile)
    	defer zipWriter.Close()
    
    	for _, filePath := range filePaths {
    		idStr := fmt.Sprintf("%v", filePath)
    		filePath := filepath.Join("nuclei-templates-original", idStr+".yaml")
    		fmt.Printf(filePath)
    
    		// 添加文件到 ZIP 归档
    		err = addFileToZip(zipWriter, filePath)
    		if err != nil {
    			fmt.Println("无法添加文件到压缩包:", err)
    			return
    		}
    
    		fmt.Println("文件已成功添加到压缩包中。")
    	}
    
    	// 关闭 ZIP 归档,确保所有数据都被写入压缩包文件
    	err = zipWriter.Close()
    	if err != nil {
    		fmt.Println("无法关闭 ZIP 归档:", err)
    		return
    	}
    
    	file, err := os.Open(tempZipPath)
    	if err != nil {
    		c.String(http.StatusInternalServerError, "无法打开压缩包")
    		return
    	}
    
    	// 获取文件信息
    	fileInfo, err := file.Stat()
    	if err != nil {
    		c.String(http.StatusInternalServerError, "无法获取压缩包信息")
    		return
    	}
    
    	// 设置响应头
    	c.Header("Content-Type", "application/zip")
    	c.Header("Content-Disposition", "attachment; filename="+tempZipPath)
    	c.Header("Content-Length", strconv.FormatInt(fileInfo.Size(), 10))
    
    	// 将压缩包内容发送给客户端
    	_, err = io.Copy(c.Writer, file)
    	if err != nil {
    		c.String(http.StatusInternalServerError, "无法发送压缩包")
    		return
    	}
    
    }
    
    func addFileToZip(zipWriter *zip.Writer, filePath string) error {
    	// 打开要添加的文件
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// 获取文件信息
    	info, err := file.Stat()
    	if err != nil {
    		return err
    	}
    
    	// 创建 ZIP 归档中的文件
    	header, err := zip.FileInfoHeader(info)
    	if err != nil {
    		return err
    	}
    
    	// 设置 ZIP 归档中的文件名
    	header.Name = filepath.Base(filePath)
    
    	// 写入文件到 ZIP 归档
    	writer, err := zipWriter.CreateHeader(header)
    	if err != nil {
    		return err
    	}
    
    	_, err = io.Copy(writer, file)
    	return err
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    gin框架跟着 狂神说,一个小时速成,讲的很好
    这是老师课上的源码

    package main
    import (
        "encoding/json"
        "log"
        "net/http"
        "github.com/gin-gonic/gin"
        "github.com/thinkerou/favicon"
    )
    //自定义go中间件即拦截器
    //给所有请求使用  则不不写在下列方法里,写了则拦截指定方法的请求
    
    func myHandler() (gin.HandlerFunc) {
        //通过自定义的中间件,设置的值,在后续处理只要调用了这个中间件的都可以拿到这里的参数
        return func(context *gin.Context) {
            context.Set("usersession","userid-1")
            //if ...
            context.Next() //放行
            context.Abort() //阻止
        }
    }
    func main() {
        //创建一个服务
        ginServer := gin.Default()
        ginServer.Use(favicon.New("./favicon.ico"))
        //加载静态页面
        ginServer.LoadHTMLGlob("templates/*")
        //加载资源目录
        ginServer.Static("/static","./static")
        //Gin Restful
        ginServer.GET("/hello",myHandler(),func(Context *gin.Context) {
            //取出中间件中的值
            usersession := Context.MustGet("userSession").(string) //空接口转换为string
            log.Println("------->",usersession)
            Context.JSON(200,gin.H{"msg":"hello,world"})
        })
        ginServer.POST("/user",func(c *gin.Context) {
            c.JSON(200,gin.H{"msg":"post,user"})
        })
        ginServer.PUT("/user")
        ginServer.DELETE("/user")
        //响应一个页面给前端
        ginServer.GET("/index",func(Context *gin.Context) {
            Context.HTML(http.StatusOK,"index.html",gin.H{
                "msg":"这是go后台传递来的数据",
            })      
        //接收前端传递过来的参数
        //info?userid=xxx&username=kuangshen
        // ginServer.GET("/user/info",func(context *gin.Context) {
        //  userid := context.Query("userid")
        //  username := context.Query("username")
        //  context.JSON(http.StatusOK,gin.H{
        //      "userid": userid,
        //      "username": username,
        //  })  
        // })
        //info/1/kaungshen
        ginServer.GET("/user/info/:userid/:username",func(context *gin.Context) {
            userid := context.Param("userid")
            username := context.Param("username")
            context.JSON(200,gin.H{
                "userid": userid,
                "username": username,
            })
        })
        //掌握技术后面的应用- 掌握基础知识,加以了解web知识
        // 前端给后端传递 json
        ginServer.POST("/json",func(context *gin.Context) {
            //request.body
            //[]body 返回的是切片
            data,_ := context.GetRawData()
            var m map[string]interface{}
            //包装为json数据 []byte
            _ = json.Unmarshal(data,&m)
            context.JSON(200,m)
        })
        //支持表单
        ginServer.POST("/user/add",func(context *gin.Context) {
            username := context.PostForm("username")
            password := context.PostForm("password")
            context.JSON(200,gin.H{
                "msg":"ok",
                "username":username,
                "password":password,
            })
        })
        //路由
        ginServer.GET("/test",func(context *gin.Context) {
            //重定向
            context.Redirect(301,"http://baidu.com")        
        })
        //404 NoRoute
        ginServer.NoRoute(func(context *gin.Context) {
            context.HTML(http.StatusNotFound,"404.html",nil)
        })
        //路由组
        userGroup := ginServer.Group("/user")
        {
            userGroup.GET("/add")
            userGroup.POST("/login")
            userGroup.POST("/logout")
        }
        orderGroup := ginServer.Group("order")
        {
            orderGroup.GET("/add")
            orderGroup.DELETE("/delete")
        }  
    })
        //服务器端口
        ginServer.Run(":8082")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
  • 相关阅读:
    前端部署项目
    Mysql语法三:表的约束和表与表之间的关系以及高级查询
    解锁新技能《SkyWalking-aop服务搭建》
    基于先验激光雷达地图的2D-3D线特征单目定位
    手机怎么把几个PDF文件合并到一起?教你一分钟搞定
    java项目线上cpu过高如何排查
    低温烹饪过程中真空压力的自动控制
    C++ | C++11新特性(下)
    电脑入门:电脑硬件入门到精通
    IntelliJ_IDEA的下载和安装的准备
  • 原文地址:https://blog.csdn.net/qq_55675216/article/details/133776540