Gin(六):文件的上传

【Gin框架入门到精通系列09】Gin中的文件上传与处理 本文详细介绍了Gin框架中的文件上传与处理功能,包括单文件和多文件上传实现、文件验证安全处理以及高效的文件存储策略,帮助您构建功能完善的文件处理系统。 阅读详情


点击蓝色字关注我们!


一个努力中的公众号

长的好看的人都关注了

640?

之前使用了数据库做了简单的增加和查询功能,今天再次使用数据库完成一些其他功能,比如说头像的上传和显示。


640

?新增用户头像

640


当用户登录完成后,页面右上角会显示当前用户的用户 email 。下面我们做点击 email 进入用户详情页,并可以修改信息。

先完善后端接口。通过用户的 id 来获取用户的详细信息,同时我们写了一个错误页 error.tmpl,来进行错误信息的展示。

userHandler.go


 

 func UserProfile(context *gin.Context) {     id := context.Query("id")     var user model.UserModel     i, err := strconv.Atoi(id)     u, e := user.QueryById(i)     if e != nil || err != nil {         context.HTML(http.StatusOK, "error.tmpl", gin.H{             "error": e,         }) }     context.HTML(http.StatusOK, "user_profile.tmpl", gin.H{         "user": u, }) }

代码中获取前端传递的id,通过 strconv.Atoi() 将 String 类型转化为 int 类型。user.QueryById() 方法是我们用来进行对 id 查询的方法。

在进行 QueryById 方法之前,我们要对 user 结构体和数据库进行一下简单的修改。


 

 type UserModel struct {     Id       int            `form:"id"`     Email    string         `form:"email" binding:"email"`     Password string         `form:"password" `     Avatar   sql.NullString }

我们新增一行 Avatar ,类型为 sql.NullString 。为什么是 sql.NullString ?因为我们数据库中该字段初始时为 null ,而 string 类型是不可以接收 null 类型的,所以我们只能采用 NullString 来对 null 字符串进行处理。

同时,要对数据库进行添加,新增一列 avatar 字段。

修改后数据库

 create table user (     id int auto_increment         primary key,     email varchar(30) not null,     password varchar(40) not null,     avatar varchar(100) null ) comment '用户表';

完成前期的修改工作,可以做剩下的事情。


640

?️‍获取用户信息

640

在 userModel.go 中获取用户信息,完成 QueryById 方法


 

 func (user *UserModel) QueryById(id int) (UserModel, error) {     u := UserModel{}     row := initDB.Db.QueryRow("select * from user where id = ?;", id)     e := row.Scan(&u.Id, &u.Email, &u.Password, &u.Avatar)     if e != nil {         log.Panicln(e) }     return u, e }

该方法基本和上一节的通过邮箱查询用户方法基本一致。

完成该方法后,就可以将我们的路由添加上。

userRouter.GET("/profile/", handler.UserProfile)

此时就完成了后台的工作,剩下来就是对前端进行修改。

首先要重写划分一下前端的代码块。


 

 template | |-error.tmpl |-header.tmpl |-index.tmpl |-login.tmpl |-nav.tmpl |-user_profile.tmpl

我们将原来 index 中 head 标签部分的代码移动到 header 中,将 header 原有的代码移动到 nav.tmpl 中。

index.tmpl

{{template "header"}} <header>     {{template "nav" .}} </header> <main>  </main>

header.tmpl


 

 {{ define "header" }}     <!doctype html>     <html lang="en">     <head>         <meta charset="UTF-8">         <meta name="viewport"               content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">         <meta http-equiv="X-UA-Compatible" content="ie=edge">         <link rel="stylesheet" href="/statics/css/bootstrap.min.css">         <link rel="stylesheet" href="/statics/css/bootstrap-grid.min.css">         <link rel="stylesheet" href="/statics/css/bootstrap-reboot.min.css">         <script src="/statics/js/jquery.min.js" rel="script"></script>         <script src="/statics/js/Popper.js" rel="script"></script>         <script rel="script" src="/statics/js/bootstrap.bundle.js"></script>         <title>Gin Hello</title>     </head> {{end}}

