Go-Spring 入门篇(三)

Golang
395
0
0
2022-07-29
标签   Golang基础

序言

示例代码 github.com/acrossmountain/gs-demo

上章 Go-Spring 入门篇(二)讲到 controller 的主要能力为路由注册,参数处理复杂的逻辑应当拆分到 service 中。

本章我们讲复杂的逻辑拆分到 service 中,为了不作为一个示例而太简单,让学习者觉得没有什么意义,决定先做一个上传的能力,先看拆分 service 的情况。

controllers/upload/upload.go

package upload

import (
    "io" 
    "os" 
    "path"

    "github.com/go-spring/spring-core/web"
)

type Controller struct {
}

func (c *Controller) Upload(ctx web.Context) {

    file, err := ctx.FormFile("file")
    if err != nil {
        // ... 
        return
    }

    f, err := file.Open()
    if err != nil {
        // ... 
        return
    }
    defer func() {
        // 打开的资源。一定要记住主动关闭
        _ = f.Close()
    }()

    out := path.Join("temp", file.Filename)
    if !PathExists(out) {

        // 创建目录
        dir := path.Dir(out)
        if !PathExists(dir) {
            err := os.MkdirAll(dir, os.ModeDir)
            if err != nil {
                // ... 
                return
            }
        }

        // 创建文件
        dst, err := os.OpenFile(out, os.O_CREATE, 0644)
        if err != nil {
            // ... 
            return
        }
        defer func() {
            _ = dst.Close()
        }()

        // 保存文件
        _, err = io.Copy(dst, f)
        if err != nil {
            // ... 
            return
        }

    } else {
        // ... 
        return
    }

    ctx.JSON(map[string]interface{}{
        "code": 0,
        "msg":  "上传文件成功",
        "data": map[string]interface{}{
            "url": out,
        },
    })
    return
}

func PathExists(name string) bool {
    // ....
}

controllers/controllers.go

package controllers

import (
    // ... 
    "learn/controllers/upload" 
    // ...
)

func init() {
    // ...

    gs.Object(new(upload.Controller)).Init(func(c *upload.Controller) {
        gs.PostMapping("/upload", c.Upload)
    })
}

运行 go run main.go,然后用 curl 上传测试

$ curl -F "file=@./1.jpg" http://127.0.0.1:8080/upload
$ {"code":0,"data":{"url":"temp/1.jpg"},"msg":"上传文件成功"}
$ # 重复上传,会发现文件已存在
$ curl -F "file=@./1.jpg" http://127.0.0.1:8080/upload
$ {"code":-1,"msg":"文件已存在,请勿重复上传"}

在项目下的 temp 文件夹中能够找到上传后的文件。

以上能正常运行但是 controller 中包含了大量的逻辑而且均为文件操作,api 耦合性过高。我们需要把上面的文件操作拆分到 service 当中。

services/filesystem/filesystem.go

将文件操作逻辑抽取为 PutObject(name string, r io.Reader, size int64) (string, error)ExistsObject(name string) bool

package filesystem

import (
    "errors" 
    "io" 
    "os" 
    "path"
)

type Service struct {
}

func (s *Service) PutObject(name string, r io.Reader, size int64) (string, error) {
    // ...
}

func (s *Service) ExistsObject(name string) bool {
    // ...
}

services/services.go

package services

import (
    "learn/services/filesystem"

    "github.com/go-spring/spring-core/gs"
)

func init() {
    gs.Object(new(filesystem.Service))
}

main.go

增加 service 的导入

package main

import (
    // ...
    _ "learn/services" 
    // ...
)

controllers/upload/upload.go

在 Controller 上声明 FileService 并设置 tag autowire,这样 go-spring 会自动注入 service 那边注册的实例。

package upload

import (
    "learn/services/filesystem" 
    // ...
)

type Controller struct {
    FileService *filesystem.Service `autowire:""`
}

func (c *Controller) Upload(ctx web.Context) {
    // ... 
    if out, err := c.FileService.PutObject(file.Filename, f, file.Size); err == nil {
        // 上传成功 
        return
    } else {
        // ... 
        return
    }
}

重新运行 go run main.go 并测试,功能正常

$ curl -F "file=@./1.jpg" http://127.0.0.1:8080/upload
$ {"code":0,"data":{"url":"temp/1.jpg"},"msg":"上传文件成功"}

$ curl -F "file=@./1.jpg" http://127.0.0.1:8080/upload
$ {"code":-1,"msg":"文件已存在,请勿重复上传"}

官网及交流

Go-Spring 官网

Github