Go後台項目實戰

來源:互聯網
上載者:User

本項目完全使用原生開發,沒有使用任何WEB架構(如:gin,beego,Martini等),和ORM(如:gorm,xorm,beego)

三層架構

三層架構(3-tier architecture) 通常意義上的三層架構就是將整個業務應用劃分為:介面層(User Interface layer)、商務邏輯層(Business Logic Layer)、資料訪問層(Data access layer)。區分層次的目的即為了“高內聚低耦合”的思想。在軟體體系架構設計中,分層式結構是最常見,也是最重要的一種結構。

控制層/介面層

因為我的項目中並沒有寫WEB頁面,所以就拿控制層來說,就是將你的請求從頁面傳到後台代碼

服務層/商務邏輯層

針對具體問題的操作,也可以說是對資料層的操作,對資料商務邏輯處理。(關鍵在於由未經處理資料抽象出邏輯資料)能夠提供interface\API層次上所有的功能。,“中間業務層”的實際目的是將“資料訪問層”的最基礎的儲存邏輯組合起來,形成一種商務規則

持久層/資料訪問層

該層所做事務直接操作資料庫,針對資料的增添、刪除、修改、尋找等。(關鍵在於粒度的把握)要保證“資料訪問層”的中的函數功能的原子性!即最小性和不可再分。“資料訪問層”只管負責儲存或讀取資料就可以了。

Controller組合封裝

Controller"基類"封裝,主要提供了一個儲存檔案的方法,主要用於form-data請求

