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

1 文章列表

(1)先保证文章已经有多篇,可以直接在数据库中添加,或者访问链接: localhost:3000/articles/create,增加几篇文章。
在这里插入图片描述
(2)之前设置好了articles.index 路由,访问 localhost:3000/articles 显示文章列表
在这里插入图片描述
(3)完善articlesIndexHandler()使之能够显示数据库中的数据

.
.
.
func articlesIndexHandler(w http.ResponseWriter, r *http.Request) {
    // 1. 执行查询语句,返回一个结果集
    rows, err := db.Query("SELECT * from articles")
    checkError(err)
    defer rows.Close()

    var articles []Article
    //2. 循环读取结果
    for rows.Next() {
        var article Article
        // 2.1 扫描每一行的结果并赋值到一个 article 对象中
        err := rows.Scan(&article.ID, &article.Title, &article.Body)
        checkError(err)
        // 2.2 将 article 追加到 articles 的这个数组中
        articles = append(articles, article)
    }

    // 2.3 检测遍历时是否发生错误
    err = rows.Err()
    checkError(err)

    // 3. 加载模板
    tmpl, err := template.ParseFiles("resources/views/articles/index.gohtml")
    checkError(err)

    // 4. 渲染模板,将所有文章的数据传输进去
    err = tmpl.Execute(w, articles)
    checkError(err)
}
.
.
.

添加模板
resources/views/articles/index.gohtml

<!DOCTYPE html>
<html lang="en">
<head>
    <title>所有文章 —— 我的技术博客</title>
    <style type="text/css">.error {color: red;}</style>
</head>
<body>
    <h1>所有文章</h1>
    <ul>
        {{ range $key, $article := . }}
            <li><a href=""><strong>{{ $article.ID }}</strong>: {{ $article.Title }}</a></li>
        {{ end }}
    </ul>
</body>
</html>

访问 localhost:3000/articles
在这里插入图片描述
为列表里的文章加上链接

.
.
'
// Article  对应一条文章数据
type Article struct {
    .
    .
    .
}

// Link 方法用来生成文章链接
func (a Article) Link() string {
    showURL, err := router.Get("articles.show").URL("id", strconv.FormatInt(a.ID, 10))
    if err != nil {
        checkError(err)
        return ""
    }
    return showURL.String()
}
.
.
.

保存后刷新页面并查看页面源码:

在这里插入图片描述

2 删除文章

先开发后台的删除逻辑,然后在文章详情页里显示删除按钮
(1)注册articles.delete 路由
在这里插入图片描述
(2)添加articlesDeleteHandler()函数

.
.
.
func articlesDeleteHandler(w http.ResponseWriter, r *http.Request) {

    // 1. 获取 URL 参数
    id := 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 数据库错误
            checkError(err)
            w.WriteHeader(http.StatusInternalServerError)
            fmt.Fprint(w, "500 服务器内部错误")
        }
    } else {
        // 4. 未出现错误,执行删除操作
        rowsAffected, err := article.Delete()

        // 4.1 发生错误
        if err != nil {
            // 应该是 SQL 报错了
            checkError(err)
            w.WriteHeader(http.StatusInternalServerError)
            fmt.Fprint(w, "500 服务器内部错误")
        } else {
            // 4.2 未发生错误
            if rowsAffected > 0 {
                // 重定向到文章列表页
                indexURL, _ := router.Get("articles.index").URL()
                http.Redirect(w, r, indexURL.String(), http.StatusFound)
            } else {
                // Edge case
                w.WriteHeader(http.StatusNotFound)
                fmt.Fprint(w, "404 文章未找到")
            }
        }
    }
}

添加Article 的 Delete() 方法 ,上面代码块用到了Delete方法


// // 为 Article 添加一个 Delete 方法,删除文章
func (a Article) Delete() (rowsAffected int64, err error) {
    rs, err := db.Exec("DELETE FROM articles WHERE id = " + strconv.FormatInt(a.ID, 10))

    if err != nil {
        return 0, err
    }

    // √ 删除成功
    if n, _ := rs.RowsAffected(); n > 0 {
        return n, nil
    }

    return 0, nil
}


(3)文章详情页面添加删除按钮

.
.
.
func  articlesShowHandler(w http.ResponseWriter, r *http.Request) {
    .
    .
    .
    // 3. 如果出现错误
    if err !=  nil {
        .
        .
        .
    } else {
        // 4. 读取成功,显示文章
        tmpl, err := template.New("show.gohtml").
            Funcs(template.FuncMap{
                "RouteName2URL": RouteName2URL,
                "Int64ToString": Int64ToString,
            }).
            ParseFiles("resources/views/articles/show.gohtml")
        checkError(err)
        err = tmpl.Execute(w, article)
        checkError(err)
    }
}

template.New() 先初始化,然后使用 Funcs() 注册函数,再使用 ParseFiles (),需要注意的是 New() 的参数是模板名称,需要对应 ParseFiles() 中的文件名,否则会无法正确读取到模板,最终显示空白页面。

创建上面代码中的两个函数RouteName2URL 和 Int64ToString

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

    return url.String()
}

// Int64ToString 将 int64 转换为 string
func Int64ToString(num int64) string {
    return strconv.FormatInt(num, 10)
}

func (a Article) Delete() (rowsAffected int64, err error) {
.
.
.

修改模板 show.gohtml

<!DOCTYPE html>
<html lang="en">

<head>
    <title>{{ .Title }} —— 我的技术博客</title>
    <style type="text/css">
        .error {
            color: red;
        }
    </style>
</head>

<body>
    <p>ID: {{ .ID }}</p>
    <p>标题: {{ .Title }}</p>
    <p>内容:{{ .Body }}</p>

    {{/* 构建删除按钮  */}}
    {{ $idString := Int64ToString .ID  }}
    <form action="{{ RouteName2URL "articles.delete" "id" $idString }}" method="post">
        <button type="submit" onclick="return confirm('删除动作不可逆,请确定是否继续')">删除</button>
    </form>

</body>

</html>

在这里插入图片描述
打开articles.show文章详情页localhost:3000/articles/4
在这里插入图片描述
在这里插入图片描述
点击删除,确定删除
在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值