使用Golang的Gin框架和vue編寫web應用
背景: 之前使用Golang的Gin框架進行一些運維內部後端的API介面開發,對外提供提供 json
型別的資料響應,但是該種方式在瀏覽器訪問資料時資料格式不友好(由於是API介面,一般需要使用postman之類的工具來驗證介面返回資料),後來嘗試了使用Golang的 template
模板來結合html進行資料渲染,但也發現比較缺乏美感。之後決定使用前端框架來渲染後端資料,由於vue框架的各種優勢,比如簡單、資料的雙向繫結等等好處,決定使用vue框架來開啟我的前端之旅。接下來簡單來講解下使用Golang後端和vue前端進行融合的示例。
基於Gin框架的後端API
編寫基於Gin框架的API:
# 檢視原始碼檔案 $ cat main.go /** * @File Name: main.go * @Author: xxbandy @http://xxbandy.github.io * @Email: * @Create Date: 2018-12-02 22:12:59 * @Last Modified: 2018-12-02 22:12:52 * @Description: */ package main import ( _ "fmt" "github.com/gin-gonic/gin" "math/rand" "net/http" ) func HelloPage(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "welcome to bgops,please visit https://xxbandy.github.io!", }) } func main() { r := gin.Default() v1 := r.Group("/v1") { v1.GET("/hello", HelloPage) v1.GET("/hello/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) v1.GET("/line", func(c *gin.Context) { // 注意:在前後端分離過程中,需要注意跨域問題,因此需要設定請求頭 c.Writer.Header().Set("Access-Control-Allow-Origin", "*") legendData := []string{"週一", "週二", "週三", "週四", "週五", "週六", "週日"} xAxisData := []int{120, 240, rand.Intn(500), rand.Intn(500), 150, 230, 180} c.JSON(200, gin.H{ "legend_data": legendData, "xAxis_data":xAxisData, }) }) } //定義預設路由 r.NoRoute(func(c *gin.Context) { c.JSON(http.StatusNotFound, gin.H{ "status": 404, "error":"404, page not exists!", }) }) r.Run(":8000") } # 執行程式 $ go run main.go [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env:export GIN_MODE=release - using code:gin.SetMode(gin.ReleaseMode) [GIN-debug] GET/v1/hello--> main.HelloPage (3 handlers) [GIN-debug] GET/v1/hello/:name--> main.main.func1 (3 handlers) [GIN-debug] GET/v1/line--> main.main.func2 (3 handlers) # 測試相關的介面 $curl -slocalhost:8000/v1/hello | python -m json.tool { "message": "welcome to bgops,please visit https://xxbandy.github.io!" } $ curl -slocalhost:8000/v1/hello/bgops Hello bgops $ curl -slocalhost:8000/v1/line {"legend_data":["週一","週二","週三","週四","週五","週六","週日"],"xAxis_data":[120,240,81,387,150,230,180]} # 可以看到該介面會返回一個json結構的資料 $ curl -slocalhost:8000/v1/line | python -m json.tool { "legend_data": [ "\u5468\u4e00", "\u5468\u4e8c", "\u5468\u4e09", "\u5468\u56db", "\u5468\u4e94", "\u5468\u516d", "\u5468\u65e5" ], "xAxis_data": [ 120, 240, 347, 59, 150, 230, 180 ] }
基於vue框架的前端專案
使用 vue-cli
腳手架快速構建一個vue專案。
注意:前提是需要node環境,並且有可用的npm源
# 檢視版本 $ npm -v 2.3.0 #升級 npm cnpm install npm -g # 升級或安裝 cnpm npm install cnpm -g # 最新穩定版 $ cnpm install vue # 全域性安裝 vue-cli $ cnpm install --global vue-cli # 建立一個基於 webpack 模板的新專案 ➜vue-doc vue init webpack vue-test ? Target directory exists. Continue? Yes ? Project name vue-test ? Project description A Vue.js project ? Author xxbandy ? Vue build standalone ? Install vue-router? Yes ? Use ESLint to lint your code? Yes ? Pick an ESLint preset Standard ? Set up unit tests Yes ? Pick a test runner jest ? Setup e2e tests with Nightwatch? Yes //提供了兩種方式[npm和yarn,如果預設選擇npm時會去外網下載資源,可能無法訪問谷歌外網] ? Should we run `npm install` for you after the project has been created? (recommended) no vue-cli · Generated "vue-test". # Project initialization finished! # ======================== To get started: cd vue-test npm install (or if using yarn: yarn) npm run lint -- --fix (or for yarn: yarn run lint --fix) npm run dev Documentation can be found at https://vuejs-templates.github.io/webpack $cd vue-test $cnpm install ✔ Installed 58 packages ✔ Linked 0 latest versions ✔ Run 0 scripts ✔ All packages installed (used 237ms(network 227ms), speed 0B/s, json 0(0B), tarball 0B) # run的時候會根據配置進行webpack靜態資源編譯 $ cnpm run dev DONECompiled successfully in 4388ms > Listening at http://localhost:8080
當使用了 cnpm run dev
後,即成功執行起來一個前端服務,因此你會看到類似下面的頁面。

