1.GoWeb開發(fā)
Go語(yǔ)言(Golang)是一種高效、靜態(tài)類型的編程語(yǔ)言,由Google開發(fā),非常適合現(xiàn)代Web開發(fā)。它特別強(qiáng)調(diào)簡(jiǎn)潔、易用和高性能,使其成為構(gòu)建Web應(yīng)用程序的流行選擇。以下是Go在Web開發(fā)中的基本特點(diǎn)及其在某些方面的不足,以及如何通過(guò)使用Gin框架來(lái)彌補(bǔ)這些不足。
1.Go在Web開發(fā)中的應(yīng)用
-
簡(jiǎn)潔的標(biāo)準(zhǔn)庫(kù):Go的標(biāo)準(zhǔn)庫(kù)提供了構(gòu)建Web服務(wù)的基本工具,如HTTP服務(wù)器和客戶端。
-
高性能:Go的性能接近編譯型語(yǔ)言,如C/C++,這對(duì)于構(gòu)建高性能Web應(yīng)用非常有利。
-
原生的并發(fā)支持:Go的并發(fā)模型基于Goroutines和Channels,為并發(fā)處理提供了強(qiáng)大的支持。
-
簡(jiǎn)單的部署過(guò)程:Go編譯后的二進(jìn)制文件包含了所有依賴,這簡(jiǎn)化了部署過(guò)程。
-
靜態(tài)類型和強(qiáng)大的類型系統(tǒng):這提供了更好的性能和安全性。
-
工具化:Go自帶工具集,如格式化工具
gofmt
和文檔工具godoc
。
2.Go在Web開發(fā)中的不足
盡管Go在構(gòu)建Web應(yīng)用方面有許多優(yōu)勢(shì),但它在某些方面仍有不足:
-
基礎(chǔ)的路由和中間件支持:Go的標(biāo)準(zhǔn)庫(kù)提供了最基礎(chǔ)的路由功能,但對(duì)于復(fù)雜的路由設(shè)計(jì)和中間件管理不夠靈活。
-
缺乏高級(jí)特性:如對(duì)象關(guān)系映射(ORM)、模板引擎等在標(biāo)準(zhǔn)庫(kù)中缺失或僅提供基礎(chǔ)支持。
-
錯(cuò)誤處理:Go的錯(cuò)誤處理相對(duì)繁瑣,需要大量的錯(cuò)誤檢查代碼。
-
陡峭的學(xué)習(xí)曲線:對(duì)于初學(xué)者來(lái)說(shuō),理解并發(fā)模型和接口的使用可能較為困難。
3.Gin框架的引入
Gin是一個(gè)用Go編寫的高性能Web框架,它通過(guò)提供更高級(jí)的功能和簡(jiǎn)化的操作,解決了Go標(biāo)準(zhǔn)庫(kù)在Web開發(fā)方面的一些不足:
-
高效的路由:Gin提供了一種更快、更方便的路由方法。
-
中間件支持:Gin有著出色的中間件支持,使得編寫日志、用戶認(rèn)證、數(shù)據(jù)驗(yàn)證等功能變得簡(jiǎn)單。
-
更少的樣板代碼:Gin簡(jiǎn)化了錯(cuò)誤處理和JSON序列化等常見(jiàn)任務(wù),減少了樣板代碼的數(shù)量。
-
快速開發(fā):Gin的API設(shè)計(jì)簡(jiǎn)潔,易于學(xué)習(xí),有助于加速開發(fā)過(guò)程。
-
豐富的功能集:Gin提供了許多內(nèi)置功能,如參數(shù)解析、JSON渲染等,還有一個(gè)活躍的社區(qū),提供各種中間件和插件。
4.使用Gin的示例
以下是一個(gè)使用Gin創(chuàng)建基本W(wǎng)eb服務(wù)器的示例代碼:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello world!",
})
})
r.Run() // 默認(rèn)在8080端口
}
這個(gè)例子展示了Gin的簡(jiǎn)潔性和易用性,它使得Go在Web開發(fā)方面更具吸引力,特別是對(duì)于需要快速開發(fā)復(fù)雜應(yīng)用的場(chǎng)景??偟膩?lái)
2.Gin框架
Gin是一個(gè)用Go(Golang)編寫的高性能Web框架,它因其簡(jiǎn)潔、高效和易于使用而在Go開發(fā)者中非常受歡迎。以下是Gin框架的詳細(xì)介紹:
1.核心特性
-
高性能:Gin是一個(gè)極其高效的HTTP Web框架。在性能測(cè)試中,它表現(xiàn)出比許多其他Go Web框架更快的速度,這得益于其基于
httprouter
的路由。 -
輕量級(jí):Gin框架保持了極簡(jiǎn)的設(shè)計(jì),沒(méi)有引入過(guò)多的依賴。
-
易用的路由語(yǔ)法:Gin提供了類似于martini框架的API,但沒(méi)有帶來(lái)性能損失,使路由的聲明既簡(jiǎn)單又直觀。
-
錯(cuò)誤處理:Gin提供了一套便捷的方式來(lái)集中處理錯(cuò)誤。
-
中間件支持:Gin允許開發(fā)者使用中間件,這些中間件可以實(shí)現(xiàn)日志記錄、用戶身份驗(yàn)證、數(shù)據(jù)驗(yàn)證等功能。
-
模板渲染:支持HTML模板渲染功能,便于生成動(dòng)態(tài)HTML頁(yè)面。
-
JSON和XML渲染:Gin可以輕松地渲染JSON或XML響應(yīng)。
-
表單和查詢參數(shù)處理:Gin使處理表單和查詢參數(shù)變得容易,提供了直接和方便的方式來(lái)獲取用戶輸入。
-
分組路由:方便的API來(lái)對(duì)路由進(jìn)行分組,使得路由和中間件的管理變得更加清晰和有組織。
2.使用場(chǎng)景
Gin適用于構(gòu)建各種Web應(yīng)用程序,尤其是在需要高性能和快速開發(fā)的場(chǎng)合,比如:
- RESTful API服務(wù)
- 微服務(wù)架構(gòu)
- 動(dòng)態(tài)網(wǎng)站和應(yīng)用程序
3.安裝和基本用法
要開始使用Gin,首先需要安裝它。如果你已經(jīng)配置了Go環(huán)境,可以使用以下命令安裝:
go get -u github.com/gin-gonic/gin
以下是一個(gè)基本的Gin應(yīng)用程序示例:
package main
import "github.com/gin-gonic/gin"
func main() {
// 創(chuàng)建一個(gè)默認(rèn)的路由引擎
r := gin.Default()
// 定義一個(gè)GET請(qǐng)求的路由
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
// 運(yùn)行服務(wù)器
r.Run() // 默認(rèn)監(jiān)聽并在 0.0.0.0:8080 上啟動(dòng)服務(wù)
}
4.社區(qū)和生態(tài)系統(tǒng)
Gin有一個(gè)活躍的開發(fā)社區(qū),這意味著有大量的中間件和插件可供使用。這些資源可以幫助解決諸如用戶認(rèn)證、日志記錄、CORS等常見(jiàn)Web開發(fā)問(wèn)題。
5.注意事項(xiàng)
- 錯(cuò)誤處理:Gin有自己的錯(cuò)誤處理邏輯,這可能與Go的傳統(tǒng)錯(cuò)誤處理方式不同。
- 學(xué)習(xí)曲線:雖然Gin相對(duì)容易上手,但理解其中的一些高級(jí)特性可能需要一些時(shí)間。
- 社區(qū)和支持:雖然Gin社區(qū)活躍,但它可能沒(méi)有像一些其他大型框架(如Express.js)那樣廣泛的用戶基礎(chǔ)和支持。
總體而言,Gin提供了一個(gè)快速、簡(jiǎn)單且高效的方式來(lái)構(gòu)建Go Web應(yīng)用程序,是Go開發(fā)者的一個(gè)極佳選擇。
3.Restful風(fēng)格API
在Gin框架中使用RESTful風(fēng)格的API涉及到創(chuàng)建具有明確目的和功能的路由,這些路由對(duì)應(yīng)于REST架構(gòu)中定義的各種HTTP方法(如GET、POST、PUT、DELETE等)。下面是在Gin中構(gòu)建RESTful API的詳細(xì)步驟和示例:
1. 創(chuàng)建一個(gè)基本的Gin服務(wù)器
首先,你需要設(shè)置一個(gè)Gin服務(wù)器。這是創(chuàng)建任何Gin應(yīng)用程序的基本步驟。
package main
import "github.com/gin-gonic/gin"
func main() {
router := gin.Default()
// 在這里設(shè)置路由
router.Run(":8080") // 在localhost的8080端口啟動(dòng)服務(wù)
}
2. 定義RESTful路由
在Gin中,你可以為不同的HTTP方法定義路由,這些方法代表了RESTful API中的不同操作。
使用GET方法獲取資源
router.GET("/books", getBooks) // 獲取書籍列表
router.GET("/books/:id", getBookByID) // 根據(jù)ID獲取特定書籍
使用POST方法創(chuàng)建資源
router.POST("/books", createBook) // 創(chuàng)建新書籍
使用PUT方法更新資源
router.PUT("/books/:id", updateBook) // 更新特定書籍
使用DELETE方法刪除資源
router.DELETE("/books/:id", deleteBook) // 刪除特定書籍
3. 實(shí)現(xiàn)處理函數(shù)
對(duì)于每個(gè)路由,你需要實(shí)現(xiàn)一個(gè)相應(yīng)的處理函數(shù)。這些函數(shù)將包含處理HTTP請(qǐng)求并返回響應(yīng)的邏輯。
func getBooks(c *gin.Context) {
// 實(shí)現(xiàn)獲取書籍列表的邏輯
}
func getBookByID(c *gin.Context) {
id := c.Param("id")
// 實(shí)現(xiàn)根據(jù)ID獲取書籍的邏輯
}
func createBook(c *gin.Context) {
// 實(shí)現(xiàn)創(chuàng)建書籍的邏輯
}
func updateBook(c *gin.Context) {
id := c.Param("id")
// 實(shí)現(xiàn)更新書籍的邏輯
}
func deleteBook(c *gin.Context) {
id := c.Param("id")
// 實(shí)現(xiàn)刪除書籍的邏輯
}
4. 返回JSON響應(yīng)
在RESTful API中,通常使用JSON格式返回?cái)?shù)據(jù)。在Gin中,你可以使用c.JSON()
來(lái)發(fā)送JSON格式的響應(yīng)。
func getBooks(c *gin.Context) {
// 示例:返回一個(gè)書籍列表
books := []string{"Book 1", "Book 2", "Book 3"}
c.JSON(http.StatusOK, gin.H{"books": books})
}
5. 接收和處理請(qǐng)求數(shù)據(jù)
對(duì)于POST和PUT請(qǐng)求,你通常需要從請(qǐng)求體中獲取數(shù)據(jù)。在Gin中,可以使用c.BindJSON()
來(lái)解析JSON格式的請(qǐng)求體。
type Book struct {
Title string `json:"title"`
Author string `json:"author"`
}
func createBook(c *gin.Context) {
var newBook Book
if err := c.BindJSON(&newBook); err != nil {
return
}
// 使用newBook中的數(shù)據(jù)創(chuàng)建書籍
}
6. 錯(cuò)誤處理
合適的錯(cuò)誤處理是構(gòu)建RESTful API的關(guān)鍵部分。確保適當(dāng)?shù)靥幚礤e(cuò)誤,并返回相應(yīng)的HTTP狀態(tài)碼。
if err := c.BindJSON(&newBook); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
通過(guò)定義清晰的路由和處理函數(shù),Gin使得創(chuàng)建遵循RESTful原則的API變得簡(jiǎn)單而直接。確保為不同的HTTP動(dòng)詞(GET、POST、PUT、DELETE)實(shí)現(xiàn)適當(dāng)?shù)奶幚磉壿?,并通過(guò)合適的HTTP狀態(tài)碼和JSON響應(yīng)與客戶端進(jìn)行通信。這樣可以創(chuàng)建一個(gè)既強(qiáng)大又易于維護(hù)的Web服務(wù)。
4.請(qǐng)求參數(shù)獲取
在Gin框架中,處理HTTP請(qǐng)求時(shí),通常需要從客戶端獲取數(shù)據(jù)。Gin提供了多種方式來(lái)傳遞參數(shù),這些方式適用于不同的場(chǎng)景。以下是Gin中各種傳參方式的總結(jié):
1. URL路徑參數(shù)
這種方式通常用于RESTful API中,參數(shù)直接嵌入在URL路徑中。
-
定義路由:在路由路徑中使用
:
來(lái)定義參數(shù)。 -
獲取參數(shù):使用
c.Param
方法獲取參數(shù)值。
router.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello, %s", name)
})
2. 查詢字符串參數(shù)
查詢字符串位于URL中?
之后,多個(gè)查詢字符串以&
分隔。
-
獲取參數(shù):使用
c.Query
獲取單個(gè)查詢參數(shù),或使用c.QueryMap
獲取全部查詢參數(shù)。
router.GET("/users", func(c *gin.Context) {
name := c.Query("name")
age := c.Query("age")
c.String(http.StatusOK, "Name: %s, Age: %s", name, age)
})
3. 表單參數(shù)
用于處理application/x-www-form-urlencoded
和multipart/form-data
(用于文件上傳)的表單數(shù)據(jù)。
-
獲取參數(shù):使用
c.PostForm
獲取單個(gè)表單字段,或使用c.PostFormMap
獲取全部表單字段。
router.POST("/form", func(c *gin.Context) {
type := c.PostForm("type")
value := c.PostForm("value")
c.String(http.StatusOK, "Type: %s, Value: %s", type, value)
})
4. JSON、XML等請(qǐng)求體
當(dāng)客戶端發(fā)送JSON、XML或其他格式的數(shù)據(jù)時(shí),可以使用Gin提供的綁定功能來(lái)解析這些數(shù)據(jù)。
-
使用
BindJSON
等方法:自動(dòng)解析請(qǐng)求體并將數(shù)據(jù)綁定到指定的結(jié)構(gòu)體。
type Login struct {
User string `json:"user"`
Password string `json:"password"`
}
router.POST("/login", func(c *gin.Context) {
var login Login
if err := c.BindJSON(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "logged in"})
})
5. 頭部參數(shù)
用于獲取HTTP頭部信息。
-
獲取參數(shù):使用
c.GetHeader
獲取指定的頭部信息。
router.GET("/headers", func(c *gin.Context) {
contentType := c.GetHeader("Content-Type")
c.String(http.StatusOK, "Content-Type: %s", contentType)
})
6. Cookie參數(shù)
用于獲取HTTP請(qǐng)求中的Cookie。
-
獲取Cookie:使用
c.Cookie
獲取單個(gè)Cookie。
router.GET("/cookie", func(c *gin.Context) {
cookie, err := c.Cookie("gin_cookie")
if err != nil {
cookie = "Not Set"
}
c.String(http.StatusOK, "Cookie value: %s", cookie)
})
在Gin框架中,有多種方式可以從客戶端獲取數(shù)據(jù),包括URL路徑參數(shù)、查詢字符串參數(shù)、表單參數(shù)、請(qǐng)求體綁定、頭部參數(shù)和Cookie。選擇哪種方式取決于具體的應(yīng)用場(chǎng)景和客戶端發(fā)送數(shù)據(jù)的方式。了解和正確使用這些方法對(duì)于構(gòu)建高效和可靠的Web應(yīng)用至關(guān)重要。
5.路由和重定向
在Gin框架中,路由是指將HTTP請(qǐng)求按照路徑和方法分發(fā)到相應(yīng)的處理函數(shù)的過(guò)程。重定向是一種特殊的路由處理,它會(huì)將客戶端指向一個(gè)不同的URL。以下是Gin中路由和重定向的基本使用方法:
1.路由基礎(chǔ)
在Gin中定義路由是通過(guò)將HTTP方法、路徑和對(duì)應(yīng)的處理函數(shù)綁定來(lái)實(shí)現(xiàn)的。
func main() {
r := gin.Default()
r.GET("/someGet", getting)
r.POST("/somePost", posting)
// ... 其他HTTP方法
r.Run() // 在0.0.0.0:8080啟動(dòng)服務(wù)
}
func getting(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "GET"})
}
func posting(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "POST"})
}
2.路由參數(shù)
路由參數(shù)允許你在URL中嵌入變量。
r.GET("/user/:name", func(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello, %s", name)
})
3.路由組
路由組是一種組織路由的方式,允許你共享公共路徑或中間件。
v1 := r.Group("/v1")
{
v1.GET("/login", loginEndpoint)
v1.GET("/submit", submitEndpoint)
}
v2 := r.Group("/v2")
{
v2.GET("/login", loginEndpoint)
v2.GET("/submit", submitEndpoint)
}
4.重定向
在Gin中,重定向可以通過(guò)c.Redirect
方法實(shí)現(xiàn),它接受兩個(gè)參數(shù):HTTP狀態(tài)碼和重定向的目標(biāo)URL。
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})
5.使用c.Request.URL.Path
你可以修改c.Request.URL.Path
,然后使用c.Redirect
來(lái)實(shí)現(xiàn)重定向。
r.GET("/test2", func(c *gin.Context) {
c.Request.URL.Path = "/test"
r.HandleContext(c)
})
Gin的路由和重定向功能提供了靈活的方式來(lái)處理HTTP請(qǐng)求。你可以定義簡(jiǎn)單或復(fù)雜的路由模式,組織它們成路由組,并實(shí)現(xiàn)標(biāo)準(zhǔn)的或自定義的重定向邏輯。這使得Gin成為構(gòu)建現(xiàn)代Web應(yīng)用程序和API的強(qiáng)大工具。
6.Gin連接數(shù)據(jù)庫(kù)
在Gin框架中連接數(shù)據(jù)庫(kù)通常涉及幾個(gè)步驟:選擇一個(gè)適合的數(shù)據(jù)庫(kù)驅(qū)動(dòng),創(chuàng)建數(shù)據(jù)庫(kù)連接,并在Gin的路由處理函數(shù)中使用這個(gè)連接來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作。以下是一個(gè)基本的示例,說(shuō)明如何在Gin中連接并使用數(shù)據(jù)庫(kù):
1. 選擇數(shù)據(jù)庫(kù)驅(qū)動(dòng)
首先,你需要選擇一個(gè)適合你使用的數(shù)據(jù)庫(kù)的Go語(yǔ)言驅(qū)動(dòng)。例如,對(duì)于MySQL,你可以使用mysql
驅(qū)動(dòng),對(duì)于PostgreSQL,可以使用pq
驅(qū)動(dòng)。
2. 安裝數(shù)據(jù)庫(kù)驅(qū)動(dòng)
使用go get
來(lái)安裝所需的數(shù)據(jù)庫(kù)驅(qū)動(dòng)。例如,對(duì)于MySQL:
go get -u github.com/go-sql-driver/mysql
3. 創(chuàng)建數(shù)據(jù)庫(kù)連接
在你的Go程序中,使用數(shù)據(jù)庫(kù)驅(qū)動(dòng)來(lái)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接。這通常是通過(guò)使用sql.Open
來(lái)完成的。
4. 在Gin中使用數(shù)據(jù)庫(kù)連接
在Gin的路由處理函數(shù)中,你可以使用這個(gè)數(shù)據(jù)庫(kù)連接來(lái)執(zhí)行查詢、插入、更新或刪除操作。
以下是一個(gè)完整的示例,展示了如何在Gin Web應(yīng)用中使用MySQL數(shù)據(jù)庫(kù):
package main
import (
"database/sql"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
"log"
)
func main() {
// 連接到數(shù)據(jù)庫(kù)
db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 確保連接正常
if err := db.Ping(); err != nil {
log.Fatal(err)
}
// 設(shè)置Gin路由
r := gin.Default()
// 定義一個(gè)路由
r.GET("/users", func(c *gin.Context) {
// 在這里使用數(shù)據(jù)庫(kù)來(lái)獲取用戶信息等
var (
id int
name string
)
// 示例查詢
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 遍歷查詢結(jié)果
for rows.Next() {
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
log.Println(id, name)
}
// 檢查遍歷過(guò)程中是否有錯(cuò)誤發(fā)生
err = rows.Err()
if err != nil {
log.Fatal(err)
}
c.JSON(200, gin.H{
"message": "用戶列表",
})
})
// 運(yùn)行Gin服務(wù)器
r.Run()
}
在上述代碼中,我們首先創(chuàng)建了一個(gè)指向MySQL數(shù)據(jù)庫(kù)的連接。之后,在Gin路由處理函數(shù)中,我們使用這個(gè)數(shù)據(jù)庫(kù)連接來(lái)執(zhí)行SQL查詢。
注意事項(xiàng)
- 數(shù)據(jù)庫(kù)憑據(jù):不要在代碼中硬編碼數(shù)據(jù)庫(kù)用戶名和密碼??紤]使用環(huán)境變量或配置文件來(lái)安全地管理這些敏感信息。
- 錯(cuò)誤處理:確保妥善處理所有可能的錯(cuò)誤,并在操作完成后關(guān)閉數(shù)據(jù)庫(kù)連接。
-
數(shù)據(jù)庫(kù)連接池:
sql.Open
實(shí)際上創(chuàng)建了一個(gè)數(shù)據(jù)庫(kù)連接池,適用于并發(fā)使用,而不是每個(gè)請(qǐng)求一個(gè)新的連接。
在實(shí)際應(yīng)用中,你可能需要考慮更多的因素,如事務(wù)管理、錯(cuò)誤處理策略、連接池配置等。
7.中間件
在Gin框架中,中間件(Middleware)和攔截器(Interceptor)是用于處理HTTP請(qǐng)求或響應(yīng)的一種方式。它們?cè)谔幚砭唧w的業(yè)務(wù)邏輯之前或之后執(zhí)行,提供了一種靈活的方法來(lái)插入日志、身份驗(yàn)證、錯(cuò)誤處理等功能。
中間件是在請(qǐng)求被處理之前或之后運(yùn)行的函數(shù)。在Gin中,中間件可以操作gin.Context
對(duì)象,決定是否繼續(xù)執(zhí)行請(qǐng)求鏈。
使用中間件文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-808075.html
- 全局中間件:對(duì)所有路由生效。
- 單個(gè)路由中間件:僅對(duì)特定路由生效。
- 路由組中間件:對(duì)路由組中的所有路由生效。
示例:定義和使用中間件文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-808075.html
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 設(shè)置example變量
c.Set("example", "12345")
// 請(qǐng)求前
c.Next() // 處理請(qǐng)求
// 請(qǐng)求后
latency := time.Since(t)
log.Print(latency)
// 訪問(wèn)發(fā)送的狀態(tài)
status := c.Writer.Status()
log.Println(status)
}
}
func main() {
r := gin.Default()
r.Use(Logger()) // 全局中間件
r.GET("/test", func(c *gin.Context) {
// 獲取設(shè)置的example的值
example := c.MustGet("example").(string)
// 打印:"12345"
log.Println(example)
})
r.Run(":8080")
}
到了這里,關(guān)于Gin框架實(shí)戰(zhàn):構(gòu)建快速、可靠的GoWeb服務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!