gin 怎么通过 post 发送结构体_Go Web 框架 Gin 实践12—优化配置结构及实现图片上传...

Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!

9d1a5981b70a0a4ba6c5317cd9ab9990.png

项目地址:https://github.com/EDDYCJY/go-gin-example

如果对你有所帮助,欢迎点个 Star

前言

一天,产品经理突然跟你说文章列表,没有封面图,不够美观,!)&¥*!&)#&¥*!加一个吧,几分钟的事

你打开你的程序,分析了一波写了个清单:

  • 优化配置结构(因为配置项越来越多)
  • 抽离 原 logging 的 File 便于公用(logging、upload 各保有一份并不合适)
  • 实现上传图片接口(需限制文件格式、大小)
  • 修改文章接口(需支持封面地址参数)
  • 增加 blog_article (文章)的数据库字段
  • 实现 http.FileServer

嗯,你发现要较优的话,需要调整部分的应用程序结构,因为功能越来越多,原本的设计也要跟上节奏

也就是在适当的时候,及时优化

优化配置结构

一、讲解

在先前章节中,采用了直接读取 KEY 的方式去存储配置项,而本次需求中,需要增加图片的配置项,总体就有些冗余了

我们采用以下解决方法:

  • 映射结构体:使用 MapTo 来设置配置参数
  • 配置统管:所有的配置项统管到 setting 中

映射结构体(示例)

在 go-ini 中可以采用 MapTo 的方式来映射结构体,例如:

5b66a4cdd24706331fe6b49006657101.png

在这段代码中,可以注意 ServerSetting 取了地址,为什么 MapTo 必须地址入参呢?

30c6efd6fd37bf8de33e068d1982b35c.png

在 MapTo 中 typ.Kind() == reflect.Ptr 约束了必须使用指针,否则会返回 cannot map to non-pointer struct 的错误。这个是表面原因

更往内探究,可以认为是 field.Set 的原因,当执行 val := reflect.ValueOf(v) ,函数通过传递 v 拷贝创建了 val,但是 val 的改变并不能更改原始的 v,要想 val 的更改能作用到 v,则必须传递 v 的地址

显然 go-ini 里也是包含修改原始值这一项功能的,你觉得是什么原因呢?

配置统管

在先前的版本中,models 和 file 的配置是在自己的文件中解析的,而其他在 setting.go 中,因此我们需要将其在 setting 中统一接管

你可能会想,直接把两者的配置项复制粘贴到 setting.go 的 init 中,一下子就完事了,搞那么麻烦?

但你在想想,先前的代码中存在多个 init 函数,执行顺序存在问题,无法达到我们的要求,你可以试试

(此处是一个基础知识点)

在 Go 中,当存在多个 init 函数时,执行顺序为:

  • 相同包下的 init 函数:按照源文件编译顺序决定执行顺序(默认按文件名排序)
  • 不同包下的 init 函数:按照包导入的依赖关系决定先后顺序

所以要避免多 init 的情况,尽量由程序把控初始化的先后顺序

二、落实

修改配置文件

打开 conf/app.ini 将配置文件修改为大驼峰命名,另外我们增加了 5 个配置项用于上传图片的功能,4 个文件日志方面的配置项

[app]PageSize = 10JwtSecret = 233RuntimeRootPath = runtime/ImagePrefixUrl = http://127.0.0.1:8000ImageSavePath = upload/images/# MBImageMaxSize = 5ImageAllowExts = .jpg,.jpeg,.pngLogSavePath = logs/LogSaveName = logLogFileExt = logTimeFormat = 20060102[server]#debug or releaseRunMode = debugHttpPort = 8000ReadTimeout = 60WriteTimeout = 60[database]Type = mysqlUser = rootPassword = rootrootHost = 127.0.0.1:3306Name = blogTablePrefix = blog_

优化配置读取及设置初始化顺序

第一步

将散落在其他文件里的配置都删掉,统一在 setting 中处理以及修改 init 函数为 Setup 方法

打开 pkg/setting/setting.go 文件,修改如下:

d4a7590aba8162c277cbe69873443afc.png

在这里,我们做了如下几件事:

  • 编写与配置项保持一致的结构体(App、Server、Database)
  • 使用 MapTo 将配置项映射到结构体上
  • 对一些需特殊设置的配置项进行再赋值