在 nav.tmpl 中


 

 {{ if .email }}     <ul class="navbar-nav ">         <li class="nav-item">             <a class="nav-link" href="/user/profile?id={{.id}}">{{ .email }}</a>         </li>     </ul> {{ else }}     <ul class="navbar-nav ">         <li class="nav-item">             <a class="nav-link" data-toggle="modal" data-target="#login-modal">登录</a>         </li>         <li class="nav-item">             <a class="nav-link" data-toggle="modal" data-target="#register-modal">注册</a>         </li>     </ul> {{end}}

通过路径 /user/profile?id={{ .id }} 将 id 数据传递后台。

当数据获取成功后,会转跳到 user_profile.tmpl 中

user_profile.tmpl

{{template "header"}} {{template "nav"}} <div class="container">     <div class="row">         <div class="col-sm">              <div>                 <img src="{{ .user.Avatar.String }}" alt="avatar" class="rounded-circle">             </div>          </div>         <div class="col-sm">             <form method="post" action="/user/update" enctype="multipart/form-data">                 <div class="form-group" hidden>                     <label for="user-id">id</label>                     <input type="text" id="user-id"                            name="id"                            value="{{ .user.Id }}">                 </div>                 <div class="form-group">                     <label for="user-email">Email</label>                     <input type="email" class="form-control" id="user-email" aria-describedby="emailHelp"                            name="email"                            readonly                            placeholder="Enter email"                            value="{{ .user.Email }}">                 </div>                 <div class="form-group">                     <label for="user-password">密码</label>                     <input type="password" class="form-control" id="user-password" placeholder="密码" name="password"                            value="{{.user.Password}}">                 </div>                 <div class="form-group">                     <label for="user-avatar">上传头像</label>                     <input type="file" class="form-control-file" id="user-avatar" name="avatar-file">                 </div>                 <button type="submit" class="btn btn-primary">保存</button>             </form>         </div>         <div class="col-sm"></div>     </div> </div>

该页面的 Email 不可编辑,密码可以修改,头像可以上传。

此时我们的页面就完成了。


640

?上传头像

640

完成了基本页面,就要进行头像上传了。

在 userHandler.go 添加 UpdateUserProfile 方法

func UpdateUserProfile(context *gin.Context) {     var user model.UserModel     if err := context.ShouldBind(&user); err != nil {         context.HTML(http.StatusOK, "error.tmpl", gin.H{             "error": err.Error(),         })         log.Panicln("绑定发生错误 ", err.Error()) }     file, e := context.FormFile("avatar-file")     if e != nil {         context.HTML(http.StatusOK, "error.tmpl", gin.H{             "error": e,         })         log.Panicln("文件上传错误", e.Error()) } }

通过数据绑定来将 idemail 和 密码进行绑定,然后通过 context.FormFile() 将文件数据进行获取。

文件数据可以获取,那么获取的文件应该进行保存。

先写一个工具类来获取我们的项目根路径。

新建一个 utils 文件夹, utils 中新建 pathUtils.go

package utils  import (     "log"     "os"     "os/exec"     "strings" )  func RootPath() string {     s, err := exec.LookPath(os.Args[0])     if err != nil {         log.Panicln("发生错误",err.Error()) }     i := strings.LastIndex(s, "\\")     path := s[0 : i+1]     return path }

编写工具类,方便我们日后对它直接使用。

// 省略部分代码 path := utils.RootPath() path = path + "avatar\\" e = os.MkdirAll(path, os.ModePerm) if e != nil {     context.HTML(http.StatusOK, "error.tmpl", gin.H{         "error": e, })     log.Panicln("无法创建文件夹", e.Error()) } fileName := strconv.FormatInt(time.Now().Unix(), 10) + file.Filename e = context.SaveUploadedFile(file, path+fileName) if e != nil {     context.HTML(http.StatusOK, "error.tmpl", gin.H{         "error": e, })     log.Panicln("无法保存文件", e.Error()) }

通过获取当前时间来确保图片的唯一性,保障上传的图片不会因为重名而覆盖。

在这里要思考一个问题,既然我们上传了头像,就要在页面上进行展示,头像展示需要获取地址,那么如何获取图片保存后的地址?

