示例程式碼後續會提交到 Github 上
上章 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 當中。
將檔案操作邏輯抽取為 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 {
// ...
}
package services
import (
"learn/services/filesystem"
"github.com/go-spring/spring-core/gs"
)
func init() {
gs.Object(new(filesystem.Service))
}
增加 service 的匯入
package main
import (
// ...
_ "learn/services"
// ...
)
在 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":"檔案已存在,請勿重複上傳"}
本作品採用《CC 協議》,轉載必須註明作者和本文連結