• golang(10):web开发 & 连接数据库


    http编程

    1) Go原生支持 http : import ("net/http")
    2) Go 的 http 服务性能和 nginx 比较接近
    3) 几行代码就可以实现一个 web 服务

    http 服务端

    // 示例代码:
    package main
    
    import (
        "fmt"
        "net/http"
    )
    
    func Hello(w http.ResponseWriter, r *http.Request){
        fmt.Println("hello world
    ")
        fmt.Fprintf(w,"hello world")    // 返回响应
    }
    
    
    func main(){
        http.HandleFunc("/",Hello)        // 路由;第一个参数是路径,第二个参数是视图函数
        err := http.ListenAndServe("0.0.0.0:8080",nil)        // 监听并等待请求
        if err != nil{
            fmt.Println("http listened failed")
        }
    }

    http 客户端

    // 示例代码:
    package main
    
    import (
        "fmt"
        "net/http"
        "io/ioutil"
    )
    
    func main(){
        ret,err := http.Get("https://www.baidu.com/")    // 向一个服务器发送 GET 请求;返回的数据都在 ret.Body 里面
        if err != nil {
            fmt.Println("get err:",err)
            return
        }
    
        data,err := ioutil.ReadAll(ret.Body)    // 返回的数据都在 ret.Body 里面
        if err != nil {
            fmt.Println("get data err:",err)
            return
        }
    
        fmt.Printf("Type:%T
    ",data)
        fmt.Println(string(data))
    }
    
    
    // 运行结果:
    [root@NEO example01_http_client]# go run main/main.go
    Type:[]uint8
    <html>
    <head>
        <script>
            location.replace(location.href.replace("https://","http://"));
        </script>
    </head>
    <body>
        <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
    </body>
    </html>
    [root@NEO example01_http_client]# 

    http常见请求方法

    1)Get请求
    2)Post请求
    3)Put请求
    4)Delete请求
    5)Head请求        -- > 只请求页面的头部

    发送 HEAD 请求

    // 示例代码:
    package main
    
    import (
        "fmt"
        "net/http"
    )
    
    var urls = []string{
        "http://www.baidu.com",
        "http://www.google.com",
        "http://www.taobao.com",
    }
    
    func main(){
        for _,v := range urls{
            resp,err := http.Head(v)    // 发送 Head 请求
            if err != nil {
                fmt.Printf("head %s failed,err:%v
    ",v,err)
                continue
            }
            fmt.Printf("head success,status:%v
    ",resp.Status)        // resp.Status --> 状态码
        }
    }
    
    // 运行结果:
    [root@NEO example01_http_head_request]# go run main/main.go
    head success,status:200 OK
    head http://www.google.com failed,err:Head http://www.google.com: dial tcp 75.126.2.43:80: connect: connection timed out
    head success,status:200 OK
    [root@NEO example01_http_head_request]# 
    
    
    // 自定义超时时间
    // 示例代码:
    package main
    
    import (
        "fmt"
        "net/http"
        "time"
        "net"
    )
    
    var urls = []string{
        "http://www.baidu.com",
        "http://www.google.com",
        "http://www.taobao.com",
    }
    
    func main(){
        for _,v := range urls{
            c := http.Client{        // 自定义客户端
                Transport: &http.Transport{
                    Dial: func(network, addr string) (net.Conn, error){
                        timeout := time.Second * 2        // 自定义超时时间
                        return net.DialTimeout(network, addr, timeout)
                    },
                },
            }    
    
            start := time.Now()
            resp,err := c.Head(v)    // 用自定义的客户端发送请求
            end := time.Now()
            interval := end.Sub(start)
            fmt.Println("interval:",interval)
            //resp,err := http.Head(v)    // 发送 Head 请求
            if err != nil {
                fmt.Printf("head %s failed,err:%v
    ",v,err)
                continue
            }
            fmt.Printf("head success,status:%v
    ",resp.Status)        // resp.Status --> 状态码
        }
    }
    
    
    // 运行结果:
    [root@NEO example01_http_head_request]# go run main/main.go
    interval: 171.062376ms
    head success,status:200 OK
    interval: 2.000789206s
    head http://www.google.com failed,err:Head http://www.google.com: dial tcp 69.63.184.142:80: i/o timeout
    interval: 749.542763ms
    head success,status:200 OK
    [root@NEO example01_http_head_request]# 

    http 常见状态码:

    http.StatusContinue = 100
    http.StatusOK = 200
    http.StatusFound = 302
    http.StatusBadRequest = 400
    http.StatusUnauthorized = 401
    http.StatusForbidden = 403
    http.StatusNotFound = 404
    http.StatusInternalServerError = 500

    表单处理:

    // 示例代码:
    package main
    import (
        "io"
        "net/http"
    )
    
    
    // 常量 form 是一段 html 代码
    const form = `<html><body><form action="#" method="post" name="bar">
                        <input type="text" name="in"/>
                        <input type="text" name="in"/>
                         <input type="submit" value="Submit"/>
                 </form></html></body>`
    
    func SimpleServer(w http.ResponseWriter, request *http.Request) {        // 请求信息都在 request 中
        io.WriteString(w, "<h1>hello, world</h1>")        // 返回给客户端一段html代码
    }
    
    func FormServer(w http.ResponseWriter, request *http.Request) {
        w.Header().Set("Content-Type", "text/html")            // w.Head().Set(key,val)  --->  设置响应头
        switch request.Method {                                // request.Method --> 请求方法
        case "GET":
            io.WriteString(w, form)            // 把 form 表单返回给客户端
        case "POST":
            request.ParseForm()        // 需要先解析表单
            io.WriteString(w, request.Form["in"][0])        // request.Form["in"]    是一个数组
            io.WriteString(w, "
    ")
            io.WriteString(w, request.FormValue("in"))        // request.FormValue("in")  ---> 获取表单中的值(name重复时,取最近的一个);推荐使用这个
        }
    }
    func main() {
        http.HandleFunc("/test1", SimpleServer)
        http.HandleFunc("/test2", FormServer)
        if err := http.ListenAndServe(":8088", nil); err != nil {
        }
    }

    模板操作

    1) 替换

    main.go 文件内容如下:

    // 示例代码:
    package main
    
    import (
        "fmt"
        "os"
        "text/template"        // 导入 模板 包
    )
    
    type Person struct {
        Name string
        age  string
    }
    
    func main() {
        t, err := template.ParseFiles("./index.html")        // 解析模板文件; t 是模板对象
        if err != nil {
            fmt.Println("parse file err:", err)
            return
        }
        p := Person{Name: "Mary", age: "31"}    // 结构体对象首字母大写的字段可以导入到模板中
        if err := t.Execute(os.Stdout, p); err != nil {        // t.Execute()  --> 执行模板对象,第一个参数表示输出到终端,第二个参数表示 导入的结构体对象
            fmt.Println("There was an error:", err.Error())
        }
    }

    index.html 代码如下:

    <html>
        <head>
            // 结构体对象没有的字段不能导入,要不然会报错,如下 
        </head>
        <body>
            <p>{{.}} </p>    //  .表示 p 那个对象 
            <p> hello, {{.Name}}</p>    //  .Name 表示 p 对象 的Name字段的值 #}
            // 首字母小写的字段也不能在模板中渲染
        </body>
    </html>

    运行结果:

    // 运行结果:
    [root@NEO main]# go run main.go 
    <html>
        <head>
            // 结构体对象没有的字段不能导入,要不然会报错,如下 
        </head>
        <body>
            <p>{Mary 31} </p>    //  .表示 p 那个对象 
            <p> hello, Mary</p>    //  .Name 表示 p 对象 的Name字段的值 #}
            // 首字母小写的字段也不能在模板中渲染
        </body>
    </html>
    [root@NEO main]# 

    2) if 判断 

    main.go 文件内容:

    // 示例代码:
    package main
    
    import (
        "fmt"
        "text/template"        // 导入 模板 包
        "net/http"
    )
    
    type Person struct {
        Name string
        Age  int
    }
    
    func RenderTemplate(w http.ResponseWriter, request *http.Request){
        t, err := template.ParseFiles("./index.html")       // 解析模板文件; t 是模板对象
        if err != nil {
            fmt.Println("parse file err:", err)
            return
        } 
        p := Person{Name: "Mary", Age: 31}    // 结构体对象首字母大写的字段可以导入到模板中 
        if err := t.Execute(w, p); err != nil {     // 模板写入到在 http.ResponseWriter 中,返回给客户端 
            fmt.Println("There was an error:", err.Error())
        }    
    }
    
    func main() {
        http.HandleFunc("/template",RenderTemplate)
        if err := http.ListenAndServe(":8080",nil); err != nil {
        }
    }

    index.html 文件内容:

    <html>
        <head>
        </head>
        <body>
            /*
            if 语法:
            {{if ...}}
            {{else}}
            {{end}}
            */
            {# gt 表示大于 #}
            {{if gt .Age 18}}
            <p>hello oldman,{{.Name}} </p>
            {{else}}
            <p>hello young {{.Name}}</p>
            {{end}}
        </body>
    </html>

    if常见操作符:

    not 非
    {{if not .condition}} 
    {{end}}
    
    and 与
    {{if and .condition1 .condition2}} 
    {{end}}
    
    or 或
    {{if or .condition1 .condition2}} 
    {{end}}
    
    eq 等于
    {{if eq .var1 .var2}} 
    {{end}}
    
    ne 不等于
    {{if ne .var1 .var2}} 
    {{end}}
    
    lt 小于 (less than)
    {{if lt .var1 .var2}} 
    {{end}}
    
    le 小于等于
    {{if le .var1 .var2}} 
    {{end}}
    
    gt 大于
    {{if gt .var1 .var2}} 
    {{end}}
    
    ge 大于等于
    {{if ge .var1 .var2}} 
    {{end}}

    模板中with的用法:

    {{with .Var}}
    {end}}

    示例代码:

    <html>
        <head>
        </head>
        <body>
            {{with .Name}}        <!-- 通过这行的 with ,. 就代表 Name ;只有 with 语句中 . 是 Name -->
            <p>hello, old man, {{.}}</p>
            {{end}}
        </body>
    </html>

    模板的循环:

    {{range.}} 
    
    {{end }}

    示例代码:

    <html>
        <head>
        </head>
        <body>
            <!-- 遍历 变量-->
            {{range .}}
                {{if gt .Age 18}}
                <p>hello, old man, {{.Name}}</p>
                {{else}}
                <p>hello,young man, {{.Name}}</p>
                {{end}}
            {{end}}
        </body>
    </html>

    Mysql

    新建测试表

    CREATE TABLE person (
        user_id int primary key auto_increment,
        username varchar(260),
        sex varchar(260),
        email varchar(260)
    );
    
    CREATE TABLE place (
        country varchar(200),
        city varchar(200),
        telcode int
    );

    安装连接数据库的第三方包:

    go get -u github.com/go-sql-driver/mysql        // 安装 mysql 驱动
    go get github.com/jmoiron/sqlx

    链接mysql:

    // 先在 数据库主机上分配权限,如下:
    mysql> grant all privileges on gotest.* to 'root'@'172.16.1.%' identified by '123456';
    mysql> flush privileges;
    // 代码运行服务器内网地址: 172.16.1.122
    
    database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
    // 参数说明:
    // "mysql"            ---> 数据库类型
    // root                ---> 用户名
    // 123456            ---> 密码
    // tcp                ---> 连接协议
    // 172.16.1.50        ---> 数据库主机地址
    // 3306                ---> 端口
    // gotest            ---> 数据库名称

    go 数据库的增删改查

    insert操作

    r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")        // ? 是占位符

    示例代码:

    package main
    
    import (
        "fmt"
        _ "github.com/go-sql-driver/mysql"        // _ 表示只是把这个库引进来做初始化,但并不直接引用这个库
        "github.com/jmoiron/sqlx"        // sqlx 在 mysql 驱动的层面上又做了封装,会更好用些
    )
    
    type Person struct {
        UserId   int    `db:"user_id"`            // tag 就是数据库中的列名
        Username string `db:"username"`
        Sex      string `db:"sex"`
        Email    string `db:"email"`
    }
    
    type Place struct {
        Country string `db:"country"`
        City    string `db:"city"`
        TelCode int    `db:"telcode"`
    }
    
    var Db *sqlx.DB        // Db 就代表一个数据库;Db 这个变量是线程安全的,因为其内部已经内置实现了一个 连接池
    
    func init() {        // init() 函数在 main 函数之前自动执行
        database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")        // database 是一个数据库实例
        if err != nil {
            fmt.Println("open mysql failed,", err)
            return
        }
        Db = database
    }
    
    func main() {
        r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")
    
        if err != nil {
            fmt.Println("exec failed, ", err)
            return
        }
        id, err := r.LastInsertId()        // 刚插入的那条记录的 id
        if err != nil {
            fmt.Println("exec failed, ", err)
            return
        }
    
        fmt.Println("insert succ:", id)
    }

    Select 操作

    err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)

    示例代码:

    package main
    
    import (
        "fmt"
        _ "github.com/go-sql-driver/mysql"
        "github.com/jmoiron/sqlx"
    )
    
    type Person struct {
        UserId   int    `db:"user_id"`
        Username string `db:"username"`
        Sex      string `db:"sex"`
        Email    string `db:"email"`
    }
    
    type Place struct {
        Country string `db:"country"`
        City    string `db:"city"`
        TelCode int    `db:"telcode"`
    }
    var Db *sqlx.DB
    func init() {
    
        database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
        if err != nil {
            fmt.Println("open mysql failed,", err)
            return
        }
    
        Db = database
    }
    
    func main() {
    
        var person []Person
        err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)    // 从数据库中查询出来结果会自动填充到 person 这个结构体中
        if err != nil {
            fmt.Println("exec failed, ", err)
            return
        }
    
        fmt.Println("select succ:", person)
    }
    
    
    // 运行结果:
    [root@NEO example02_mysql_select]# go run main/main.go
    select succ: [{1 stu001 man stu01@qq.com}]
    [root@NEO example02_mysql_select]#

    update操作

    _, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)

    示例代码:

    package main
    
    import (
        "fmt"
        _ "github.com/go-sql-driver/mysql"
        "github.com/jmoiron/sqlx"
    )
    
    type Person struct {
        UserId   int    `db:"user_id"`
        Username string `db:"username"`
        Sex      string `db:"sex"`
        Email    string `db:"email"`
    }
    
    type Place struct {
        Country string `db:"country"`
        City    string `db:"city"`
        TelCode int    `db:"telcode"`
    }
    
    var Db *sqlx.DB
    
    func init() {
    
        database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
        if err != nil {
            fmt.Println("open mysql failed,", err)
            return
        }
    
        Db = database
    }
    
    func main() {
    
        _, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)        // 更新操作
        if err != nil {
            fmt.Println("exec failed, ", err)
            return
        }
    
    }

    Delete 操作

    _, err := Db.Exec("delete from person where user_id=?", 1)

    示例代码:

    package main
    
    import (
        "fmt"
        _ "github.com/go-sql-driver/mysql"
        "github.com/jmoiron/sqlx"
    )
    
    type Person struct {
        UserId   int    `db:"user_id"`
        Username string `db:"username"`
        Sex      string `db:"sex"`
        Email    string `db:"email"`
    }
    
    type Place struct {
        Country string `db:"country"`
        City    string `db:"city"`
        TelCode int    `db:"telcode"`
    }
    
    var Db *sqlx.DB
    
    func init() {
    
        database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest")
        if err != nil {
            fmt.Println("open mysql failed,", err)
            return
        }
    
        Db = database
    }
    
    func main() {
    
        _, err := Db.Exec("delete from person where user_id=?", 1)
        if err != nil {
            fmt.Println("exec failed, ", err)
            return
        }
    
        fmt.Println("delete succ")
    }
  • 相关阅读:
    通过gridview隐藏的一列的值,来设置该行的背景颜色。
    修改js文件后,浏览器不会立即发现js文件更新,连接状态是200 (from cache)缓存
    getDate()显示格式
    设置gridview自动分页的页码不显示
    数据库字段类型,如果是bool类型,数据库中用bit
    给dropdownlist手动添加一列"请选择"(不是从数据库中读取的数据)
    数据库中使用关键词时注意
    获取服务器控件的id时,遇到使用到模板列取不到的问题
    页面自动刷新代码
    启用IIS的Gzip压缩功能
  • 原文地址:https://www.cnblogs.com/neozheng/p/11355592.html
Copyright © 2020-2023  润新知