【go项目01_学习记录14】

1 路由和控制器

本节要将业务代码从main.go中移走,先从首页、关于和404静态页面开始。

1.1 新建路由文件

routes/web.go

// Package routes 存放应用路由
package routes

import (
    "net/http"

    "github.com/gorilla/mux"
)

// RegisterWebRoutes 注册网页相关路由
func RegisterWebRoutes(r *mux.Router) {

    // 静态页面
    r.HandleFunc("/", homeHandler).Methods("GET").Name("home")
    r.HandleFunc("/about", aboutHandler).Methods("GET").Name("about")
    r.NotFoundHandler = http.HandlerFunc(notFoundHandler)
}

暂时会报错,routes包中没有定义homeHandler等函数,后面再进行调用修改

1.2 注册路由

更新pkg/route/router.go文件内容

.
.
.
// Initialize 初始化路由
func Initialize() {
    Router = mux.NewRouter()
    routes.RegisterWebRoutes(Router)
}
.
.
.

1.3 添加控制器 pages_controller

新建app/http/controllers/pages_controller.go

// Package controllers 应用控制层
package controllers

import (
    "fmt"
    "net/http"
)

// PagesController 处理静态页面
type PagesController struct {
}

// Home 首页
func (*PagesController) Home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "<h1>Hello, 欢迎来到 goblog!</h1>")
}

// About 关于我们页面
func (*PagesController) About(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "此博客是用以记录编程笔记,如您有反馈或建议,请联系 "+
        "<a href=\"mailto:summer@example.com\">summer@example.com</a>")
}

// NotFound 404 页面
func (*PagesController) NotFound(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusNotFound)
    fmt.Fprint(w, "<h1>请求页面未找到 :(</h1><p>如有疑惑,请联系我们。</p>")
}

1.4 完善路由文件

完善routes/web.go

.
.
.
// RegisterWebRoutes 注册网页相关路由
func RegisterWebRoutes(r *mux.Router) {

    // 静态页面
    pc := new(controllers.PagesController)
    r.NotFoundHandler = http.HandlerFunc(pc.NotFound)
    r.HandleFunc("/", pc.Home).Methods("GET").Name("home")
    r.HandleFunc("/about", pc.About).Methods("GET").Name("about")
}

1.5 删除路由

main.go ,将以下几个多余的路由删除:

router.HandleFunc("/", homeHandler).Methods("GET").Name("home")
router.HandleFunc("/about", aboutHandler).Methods("GET").Name("about")

// 自定义 404 页面
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)

2 循环引用

articles.show ,将 main.go 里的控制器逻辑移到专属的文章控制器中

2.1 routes/web.go中注册路由

.
.
.
func  RegisterWebRoutes(r *mux.Router) {
    .
    .
    .

    // 文章相关页面
    ac := new(controllers.ArticlesController)
    r.HandleFunc("/articles/{id:[0-9]+}", ac.Show).Methods("GET").Name("articles.show")
}

main.go 文件中,将不再需要的代码删除:

router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandler).Methods("GET").Name("articles.show")

2.2 ArticlesController 控制器

添加app/http/controllers/articles_controller.go

package controllers

import (
    "net/http"
)

// ArticlesController 文章相关页面
type ArticlesController struct {
}

// Show 文章详情页面
func (*ArticlesController) Show(w http.ResponseWriter, r *http.Request) {

}

2.3 完善app/http/controllers/articles_controller.go

articlesShowHandler 将内容复制到刚刚创建的 Show 方法中:
app/http/controllers/articles_controller.go

.
.
.
func (*ArticlesController) Show(w http.ResponseWriter, r *http.Request) {
    // 1. 获取 URL 参数
    id := route.GetRouteVariable("id", r)

    // 2. 读取对应的文章数据
    article, err := getArticleByID(id)

    // 3. 如果出现错误
    if err != nil {
        if err == sql.ErrNoRows {
            // 3.1 数据未找到
            w.WriteHeader(http.StatusNotFound)
            fmt.Fprint(w, "404 文章未找到")
        } else {
            // 3.2 数据库错误
            logger.LogError(err)
            w.WriteHeader(http.StatusInternalServerError)
            fmt.Fprint(w, "500 服务器内部错误")
        }
    } else {
        // 4. 读取成功,显示文章
        tmpl, err := template.New("show.gohtml").
            Funcs(template.FuncMap{
                "RouteName2URL": route.Name2URL,
                "Int64ToString": types.Int64ToString,
            }).
            ParseFiles("resources/views/articles/show.gohtml")
        logger.LogError(err)
        err = tmpl.Execute(w, article)
        logger.LogError(err)
    }
}

