使用Golang构建REST应用实现图片管理

使用Golang构建REST应用实现图片管理 我想介绍一下我的最新项目。这是一个REST应用程序,可以连接到Dropbox账户,帮助用户将照片按分类进行整理:

GitHub

gchumillas/photomanager

一个用GO编写的用于整理图片的REST应用程序(开发中)。

欢迎对源代码改进提出任何建议。

希望你喜欢!


更多关于使用Golang构建REST应用实现图片管理的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用Golang构建REST应用实现图片管理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个很棒的Go项目!我来分析一下你的REST应用架构,并提供一些技术实现细节和示例代码。

你的项目结构看起来是基于标准Go Web开发模式。以下是一个典型的图片管理REST API实现示例:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "path/filepath"
    
    "github.com/gorilla/mux"
    "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox"
    "github.com/dropbox/dropbox-sdk-go-unofficial/v6/dropbox/files"
)

type Photo struct {
    ID       string `json:"id"`
    Filename string `json:"filename"`
    Category string `json:"category"`
    URL      string `json:"url,omitempty"`
}

type PhotoManager struct {
    dbxConfig dropbox.Config
}

func NewPhotoManager(accessToken string) *PhotoManager {
    config := dropbox.Config{
        Token: accessToken,
    }
    return &PhotoManager{dbxConfig: config}
}

func (pm *PhotoManager) listPhotos(w http.ResponseWriter, r *http.Request) {
    dbx := files.New(pm.dbxConfig)
    
    arg := files.NewListFolderArg("")
    result, err := dbx.ListFolder(arg)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    var photos []Photo
    for _, entry := range result.Entries {
        if photo, ok := entry.(*files.FileMetadata); ok {
            ext := filepath.Ext(photo.Name)
            if isImageExtension(ext) {
                photos = append(photos, Photo{
                    ID:       photo.Id,
                    Filename: photo.Name,
                    Category: extractCategory(photo.PathLower),
                })
            }
        }
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(photos)
}

func (pm *PhotoManager) organizePhoto(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    photoID := vars["id"]
    
    var req struct {
        Category string `json:"category"`
    }
    
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, "Invalid request body", http.StatusBadRequest)
        return
    }
    
    dbx := files.New(pm.dbxConfig)
    
    // 获取文件当前路径
    searchArg := files.NewSearchArg("", photoID)
    searchResult, err := dbx.Search(searchArg)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    if len(searchResult.Matches) == 0 {
        http.Error(w, "Photo not found", http.StatusNotFound)
        return
    }
    
    currentPath := searchResult.Matches[0].Metadata.(*files.FileMetadata).PathDisplay
    newPath := fmt.Sprintf("/%s/%s", req.Category, filepath.Base(currentPath))
    
    // 移动文件到新分类目录
    moveArg := files.NewRelocationArg(currentPath, newPath)
    _, err = dbx.MoveV2(moveArg)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]string{
        "message": "Photo organized successfully",
        "new_path": newPath,
    })
}

func isImageExtension(ext string) bool {
    imageExts := []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"}
    for _, imgExt := range imageExts {
        if ext == imgExt {
            return true
        }
    }
    return false
}

func extractCategory(path string) string {
    // 从路径中提取分类逻辑
    if len(path) > 1 {
        dir := filepath.Dir(path)
        if dir != "." && dir != "/" {
            return filepath.Base(dir)
        }
    }
    return "uncategorized"
}

func main() {
    pm := NewPhotoManager("your-dropbox-access-token")
    
    r := mux.NewRouter()
    r.HandleFunc("/photos", pm.listPhotos).Methods("GET")
    r.HandleFunc("/photos/{id}/organize", pm.organizePhoto).Methods("POST")
    
    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}

对于图片分类功能,这里是一个基于EXIF数据的自动分类实现:

import (
    "github.com/rwcarlsen/goexif/exif"
    "github.com/rwcarlsen/goexif/mknote"
)

func extractPhotoMetadata(fileData []byte) (map[string]interface{}, error) {
    exif.RegisterParsers(mknote.All...)
    
    x, err := exif.Decode(bytes.NewReader(fileData))
    if err != nil {
        return nil, err
    }
    
    metadata := make(map[string]interface{})
    
    if date, err := x.DateTime(); err == nil {
        metadata["date_taken"] = date.Format("2006-01-02")
    }
    
    if lat, long, err := x.LatLong(); err == nil {
        metadata["latitude"] = lat
        metadata["longitude"] = long
    }
    
    if camera, err := x.Get(exif.Model); err == nil {
        metadata["camera_model"] = camera.String()
    }
    
    return metadata, nil
}

func autoCategorizePhoto(metadata map[string]interface{}) string {
    // 基于元数据的自动分类逻辑
    if date, exists := metadata["date_taken"]; exists {
        year := date.(string)[0:4]
        return fmt.Sprintf("photos-%s", year)
    }
    return "general"
}

这个实现展示了:

  • 使用Gorilla Mux进行路由管理
  • Dropbox SDK集成进行文件操作
  • RESTful API设计模式
  • 图片元数据提取和自动分类
  • 错误处理和JSON响应

项目架构清晰,遵循了Go的最佳实践。继续完善这个项目会是一个很有价值的图片管理解决方案。

回到顶部