在之前设置路由的时候,我们设置过一次静态文件目录,头像图片也属于静态文件,所以我们要对我们的上传目录再进行设置。

initRouter.go

 router.StaticFS("/avatar", http.Dir(utils.RootPath()+"avatar/"))

我们将我们上传的路径,映射为 /avatar 之后,我们就可以通过改路径进行访问资源。

完善我们最后的代码

avatarUrl := "http://localhost:8080/avatar/" + fileName user.Avatar = sql.NullString{String: avatarUrl} e = user.Update(user.Id) if e != nil {     context.HTML(http.StatusOK, "error.tmpl", gin.H{         "error": e,     })     log.Panicln("数据无法更新", e.Error()) } context.Redirect(http.StatusMovedPermanently, "/user/profile?id="+strconv.Itoa(user.Id))

当图片进行报错后我们再次重定向到 /user/profile 路由,这也页面上就会显示我们新的数据。

640?wx_fmt=jpeg


640

✍总结

640


通过本章节的学习 再次使用到了数据库的一些操作,同时也对文件上传进行了学习,并且完善了页面对于静态文件的显示。


640

?‍?本章节代码

640

Github 代码点击阅读原文查看

640?wx_fmt=jpeg


往期推荐

Gin(一):Hello Gin

Gin(二):路由Router

Gin(三):配合模板 Tmpl

Gin(四):表单数据提交和模型绑定

Gin(五):连接MySQL

好看的人才能点

640


jemalloc实战:5分钟搞定C程序内存泄漏检测(附PDF报告生成技巧) 本文详细介绍了使用jemalloc的heap profiling功能快速检测C/C++程序内存泄漏的实战方法。通过预编译库和LD_PRELOAD注入,无需修改代码即可启动低开销剖析,并利用jeprof工具进行深度分析和生成可视化PDF报告,帮助开发者高效定位线上或开发环境中的内存问题。 阅读详情

相关推荐

Claude Code插件安装与VSCode深度集成实战指南

Claude Code是一款专为IDE设计的AI编程助手插件,其核心价值在于将自然语言意图转化为可运行代码,从而优化开发者认知带宽分配。它依赖Node.js运行时、git版本上下文和VSCode编辑器API三者协同工作,技术原理涉及本地进程通信、权限策略绕过、上下文感知补全等关键机制。该工具显著提升工程效率,适用于CLI开发、EXIF元数据处理、异步逻辑生成等典型JavaScript/TypeScript应用场景。本文聚焦Claude Code插件在VSCode中的真实落地链路,覆盖Windows/macO

weixin_34006468的博客 477

GIN文件上传与返回

上传文件 使用postman模拟上传文件 无论使用postman还是前端的同学直接上传文件,都需要在请求头中使用Content-Type来告知,即带值multipart/form-data来进行上传文件 form-data传参 此时在post请求里已经不能传json了,要使用form-data。 此时在postman中的请求参数体,Body中新建一个key,名为file(可以任意一个key),然后将其文件格式设置为File,这时使用的文件格式,换成字符串Text也是允许的。 如果选择的是Text,在后面

一叶知秋 4413

Flutter加载本地HTML的优雅解决方案:轻松实现富文本展示

通过以上步骤,我们实现了Flutter加载本地HTML的完整流程,并简单介绍了如何通过WebView与HTML页面进行交互。HTML文件作为一种灵活、易维护的富文本展示方式,能有效提升Flutter应用的内容呈现能力。这种方法在展示新闻、资讯或帮助文档等内容时非常有用,能够让开发者灵活调整内容的样式和排版。希望这篇文章能对你在Flutter开发中的HTML加载有所帮助!

四楼没电梯的专栏 3644

gin文件上传

解析模板 等上传好图片之后,就会执行upload方法,然后upload方法对上传好的图片进行一系列操作

weixin_51656756的博客 264

【STM32】从零构建串口IAP框架:BootLoader与App双向跳转实战解析

本文详细解析了STM32串口IAP框架的构建,重点阐述了BootLoader与App双向跳转的实战原理与实现步骤。内容涵盖Flash分区规划、中断向量表重定向、通信协议设计及固件升级流程,并针对跳转失败、程序跑飞等常见问题提供了解决方案,帮助开发者掌握产品级远程升级的核心技术。