import("io""mime/multipart""net/http""path")constBASE_IMAGE_ADDRESS ="./img/"typeControllerstruct{Datainterface{}}typeFileInfoTOstruct{//圖片id -- 暫時沒有用IDint64//縮圖路徑 -- 暫時沒有用CompressPathstring//原圖路徑 ,儲存資料庫的路徑Pathstring//原始的檔案名稱OriginalFileNamestring//隱藏檔名 如:uuidutilFileNamestring//檔案大小FileSizeint64}//擷取上傳檔案的數量func(p *Controller)GetFileNum(r *http.Request,keys ...string)int{m := r.MultipartFormifm ==nil{return0}iflen(keys) ==0{varnumintfor_,fileHeaders :=rangem.File {num +=len(fileHeaders)}returnnum}else{varnumintfor_,value :=rangekeys {num +=len(m.File[value])}returnnum}}//解析Form-data中的檔案,如果不傳keys,不管上傳的檔案的欄位名(filename)是什麼,都會解析,否則只會解析keys指定的檔案func(p *Controller)SaveFiles(r *http.Request,,relativePathstring,keys ...string)[]*FileInfoTO{r.ParseMultipartForm(32<<20)m := r.MultipartFormifm ==nil{log.Println("not multipartfrom !")returnnil}fileInfos :=make([]*FileInfoTO,0)filePath := BASE_IMAGE_ADDRESS + relativePathfileutil.MakeDir(filePath)iflen(keys) ==0{for_,fileHeaders :=rangem.File {//遍曆所有的所有的欄位名(filename)擷取FileHeadersfor_,fileHeader :=rangefileHeaders{to := p.saveFile(filePath,relativePath,fileHeader)fileInfos =append(fileInfos,to)}}}else{for_,value :=rangekeys {fileHeaders := m.File[value]//根據上傳檔案時指定的欄位名(filename)擷取FileHeadersfor_,fileHeader :=rangefileHeaders{to := p.saveFile(filePath,relativePath,fileHeader)fileInfos =append(fileInfos,to)}}}returnfileInfos}//儲存單個檔案func(p *Controller)saveFile(filePath,relativePathstring,fileHeader *multipart.FileHeader)*FileInfoTO{file,err := fileHeader.Open()iferr !=nil{log.Println(err)returnnil}deferfile.Close()name,err := uuidutil.RandomUUID()iferr !=nil{log.Println(err)returnnil}fileType := fileutil.Ext(fileHeader.Filename,".jpg")newName := name + fileTypedst,err := os.Create(filePath + newName)iferr !=nil{log.Println(err)returnnil}deferdst.Close()fileSize,err := io.Copy(dst,file)iferr !=nil{log.Println(err)returnnil}return&FileInfoTO{Path:relativePath + newName,OriginalFileName:fileHeader.Filename,FileName:newName,FileSize:fileSize}}
fileutilimport("os""path")//建立多級目錄funcMkDirAll(pathstring)bool{err := os.MkdirAll(path, os.ModePerm)iferr !=nil{returnfalse}returntrue}//檢測檔案夾或檔案是否存在funcExist(filestring)bool{if_,err := os.Stat(file);os.IsNotExist(err){returnfalse}returntrue}//擷取檔案的類型,如:.jpg//如果擷取不到,返回預設類型defaultExtfuncExt(fileNamestring,defaultExtstring)string{t := path.Ext(fileName)iflen(t) ==0{returndefaultExt}returnt}/// 檢驗檔案夾是否存在,不存在 就建立funcMakeDir(filePathstring){if!Exist(filePath) {MkDirAll(filePath)}}//刪除檔案funcRemove(namestring)bool{err := os.Remove(name)iferr !=nil{returnfalse}returntrue}
uuidtuilimport("encoding/base64""math/rand")funcRandomUUID()(string,error){b :=make([]byte,32)if_,err := rand.Read(b);err !=nil{return"",err}returnbase64.URLEncoding.EncodeToString(b),nil}

ApiController主要用於使用者體系的一個登陸狀態的資訊擷取,根據請求中的session擷取服務端儲存的使用者資訊,如果你的後台分使用者體系和管理端使用者體系,並且這兩個使用者體系分別儲存在兩個表中,這時你還可以定義一個BackController

typeApiControllerstruct{Controller}func (p *ApiController) GetUserId(w http.ResponseWriter,r *http.Request) uint{user := p.GetUser(w,r)ifuser ==nil{return0}returnuser.ID}func (p *ApiController) GetUser(w http.ResponseWriter,r *http.Request) *entity.User{session := GlobalSession().SessionStart(w,r)ifsession ==nil{returnnil}key_user := session.Get(constant.KEY_USER)ifuser,ok := key_user.(*entity.User);ok{returnuser}returnnil}

database

持久層的實現:https://blog.csdn.net/cj_286/article/details/80363796

http

http server的實現:https://blog.csdn.net/cj_286/article/details/80256988

Router

路由處理的實現,其實也就是一個轉寄的功能

type RouterHandler struct {}varmux = make(map[string]func(http.ResponseWriter,*http.Request))func (p *RouterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Println(r.URL.Path)iffun, ok := mux[r.URL.Path]; ok {fun(w, r)return}//靜態資源ifstrings.HasPrefix(r.URL.Path,constant.STATIC_BAES_PATH){iffun, ok := mux[constant.STATIC_BAES_PATH]; ok {fun(w, r)return}}http.Error(w,"error URL:"+r.URL.String(), http.StatusBadRequest)}func (p *RouterHandler) Router(relativePath string, handler func(http.ResponseWriter, *http.Request)) {mux[relativePath] = handler}

session

如果有登入功能,所以需要用到session來記住使用者的狀態,以下是session技術實現的主要類型與介面定義,(摘自:https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/06.0.md),會話到期時間可以自行設定,如果設定為一小時,在停止會話一小時後session就會到期,該session就會被自動刪除,如果回話都保持在一小時之內就可以一直訪問,session不會到期

//主要用於session的管理,到期處理等type Manager struct {cookieName stringlock sync.Mutexprovider ProvidermaxLifeTime int64}//用於提供session儲存方式的一個介面標準,可以用於提供session儲存在記憶體、檔案、資料庫等方式type Provider interface {SessionInit(sid string)(Session,error)SessionRead(sid string)(Session,error)SessionDestroy(sid string) errorSessionGC(maxLifeTime int64)}//用於對session一些基本操作的定義type Session interface {Set(key, value interface{}) errorGet(key interface{}) interface{}Delete(key interface{}) errorSessionID()string}

靜態資源

靜態資源處理需要用到http.FileServer和http.StripPrefix函數,http.FileServer通常要跟http.StripPrefix結合使用http.StripPrefix函數的作用之一,就是在將請求定向到你通過參數指定的請求處理處之前,將特定的prefix從URL中過濾出去。下面是一個瀏覽器或HTTP用戶端請求資源的例子:

/static/example.png

StripPrefix 函數將會過濾掉/static/,並將修改過的請求定向到http.FileServer所返回的Handler中去,因此請求的資源將會是:

/example.png

http.FileServer 返回的Handler將會進行尋找,並將與檔案夾或檔案系統有關的內容以參數的形式返回給你(在這裡你將"static"作為靜態檔案的根目錄)。因為你的"example.txt"檔案在靜態目錄中,你必須定義一個相對路徑去獲得正確的檔案路徑。

根據需要定製訪問路徑

http.Handle("/tmpfiles/",http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))

FileServer 已經明確靜態檔案的根目錄在"/tmp",但是我們希望URL以"/tmpfiles/"開頭。如果有人請求"/tempfiles/example.txt",我們希望伺服器能將檔案發送給他。為了達到這個目的,我們必須從URL中過濾掉"/tmpfiles", 而剩下的路徑是相對於根目錄"/tmp"的相對路徑。如果我們按照如上做法,將會得到如下結果:

/tmp/example.png

示範

粗略的設計了幾個API,以下就是訪問API的請求與響應,以下除了註冊和登入不會去檢測session,其它API都會檢測,要求登入才可以訪問。

imageimageimageimage

未登入狀態下調用添加意見反饋介面

image

登入狀態下調用添加意見反饋介面

image

訪問靜態資源

image

項目地址:https://github.com/xiaojinwei/cgo

參考:https://studygolang.com/articles/9197

https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/06.0.md

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.