Go sql-web

2024-08-01 19:33:44 浏览数 (1)

Go sql-web

今天把database/sql部分的内容学习了一下,然后写了一个小项目,巩固一下,代码整体不难。

这个项目用net/http和database/sql实现了一个简单的用户注册和登录功能。

全局变量和初始化

代码语言:javascript复制
 var db *sql.DB
 var tmpl *template.Template
 ​
 func init() {
     var err error
     // 使用你自己的数据库凭证替换
     dsn := "root:root@tcp(127.0.0.1:3306)/sql-web?charset=utf8"
     db, err = sql.Open("mysql", dsn)
     if (err != nil) {
         log.Fatal(err)
     }
 ​
     // 测试数据库连接
     if (err = db.Ping(); err != nil) {
         log.Fatal(err)
     }
 ​
     tmpl, err = template.ParseFiles("index.html")
     if (err != nil) {
         log.Fatalf("解析模板失败: %v", err)
     }
 }
  • var db *sql.DB:声明一个全局变量,用于数据库连接。 var tmpl *template.Template:声明一个全局变量,用于 HTML 模板。 func init()init 函数在 main 函数之前执行。这里用于:
    • 使用数据源名称(DSN)root:root@tcp(127.0.0.1:3306)/sql-web?charset=utf8 打开 MySQL 数据库连接。
    • 使用 db.Ping() 测试数据库连接。
    • 解析 index.html 模板文件,并将其赋值给 tmpl 变量。

主函数

代码语言:javascript复制
 go复制代码func main() {
     http.HandleFunc("/register", registerHandler)
     http.HandleFunc("/login", loginHandler)
     log.Println("服务器启动在 :8080")
     log.Fatal(http.ListenAndServe(":8080", nil))
 }
  • http.HandleFunc("/register", registerHandler):注册 registerHandler 函数来处理 /register 请求。
  • http.HandleFunc("/login", loginHandler):注册 loginHandler 函数来处理 /login 请求。
  • log.Println("服务器启动在 :8080"):记录一条信息,指示服务器启动在端口 8080
  • log.Fatal(http.ListenAndServe(":8080", nil)):启动 HTTP 服务器并监听 8080 端口。如果服务器启动失败,则记录错误并退出程序。

注册处理函数

代码语言:javascript复制
 func registerHandler(w http.ResponseWriter, r *http.Request) {
     if r.Method == "POST" {
         username := r.FormValue("username")
         password := r.FormValue("password")
 ​
         if username == "" || password == "" {
             http.Error(w, "用户名和密码不能为空", http.StatusBadRequest)
             return
         }
 ​
         var exists bool
         err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE username = ?)", username).Scan(&exists)
         if err != nil {
             http.Error(w, "服务器错误", http.StatusInternalServerError)
             return
         }
 ​
         if exists {
             http.Error(w, "用户已存在", http.StatusConflict)
             return
         }
 ​
         _, err = db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", username, password)
         if err != nil {
             http.Error(w, "服务器错误", http.StatusInternalServerError)
             return
         }
 ​
         http.Redirect(w, r, "login", http.StatusSeeOther)
         return
     }
 ​
     err := tmpl.ExecuteTemplate(w, "index.html", nil)
     if err != nil {
         http.Error(w, "执行模板错误", http.StatusInternalServerError)
     }
 }
  • registerHandler :处理用户注册请求。
    • r.Method == "POST":检查请求方法是否为 POST。
    • r.FormValue("username")r.FormValue("password"):获取表单中的用户名和密码。
    • if username == "" || password == "":检查用户名和密码是否为空。如果为空,返回错误。
    • db.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE username = ?)", username).Scan(&exists):查询数据库检查用户名是否已存在。
    • if exists:如果用户已存在,返回错误。
    • db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", username, password):将新用户插入数据库。
    • http.Redirect(w, r, "login", http.StatusSeeOther):重定向到登录页面。
    • tmpl.ExecuteTemplate(w, "index.html", nil):如果请求方法不是 POST,渲染 index.html 模板。

登录处理函数

代码语言:javascript复制
 func loginHandler(w http.ResponseWriter, r *http.Request) {
     if r.Method == "POST" {
         username := r.FormValue("username")
         password := r.FormValue("password")
 ​
         if username == "" || password == "" {
             http.Error(w, "用户名和密码不能为空", http.StatusBadRequest)
             return
         }
 ​
         var dbPassword string
         err := db.QueryRow("SELECT password FROM users WHERE username = ?", username).Scan(&dbPassword)
         if err != nil {
             if err == sql.ErrNoRows {
                 http.Error(w, "用户名或密码无效", http.StatusUnauthorized)
             } else {
                 http.Error(w, "服务器错误", http.StatusInternalServerError)
             }
             return
         }
 ​
         if password != dbPassword {
             http.Error(w, "用户名或密码无效", http.StatusUnauthorized)
             return
         }
 ​
         fmt.Fprint(w, "登录成功")
         return
     }
     err := tmpl.ExecuteTemplate(w, "index.html", nil)
     if err != nil {
         http.Error(w, "执行模板错误", http.StatusInternalServerError)
     }
 }
  • loginHandler :处理用户登录请求。
    • r.Method == "POST":检查请求方法是否为 POST。
    • r.FormValue("username")r.FormValue("password"):获取表单中的用户名和密码。
    • if username == "" || password == "":检查用户名和密码是否为空。如果为空,返回错误。
    • db.QueryRow("SELECT password FROM users WHERE username = ?", username).Scan(&dbPassword):从数据库中查询用户名对应的密码。
    • if err != nil:如果查询出错,处理错误。
    • if password != dbPassword:如果密码不匹配,返回错误。
    • fmt.Fprint(w, "登录成功"):登录成功,输出成功信息。
    • tmpl.ExecuteTemplate(w, "index.html", nil):如果请求方法不是 POST,渲染 index.html 模板。

前端代码

前端代码也很简单,几个按钮和输入框

代码语言:javascript复制
 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>Register/Login</title>
 </head>
 <body>
 <h1>Register</h1>
 <form method="POST" action="/register">
     <label for="username">Username:</label>
     <input type="text" id="username" name="username">
     <br>
     <label for="password">Password:</label>
     <input type="password" id="password" name="password">
     <br>
     <input type="submit" value="Register">
 </form>
 ​
 <h1>Login</h1>
 <form method="POST" action="/login">
     <label for="username">Username:</label>
     <input type="text" id="username" name="username">
     <br>
     <label for="password">Password:</label>
     <input type="password" id="password" name="password">
     <br>
     <input type="submit" value="Login">
 </form>
 </body>
 </html>
 ​

0 人点赞