Golang + gin + vue + 阿里云oss 图片上传前后端示例

假装 2020-10-16 PM 240℃ 0条

本实例展示如何使用go语言及其优秀框架gin做后端,Vue及前端框架elmentUI做前端上传逻辑及界面,以及使用阿里云oss存储上传的视频或文件。

1、使用工具

后端:Go语言,gin框架
前端:Vue,ElmentUI
云存储:阿里云OSS
开发IDE:Goland
操作系统:Ubuntu

2、配置及路由

2.1, 项目目录下新建.env配置文件,写入服务端口、数据库等配置

PORT="9900"
OSS_ENDPOINT="oss-cn-hongkong.aliyuncs.com"
OSS_ACCESS_KEY_ID="LTAI4FrhMxuNSQr********"
OSS_ACCESS_SECRET="HvREwCWrK0rwpFAPu1********"
OSS_BUCKET="l******"

2.2, 引入gin框架,并设置路由:项目根目录下创建routers.go,写入代码:

package main

import (
    "github.com/gin-gonic/gin"
)
func CollectRoute(r *gin.Engine) *gin.Engine  {
    r.POST("upload/token", controller.UploadToken)
    return r
}

2.3, 项目根目录下main.go编写

package main
import (
    "github.com/gin-gonic/gin"
)
func main(){
        // gin框架启动
    r := gin.Default()
    r = CollectRoute(r)
    // 配置文件读取端口
    port := os.Getenv("PORT")
    if port != ""{
        panic(r.Run(":"+port))
    }
    panic(r.Run())
}

2.4, 上传controller编写

// 创建controller/upload.go
package controller

import (
        "github.com/gin-gonic/gin"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
    "github.com/google/uuid"
    "net/url"
    "os"
)

// 阿里云oss token 获取
func UploadToken(ctx *gin.Context)  {
client,err:=oss.New(os.Getenv("OSS_ENDPOINT"),os.Getenv("OSS_ACCESS_KEY_ID"),os.Getenv("OSS_ACCESS_SECRET"))
    if err!=nil{
                return ctx.JSON(http.StatusBadGateway,gin.H{"code":502,"msg":"OSS请求错误",err:err.Error()})
    }
    // 获取存储空间
    bucket,err:=client.Bucket(os.Getenv("OSS_BUCKET"))
    if err!=nil{
            return ctx.JSON(http.StatusBadGateway,gin.H{"code":502,"msg":"OSS请求错误",err:err.Error()})
    }
    // 带可选参数的签名直传
    options:=[]oss.Option{
        oss.ContentType("image/png"),
    }
    // 拼接上传图片的路径信息
    key:="upload/avatar/"+uuid.Must(uuid.NewRandom()).String()+".png"
    // 获取上传put地址
    signedPutUrl,err:=bucket.SignURL(key,oss.HTTPPut,600,options...)
    if err!=nil{
                return ctx.JSON(http.StatusBadGateway,gin.H{"code":502,"msg":"OSS bucket错误",err:err.Error()})
    }
    // 获取已上传的预览地址
    signedGetUrl,err:=bucket.SignURL(key,oss.HTTPGet,600)
    if err!=nil{
                return ctx.JSON(http.StatusBadGateway,gin.H{"code":502,"msg":"OSS bucket错误",err:err.Error()})
    }
    putUrl,_:=url.QueryUnescape(signedPutUrl)
    getUrl,_:=url.QueryUnescape(signedGetUrl)
        return ctx.JSON(http.StatusOK,gin.H{"key":key,"put":putUrl,"get":getUrl})
}

3、前端编写

//安装element
vue add element

3.1 upload Token请求API逻辑编写

// 创建src\api\upload\index.js
import axios from 'axios'
// 服务端URL
const URI = 'http://192.168.30.162:3000';

// 获取图片Token
const postUploadToken = fileName => axios.post(URI+'/upload/token',{filename:fileName}).then(res=>res.data);

export default postUploadToken;

3.2 上传页面搭建


<template>
    <div class="post-video">
        <h2>欢迎投稿</h2>
        <el-form ref="form" :model="form" label-width="80px">
            <el-form-item label="封面上传">
                <el-upload
                        class="avatar-uploader"
                        label="视频封面"
                        action=""
                        ref="upload"
                        :show-file-list="false"
                        :before-upload="fnBeforeUpload"
                        :http-request="fnHttpRequest">
                    <img v-if="imageUrl" :src="imageUrl" class="avatar">
                    <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                    <div class="el-uploader-tip" slot="tip">只能上传500kb内的png图片</div>
                </el-upload>
            </el-form-item>

        </el-form>
    </div>
</template>

<script>
    import uploadAPI from '@/api/upload/'
    export default {
        name: "PostImg",
        data(){
            return {
                imageUrl:'',
            }
        },
        methods:{
            // 上传之前判断
            fnBeforeUpload(file){
                const isPNG = file.type === "image/png",
                    isLt2M = file.size /1024 < 900;
                if(!isPNG){
                    this.$message.error("上传头像只能png")
                }
                if(!isLt2M){
                    this.$message.error("上传图片需要小于500KB")
                }
                return isPNG && isLt2M
            },
            // 上传图片到
            fnHttpRequest(option){
                uploadAPI(option.file.name).then((res)=>{
                    const req = new XMLHttpRequest();
                    req.open('PUT',res.data.put,true);
                    req.send(option.file);
                    req.onload=()=>{
                        this.imageUrl = res.data.get;
                    }
                }).catch((error)=>{
                    this.$notify.error({
                        title:"网络错误",
                        message:error
                    })
                })
            }
        }
    }
</script>

<style scoped>
    .avatar-uploader .el-upload {
        border: 1px dashed #d9d9d9;
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
    }
    .avatar-uploader .el-upload:hover {
        border-color: #409EFF;
    }
    .avatar-uploader-icon {
        font-size: 28px;
        color: #8c939d;
        width: 178px;
        height: 178px;
        line-height: 178px;
        text-align: center;
    }
    .avatar {
        width: 178px;
        height: 178px;
        display: block;
    }
</style>
标签: none

非特殊说明,本博所有文章均为博主原创。

评论啦~