2.4 import cycle not allowed 循环导入问题#

在这里插入图片描述
Go 编译器不允许这样做是出于编译性能考虑。允许循环引用会使编译时间激增,一旦某个包更新,整个依赖循环都需要重新编译。

2.5 新建 bootstrap 包

这个包将用来存放程序初始化相关逻辑,例如路由初始化、数据库初始化、配置信息初始化等。
新建文件:bootstrap/route.go

// Package bootstrap 负责应用初始化相关工作,比如初始化路由。
package bootstrap

import (
    "goblog/routes"

    "github.com/gorilla/mux"
)

// SetupRoute 路由初始化
func SetupRoute() *mux.Router {
    router := mux.NewRouter()
    routes.RegisterWebRoutes(router)
    return router
}

在这里插入图片描述
修改 pkg 里的 route 包,将初始化的代码删除,只保留两个工具函数:
pkg/route/router.go

// Package route 路由相关
package route

import (
    "net/http"

    "github.com/gorilla/mux"
)

// Name2URL 通过路由名称来获取 URL
func Name2URL(routeName string, pairs ...string) string {
    var route *mux.Router
    url, err := route.Get(routeName).URL(pairs...)
    if err != nil {
        // checkError(err)
        return ""
    }

    return url.String()
}

// GetRouteVariable 获取 URI 路由参数
func GetRouteVariable(parameterName string, r *http.Request) string {
    vars := mux.Vars(r)
    return vars[parameterName]
}

将 GetRouteVariable() 方法重新移回 main.go 中,并将这个本地的方法替换掉 route.GetRouteVariable() 的调用。
main.go 里新增 getRouteVariable() 方法,因为不需要导出,函数名首字母小写:

.
.
.
func getRouteVariable(parameterName string, r *http.Request) string {
    vars := mux.Vars(r)
    return vars[parameterName]
}

func main() {
    .
    .
    .
}

报新的错,但循环引用问题已解决
在这里插入图片描述

3 安装GORM

go get -u gorm.io/gorm

在这里插入图片描述

安装 GORM 的 MySQL 的数据库驱动

go get -u gorm.io/driver/mysql

在这里插入图片描述

3.1 创建基础模型

pkg/model/model.go

// Package model 应用模型数据层
package model

import (
    "goblog/pkg/logger"

    "gorm.io/gorm"

    // GORM 的 MySQL 数据库驱动导入
    "gorm.io/driver/mysql"
)

// DB gorm.DB 对象
var DB *gorm.DB

// ConnectDB 初始化模型
func ConnectDB() *gorm.DB {

    var err error

    config := mysql.New(mysql.Config{
        DSN: "root:secret@tcp(127.0.0.1:3306)/goblog?charset=utf8&parseTime=True&loc=Local",
    })

    // 准备数据库连接池
    DB, err = gorm.Open(config, &gorm.Config{})

    logger.LogError(err)

    return DB
}

DB 变量是一个 *gorm.DB 对象,我们会在模型文件中大量使用到。ConnectDB() 方法,将会在数据库初始化中使用。

3.2 数据库初始化

把数据库初始化的逻辑放到 bootstrap 包里:

package bootstrap

import (
    "goblog/pkg/model"
    "time"
)

// SetupDB 初始化数据库和 ORM
func SetupDB() {

    // 建立数据库连接池
    db := model.ConnectDB()

    // 命令行打印数据库请求的信息
    sqlDB, _ := db.DB()

    // 设置最大连接数
    sqlDB.SetMaxOpenConns(100)
    // 设置最大空闲连接数
    sqlDB.SetMaxIdleConns(25)
    // 设置每个链接的过期时间
    sqlDB.SetConnMaxLifetime(5 * time.Minute)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值