/
oss.go
251 lines (227 loc) · 8.05 KB
/
oss.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
package store
import (
"errors"
"strings"
"os"
"fmt"
"bytes"
"io/ioutil"
"compress/gzip"
"github.com/PuerkitoBio/goquery"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/astaxie/beego"
)
//OSS配置【这个不再作为数据库表,直接在oss.conf文件中进行配置】
type Oss struct {
EndpointInternal string //内网的endpoint
EndpointOuter string //外网的endpoint
AccessKeyId string //key
AccessKeySecret string //secret
Bucket string //供文档预览的bucket
IsInternal bool //是否内网,内网则启用内网endpoint,否则启用外网endpoint
Domain string
}
//获取oss的配置[如果使用到多个Bucket,则这里定义一个new方法,生成不同oss配置的OSS对象]
//@return oss Oss配置信息
func (this *Oss) Config() (oss Oss) {
oss = Oss{
IsInternal: beego.AppConfig.DefaultBool("oss::IsInternal", false),
EndpointInternal: beego.AppConfig.String("oss::EndpointInternal"),
EndpointOuter: beego.AppConfig.String("oss::EndpointOuter"),
AccessKeyId: beego.AppConfig.String("oss::AccessKeyId"),
AccessKeySecret: beego.AppConfig.String("oss::AccessKeySecret"),
Bucket: beego.AppConfig.String("oss::Bucket"),
Domain: strings.TrimRight(beego.AppConfig.String("oss::Domain"), "/ "),
}
return oss
}
//判断文件对象是否存在
//@param object 文件对象
//@param isBucketPreview 是否是供预览的bucket,true表示预览bucket,false表示存储bucket
//@return err 错误,nil表示文件存在,否则表示文件不存在,并告知错误信息
func (this *Oss) IsObjectExist(object string) (err error) {
var (
b bool
Client *oss.Client
Bucket *oss.Bucket
config = this.Config()
bucket = config.Bucket
)
if len(object) == 0 {
return errors.New("文件参数为空")
}
if config.IsInternal {
Client, err = oss.New(config.EndpointInternal, config.AccessKeyId, config.AccessKeySecret)
} else {
Client, err = oss.New(config.EndpointOuter, config.AccessKeyId, config.AccessKeySecret)
}
if err == nil {
if Bucket, err = Client.Bucket(bucket); err == nil {
if b, err = Bucket.IsObjectExist(object); b == true {
return nil
}
if err == nil {
err = errors.New("文件不存在")
}
}
}
return err
}
//文件移动到OSS进行存储[如果是图片文件,不要使用gzip压缩,否则在使用阿里云OSS自带的图片处理功能无法处理图片]
//@param local 本地文件
//@param save 存储到OSS的文件
//@param IsPreview 是否是预览,是预览的话,则上传到预览的OSS,否则上传到存储的OSS。存储的OSS,只作为文档的存储,以供下载,但不提供预览等访问,为私有
//@param IsDel 文件上传后,是否删除本地文件
//@param IsGzip 是否做gzip压缩,做gzip压缩的话,需要修改oss中对象的响应头,设置gzip响应
func (this *Oss) MoveToOss(local, save string, IsDel bool, IsGzip ...bool) error {
config := this.Config()
isgzip := false
//如果是开启了gzip,则需要设置文件对象的响应头
if len(IsGzip) > 0 && IsGzip[0] == true {
isgzip = true
}
endpoint := config.EndpointOuter
//如果是内网,则使用内网endpoint
if config.IsInternal {
endpoint = config.EndpointInternal
}
client, err := oss.New(endpoint, config.AccessKeyId, config.AccessKeySecret)
if err != nil {
beego.Error("OSS Client初始化错误:%v", err.Error())
return err
}
Bucket, err := client.Bucket(config.Bucket)
if err != nil {
beego.Error("OSS Bucket初始化错误:%v", err.Error())
return err
}
//在移动文件到OSS之前,先压缩文件
if isgzip {
if bs, err := ioutil.ReadFile(local); err != nil {
beego.Error(err.Error())
isgzip = false //设置为false
} else {
var by bytes.Buffer
w := gzip.NewWriter(&by)
defer w.Close()
w.Write(bs)
w.Flush()
ioutil.WriteFile(local, by.Bytes(), 0777)
}
}
err = Bucket.PutObjectFromFile(save, local)
if err != nil {
beego.Error("文件移动到OSS失败:", err.Error())
return err
}
//如果是开启了gzip,则需要设置文件对象的响应头
if isgzip {
Bucket.SetObjectMeta(save, oss.ContentEncoding("gzip")) //设置gzip响应头
}
if err == nil && IsDel {
err = os.Remove(local)
}
return err
}
//从OSS中删除文件
//@param object 文件对象
//@param IsPreview 是否是预览的OSS
func (this *Oss) DelFromOss(object ...string) error {
config := this.Config()
bucket := config.Bucket
endpoint := config.EndpointOuter
//如果是内网,则使用内网endpoint
if config.IsInternal {
endpoint = config.EndpointInternal
}
client, err := oss.New(endpoint, config.AccessKeyId, config.AccessKeySecret)
if err != nil {
return err
}
Bucket, err := client.Bucket(bucket)
if err != nil {
return err
}
_, err = Bucket.DeleteObjects(object)
return err
}
//设置文件的下载名
//@param obj 文档对象
//@param filename 文件名
func (this *Oss) SetObjectMeta(obj, filename string) {
config := this.Config()
if client, err := oss.New(config.EndpointOuter, config.AccessKeyId, config.AccessKeySecret); err == nil {
if Bucket, err := client.Bucket(config.Bucket); err == nil {
Bucket.SetObjectMeta(obj, oss.ContentDisposition(fmt.Sprintf("attachment; filename=%v", filename)))
//Bucket.SetObjectMeta(obj, oss.Meta("ContentDisposition", fmt.Sprintf("attachment; filename=%v", filename)))
//Bucket.SetObjectMeta(obj, )
}
}
}
//处理html中的OSS数据:如果是用于预览的内容,则把img等的链接的相对路径转成绝对路径,否则反之
//@param htmlstr html字符串
//@param forPreview 是否是供浏览的页面需求
//@return str 处理后返回的字符串
func (this *Oss) HandleContent(htmlstr string, forPreview bool) (str string) {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlstr))
config := this.Config()
if err == nil {
doc.Find("img").Each(func(i int, s *goquery.Selection) {
// For each item found, get the band and title
if src, exist := s.Attr("src"); exist {
//预览
if forPreview {
//不存在http开头的图片链接,则更新为绝对链接
if !(strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://")) {
s.SetAttr("src", config.Domain+"/"+strings.TrimLeft(src, "./"))
}
} else {
s.SetAttr("src", strings.TrimPrefix(src, config.Domain))
}
}
})
str, _ = doc.Find("body").Html()
}
return
}
//从HTML中提取图片文件,并删除
func (this *Oss) DelByHtmlPics(htmlstr string) {
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlstr))
config := this.Config()
if err == nil {
doc.Find("img").Each(func(i int, s *goquery.Selection) {
// For each item found, get the band and title
if src, exist := s.Attr("src"); exist {
//不存在http开头的图片链接,则更新为绝对链接
if !(strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://")) {
this.DelFromOss(strings.TrimLeft(src, "./")) //删除
} else if strings.HasPrefix(src, config.Domain) {
this.DelFromOss(strings.TrimPrefix(src, config.Domain)) //删除
}
}
})
}
return
}
//根据oss文件夹
func (this *Oss) DelOssFolder(folder string) (err error) {
config := this.Config()
if client, err := oss.New(config.EndpointOuter, config.AccessKeyId, config.AccessKeySecret); err == nil {
if Bucket, err := client.Bucket(config.Bucket); err == nil {
folder = strings.Trim(folder, "/")
if lists, err := Bucket.ListObjects(oss.Prefix(folder)); err != nil {
return err
} else {
var objs []string
for _, list := range lists.Objects {
objs = append(objs, list.Key)
}
if len(objs) > 0 {
this.DelFromOss(objs...)
}
this.DelFromOss(folder)
}
}
}
return
}