wind6的博客 838

【OpenClaw从入门到精通】第17篇:OpenClaw巨头布局实战:阿里CoPaw/腾讯云/百度/火山引擎深度拆解(2026实操版)

2026年OpenClaw以22.8万星标登顶GitHub,引发阿里、腾讯、百度、字节等互联网巨头入局角逐。本文基于公开技术文档与实测经验,深度解析四大巨头的OpenClaw布局战略:阿里云CoPaw的全栈托管、腾讯云的流量入口绑定、百度智能云的搜索生态内嵌、火山引擎的极致智力供给。从核心原理、算法构建、实操流程三个维度,提供可直接落地的接入方案,包含完整代码示例与执行结果验证。通过流程图可视化核心架构,搭配避坑指南与选型矩阵,帮助新手快速上手、进阶读者实现多厂商协同部署。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1685

golang用腾讯云的cos来实现上传头像

废话不多说直接上代码 前提条件你需要下载COS的SDK go get -u github.com/tencentyun/cos-go-sdk-v5 ps:以下代码是用gin框架,这里主要是对这上传头像的使用 其他的逻辑就直接省略了。 //修改头像 func changeAvatar(ctx *gin.Context) { img, err := ctx.FormFile("avatar") //大小限制2Mb if img.Size > (2 << 20) {

qq_62345961的博客 1154

把慢点掰开看:在 SAP HANA 中启用 SQL 优化耗时跟踪 SqlOptTime 的实战指南

摘要:SAP HANA 性能排查中,常出现SQL查询时快时慢的现象,表面看似执行问题,实则是编译阶段耗时过长。通过SQL优化跟踪工具SqlOptStep和SqlOptTime,可精准区分编译与执行时间。SqlOptStep展示优化树变化过程,而SqlOptTime则记录各阶段耗时,帮助定位问题根源。启用SqlOptTime需配置traceprofile,建议限定特定用户以减少系统负载。实际案例显示,报表响应慢常由计算视图编译(CeQo)导致,而非执行阶段问题。解决方案包括调整计算视图展开方式或优化基础视图结

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1013

基于gin框架实现图片上传到七牛云并返回URL(接口的形式)

【代码】基于gin框架实现图片上传到七牛云并返回URL(接口的形式)

qq_51537858的博客 716

Python爬虫博客:如何抓取时事新闻信息 —— 从各大新闻网站获取实时新闻数据

发送请求:向目标新闻网站发送 HTTP 请求,获取网页内容。解析网页:使用解析库(如)从网页中提取新闻标题、摘要、内容、发布时间等。绕过反爬虫机制:使用代理、设置请求头、模拟浏览器行为等策略绕过反爬虫技术。数据存储与清洗:将抓取的数据保存到本地文件或数据库中,并进行清洗,确保数据的可用性。在抓取过程中,我们还会面对很多实际问题,比如反爬虫技术、分页抓取、动态加载的内容等。接下来,我们将逐步介绍如何使用不同技术抓取静态和动态网页,并对抓取的内容进行处理。Scrapy。

2201_76125261的博客 2135

YOLOv8改进 | 注意力机制 | 添加DAttention (DAT)注意力机制实现极限涨点

本文给大家带来的是YOLOv8改进DAT的教程,其发布于2022年CVPR2022上同时被评选为Best Paper,由此可以证明其是一种十分有效的改进机制,其主要的核心思想是:引入可变形注意力机制和动态采样点(听着是不是和可变形动态卷积DCN挺相似)。同时在网络结构中引入一个DAT计算量由8.9GFLOPs涨到了9.4GFLOPs。本文的讲解主要包含三方面:DAT的网络结构思想、DAttention的代码复现,如何添加DAttention到你的结构中实现涨点,下面先来分享我测试的对比图。

Snu77的博客 1万+

Go学习第十六章——Gin文件上传与下载

Go web框架——Gin文件上传与下载

Hai_Helloyou的博客 4805

rk3568 点亮双LVDS 屏

