gin 图片上传到本地或者oss
路由层
func registerCommonRouter(v1 *gin.RouterGroup) {
up := v1.Group("upload")
{
up.POST("/upLoadFile", commons.FileUpLoad) //单文件上传
up.POST("/upLoadMultipartFile", commons.FileUpLoadMultipart) //单文件上传
}
}
控制器
//单文件上传
/**
@ 单文件上传
@ name="file" 文件名
@ multipart/form-data;
*/
func FileUpLoad(c *gin.Context) {
err,host, pathRelative := tools.UplaodFile(c)
if err != nil {
app.Error(c, 400, err, "")
return
}
app.OK(c, gin.H{
"host": host,
"uri": pathRelative,
"url": path.Join(host,pathRelative),
}, "success")
}
/**
@ 多文件上传
@ name="files[]" 文件名
@ multipart/form-data;
*/
func FileUpLoadMultipart(c *gin.Context) {
resFileInfo ,err:= tools.UpLoadMultipartFile(c)
if err != nil {
app.Error(c, 400, err, "")
return
}
app.OK(c, resFileInfo, "ok")
}
tools里
package tools
import (
"errors"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gin-gonic/gin"
"mime/multipart"
"os"
"path"
"reflect"
"strings"
"time"
)
// @ author haima
type UploadConf struct {
UpdateVilidateExtString string `json:"updateVilidateExtString"` //从配置里获取,空为不限制 示例 "jpg,jpeg,png,gif,bmp"
FileMaxSize int64 `json:"fileMaxSize"` //单位Mb 0:不限制大小 / 5
Drive string `json:"drive"`
UploadConfLocal *UploadConfLocal `json:"uploadConfLocal"`
UploadConfOss *UploadConfOss `json:"uploadConfOss"`
UploadConfQiniu *UploadConfQiniu `json:"uploadConfQiniu"`
}
// 本地配置
type UploadConfLocal struct {
Host string `json:"updateVilidateExtString"` //根域名
}
// oss配置
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
type UploadConfOss struct {
Host string `json:"host"` //根域名
Endpoint string `json:"endpoint"` //根域名
AccessKeyId string `json:"accessKeyId"`
AccessKeySecret string `json:"accessKeySecret"`
BucketName string `json:"bucketName"`
}
type UploadConfQiniu struct {
AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"`
Bucket string `json:"bucket"`
ImgPath string `json:"imgPath"`
}
func InitUploadConf() *UploadConf {
return &UploadConf{
UpdateVilidateExtString: "", //从配置里获取,空为不限制 示例 "jpg,jpeg,png,gif,bmp"
FileMaxSize: 5, //单位Mb 0:不限制大小 / 5
Drive: "local", // local / oss / qiniu
UploadConfLocal: &UploadConfLocal{
Host: "http://localhost:8001", //根域名
},
//以下oss账号仅限测试。非法操作者。请自重 感谢 壹cup清茶 贡献的测试账号
UploadConfOss: &UploadConfOss{
//公司的账号
Endpoint: "http://oss-cn-beijing.aliyuncs.com", //阿里云请求地址 定值,写死
Host: "https://test.oss-cn-beijing.aliyuncs.com", //返回的自己的阿里云域名
AccessKeyId: "LTAI4FbzKpo9UcoQeXWqVabc",
AccessKeySecret: "n6xiRIUZhn6dZsnsXYFtA2cZ9jFabc",
BucketName: "test",
},
//请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址
UploadConfQiniu: &UploadConfQiniu{
AccessKey: "",
SecretKey: "",
Bucket: "",
ImgPath: "",
},
}
}
// 初使化配置
var UploadConfig = new(UploadConf)
func init() {
UploadConfig = InitUploadConf()
}
//单个文件 上传文件到本地目录里
func UplaodFile(c *gin.Context) (err error, host, pathRelative string) {
// 单个文件
file, err := c.FormFile("file")
if err != nil {
err = errors.New(fmt.Sprintf("获取数据失败,%v", err))
return
}
return actionUplaodFile(c, file)
}
//多图片返回参
type ResFiles struct {
HostListStr string `json:"hostListStr"`
UriListStr string `json:"uriListStr"`
UrlListStr string `json:"urlListStr"`
FileList []FileItem `json:"fileList"`
}
type FileItem struct {
Host string `json:"host"`
Uri string `json:"uri"`
Url string `json:"url"`
}
//多文件上传
func UpLoadMultipartFile(c *gin.Context) (resFiles ResFiles,err error) {
form, _ := c.MultipartForm()
files := form.File["files[]"]
if len(files) < 1{
err = errors.New("文件不能为空")
return
}
for _, file := range files {
err, host, pathRelative := actionUplaodFile(c, file)
if err != nil {
continue
}
var rItem FileItem
rItem.Host = host
rItem.Uri = pathRelative
rItem.Url = path.Join(host , pathRelative)
resFiles.FileList = append(resFiles.FileList, rItem)
if resFiles.HostListStr == "" {
resFiles.HostListStr = rItem.Host
resFiles.UriListStr = rItem.Uri
resFiles.UrlListStr = rItem.Url
} else {
resFiles.HostListStr += fmt.Sprintf(",%s", rItem.Host)
resFiles.UriListStr += fmt.Sprintf(",%s", rItem.Uri)
resFiles.UrlListStr += fmt.Sprintf(",%s", rItem.Url)
}
}
return resFiles ,nil
}
/**
@ 执行单个文件 上传文件到本地目录里
@ 调用方法 上传图片流,文件名为file 调用tools.UplaodFileToLocal(c)
@ return host 根域名
@ return path 上传后的相对文件路径
@ author haima
*/
func actionUplaodFile(c *gin.Context, file *multipart.FileHeader) (err error, host, pathRelative string) {
// 判断上传文件的大小
if UploadConfig.FileMaxSize != 0 {
fsize := file.Size //上传文件的大小
if fsize > UploadConfig.FileMaxSize*1024*1024 {
err = errors.New(fmt.Sprintf("只能上传小于 %dMb 的文件 ", UploadConfig.FileMaxSize))
return
}
}
//获取上传文件后缀
extString := strings.ToUpper(Ext(file.Filename))
if extString == "" {
err = errors.New(fmt.Sprintf("上传失败,文件类型不支持,只能上传 %s 格式的。", UploadConfig.UpdateVilidateExtString))
return
}
//验证文件类型
if len(UploadConfig.UpdateVilidateExtString) > 0 {
VilidateExtStrSliceTmp := strings.Split(strings.ToUpper(UploadConfig.UpdateVilidateExtString), ",")
VilidateExtStrSlice := make([]string, 0)
for _, v := range VilidateExtStrSliceTmp {
VilidateExtStrSlice = append(VilidateExtStrSlice, fmt.Sprintf(".%s", v))
}
//验证文件类型
//extString .JPG
//VilidateExtStrSlice []string{".JPG",".JPEG",".PNG",".GIF",".BMP"}
if !ContainArray(extString, VilidateExtStrSlice) {
err = errors.New(fmt.Sprintf("上传失败,文件类型不支持,只能上传 %s 格式的。", UploadConfig.UpdateVilidateExtString))
return
}
}
//上传的文件名
file.Filename = fmt.Sprintf("%s%s", time.Now().Format("20060102150405"), file.Filename) // 文件名格式 自己可以改 建议保证唯一性 20060102150405test.xlsx
switch UploadConfig.Drive {
case "local":
return uploadfileToLocal(c, file, file.Filename)
case "oss":
return uploadfileToOss(c, file, file.Filename)
case "qiniu":
return nil, UploadConfig.UploadConfQiniu.ImgPath, "qiniu 开发中...."
default:
err = errors.New("只支持上传到本地,oss,七牛")
return
}
}
func uploadfileToLocal(c *gin.Context, file *multipart.FileHeader, filename string) (err error, host, pathRelative string) {
host = UploadConfig.UploadConfLocal.Host
filepath := path.Join("static/uploadfile",time.Now().Format("20060102"))
//上传到的路径
pathRelative = path.Join(filepath, filename) //路径+文件名上传
//如果没有filepath文件目录就创建一个
if _, err := os.Stat(filepath); err != nil {
if !os.IsExist(err) {
os.MkdirAll(filepath, os.ModePerm)
}
}
// 上传文件到指定的目录
err = c.SaveUploadedFile(file, pathRelative)
if err != nil {
err = errors.New(fmt.Sprintf("上传失败,%v", err))
return
}
return
}
func uploadfileToOss(c *gin.Context, file *multipart.FileHeader, filename string) (err error, host, ossPathFileName string) {
host = UploadConfig.UploadConfOss.Host
err, _, localPathFileName := uploadfileToLocal(c, file, filename)
if err != nil {
err = errors.New(fmt.Sprintf("上传失败,%v", err))
}
ossPath := path.Join("upload" ,time.Now().Format("20060102"))
ossPathFileName = path.Join(ossPath , file.Filename)
// 创建OSSClient实例。
client, err := oss.New(UploadConfig.UploadConfOss.Endpoint, UploadConfig.UploadConfOss.AccessKeyId, UploadConfig.UploadConfOss.AccessKeySecret)
if err != nil {
os.Remove(localPathFileName)
err = errors.New(fmt.Sprintf("文件上传服务器失败. err:%s", err.Error()))
return
}
// 获取存储空间。
bucket, err := client.Bucket(UploadConfig.UploadConfOss.BucketName)
if err != nil {
os.Remove(localPathFileName)
err = errors.New(fmt.Sprintf("文件上传云端失败. err:%s", err.Error()))
return
}
// 上传文件。
err = bucket.PutObjectFromFile(ossPathFileName, localPathFileName)
if err != nil {
os.Remove(localPathFileName)
err = errors.New(fmt.Sprintf("文件上传云端失败. err:%s", err.Error()))
return
}
err = os.Remove(localPathFileName) //如果本地不想删除,可以注释了
if err != nil {
fmt.Println(err)
}
return
}
//获取文件的扩展名
func Ext(path string) string {
for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
if path[i] == '.' {
return path[i:]
}
}
return ""
}
//Contain 判断obj是否在target中,target支持的类型array,slice,map false:不在 true:在
func ContainArray(obj interface{}, target interface{}) bool {
targetValue := reflect.ValueOf(target)
switch reflect.TypeOf(target).Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < targetValue.Len(); i++ {
if targetValue.Index(i).Interface() == obj {
return true
}
}
case reflect.Map:
if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
return true
}
}
return false
}
gin 图片上传到本地或者oss的更多相关文章
- web 图片上传实现本地预览
在说上传之前先说说如何替换or美化浏览器自带的简陋上传按钮(自定义自己的上传按钮 如:img): 1.将自定义上传按钮上方添加 input file 框,实现input实现透明处理. 2.对自定义上传 ...
- 保姆级SpringBoot+Vue图片上传到阿里云OSS教程
小二是新来的实习生,作为技术 leader,我给他安排了一个非常简单的练手任务,把前端 markdown 编辑器里上传的图片保存到服务器端,结果他真的就把图片直接保存到了服务器上,这下可把我气坏了,就 ...
- C# .net Ueditor实现图片上传到阿里云OSS 对象存储
在学习的时候,项目中需要实现在Ueditor编辑器中将图片上传到云储存中,老师演示的是上传到又拍云存储,既然看了一遍,直接照搬不算本事,咱们可以依葫芦画瓢自己来动手玩玩其它的云存储服务. 现在云计算产 ...
- SpringBoot + Vue前后端分离图片上传到本地并前端访问图片
同理应该可用于其他文件 图片上传 application.yml 配置相关常量 prop: upload-folder: E:/test/ # 配置SpringMVC文件上传限制,默认1M.注意MB要 ...
- jquery实现图片上传前本地预览
<!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...
- jquery实现图片上传前本地预览功能
HTML <img id="pic" src="" > <input id="upload" name="fil ...
- egg-multipart + el-upload 实现带参图片上传至阿里云OSS
egg-multipart有两种模式:file和stream el-upload参数传递有两种方式:利用自带参数data和手动添加参数 egg-multipart介绍 一.file 模式下的带参传递 ...
- 微信小程序中图片上传阿里云Oss
本人今年6月份毕业,最近刚在上海一家小公司实习,做微信小程序开发.最近工作遇到一个小问题. 微信小程序图片上传阿里云服务器Oss也折腾了蛮久才解决的,所以特意去记录一下. 第一步:配置阿里云地址: 我 ...
- SSM实现图片上传管理操作
Spring MVC 实现文件上传 时序图 利用 Spring MVC 实现文件上传功能,离不开对 MultipartResolver 的设置.MultipartResolver 这个类,你可以将其视 ...
- Thinkphp整合阿里云OSS图片上传实例
Thinkphp3.2整合阿里云OSS图片上传实例,图片上传至OSS可减少服务器压力,节省宽带,安全又稳定,阿里云OSS对于做负载均衡非常方便,不用传到各个服务器了 首先引入阿里云OSS类库 < ...
随机推荐
- KingbaseES V8R6集群运维案例-- 备库数据库服务意外down分析
案例说明: KingbaseES V8R6一主二备架构的集群,两个备库节点sys_log日志分别不同时间点收到'fast shutdown request'的日志信息,导致备库数据库服务down,需要 ...
- KingbaseES V8R6集群案例---一主二备架构单个备库宕机事务影响测试
KingbaseES V8R6集群案例---一主二备架构单个备库宕机事务影响测试 案例说明: 对于KingbaseES V8R6集群,在sync模式下,对于一主一备架构,如果备库宕机时,主库事务com ...
- html中怎样获取子元素的索引位置
jQuery 的 index() 方法返回指定元素相对于其他指定元素的索引值, 注意:索引值是从0开始计数的. 获得当前元素的索引值可用click事件触发 1 $(selector).click(fu ...
- Android---intent和startActivityForResult方法的使用---页面跳转和数据回传
Android页面跳转和数据回传 今天我尝试用两个页面实现数据的传递和回传,出现了一些问题,把问题已经成功的案例总结如下: 具体是这样的: 有两个layout布局,两个activity.MainAct ...
- Hadoop_08 Hadoop重装
今日总结: 由于之前配置存在问题,今天学到后面之后发现很多bug,需要全部卸载重新配置Hadoop.ZooKeeper以及Hbase.
- 鸿蒙HarmonyOS实战-ArkUI组件(Button)
一.Button Button(按钮)是一种常见的用户界面控件,通常用于触发操作或提交数据.Button 拥有文本标签和一个可点击的区域,用户点击该区域即可触发相应的操作或事件. Button 的主要 ...
- #搜索#AT2368 [AGC013B] Hamiltonish Path
题目 求一条简单路径使得路径端点不能再被延伸 分析 一开始想到可能和度数有关,其实没必要, 随便以一个点作为路径中的点深搜两次即可 代码 #include <cstdio> #includ ...
- #保序回归问题,单调栈,二分#洛谷 5294 [HNOI2019]序列
题目 给定一个长度为 \(n\) 的序列 \(A\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k\). 第一次修改之前及每次修改之后,都要求你找到一个同样长度为 \(n\ ...
- OpenHarmony父子组件双项同步使用:@Link装饰器
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定. 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用. 概述 @Link装饰的变量与其父组件中的数 ...
- 【直播回顾】OpenHarmony知识赋能五期第三课——多媒体整体介绍
5月5日晚上19点,知识赋能第五期第三节课<OpenHarmony标准系统多媒体子系统整体介绍>,在OpenHarmony开发者成长计划社群内成功举行. 本期课程,由深开鸿资深技术专家郭岳 ...