管理后台操作流程:
- 前端上传 zip / 单个文件
- 后端接收到后,将文件写入 /tmp 目录
- 调用一些 api 对 /tmp 目录下的文件 进行 文件大小、尺寸 校验
- 文件满足要求,将文件上传oss
- 返给前端oss url
主要难点:
- 读取内存文件,写入本地
- 素材校验
- 上传失败重试
参考代码:
代码段1
func writeLocal(file multipart.File, fileName string) (string, string, string, error) {
id := idgen.GenId()
day := time.Now().Format("2006-01-02")
path := conf.C.App.FileSrcDir + "/" + day + "/" + id + "/" + fileName
var fd *os.File
var err error
dir := filepath.Dir(path)
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
return "", "", "", err
}
fd, err = os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
return "", "", "", err
}
defer fd.Close()
wt := bufio.NewWriter(fd)
file.Seek(0, os.SEEK_SET)
_, err = io.Copy(wt, file)
if err != nil {
return "", "", "", err
}
wt.Flush()
return path, day, id, err
}
代码段2:
func DecodeImage(path string) (int, int, error) {
var err error
reader, err := os.Open(path)
if err != nil {
return 0, 0, err
}
defer reader.Close()
im, _, err := image.DecodeConfig(reader)
if err != nil {
return 0, 0, err
}
logger.Infof("图片分辨率 %v %v %v", path, im.Width, im.Height)
return im.Width, im.Height, nil
}
// 文件大小
fe, _ := os.Stat(path)
代码段3:
// 解压缩zip包,放到新目录
func Unzip(src string, dest string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
if err != nil {
return filenames, err
}
defer r.Close()
for _, f := range r.File {
fpath := filepath.Join(dest, f.Name)
// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return filenames, fmt.Errorf("%s: illegal file path", fpath)
}
filenames = append(filenames, fpath)
if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(fpath, os.ModePerm)
continue
}
// Make File
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return filenames, err
}
rc, err := f.Open()
if err != nil {
return filenames, err
}
_, err = io.Copy(outFile, rc)
// Close the file without defer to close before next iteration of loop
outFile.Close()
rc.Close()
if err != nil {
return filenames, err
}
}
return filenames, nil
}
代码段4:
for i := 0; i < 3; i++ {
err := bucket.PutObjectFromFile(key, path)
if err == nil {
break
}
if i == 2 {
logger.Errorf("上传出错 %v %v", err, key)
return "", err
}
time.Sleep(time.Duration(2) * time.Second)
}