gpt4 book ai didi

mysql - 如何从 View 中 *sql.Rows 类型的变量中获取值?

转载 作者:IT王子 更新时间:2023-10-29 02:37:04 26 4
gpt4 key购买 nike

posts表中,有titlecontent等属性。我可以获取 *sql.Rows 类型的数据并将它们传递给 View

 posts, err := db.Query("SELECT id, title FROM posts WHERE id = 1")

  err = tpl.ExecuteTemplate(w, "index.gohtml", posts)

但我无法在 View 中显示 title 值。这是我的代码。

index.go

package main

import (
"net/http"
"fmt"
"log"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)

func index(w http.ResponseWriter, r *http.Request) {
db, err := sql.Open("mysql", "root:****@/database")
if err != nil {
panic(err.Error())
}
defer db.Close()

posts, err := db.Query("SELECT id, title FROM posts WHERE id = 1")
var id int
var title string
for posts.Next() {
err = posts.Scan(&id, &title)
if err != nil {
panic(err.Error())
}
}

fmt.Println(posts)

defer posts.Close()

err = tpl.ExecuteTemplate(w, "index.gohtml", posts)
if err != nil {
log.Println(err)
}
}

index.gohtml

  <h1>Awesome Posts</h1>

{{$posts := .}}
<p>{{$posts}}</p>

最佳答案

您的代码中有一些错误,我认为您误解了如何使用 sql 包提取数据。

正如 Flimzy 在评论中所说,您应该传递一个适当的上下文结构,其中包含您的 ID 和 Title 值。

如果您检查 docs for sql.Rows您将看到如何从查询中提取每一行的数据...事实上,您已经知道如何获取行和列值 - 通过使用 Next()Scan() 方法。但这不应该由 HTML 模板中的代码完成,它应该将结果存储在传递给模板的某个变量中。

快速回答

对您的问题的快速回答是更改将值传递到模板的方式并修改模板。当您声明 idtitle 变量时,您应该将它们传递给模板:

err = tpl.ExecuteTemplate(w, "index.gohtml", map[string]interface{}{"ID": id,"Title": title})
if err != nil {
log.Println(err)
}


<h1>Awesome Posts</h1>
<p>{{.ID}} - {{.Title}}</p>

拥有一个 Post 模型

更好的解决方案是拥有一个包含帖子所有属性的结构,并使用它扫描进入。

type Post struct{
ID int
Title string
}

...
var p Post
...
_ = rows.Scan(&p)

但是,存储查询结果的方式还有另一个问题。您正在使用 db.Query 返回单行 - 这是一个假设,因为您有 WHERE ID=1。如果您希望只返回一个帖子,则使用 QueryRow 方法:(注意为了简单起见,您可以链接 Scan 方法)

var p Post
// error handling removed for brevity
_ = db.QueryRow("SELECT id, title FROM posts WHERE id = 1").Scan(&p)
_ = tpl.ExecuteTemplate(w, "index.gohtml", p)

但是,如果您希望检索多个帖子(并且您只是为了简单起见而添加了 where 子句),那么您需要将 Scan 放入 Post 结构中, 并追加到 Posts 的 slice 中。

rows, _ := db.Query("SELECT id, title FROM posts")
defer rows.Close()
var posts []Post
for rows.Next() {
var p Post
_ = posts.Scan(&id, &p) // you should handle error here.
posts = append(posts, p)
}
if err = tpl.ExecuteTemplate(w, "index.gohtml", posts); err!=nil{
log.Println(err)
}

其他注意事项

您不应该在 HTTP 处理程序中创建到数据库的连接。一种方法是使用一个全局变量来保存连接。具有嵌入式连接的结构可以工作和/或也可以将连接抽象到一个包中。

/db/db.go

package db

import (
"database/sql"
// MYSQL driver
_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

// Open handles the opening of the DB
func Open(connstr string) (err error) {
db, err = sql.Open("mysql", connstr)
if err != nil {
return err
}
return nil
}

// Close handles the closing of the DB
func Close() error {
return db.Close()
}

/db/posts.go

package db

// Post model
type Post struct {
ID uint
Title string
Body string
}

const (
getPosts = `SELECT id, title, body FROM posts`
getAPost = `SELECT id, title, body FROM posts WHERE id=?`
)

// GetPosts will return all posts from the DB
func GetPosts() ([]Post, error) {
rows, err := db.Query(getPosts)
if err != nil {
return nil, err
}
var posts []Post
for rows.Next() {
var p Post
if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil {
return nil, err
}
posts = append(posts, p)
}

return posts, nil
}

// GetPost will return single post identified by ID from the DB
func GetPost(id uint) (Post, error) {
var p Post
if err := db.QueryRow(getAPost, id).Scan(&p.ID, &p.Title, &p.Body); err != nil {
return p, err
}
return p, nil
}

ma​​in.go

import (
"chilledoj/sopost/db" // this is the absolute path to the db folder
"html/template"
"log"
"net/http"
"strconv"
"flag"

"github.com/gorilla/mux"
)

var dbconn string

func init() {
flag.StringVar(&dbconn, "dbconn", "", "MYSQL DB Connection string")
flag.Parse()
}

func main() {

if dbconn == "" {
log.Fatal("DB Connection string not set")
}

if err := db.Open(dbconn); err != nil {
log.Fatal(err)
}
defer db.Close()

r := mux.NewRouter()

r.HandleFunc("/", indexHandler())
r.HandleFunc("/posts", postsHandler())
r.HandleFunc("/posts/{id}", postHandler())

if err := http.ListenAndServe(":8080", r); err != nil {
log.Panic(err)
}
}

var indexHandler = func() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`<h1>Welcome</h1><a href="/posts">Posts</a>`))
}
}

var postsHandler = func() http.HandlerFunc {
tmpl, err := template.New("posts").Parse(`<h1>Awesome Posts</h1>
<ul>{{range .}}
<li><a href="/posts/{{.ID}}">{{.Title}}</a></li>
{{end}}</ul>
<hr/>
<a href="/">Home</a>`)
if err != nil {
log.Panic(err)
}
return func(w http.ResponseWriter, r *http.Request) {
posts, err := db.GetPosts()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
err = tmpl.Execute(w, posts)
if err != nil {
log.Printf("There was a template Error.\n%v\n", err)
}
}
}

var postHandler = func() http.HandlerFunc {
tmpl, err := template.New("posts").Parse(`<h1>Awesome Posts</h1>
<h2>{{.Title}}</h2>
<p>{{.Body}}</p>
<hr/>
<a href="/">Home</a>
<a href="/posts">Posts</a>`)
if err != nil {
log.Panic(err)
}
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.ParseInt(vars["id"], 10, 32)
if err != nil {
http.NotFound(w, r)
return
}
post, err := db.GetPost(uint(id))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
tmpl.Execute(w, post)
}
}

运行以上使用

go run main.go -dbconn [dbuser]:[dbpass]@/[dbname]?parseTime=true

另一种方法是使用依赖注入(inject)并让一个函数接受数据库连接但返回一个http.HandlerFunc。例如

var indexHandler = function (db *sql.DB) http.HandlerFunc{
return function(w http.ResponseWriter, r *http.Request){
// now have access to db
}
}

http.HandleFunc("/posts", indexHandler())

关于mysql - 如何从 View 中 *sql.Rows 类型的变量中获取值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51893641/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com