image.png
vue渲染後端API資料
1. 首先快速看一下 vue
專案的程式碼結構.
$ tree -L 1 . . ├── README.md ├── build ├── config ├── index.html ├── node_modules ├── package.json ├── src ├── static └── test # 對於快速開發而言,只需要知道src目錄下為vue相關的程式碼,即我們看到vue的歡迎頁面就是src下的 $ tree -L 2 src src ├── App.vue ├── assets │└── logo.png ├── components │└── HelloWorld.vue ├── main.js └── router └── index.js
注意:
可以看到一個vue專案的原始碼部分由這麼幾個部分組成
main.js App.vue assets components router
我們首先來看一下 App.vue
程式碼
# 我們可以看到在div 這裡有個img標籤,這裡其實就是我們剛才看到歡迎頁面的vue的logo # 其實可以看到使用了<router-view>標籤,這裡其實是定義了預設的元件,也就是下面匯入的HelloWorld $ cat App.vue <!--展示模板--> <template> <!--這裡用的是id選擇器來繫結css樣式的--> <div id="app"> <img src="./assets/logo.png"> <router-view></router-view> </div> </template> <script> import HelloWorld from './components/HelloWorld' export default { name: 'helloworld', components: { HelloWorld } } </script> <!--樣式程式碼--> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
我們再來檢視一下 components/HelloWorld.vue
檔案:
# 其實就是我們剛才看到的歡迎頁下面的一些超連結 $ cat components/HelloWorld.vue <template> <div class="HelloWorld"> <h1>{{ msg }}</h1> <h2>Essential Links</h2> <ul> <li> <a href="https://vuejs.org" target="_blank" > Core Docs </a> </li> <li> <a href="https://forum.vuejs.org" target="_blank" > Forum </a> </li> <li> <a href="https://chat.vuejs.org" target="_blank" > Community Chat </a> </li> <li> <a href="https://twitter.com/vuejs" target="_blank" > Twitter </a> </li> .........
其實到這裡,我們基本就知道了整個vue專案是如何把資源渲染出來的。不過我們再來看一下 router
下的定義。
# 其實就是定義我們如何能訪問到這個資源 $ cat router/index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld } ] })
2. 思考我們接下來要做什麼
現在我們知道vue是如何渲染的相關資料,並且知道了大概的編碼規則,但是我們的資料並不在本地,而是一個對外API,此時我們需要想辦法讓vue獲取到後端的資料。
沒錯,這個時候,我們需要一些非同步請求的方式讓vue拿到資料,比如 ajax
之類的,不過在大前端時代,有更好的工具,即 axios
,接下來在我們的vue環境中安裝 axios
環境:
# 安裝非同步請求包 $ cnpm install --save axios
3. vue渲染後端資料
模擬編寫一個 components/HelloWorld
元件
# 編寫一個ApiData.vue的元件 $ cat components/ApiData.vue <template> <!--使用class來繫結css的樣式檔案--> <div class="hello"> <!--{{}} 輸出物件屬性和函式返回值--> <h1>{{ msg }}</h1> <h1>site : {{site}}</h1> <h1>url : {{url}}</h1> <h3>{{details()}}</h3> <h1 v-for="data in ydata" :key="data">{{data}}</h1> <h3 v-for="item in xdata" :key="item">{{item}}</h3> </div> </template> <script> import axios from 'axios' export default { name: 'apidata', // data用來定義返回資料的屬性 data () { return { msg: 'hello,xxbandy!', site: "bgops", url: "https://xxbandy.github.io", xdata: null, ydata: null, } }, // 用於定義js的方法 methods: { details: function() { return this.site }, }, mounted () { // response返回一個json{"data": "資料","status": "狀態碼","statusText":"狀態文字","headers":{ "content-type": "application/json; charset=utf-8" },"config":"配置檔案","method":"方法","url":"請求url","request":"請求體"} axios.get('http://localhost:8000/v1/line').then(response => (this.xdata = response.data.legend_data,this.ydata = response.data.xAxis_data)) } } </script> <!--使用css的class選擇器[多重樣式的生效優先順序]--> <style> .hello { font-weight: normal; text-align:center; font-size:8pt; } h3 { text-align:center; font-size:20pt; color:red; } </style>
在路由中增加我們的components
# 增加路由 cat router/index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' // 增加我們自定義的ApiData元件 import Hello from '@/components/ApiData' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'HelloWorld', component: HelloWorld }, // 在這裡引用我們的元件 { path: '/xxb', name: 'Hello', component: Hello } ] })
在 App.vue
檔案中定義我們的vue指令碼
# 增加如下內容 <script> import Hello from './components/ApiData' export default { name: 'xxb', components: { Hello } } </script>
執行服務
此時,我們可以執行服務,來檢測我們的程式。
# 在vue的專案家目錄下執行(由於我們的golang的api介面執行的是8000埠,因此vue的埠需要修改一下) $ cnpm run dev Your application is running here: http://localhost:8082


此時,我們就可以看到vue成功將後端Golang的API資料進行渲染出來了。雖然只是簡單渲染,但,基本上已經實現了後端API和前端 vue
專案的融合。接下來就需要根據需求繼續改造了。