承接文章《rk3568点亮LCD(lvds)》中仅仅只能使用亮单LVDS;经过厂商的努力,陆续发布新补丁。目前支持双lvds显示,缺憾是需要自己额外移植相关补丁。受限于通信频率和VOP编码能力,支持最大分辨仍然是1920x1080、60fps。

weixin_35723192的博客 3008

Gin(六):文件上传

之前使用了数据库做了简单的增加和查询功能,今天再次使用数据库完成一些其他功能,比如说头像的上传和显示。

代码猎奇站 1614

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

go的gin框架使用(六):文件上传

文件上传使用post方法,类型使用 multipart/form-data,这个前面讲过

美丽的泡沫 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

探索Gin框架:Golang使用Gin完成文件上传

Go标准库net/http对文件上传已经提供了非常完善的支持,Gin框架在其基础做了封装,使用更加简单便捷。作者:鼠鼠我捏,要死了捏

qq_35716689的博客 37万+

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Golang使用gin框架上传文件到MinIO

一、环境介绍二、开始整合1、前端页面代码2、gin代码3、上传minio代码 一、环境介绍 Go版本:1.13.1 开发工具:IntelliJ IDEA 2019.2.3 x64 开发环境:windows10 64位 二、开始整合 1、前端页面代码 注意name="datasetPath[] <label>选择文件</label> <input type="file" id="datasetPath" name="datasetPath[]" multiple.

reachyu的博客 4657

Gin框架入门(二)—文件上传

官方文档:https://godoc.org/github.com/gin-gonic/gin 官方地址:https://github.com/gin-gonic/gin 测试工具:postman https://www.getpostman.com/downloads/ 1.单文件上传 func main() { router := gin.Default() router.POST(&quot;/u...

Samdom的博客 1万+

[GoLang]Gin实现文件上传

简单实现了Gin处理单文件和多文件上传的功能

m0_48587804的博客 1414

一文搞懂gin各种上传文件

一、先封装一个根据年月日时间方式来创建目录 1、创建一个utils的文件夹并且创建folder.go的文件 package utils import ( "os" "path/filepath" "time" ) //定义一个创建文件目录的方法 func Mkdir(basePath string) string { // 1.获取当前时间,并且格式化时间 folderName := time.Now().Format("2006/01/02") folderPath := filepa

水痕 8502

gin上传文件

gin上传文件测试用例 传文件的文件名可以由用户自定义,所以可能包含非法字符串,为了安全起见,应该由服务端统一文件名规则 func main() { router := gin.Default() // 给表单限制上传大小 (默认 32 MiB) // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // 单文件 file, _ :=

994

gin框架学习-文件上传

gin框架学习-文件上传

林钟一的博客 6324

Golang Gin框架HTTP上传文件

这个函数会返回一个新的 Reader 对象,该对象会在读取请求的正文时自动检查字节数,如果超过指定的最大字节数,则会自动停止读取,返回错误。HTTP协议的文件上传是通过HTTP POST请求实现的,使用multipart/form-data格式将待上传的文件放入请求体中。要实现 Gin 框架中的文件上传进度,在文件上传中,计算已上传的字节数,并将其与文件的总大小进行比较,以确定上传的进度。该代码不能限制文件上传大小,只是设置内存大小,即使文件大小比这个大,也会写入临时文件。

地球流浪猫的博客 2713

Gin:文件上传

目录1. 单文件上传2. 多文件上传3. 根据上传时间保存4. 配置路由5. 启动服务 1. 单文件上传 func uploadFile(c *gin.Context) { file, err := c.FormFile("file") if err == nil { dst := path.Join("./static", file.Filename) saveErr := c.SaveUploadedFile(file, dst) if saveErr == nil { c.JSO

Fisher3652的博客 3294

10-Gin 文件上传 --[Gin 框架入门精讲与实战案例]

使用 Gin 框架处理文件上传是一个常见的任务,Gin 提供了简单而直观的方法来处理文件上传。下面将介绍如何用 Gin 实现文件上传功能。

桃园码工的博客 1070

【Gin】Gin 文件上传

Gin 文件上传

徒挽的博客 593
上一篇: 随机洗牌算法之Knuth-Durstenfeld Shuffle
下一篇: Gin(八): Cookie 的使用
代码猎奇站
博客等级 码龄7年 39粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值