一,演示项目的信息
1,项目地址:
https://github.com/liuhongdi/digv13
2,功能说明:
演示了通过gin框架上传图片文件,包括单张上传和多张上传
3, 项目结构:如图:
说明:刘宏缔的go森林是一个专注golang的博客,
地址:https://blog.csdn.net/weixin_43881017
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,配置文件说明:
1,config/config.yaml
-
Database:
-
DBType: mysql
-
UserName: root
-
Password: password
-
Host: 127.0.0.1:3306
-
DBName: dig
-
Charset: utf8
-
ParseTime: True
-
MaxIdleConns: 10
-
MaxOpenConns: 30
-
Server:
-
RunMode: debug
-
HttpPort: 8000
-
ReadTimeout: 60
-
WriteTimeout: 60
-
Log:
-
LogFilePath: /data/gologs/logs
-
LogInfoFileName: info
-
LogWarnFileName: warn
-
LogFileExt: log
-
AccessLog:
-
LogFilePath: /data/gologs/logs
-
LogFileName: access
-
LogFileExt: log
-
Static:
-
StaticDir: /data/liuhongdi/digv13/static
-
ArticleImage:
-
UploadDir: /data/liuhongdi/digv13/static/ware/article
-
ImageHost: http://127.0.0.1:8000
说明:StaticDir:静态文件的保存目录
UploadDir:文章配图的上传后保存目录
ImageHost:访问文章配图url的host
三,go代码说明
1,global/setting.go
-
package global
-
-
import (
-
"fmt"
-
"github.com/liuhongdi/digv13/pkg/setting"
-
"time"
-
)
-
//服务器配置
-
type ServerSettingS struct {
-
RunMode string
-
HttpPort string
-
ReadTimeout time.Duration
-
WriteTimeout time.Duration
-
}
-
//数据库配置
-
type DatabaseSettingS struct {
-
DBType string
-
UserName string
-
Password string
-
Host string
-
DBName string
-
Charset string
-
ParseTime bool
-
MaxIdleConns int
-
MaxOpenConns int
-
}
-
//日志配置
-
type LogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogInfoFileName string //info级日志文件的名字
-
LogWarnFileName string //warn级日志文件的名字
-
LogAccessFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//访问日志配置
-
type AccessLogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//静态目录配置
-
type StaticSettingS struct {
-
StaticDir string //静态文件目录
-
}
-
//配图的文件路径和host
-
type ArticleImageSettings struct {
-
UploadDir string //文章图片文件目录
-
ImageHost string //访问文章图片文件的host
-
}
-
-
//定义全局变量
-
var (
-
ServerSetting *ServerSettingS
-
DatabaseSetting *DatabaseSettingS
-
LogSetting *LogSettingS
-
AccessLogSetting *AccessLogSettingS
-
StaticSetting *StaticSettingS
-
ArticleImageSetting *ArticleImageSettings
-
)
-
-
//读取配置到全局变量
-
func SetupSetting() error {
-
s, err := setting.NewSetting()
-
if err != nil {
-
return err
-
}
-
err = s.ReadSection("Database", &DatabaseSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Server", &ServerSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Log", &LogSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Static", &StaticSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("ArticleImage", &ArticleImageSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("AccessLog", &AccessLogSetting)
-
if err != nil {
-
return err
-
}
-
-
fmt.Println("setting:")
-
fmt.Println(ServerSetting)
-
fmt.Println(DatabaseSetting)
-
fmt.Println(LogSetting)
-
fmt.Println(AccessLogSetting)
-
fmt.Println(StaticSetting)
-
fmt.Println(ArticleImageSetting)
-
return nil
-
}
2,router/touter.go
-
package router
-
-
import (
-
"github.com/gin-gonic/gin"
-
"github.com/liuhongdi/digv13/controller"
-
"github.com/liuhongdi/digv13/global"
-
"github.com/liuhongdi/digv13/middleware"
-
"github.com/liuhongdi/digv13/pkg/result"
-
"net/http"
-
"runtime/debug"
-
)
-
-
func Router() *gin.Engine {
-
router := gin.Default()
-
//处理异常
-
router.NoRoute(HandleNotFound)
-
router.NoMethod(HandleNotFound)
-
router.Use(middleware.AccessLog())
-
router.Use(Recover)
-
-
//static
-
router.StaticFS("/static", http.Dir(global.StaticSetting.StaticDir))
-
// 路径映射
-
articlec:=controller.NewArticleController()
-
router.GET("/article/getone/:id", articlec.GetOne);
-
router.GET("/article/list", articlec.GetList);
-
-
//图片上传
-
imagec:=controller.NewImageController()
-
router.POST("/image/uploadone", imagec.UploadOne);
-
router.POST("/image/uploadmore", imagec.UploadMore);
-
return router
-
}
-
-
//404
-
func HandleNotFound(c *gin.Context) {
-
global.Logger.Errorf("handle not found: %v", c.Request.RequestURI)
-
//global.Logger.Errorf("stack: %v",string(debug.Stack()))
-
result.NewResult(c).Error(404,"资源未找到")
-
return
-
}
-
-
//500
-
func Recover(c *gin.Context) {
-
defer func() {
-
if r := recover(); r != nil {
-
//打印错误堆栈信息
-
//log.Printf("panic: %v ", r)
-
global.Logger.Errorf("panic: %v", r)
-
//log stack
-
global.Logger.Errorf("stack: %v",string(debug.Stack()))
-
//print stack
-
debug.PrintStack()
-
//return
-
result.NewResult(c).Error(500,"服务器内部错误")
-
}
-
}()
-
//继续后续接口调用
-
c.Next()
-
}
3,controller/imageController.go
-
package controller
-
-
import (
-
"fmt"
-
"github.com/gin-gonic/gin"
-
"github.com/liuhongdi/digv13/global"
-
"github.com/liuhongdi/digv13/pkg/result"
-
"github.com/liuhongdi/digv13/pkg/validCheck"
-
"github.com/liuhongdi/digv13/request"
-
"strconv"
-
)
-
-
type ImageController struct{}
-
-
func NewImageController() ImageController {
-
return ImageController{}
-
}
-
//上传单张图片
-
func (a *ImageController) UploadOne(c *gin.Context) {
-
resultRes := result.NewResult(c)
-
param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
-
valid, errs := validCheck.BindAndValid(c, ¶m)
-
if !valid {
-
resultRes.Error(400,errs.Error())
-
return
-
}
-
-
//save image
-
//得到图片文件
-
f, err := c.FormFile("f1s")
-
//错误处理
-
if err != nil {
-
fmt.Println(err.Error())
-
resultRes.Error(1,"图片上传失败")
-
} else {
-
//将文件保存至本项目根目录中
-
idstr:=strconv.FormatUint(param.ID, 10)
-
destImage := global.ArticleImageSetting.UploadDir+"/"+idstr+".jpg"
-
err := c.SaveUploadedFile(f, destImage)
-
if (err != nil){
-
fmt.Println("save err:")
-
fmt.Println(err)
-
resultRes.Error(1,"图片保存失败")
-
} else {
-
imageUrl := global.ArticleImageSetting.ImageHost+"/static/ware/article/"+idstr+".jpg"
-
resultRes.Success(gin.H{"url":imageUrl})
-
}
-
}
-
return
-
}
-
-
//上传多张图片
-
func (a *ImageController) UploadMore(c *gin.Context) {
-
resultRes := result.NewResult(c)
-
param := request.ArticleRequest{ID: validCheck.StrTo(c.Param("id")).MustUInt64()}
-
valid, errs := validCheck.BindAndValid(c, ¶m)
-
if !valid {
-
resultRes.Error(400,errs.Error())
-
return
-
}
-
-
//save image,
-
//得到form
-
form,err:=c.MultipartForm()
-
//得到文件列表
-
files:=form.File["f1m"]
-
//错误处理
-
if err != nil {
-
resultRes.Error(1,"图片上传失败")
-
return
-
}
-
idstr:=strconv.FormatUint(param.ID, 10)
-
var images []string
-
for i,f:=range files{
-
//fmt.Println(f.Filename)
-
istr := strconv.Itoa(i)
-
destImage := global.ArticleImageSetting.UploadDir+"/"+idstr+"_"+istr+".jpg"
-
c.SaveUploadedFile(f,destImage)
-
//return image url
-
imageUrl := global.ArticleImageSetting.ImageHost+"/static/ware/article/"+idstr+"_"+istr+".jpg"
-
images = append(images, imageUrl)
-
}
-
resultRes.Success(gin.H{"imagesurls":images})
-
return
-
}
说明:代码没有放到service中,主要功能是保存图片文件后返回url地址
4,static/upload.html
-
-
<html lang="zh-CN">
-
<head>
-
<title>上传文件示例</title>
-
</head>
-
<body>
-
单文件上传:<br/>
-
<form action="/image/uploadone" method="post" enctype="multipart/form-data">
-
<input type="text" name="id" id="id" placeholder="请输入id" /> <br/>
-
<input type="file" name="f1s" /><br/>
-
<input type="submit" value="上传">
-
</form>
-
<br/><br/><br/>
-
多文件上传(可多选):<br/>
-
<form action="/image/uploadmore" method="post" enctype="multipart/form-data">
-
<input type="text" name="id" id="id" placeholder="请输入id" /> <br/>
-
<input type="file" name="f1m" multiple /><br/>
-
<input type="submit" value="上传">
-
</form>
-
-
</body>
-
</html>
5,其他相关代码可访问github
四,测试效果
1,查看上传页面:
访问:
http://127.0.0.1:8000/static/upload.html
返回:
2, 上传单张
返回:
3, 上传多张
返回:
五,todo:
1,文件的扩展名要记录下来,通常要写入到数据库
我们这里因为没有记录就只支持jpg一种格式了
2,一个记录下有多张图片,通常会把图片的id记录到数据库中
3,生产环境中不会直接展示用户上传的图片,避免文件太大等问题,
而是会用工具处理缩小为指定大小
这些大家可以自己去实现
六,查看库的版本:
-
module github.com/liuhongdi/digv13
-
-
go 1.15
-
-
require (
-
github.com/gin-gonic/gin v1.6.3
-
github.com/go-playground/universal-translator v0.17.0
-
github.com/go-playground/validator/v10 v10.2.0
-
github.com/jinzhu/gorm v1.9.16
-
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
-
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
-
github.com/magiconair/properties v1.8.4 // indirect
-
github.com/mitchellh/mapstructure v1.3.3 // indirect
-
github.com/pelletier/go-toml v1.8.1 // indirect
-
github.com/pkg/errors v0.9.1 // indirect
-
github.com/spf13/afero v1.4.1 // indirect
-
github.com/spf13/cast v1.3.1 // indirect
-
github.com/spf13/jwalterweatherman v1.1.0 // indirect
-
github.com/spf13/pflag v1.0.5 // indirect
-
github.com/spf13/viper v1.7.1
-
go.uber.org/multierr v1.6.0 // indirect
-
go.uber.org/zap v1.16.0
-
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
-
golang.org/x/text v0.3.4 // indirect
-
gopkg.in/ini.v1 v1.62.0 // indirect
-
gopkg.in/yaml.v2 v2.3.0 // indirect
-
)