需要你去做的事:

  • 将 models.go、setting.go、pkg/logging/log.go 的 init 函数修改为 Setup 方法
  • 将 models/models.go 独立读取的 DB 配置项删除,改为统一读取 setting
  • 将 pkg/logging/file 独立的 LOG 配置项删除,改为统一读取 setting

这几项比较基础,并没有贴出来,我希望你可以自己动手,有问题的话可右拐 项目地址 https://github.com/EDDYCJY/go-gin-example

第二步

在这一步我们要设置初始化的流程,打开 main.go 文件,修改内容:

0a69ca1714f4213ccea6ace2eec03ff3.png

修改完毕后,就成功将多模块的初始化函数放到启动流程中了(先后顺序也可以控制)

验证

在这里为止,针对本需求的配置优化就完毕了,你需要执行 go run main.go 验证一下你的功能是否正常哦

顺带留个基础问题,大家可以思考下

ServerSetting.ReadTimeout = ServerSetting.ReadTimeout * time.SecondServerSetting.WriteTimeout = ServerSetting.ReadTimeout * time.Second

若将 setting.go 文件中的这两行删除,会出现什么问题,为什么呢?

抽离 File

在先前版本中,在 logging/file.go 中使用到了 os 的一些方法,我们通过前期规划发现,这部分在上传图片功能中可以复用

第一步

在 pkg 目录下新建 file/file.go ,写入文件内容如下:

6f2b57543ba657a8f305fc8dacb6f3b3.png

在这里我们一共封装了 7个 方法

  • GetSize:获取文件大小
  • GetExt:获取文件后缀
  • CheckExist:检查文件是否存在
  • CheckPermission:检查文件权限
  • IsNotExistMkDir:如果不存在则新建文件夹
  • MkDir:新建文件夹
  • Open:打开文件

在这里我们用到了 mime/multipart 包,它主要实现了 MIME 的 multipart 解析,主要适用于 HTTP 和常见浏览器生成的 multipart 主体

multipart 又是什么,rfc2388 的 multipart/form-data 了解一下 https://tools.ietf.org/html/rfc2388

第二步

我们在第一步已经将 file 重新封装了一层,在这一步我们将原先 logging 包的方法都修改掉

1、打开 pkg/logging/file.go 文件,修改文件内容:

2d6e123f5ad8f74842605c56d85ddc3d.png

我们将引用都改为了 file/file.go 包里的方法

2、打开 pkg/logging/log.go 文件,修改文件内容:

f590913a9e17ba38f44da0a571f03736.png

由于原方法形参改变了,因此 openLogFile 也需要调整

实现上传图片接口

这一小节,我们开始实现上次图片相关的一些方法和功能

首先需要在 blog_article 中增加字段 cover_image_url,格式为 varchar(255) DEFAULT '' COMMENT '封面图片地址'

第零步

一般不会直接将上传的图片名暴露出来,因此我们对图片名进行 MD5 来达到这个效果

在 util 目录下新建 md5.go,写入文件内容:

6cbe41dbd967baa7491320dc062786b3.png

第一步

在先前我们已经把底层方法给封装好了,实质这一步为封装 image 的处理逻辑

在 pkg 目录下新建 upload/image.go 文件,写入文件内容:

6c4cad687baf67430bb8cc589e3c7f88.png

在这里我们实现了 7 个方法,如下:

  • GetImageFullUrl:获取图片完整访问URL
  • GetImageName:获取图片名称
  • GetImagePath:获取图片路径
  • GetImageFullPath:获取图片完整路径
  • CheckImageExt:检查图片后缀
  • CheckImageSize:检查图片大小
  • CheckImage:检查图片

这里基本是对底层代码的二次封装,为了更灵活的处理一些图片特有的逻辑,并且方便修改,不直接对外暴露下层

第二步

这一步将编写上传图片的业务逻辑,在 routers/api 目录下 新建 upload.go 文件,写入文件内容:

ea8961b2c147a0178fe2e05c4dbe9e5a.png

所涉及的错误码(需在 pkg/e/code.go、msg.go 添加):

