1.Abstract
在學(xué)習(xí)web開發(fā)的過程中會(huì)遇到很多困難,因此寫洗一篇類似綜述類的文章。作為路線圖從web開發(fā)要素的index出發(fā)來介紹golang開發(fā)的學(xué)習(xí)流程以及Example代碼。
在描述中多是使用代碼來描述使用方法不會(huì)做過多的說明。最后可以方便的copy代碼來實(shí)現(xiàn)自己的需求。
本文適應(yīng)對(duì)象:
對(duì)web開發(fā)有一定經(jīng)驗(yàn)的人
能夠靈活使用ajax的人(至少懂得前后分離)
golang web 開發(fā)有一定了解,至少略讀過一些golang web開發(fā)的書籍
看完本文之后您會(huì)收獲:
golang web開發(fā)的一些技巧
golang web開發(fā)的一些實(shí)用API
本文在描述的時(shí)候?yàn)榱私忉尡M量詳細(xì),已經(jīng)把解釋寫到代碼注釋中。
2.golang web 開發(fā)check list
略過的部分:基本流程控制,OOP等基礎(chǔ)語法知識(shí)。
2.1本章節(jié)提供golang web開發(fā)的知識(shí)面參考。
1.Abstract
2.golang web 開發(fā)check list
2.1 本章節(jié)提供golang_web開發(fā)的知識(shí)面參考。
3.路由器
3.1 手動(dòng)路由
3.2 手動(dòng)路由的綁定
3.2.1 靜態(tài)文件
3.2.2 固定函數(shù)與資源獲取
4.頁面加載
4.1 純靜態(tài)頁(HTML)
4.2 模板頁面的加載
5.表示層腳本
5.1 require.js
5.1.1 加載
5.1.2 頁面Business
5.2 JQuery
6.業(yè)務(wù)層
7.持久層
7.1 Mysql
7.2 Mongodb
8.單元測試注意事項(xiàng)
9.LOG
總結(jié)
3.路由器
路由器是整個(gè)網(wǎng)站對(duì)外的靈魂,如果路由做的不好URL會(huì)非常惡心。
所以這部分設(shè)計(jì)成第一個(gè)要說的內(nèi)容。
路由分兩種一種是手動(dòng)路由為了通過tul調(diào)度固定的功能,另外一點(diǎn)就是資源
的獲取,通過url的分析來模仿靜態(tài)頁的方式來獲取資源(類似get)
自動(dòng)路由,主要使用OOP的COMMAND模式來實(shí)現(xiàn)。所有功能使用post,
統(tǒng)一入口,方便權(quán)限管理,安全管理,跨域管理。但是如此強(qiáng)大的功能還是
交給框架來做吧。這里就不給新手做參考了。
3.1手動(dòng)路由
package main
import (
"log"
"net/http"
)
func main() {
RouterBinding() // 路由綁定函數(shù)
err := http.ListenAndServe(":9090", nil) //設(shè)置監(jiān)聽的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
在httpserver運(yùn)行之前先綁定路由
3.2 手動(dòng)路由的綁定
3.2.1 靜態(tài)文件
http.Handle("/pages/", http.StripPrefix("/pages/", http.FileServer(http.Dir("./pages"))))
3.2.2 固定函數(shù)與資源獲取
他們都是一樣的
http.HandleFunc("/images/", fileUpload.DownloadPictureAction)
4.頁面加載
4.1 純靜態(tài)頁(HTML)
直接交給路由就行了。自動(dòng)就訪問那個(gè)文件夾了。不過生產(chǎn)環(huán)境果然還得是cdn,如果自己服務(wù)器比較多??梢詎ginx反向代理。
主要好處前后分離,能上CDN就是通訊次數(shù)多了。不過通過優(yōu)化改善之類的都還ok啦。
4.2 模板頁面的加載僅提供關(guān)鍵代碼。
commonPage, err := template.ParseFiles("pages/common/head.gtpl", //加載模板
"pages/common/navbar.gtpl", "pages/common/tail.gtpl")
if err != nil {
panic(err.Error())
}
navArgs := map[string]string{"Home": "home", "User": "yupengfei"}//復(fù)雜的參數(shù)開始往里塞
knowledgePage, err := template.ParseFiles("pages/knowledge/knowledge.gtpl")
knowledgeArgs := map[string]interface{}{"Head": "This is a test title",
"Author": "kun.wang", "PublishDatetime": "2014-09-14",
"Content": template.HTML("<p style="text-indent: 2em">為什么要用語義呢?</p>")}//不是不好,只是做字符串分析會(huì)影響工程效率
commonPage.ExecuteTemplate(w, "header", nil)// render 開始
commonPage.ExecuteTemplate(w, "navbar", navArgs)
knowledgePage.ExecuteTemplate(w, "knowledge", knowledgeArgs)
commonPage.ExecuteTemplate(w, "tail", nil)
僅提供關(guān)鍵代碼。
字符串?dāng)?shù)組作為輸入?yún)?shù)差錯(cuò)比較困難
總結(jié):雖然減少的通訊次數(shù),但是沒辦法上CDN蛋疼,另外,模板的mapping蛋疼。
5.表示層腳本
表示層腳本做的比較困難也不是很好學(xué)。
但是一旦搞定了,代碼的復(fù)用性會(huì)有非??捎^的提升。
就普通情況而言JS開發(fā)效率是非常高的靈活度高,并且使用的是客戶端的cpu
性能好,免費(fèi)資源多,學(xué)習(xí)的人也多,好招聘。
5.1 require.js
5.1.1 加載
<script data-main="/reqmod/login_main" language="JavaScript" defer async="true" src="js/r.js"></script>
整個(gè)網(wǎng)頁之留這么一個(gè)加載腳本的入口(每個(gè)頁面最好只有一個(gè)js文件)
好處
js是延遲加載。不會(huì)出現(xiàn)網(wǎng)頁卡死的情況
最大化使用緩存。(HTTP 304)
一個(gè)網(wǎng)頁只用一個(gè)js
dom事件綁定,不用在html控件上寫js綁定了
壞處
學(xué)習(xí)比較難
網(wǎng)站更新始終有緩存沒更新的瀏覽器。造成錯(cuò)誤(所以有些情況客戶自己就知道多刷新幾次了,已經(jīng)成用戶習(xí)慣了)
參數(shù)解釋
`data-main` 業(yè)務(wù)邏輯入口,載入當(dāng)前字符串.js這個(gè)文件
`language` 不解釋
`defer async` 字面意思
`src` r.js就是require.js的意思。代碼到處都能搞到。
5.1.2 頁面Business
加載依賴文件
require.baseUrl = "/"
require.config({
baseUrl: require.baseUrl,
paths: {
"jquery": "js/jquery-1.10.2.min",
"domready" : "reqmod/domReady",
"pm" : "reqmod/pmodal",
"cookie":"reqmod/cookie",
"user":"reqmod/user",
"bootstrap": "reqmod/bootstrap.min",
"nav":"reqmod/nav"
},
shim: {
'bootstrap': {
deps: ['jquery']
}
}
});
//直接copy全搞定。
執(zhí)行頁面business
執(zhí)行里面做的最多的就是dom跟事件綁定而已。加載各種js庫直接引用。
代碼美觀,開發(fā)效率,執(zhí)行效率都是非常棒的。
require(['nav','domready', 'jquery', 'user','pm'], function (nav,doc, $, user,pm){
//這個(gè)函數(shù)的第一個(gè)`數(shù)組`參數(shù)是選擇的依賴的模塊。1. 網(wǎng)站絕對(duì)路徑。 2. 使用加載依賴模塊的時(shí)候選擇export的內(nèi)容
//數(shù)組的順序要跟function順序一致,如果有兩個(gè)模塊依賴比如說jquery插件,就寫道最后不用變量,直接使用`$`
doc(function () { // domReady
pm.load();//加載各種插件HTML模板之類的都o(jì)k
$('#btn_login')[0].onclick = function(){user.login();}//button 事件綁定
});
});
頁面MODEL
define(['jquery','reqmod/cookie','user','bootstrap'],function ($,cookie,user){
//define 函數(shù)的參數(shù)內(nèi)容require是一樣的。
// 這里依賴的模塊要在調(diào)用此模塊中的模塊中有path配置。不然會(huì)死的很慘,報(bào)錯(cuò)的時(shí)候不會(huì)說缺少什么什么地方錯(cuò)了。
var nav_load = function () { // 注意函數(shù)定義的方式copy就行
$.get('/nav.html', function(result){
var newNode = document.createElement("div");
newNode.innerHTML = result;
$('body')[0].insertBefore(newNode,$('body')[0].firstChild);
//document.body.innerHTML = result + document.body.innerHTML;
$('#btn_login')[0].onclick = function(){user.login();}
$('#btn_reg')[0].onclick = function(){window.location='/register.html'}
$.post('/login_check',{},function(data){
if(data==0){
Form_login.style.display=""
}
else{
form_userInfo.style.display=""
}
})
});
}
return {//這里類似微型路由。非常靈活,非常方便
load :nav_load
};
});
5.2 JQuery
JQ的功能只要require.js引用了之后基本上都是一樣的。
如果有需要可以到w3school上學(xué)習(xí)一下。
6.業(yè)務(wù)層
Post分析
func XXXAction(w http.ResponseWriter, r *http.Request) {
r.parseForm() //有這個(gè)才能獲取參數(shù)
r.Form["Email"] // 獲取Email 參數(shù)(String)
// 寫接下來的業(yè)務(wù)。
}
資源入口函數(shù)資源require分析(url分析固定寫法)
func Foo(w http.ResponseWriter, r *http.Request) {
queryFile := strings.Split(r.URL.Path, "/")
queryResource := queryFile[len(queryFile)-1] // 解析文件
}
//完成字符串分割之后,按照需求來獲取資源就可以了。
直接輸入object
data, err := ioutil.ReadAll(r.Body) //直接讀取form為 json 字符串
if err != nil {
utility.SimpleFeedBack(w, 10, "failed to read body")
pillarsLog.PillarsLogger.Print("failed to read body")
return
}
k := 【BUSINESS OBJECT】
err = json.Unmarshal(data, &k)
if err != nil {
utility.SimpleFeedBack(w, 13, "Pramaters failed!")
pillarsLog.PillarsLogger.Print("Pramaters failed!")
return
}
//方便快捷。再訪問參數(shù)的時(shí)候,直接調(diào)用結(jié)構(gòu)體參數(shù)就可以了。
//注意ajax調(diào)用函數(shù)的時(shí)候需要做出一些調(diào)整代碼如下:
$.ajax([dist],JSON.stringify([data]),function(){},'json');//注意JSON
7.持久層
7.1 Mysql
其實(shí)不管什么語言的Mysql驅(qū)動(dòng)都是從PRO*C來的,所以會(huì)PRO*C之后,啥都好說
Insert Delete Update
stmt, err := mysqlUtility.DBConn.Prepare("INSERT INTO credit (credit_code, user_code, credit_rank) VALUES (?, ?, ?)")
if err != nil {
pillarsLog.PillarsLogger.Print(err.Error())
return false, err
}
defer stmt.Close()
_, err = stmt.Exec(credit.CreditCode, credit.UserCode, credit.CreditRank)
if err != nil {
return false, err
} else {
return true, err
}
//還是比較方便的
Query
stmt, err := mysqlUtility.DBConn.Prepare(`SELECT commodity_code, commodity_name, description, picture,
price, storage, count, status,
insert_datetime, update_datetime FROM commodity WHERE commodity_code = ?`)
if err != nil {
return nil, err
}
defer stmt.Close()
result, err := stmt.Query(commodityCode)
if err != nil {
return nil, err
}
defer result.Close()
var commodity utility.Commodity
if result.Next() {
err = result.Scan(&(commodity.CommodityCode), &(commodity.CommodityName), &(commodity.Description),
&(commodity.Picture), &(commodity.Price), &(commodity.Storage), &(commodity.Count), &(commodity.Status),
&(commodity.InsertDatetime), &(commodity.UpdateDatetime))
if err != nil {
pillarsLog.PillarsLogger.Print(err.Error())
return nil, err
}
}
return &commodity, err
7.2 Mongodb
err := mongoUtility.PictureCollection.Find(bson.M{"picturecode":*pictureCode}).One(&picture)
這里只給出最簡單的例子。具體的看mgo的開發(fā)文檔就ok。還是比較簡單的。
8.單元測試注意事項(xiàng)
測試命令 go test -v (沒有其他參數(shù)了?。。。?如果不帶-v只顯示結(jié)果,不顯示調(diào)試過程,主要是調(diào)試開發(fā)的時(shí)候用
文件格式 xxx_test.go 但是建議改成 xxx_test0.go 或者喜歡改成別的也可以。
由于測試先行的原則,在開發(fā)的時(shí)候一次測試也就一兩個(gè)函數(shù)。
這樣相當(dāng)于把其他測試注釋掉
測試的時(shí)候的配置文件要放到測試目錄下面。別忘了。
心態(tài),錯(cuò)誤太多一個(gè)一個(gè)來,要有個(gè)好心態(tài)。
9.LOG
注意在調(diào)試中Log的不可缺失性。
下面api如果不知道從何而來直接doc搜索就可以了。
package utility
import "log"
import "os"
import "fmt"
// Logger Model min variable.
var Logger *log.Logger
var outFile *os.File
// init function if Logger if not inited will invoke this function
func init() {
if Logger == nil {
propertyMap := ReadProperty("pic.properties")
logFileName := propertyMap["LogFile"]
fmt.Println("Initial and Open log file ", logFileName)
var err error
outFile, err = os.OpenFile(logFileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
panic(err.Error())
}
Logger = log.New(outFile, "", log.Ldate|log.Ltime|log.Llongfile)
}
}
// CloseLogFile function : close Logger invoke file.
func CloseLogFile() {
outFile.Close()
}
使用方法:
utility.Logger.Println("Log test")
總結(jié)
看完這里copy代碼日常工作還是能好應(yīng)付一點(diǎn)。
如果是新手看完這個(gè)之后,看那么厚的書就有一定的目標(biāo)性了。能方便一點(diǎn)在學(xué)習(xí)web開發(fā)的過程中會(huì)遇到很多困難,因此寫洗一篇類似綜述類的文章。作為路線圖從web開發(fā)要素的index出發(fā)來介紹golang開發(fā)的學(xué)習(xí)流程以及Example代碼。
更多信息請(qǐng)查看IT技術(shù)專欄
2025國考·省考課程試聽報(bào)名