zoukankan      html  css  js  c++  java
  • go语言web开发系列之十三:gin框架实现图片文件上传

    一,演示项目的信息

    1,项目地址:

    https://github.com/liuhongdi/digv13

    2,功能说明:

                演示了通过gin框架上传图片文件,包括单张上传和多张上传

    3,  项目结构:如图:

    说明:刘宏缔的go森林是一个专注golang的博客,
              地址:https://blog.csdn.net/weixin_43881017

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,配置文件说明:

    1,config/config.yaml

    1.  
      Database:
    2.  
      DBType: mysql
    3.  
      UserName: root
    4.  
      Password: password
    5.  
      Host: 127.0.0.1:3306
    6.  
      DBName: dig
    7.  
      Charset: utf8
    8.  
      ParseTime: True
    9.  
      MaxIdleConns: 10
    10.  
      MaxOpenConns: 30
    11.  
      Server:
    12.  
      RunMode: debug
    13.  
      HttpPort: 8000
    14.  
      ReadTimeout: 60
    15.  
      WriteTimeout: 60
    16.  
      Log:
    17.  
      LogFilePath: /data/gologs/logs
    18.  
      LogInfoFileName: info
    19.  
      LogWarnFileName: warn
    20.  
      LogFileExt: log
    21.  
      AccessLog:
    22.  
      LogFilePath: /data/gologs/logs
    23.  
      LogFileName: access
    24.  
      LogFileExt: log
    25.  
      Static:
    26.  
      StaticDir: /data/liuhongdi/digv13/static
    27.  
      ArticleImage:
    28.  
      UploadDir: /data/liuhongdi/digv13/static/ware/article
    29.  
      ImageHost: http://127.0.0.1:8000

    说明:StaticDir:静态文件的保存目录

    UploadDir:文章配图的上传后保存目录

    ImageHost:访问文章配图url的host

    三,go代码说明

    1,global/setting.go

    1.  
      package global
    2.  
       
    3.  
      import (
    4.  
      "fmt"
    5.  
      "github.com/liuhongdi/digv13/pkg/setting"
    6.  
      "time"
    7.  
      )
    8.  
      //服务器配置
    9.  
      type ServerSettingS struct {
    10.  
      RunMode string
    11.  
      HttpPort string
    12.  
      ReadTimeout time.Duration
    13.  
      WriteTimeout time.Duration
    14.  
      }
    15.  
      //数据库配置
    16.  
      type DatabaseSettingS struct {
    17.  
      DBType string
    18.  
      UserName string
    19.  
      Password string
    20.  
      Host string
    21.  
      DBName string
    22.  
      Charset string
    23.  
      ParseTime bool
    24.  
      MaxIdleConns int
    25.  
      MaxOpenConns int
    26.  
      }
    27.  
      //日志配置
    28.  
      type LogSettingS struct {
    29.  
      LogFilePath string //保存到的目录
    30.  
      LogInfoFileName string //info级日志文件的名字
    31.  
      LogWarnFileName string //warn级日志文件的名字
    32.  
      LogAccessFileName string //Access日志文件的名字
    33.  
      LogFileExt string //文件的扩展名
    34.  
      }
    35.  
      //访问日志配置
    36.  
      type AccessLogSettingS struct {
    37.  
      LogFilePath string //保存到的目录
    38.  
      LogFileName string //Access日志文件的名字
    39.  
      LogFileExt string //文件的扩展名
    40.  
      }
    41.  
      //静态目录配置
    42.  
      type StaticSettingS struct {
    43.  
      StaticDir string //静态文件目录
    44.  
      }
    45.  
      //配图的文件路径和host
    46.  
      type ArticleImageSettings struct {
    47.  
      UploadDir string //文章图片文件目录
    48.  
      ImageHost string //访问文章图片文件的host
    49.  
      }
    50.  
       
    51.  
      //定义全局变量
    52.  
      var (
    53.  
      ServerSetting *ServerSettingS
    54.  
      DatabaseSetting *DatabaseSettingS
    55.  
      LogSetting *LogSettingS
    56.  
      AccessLogSetting *AccessLogSettingS
    57.  
      StaticSetting *StaticSettingS
    58.  
      ArticleImageSetting *ArticleImageSettings
    59.  
      )
    60.  
       
    61.  
      //读取配置到全局变量
    62.  
      func SetupSetting() error {
    63.  
      s, err := setting.NewSetting()
    64.  
      if err != nil {
    65.  
      return err
    66.  
      }
    67.  
      err = s.ReadSection("Database", &DatabaseSetting)
    68.  
      if err != nil {
    69.  
      return err
    70.  
      }
    71.  
       
    72.  
      err = s.ReadSection("Server", &ServerSetting)
    73.  
      if err != nil {
    74.  
      return err
    75.  
      }
    76.  
       
    77.  
      err = s.ReadSection("Log", &LogSetting)
    78.  
      if err != nil {
    79.  
      return err
    80.  
      }
    81.  
       
    82.  
      err = s.ReadSection("Static", &StaticSetting)
    83.  
      if err != nil {
    84.  
      return err
    85.  
      }
    86.  
       
    87.  
      err = s.ReadSection("ArticleImage", &ArticleImageSetting)
    88.  
      if err != nil {
    89.  
      return err
    90.  
      }
    91.  
       
    92.  
      err = s.ReadSection("AccessLog", &AccessLogSetting)
    93.  
      if err != nil {
    94.  
      return err
    95.  
      }
    96.  
       
    97.  
      fmt.Println("setting:")
    98.  
      fmt.Println(ServerSetting)
    99.  
      fmt.Println(DatabaseSetting)
    100.  
      fmt.Println(LogSetting)
    101.  
      fmt.Println(AccessLogSetting)
    102.  
      fmt.Println(StaticSetting)
    103.  
      fmt.Println(ArticleImageSetting)
    104.  
      return nil
    105.  
      }

    2,router/touter.go

    1.  
      package router
    2.  
       
    3.  
      import (
    4.  
      "github.com/gin-gonic/gin"
    5.  
      "github.com/liuhongdi/digv13/controller"
    6.  
      "github.com/liuhongdi/digv13/global"
    7.  
      "github.com/liuhongdi/digv13/middleware"
    8.  
      "github.com/liuhongdi/digv13/pkg/result"
    9.  
      "net/http"
    10.  
      "runtime/debug"
    11.  
      )
    12.  
       
    13.  
      func Router() *gin.Engine {
    14.  
      router := gin.Default()
    15.  
      //处理异常
    16.  
      router.NoRoute(HandleNotFound)
    17.  
      router.NoMethod(HandleNotFound)
    18.  
      router.Use(middleware.AccessLog())
    19.  
      router.Use(Recover)
    20.  
       
    21.  
      //static
    22.  
      router.StaticFS("/static", http.Dir(global.StaticSetting.StaticDir))
    23.  
      // 路径映射
    24.  
      articlec:=controller.NewArticleController()
    25.  
      router.GET("/article/getone/:id", articlec.GetOne);
    26.  
      router.GET("/article/list", articlec.GetList);
    27.  
       
    28.  
      //图片上传
    29.  
      imagec:=controller.NewImageController()
    30.  
      router.POST("/image/uploadone", imagec.UploadOne);
    31.  
      router.POST("/image/uploadmore", imagec.UploadMore);
    32.  
      return router
    33.  
      }
    34.  
       
    35.  
      //404
    36.  
      func HandleNotFound(c *gin.Context) {
    37.  
      global.Logger.Errorf("handle not found: %v", c.Request.RequestURI)
    38.  
      //global.Logger.Errorf("stack: %v",string(debug.Stack()))
    39.  
      result.NewResult(c).Error(404,"资源未找到")
    40.  
      return
    41.  
      }
    42.  
       
    43.  
      //500
    44.  
      func Recover(c *gin.Context) {
    45.  
      defer func() {
    46.  
      if r := recover(); r != nil {
    47.  
      //打印错误堆栈信息
    48.  
      //log.Printf("panic: %v ", r)
    49.  
      global.Logger.Errorf("panic: %v", r)
    50.  
      //log stack
    51.  
      global.Logger.Errorf("stack: %v",string(debug.Stack()))
    52.  
      //print stack
    53.  
      debug.PrintStack()
    54.  
      //return
    55.  
      result.NewResult(c).Error(500,"服务器内部错误")
    56.  
      }
    57.  
      }()
    58.  
      //继续后续接口调用
    59.  
      c.Next()
    60.  
      }

    3,controller/imageController.go

    1.  
      package controller
    2.  
       
    3.  
      import (
    4.  
      "fmt"
    5.  
      "github.com/gin-gonic/gin"
    6.  
      "github.com/liuhongdi/digv13/global"
    7.  
      "github.com/liuhongdi/digv13/pkg/result"
    8.  
      "github.com/liuhongdi/digv13/pkg/validCheck"
    9.  
      "github.com/liuhongdi/digv13/request"
    10.  
      "strconv"
    11.  
      )
    12.  
       
    13.  
      type ImageController struct{}
    14.  
       
    15.  
      func NewImageController() ImageController {
    16.  
      return ImageController{}
    17.  
      }
    18.  
      //上传单张图片
    19.  
      func (a *ImageController) UploadOne(c *gin.Context) {
    20.  
      resultRes := result.NewResult(c)
    21.  
      param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
    22.  
      valid, errs := validCheck.BindAndValid(c, &param)
    23.  
      if !valid {
    24.  
      resultRes.Error(400,errs.Error())
    25.  
      return
    26.  
      }
    27.  
       
    28.  
      //save image
    29.  
      //得到图片文件
    30.  
      f, err := c.FormFile("f1s")
    31.  
      //错误处理
    32.  
      if err != nil {
    33.  
      fmt.Println(err.Error())
    34.  
      resultRes.Error(1,"图片上传失败")
    35.  
      } else {
    36.  
      //将文件保存至本项目根目录中
    37.  
      idstr:=strconv.FormatUint(param.ID, 10)
    38.  
      destImage := global.ArticleImageSetting.UploadDir+"/"+idstr+".jpg"
    39.  
      err := c.SaveUploadedFile(f, destImage)
    40.  
      if (err != nil){
    41.  
      fmt.Println("save err:")
    42.  
      fmt.Println(err)
    43.  
      resultRes.Error(1,"图片保存失败")
    44.  
      } else {
    45.  
      imageUrl := global.ArticleImageSetting.ImageHost+"/static/ware/article/"+idstr+".jpg"
    46.  
      resultRes.Success(gin.H{"url":imageUrl})
    47.  
      }
    48.  
      }
    49.  
      return
    50.  
      }
    51.  
       
    52.  
      //上传多张图片
    53.  
      func (a *ImageController) UploadMore(c *gin.Context) {
    54.  
      resultRes := result.NewResult(c)
    55.  
      param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
    56.  
      valid, errs := validCheck.BindAndValid(c, &param)
    57.  
      if !valid {
    58.  
      resultRes.Error(400,errs.Error())
    59.  
      return
    60.  
      }
    61.  
       
    62.  
      //save image,
    63.  
      //得到form
    64.  
      form,err:=c.MultipartForm()
    65.  
      //得到文件列表
    66.  
      files:=form.File["f1m"]
    67.  
      //错误处理
    68.  
      if err != nil {
    69.  
      resultRes.Error(1,"图片上传失败")
    70.  
      return
    71.  
      }
    72.  
      idstr:=strconv.FormatUint(param.ID, 10)
    73.  
      var images []string
    74.  
      for i,f:=range files{
    75.  
      //fmt.Println(f.Filename)
    76.  
      istr := strconv.Itoa(i)
    77.  
      destImage := global.ArticleImageSetting.UploadDir+"/"+idstr+"_"+istr+".jpg"
    78.  
      c.SaveUploadedFile(f,destImage)
    79.  
      //return image url
    80.  
      imageUrl := global.ArticleImageSetting.ImageHost+"/static/ware/article/"+idstr+"_"+istr+".jpg"
    81.  
      images = append(images, imageUrl)
    82.  
      }
    83.  
      resultRes.Success(gin.H{"imagesurls":images})
    84.  
      return
    85.  
      }

    说明:代码没有放到service中,主要功能是保存图片文件后返回url地址

    4,static/upload.html

    1.  
      <!DOCTYPE html>
    2.  
      <html lang="zh-CN">
    3.  
      <head>
    4.  
      <title>上传文件示例</title>
    5.  
      </head>
    6.  
      <body>
    7.  
      单文件上传:<br/>
    8.  
      <form action="/image/uploadone" method="post" enctype="multipart/form-data">
    9.  
      <input type="text" name="id" id="id" placeholder="请输入id" /> <br/>
    10.  
      <input type="file" name="f1s" /><br/>
    11.  
      <input type="submit" value="上传">
    12.  
      </form>
    13.  
      <br/><br/><br/>
    14.  
      多文件上传(可多选):<br/>
    15.  
      <form action="/image/uploadmore" method="post" enctype="multipart/form-data">
    16.  
      <input type="text" name="id" id="id" placeholder="请输入id" /> <br/>
    17.  
      <input type="file" name="f1m" multiple /><br/>
    18.  
      <input type="submit" value="上传">
    19.  
      </form>
    20.  
       
    21.  
      </body>
    22.  
      </html>

    5,其他相关代码可访问github

    四,测试效果

    1,查看上传页面:

    访问:

    http://127.0.0.1:8000/static/upload.html

    返回:

    2,  上传单张

    返回:

    3, 上传多张

    返回:

    五,todo:

    1,文件的扩展名要记录下来,通常要写入到数据库

       我们这里因为没有记录就只支持jpg一种格式了

    2,一个记录下有多张图片,通常会把图片的id记录到数据库中

    3,生产环境中不会直接展示用户上传的图片,避免文件太大等问题,

         而是会用工具处理缩小为指定大小

    这些大家可以自己去实现

    六,查看库的版本:

    1.  
      module github.com/liuhongdi/digv13
    2.  
       
    3.  
      go 1.15
    4.  
       
    5.  
      require (
    6.  
      github.com/gin-gonic/gin v1.6.3
    7.  
      github.com/go-playground/universal-translator v0.17.0
    8.  
      github.com/go-playground/validator/v10 v10.2.0
    9.  
      github.com/jinzhu/gorm v1.9.16
    10.  
      github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
    11.  
      github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
    12.  
      github.com/magiconair/properties v1.8.4 // indirect
    13.  
      github.com/mitchellh/mapstructure v1.3.3 // indirect
    14.  
      github.com/pelletier/go-toml v1.8.1 // indirect
    15.  
      github.com/pkg/errors v0.9.1 // indirect
    16.  
      github.com/spf13/afero v1.4.1 // indirect
    17.  
      github.com/spf13/cast v1.3.1 // indirect
    18.  
      github.com/spf13/jwalterweatherman v1.1.0 // indirect
    19.  
      github.com/spf13/pflag v1.0.5 // indirect
    20.  
      github.com/spf13/viper v1.7.1
    21.  
      go.uber.org/multierr v1.6.0 // indirect
    22.  
      go.uber.org/zap v1.16.0
    23.  
      golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
    24.  
      golang.org/x/text v0.3.4 // indirect
    25.  
      gopkg.in/ini.v1 v1.62.0 // indirect
    26.  
      gopkg.in/yaml.v2 v2.3.0 // indirect
    27.  
      )
  • 相关阅读:
    Visual studio 调试发布到IIS站点方式一
    WPF设计界面不执行代码
    IIS发布ASP.NET Core
    mfc/格式转换
    【二维数组内存申请】
    【DLL测试】为DLL项目建立测试
    自己写的一个函数,用来自动连接对话框上的两个控件(画线)
    mfc 在VC的两个对话框类中传递参数的三种方法
    C语言extern作用(全局变量)
    图形对象的创建(常用图形对象的创建方法及特殊属性)
  • 原文地址:https://www.cnblogs.com/ExMan/p/14312249.html
Copyright © 2011-2022 走看看