// 保存图片失败ERROR_UPLOAD_SAVE_IMAGE_FAIL = 30001// 检查图片失败ERROR_UPLOAD_CHECK_IMAGE_FAIL = 30002// 校验图片错误,图片格式或大小有问题ERROR_UPLOAD_CHECK_IMAGE_FORMAT = 30003

在这一大段的业务逻辑中,我们做了如下事情:

  • c.Request.FormFile:获取上传的图片(返回提供的表单键的第一个文件)
  • CheckImageExt、CheckImageSize检查图片大小,检查图片后缀
  • CheckImage:检查上传图片所需(权限、文件夹)
  • SaveUploadedFile:保存图片

总的来说,就是 入参 -> 检查 -》 保存 的应用流程

第三步

打开 routers/router.go 文件,增加路由 r.POST("/upload

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python次方运算_neg__python 魔术方法1 运算符重载

python中存在一些特殊的方法,这些方法通常采用格式:__method__()。这些方法会在特定的情况下自动调用。例如:__new__()、__init__()、__del__() 等生命周期方法。正是这些特殊方法,构建了python的语言风格。特殊方法有很多&#x…

resnet50网络结构_AAAI2020 | 利用网络结构关系加速NAS+Layer

这是我在海康威视研究院实习的工作,被AAAI-2020接收为Spotlight。论文地址:http://xxx.itp.ac.cn/pdf/2002.12580v1引子上一个阶段的网络结构搜索(NAS)研究,主要在两个方面。1)各类搜索方法,从强化学习、进化算法等到梯度下降&…

python 去除nan inf_Python实现半自动评分卡建模(附代码)

作者:Summer Memories个人公众号:风控汪的数据分析之路知乎专栏:小鑫的数据分析笔记这次分享一个自己写的python脚本,可以实现半自动化的评分卡建模。运行脚本时需要input已经预处理好的训练集和测试集数据,所以建模前…

国嵌c语言深度,国嵌C语言3部全

课程目录:国嵌 C语言深度剖析班:1课-基本数据类型分析2 auto,register,static分析3 if,switch,do,while,for分析4 goto,void,extern,sizeof分析5 const和volatile分析6 struct和union分析7课-enum和typedef分析8 注释符号9 接续符和转义符10 单引号和双引…

linux如何判断网线插入_“Linux”中如何判断哪个网卡连接网线?

展开全部【解决方法】1、ifconfig查看现在使用的网e68a84e8a2ad3231313335323631343130323136353331333365633935卡。2、ethtool命令查看网卡的具体信息,如eth0是连接状态,则正常使用。2、在ifconfig中可以看到有eth2这个网卡,但不知道是否连线&#xff…

单调有界定理适用于函数吗_《实变函数》——论有界变差函数

一日不见如隔三秋,本人觉得有界变差函数是实变函数中最容易理解且和高等数学联系最紧密的一个概念,其在概率论中也有非常广泛的应用,也和勒贝格空间有着千丝万缕的联系。什么叫有界变差函数?若在区间(a,b)中&#xff0…

msp430 c语言开发环境,如何使用C语言来编写MSP430的高质量代码

微处理器一般用于特定环境和特定用途,出于成本、功耗和体积的考虑,一般都要求尽量节省使用资源,并且,由于微处理器硬件一般都不支持有符号数、浮点数的运算,且运算位有限,因此,分配变量时必须仔细。另外要说…

oracle 增量设为3 循环_Oracle 差异性增量 和 累计增量 原理(转)

RMAN一个强大的功能是支持增量备份,增量备份中心思想就是减少备份的数据量,我们不需要在从头开始备份了,只需要备份自上次已备份之后的数据块即可。Oracle 9i 共有五种级别 0 1 2 3 4,0级最高-4级最低,0级是1级的基础以…

springboot redis 断线重连_Redis(9)——史上最强【集群】入门实践教程

一、Redis 集群概述Redis 主从复制到 目前 为止,我们所学习的 Redis 都是 单机版 的,这也就意味着一旦我们所依赖的 Redis 服务宕机了,我们的主流程也会受到一定的影响,这当然是我们不能够接受的。所以一开始我们的想法是&#xf…

智能指针的释放_看完这篇,别再说不会智能指针了

C智能指针一、智能指针的作用上一篇介绍了内存池的原理和实现,详情请见内存池设计与实现;内存池可以帮助我们有效的对内存进行管理,智能指针可以很方便的管理指针,避免出现内存泄漏;智能指针的作用智能指针的作用&…

c语言输出后面空格,新人提问:如何将输出时每行最后一个空格删除

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼如何将每行最后一个空格删除&#xff0c;使矩阵只有数字间有空格&#xff0c;没有多余空格&#xff1f;#include#includeint main(){int i,j,k,m,n,x,h,y;int a[15][15]{0};while(scanf("%d",&i)){k1;for(n1;n<i;…

pandas 日期比较大小_pandas处理日期时间,按照时间筛选

pandas有着强大的日期数据处理功能&#xff0c;本期我们来了解下pandas处理日期数据的一些基本功能&#xff0c;主要包括以下三个方面&#xff1a;按日期筛选数据按日期显示数据按日期统计数据运行环境为 windows系统&#xff0c;64位&#xff0c;python3.5。1 读取并整理数据首…

python中符号输入_Python基础(输入、运算符)

输入 1. python2版本中 1.1 使用 raw_input()函数&#xff0c; 看如下示例: password raw_input("请输入密码:") print &#xff08;您刚刚输入的密码是:%s, % password&#xff09; 运行结果:注意: raw_input()的小括号中放入的是&#xff0c;提示信息&#xff0c;…

c语言课程教学改革,C语言课程教学改革和实践.doc

C语言课程教学改革和实践C语言课程教学改革和实践程序设计课程在计算机科学(Computer Science&#xff0c; CS)专业新生的教学中起着相当基础的作用&#xff0c;CS专业包括计算机科学与技术、软件工程和网络工程。尽管近年来涌现了很多新的程序设计语言&#xff0c;如java&…

audio接线图解_图文:主板跳线(排线)连接技巧HD AUDIO连线接法

作为一名新手&#xff0c;要真正从头组装好自己的电脑并不容易&#xff0c;也许你知道CPU应该插哪儿&#xff0c;内存应该插哪儿&#xff0c;但遇到一排排复杂跳线的时候&#xff0c;很多新手都不知道如何下手。钥匙开机其实并不神秘还记不记得你次见到装电脑的时候&#xff0c…

code blocks c语言,Code Blocks安装与使用图文教程(使用Code::Blocks编写C语言程序)...

CodeBlocks 完全支持单个源文件的编译&#xff0c;如果你的程序只有一个源文件(初学者基本上都是在单个源文件下编写代码)&#xff0c;那么不用创建项目&#xff0c;直接运行即可&#xff1b;如果有多个源文件&#xff0c;才需要创建项目。1) 新建源文件打开 CodeBlocks &#…

python链表实现栈_python实现链表队列栈

#!/usr/bin/python # -*- coding: utf-8 -*- #便于测试 data 使用数字 class Node(object): def __init__(self,data): self.data data self.next None self.prev None class List(object): def __init__(self): self.next self self.prev self self.size 0 # 是否为空 d…

python except用法和作用_Python面试题(部分附带面试标准答案) 建议收藏

1、请尽可能列举python列表的成员方法&#xff0c;并给出一下列表操作的答案&#xff1a;&#xff08;1&#xff09; a[1, 2, 3, 4, 5], a[::2]?, a[-2:] ?&#xff08;2&#xff09; 一行代码实现对列表a中的偶数位置的元素进行加3后求和&#xff1f;&#xff08;3&#xf…

c语言简单的24点游戏,C语言解24点游戏程序

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼前几天在微博上看到24点的游戏&#xff0c;6 6 610。算了很久是在算不出来&#xff0c;最后我想我何不写一个小程序解决它&#xff1f;说做就做&#xff0c;我刚开始的想法很简单&#xff0c;就是列举4个数的所有可能的表达式组合&…

chrome vue插件_VS Code 前端常用插件推荐

⊕.vscode安装插件只需要点击图片所示按钮&#xff0c;即可进入拓展&#xff0c;在搜索框中输入插件名点击安装后&#xff0c;等待安装好即可点击重新加载重启vscode使得插件生效。Ξ.当你不需要某个插件时只需要进入扩展&#xff0c;点击对应插件右下角的齿轮按钮即可选择禁用…