上代码:
#路由
route.POST("/editSpace", controller.EditspaceHandler)
func EditspaceHandler(c *gin.Context) {
portrait, err := c.FormFile("portrait") // 获取文件
if err != nil {
ResponseErrorWithMsg(c, CodeInvalidParam, err)
return
}
cover, err := c.FormFile("cover") // 获取文件
if err != nil {
ResponseErrorWithMsg(c, CodeInvalidParam, err)
return
}
username, isBool := c.GetPostForm("username")
//没有这个字段
if !isBool {
ResponseError(c, CodeInvalidParam)
return
}
if username == "" {
ResponseErrorWithMsg(c, CodeInvalidParam, "username is required ")
return
}
bio, isBool := c.GetPostForm("bio")
//没有这个字段
if !isBool {
ResponseError(c, CodeInvalidParam)
return
}
//自愿选择空内容 也是可以
//if bio == "" {
//
//}
userid, isBool := c.GetPostForm("userid")
if !isBool {
ResponseError(c, CodeInvalidParam)
return
}
if userid == "" {
ResponseErrorWithMsg(c, CodeInvalidParam, "userid is required ")
return
}
err = service.NewSpaceService(c.Request.Context()).EditSpaceProfile(portrait, cover, username, bio, userid)
if err != nil {
ResponseErrorWithMsg(c, InternalError, err)
return
}
ResponseSuccess(c)
}
func (s *SpaceService) EditSpaceProfile(portrait, cover *multipart.FileHeader, username, bio, userid string) error {
uid, _ := strconv.Atoi(userid)
//上传新头像
url, err := AWSUploadWithClient(portrait, svc, "userportrait")
if err != nil {
return err
}
usvc := NewUserService(context.Background())
userinfo, err := usvc.repo.GetUserInfoByUserid(userid)
if err != nil {
return err
}
if userinfo.Avatar != DefaultUserAvatar {
split := strings.Split(userinfo.Avatar, "/")
key := split[len(split)-2] + "/" + split[len(split)-1]
//删除旧头像
err = AWSDeleteWithClient(svc, key)
if err != nil {
return err
}
}
coverurl, err := AWSUploadWithClient(cover, svc, "usercover")
if err != nil {
return err
}
if userinfo.Cover != DefaultUserCover {
split := strings.Split(userinfo.Cover, "/")
key := split[len(split)-2] + "/" + split[len(split)-1]
//删除旧封面
err = AWSDeleteWithClient(svc, key)
if err != nil {
return err
}
}
var user models.User
user.Avatar = url
user.Userid = uid
user.Cover = coverurl
user.Name = username
user.Introduction = bio
return usvc.repo.UpdateUserByUserid(user)
}
上传图片的也可以参考我上一篇aws的文章
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"go.uber.org/zap"
"mime/multipart"
"os"
"stargate_backend/utils"
"strconv"
)
var (
// IAM账户 需要在IAM添加合适的访问策略 才有s3服务的访问权限
accessKey = "AKIArrrrrrMUrrrrrrrHB" //""
secretKey = "bsrrrrryt4vrrrrr8Gmt2rNrrrrrrrrrkvHcgy6l" //""
//根用户 MFA 非最佳实践 但具有根权限 无需配置权限 可以直接使用
//accessKey = "AKIASrrrrrrrrrrrNBX5C" //""
//secretKey = "Zfrrrrrr/UXrrrrrrrrrrrrrrrN9wnirrrrrGbpS" //""
region = "ap-northeast-1"
endpoint = "https://s3.ap-northeast-1.amazonaws.com/"
//endpoint = "arn:aws:s3:ap-northeast-1:144458791721:accesspoint/gate3-static"
svc *s3.S3
//AWSBatchDeleteClient *s3manager.BatchDelete
)
func AWSInit() error {
//只要不修改session,session就可以安全的并发使用。
sess, err := session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials(accessKey, secretKey, ""),
Endpoint: aws.String(endpoint),
Region: aws.String(region),
//minio:true,oss:false
S3ForcePathStyle: aws.Bool(false),
//SDK 支持使用客户端 TLS 证书配置的环境和会话选项,这些证书作为客户端 TLS 握手的一部分发送以进行客户端身份验证。
//如果使用,则需要 Cert 和 Key 值。如果缺少一个,或者无法加载文件的内容,则会返回一个错误。
//ClientTLSCert: nil,
//ClientTLSKey: nil,
})
if err != nil {
panic(err)
}
svc = s3.New(sess)
//AWSBatchDeleteClient = s3manager.NewBatchDelete(sess)
return err
}
func AWSDeleteWithClient(svc *s3.S3, key string) error {
input := &s3.DeleteObjectInput{
Bucket: aws.String("bucket-name"),
BypassGovernanceRetention: nil,
ExpectedBucketOwner: nil,
Key: aws.String(key),
MFA: nil,
RequestPayer: nil,
VersionId: nil,
}
object, err := svc.DeleteObject(input)
if err != nil {
zap.L().Error("delete from aws failed...", zap.Error(err))
return err
}
fmt.Printf("delete object output:%#v\n", object)
return err
}
//S3 上传管理器确定文件是否可以拆分为更小的部分并并行上传。您可以自定义并行上传的数量和上传部分的大小。
func AWSUploadWithClient(file *multipart.FileHeader, svc *s3.S3, dir string) (string, error) {
uploader := s3manager.NewUploaderWithClient(svc, func(u *s3manager.Uploader) {
//定义将在内存中缓冲25个MiB的策略
//u.BufferProvider = s3manager.NewBufferedReadSeekerWriteToPool(25 * 1024 * 1024)
//指定要上传的每个部分的缓冲区大小(以字节为单位)。每个部分的最小大小为 5 MB。 DefaultUploadPartSize
u.PartSize = 64 * 1024 * 1024 // 每个部分 64MB
// 指定要并行上传的part数量。 默认为5
u.Concurrency = s3manager.DefaultUploadConcurrency
})
open, err := file.Open() // 可以通过一个*multipart.FileHeader 的open() 方法的获取一个multipart.File文件 它实现了io.Reader接口
if err != nil {
return "", err
}
id, _ := utils.GenID()
uploadOutput, err := uploader.Upload(&s3manager.UploadInput{
Body: open, // io.Reader类型
Bucket: aws.String("bucketname"), // 指定要上传的bucket
Key: aws.String(dir + "/" + strconv.Itoa(id)), // 如果bucket下边有文件夹,那么通过在key前加上指定路径,来达到上传到指定文件夹的效果。
ACL: aws.String("public-read"), // 指定ACL权限。一般上传图片类的都是期望可以在前端通过url获取资源的,为public-read。具体可以参考 https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/acl-overview.html#CannedACL
})
if err != nil {
if multierr, ok := err.(s3manager.MultiUploadFailure); ok {
// Process error and its associated uploadID
fmt.Println("Error:", multierr.Code(), multierr.Message(), multierr.UploadID())
} else {
// Process error generically
fmt.Println("Error:", err.Error())
}
return "", err
}
//eg:https://bucketname.s3.ap-northeast-1.amazonaws.com/users/7158634979000321
url := "https://bucketname.s3.ap-northeast-1.amazonaws.com/" + dir + "/" + strconv.Itoa(id)
fmt.Printf("UploadID:%s\n", uploadOutput.UploadID)
fmt.Printf("ETag:%s\n", *uploadOutput.ETag)
fmt.Printf("Location:%s\n", uploadOutput.Location)
return url, err
}