前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go语言写Web 应用程序

Go语言写Web 应用程序

作者头像
李海彬
发布于 2018-03-22 07:11:41
发布于 2018-03-22 07:11:41
81100
代码可运行
举报
文章被收录于专栏:Golang语言社区Golang语言社区
运行总次数:0
代码可运行

介绍

涵盖内容:

  • 为载入和保存方法创建一个数据结构
  • 引用http包来创建一个web应用
  • 引用template包来处理HTML模板
  • 引用regexp包来验证用户的输入
  • 引用 闭包操作

可能涉及到的知识:

  • 设计经验
  • 明白基础的web技术(HTTP,HTML)
  • 一些UNIX命令行知识

从这里开始

你要有一个可以运行Go语言的计算机或虚拟机,怎么样安装Go,请参考安装Go教程。首先创建一个目录,在目录下创建一个wiki.go文件,用你喜欢的编辑器打开并输入以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
    "io/ioutil"
    "os"
)
代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
这fmt,ioutil和os都是go语言的标准库,一会我将增加其他方法和更多的包。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
数据结构
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
让我们声明一个数据结构,这个结构主要包含两个字段,一个是标题,一个是内容。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Page struct {
    Title    string
    Body    []byte
}
代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
接下来,我们给Page 这个结构体写个保存方法,代码如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (p *Page) save() os.Error {
    filename := p.Title + ".txt"
    return ioutil.WriteFile(filename, p.Body, 0600)
}
代码语言:javascript
代码运行次数:0
运行
复制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
这个方法的签名是:接收一个Page结构体指针,返回一个os.Error错误。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
在一下的代码中还是用了http包和模板包,具体内容参考具体代码,再这里就不详细贴出来了。下面是模板内容,把他们放到wiki.go同一目录下。

编辑页面 模板eidt.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h1>Editing {{.Title |html}}</h1>

<form action="/save/{{.Title |html}}" method="POST">
<div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body |html}}</textarea></div>
<div><input type="submit" value="Save"></div>
</form>
代码语言:javascript
代码运行次数:0
运行
复制

查看页面模板view.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h1>{{.Title |html}}</h1>

<p>[<a href="/edit/{{.Title |html}}">edit</a>]</p>

<div>{{printf "%s" .Body |html}}</div>

完整代码:wiki.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "http"
    "io/ioutil"
    "os"
    "regexp"
    "template"
)

type Page struct {
    Title string
    Body  []byte
}

func (p *Page) save() os.Error {
    filename := p.Title + ".txt"
    return ioutil.WriteFile(filename, p.Body, 0600)
}

func loadPage(title string) (*Page, os.Error) {
    filename := title + ".txt"
    body, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Title: title, Body: body}, nil
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
    p, err := loadPage(title)
    if err != nil {
        http.Redirect(w, r, "/edit/"+title, http.StatusFound)
        return
    }
    renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request, title string) {
    p, err := loadPage(title)
    if err != nil {
        p = &Page{Title: title}
    }
    renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
    body := r.FormValue("body")
    p := &Page{Title: title, Body: []byte(body)}
    err := p.save()
    if err != nil {
        http.Error(w, err.String(), http.StatusInternalServerError)
        return
    }
    http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

var templates = make(map[string]*template.Template)

func init() {
    for _, tmpl := range []string{"edit", "view"} {
        t := template.Must(template.ParseFile(tmpl + ".html"))
        templates[tmpl] = t
    }
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
    err := templates[tmpl].Execute(w, p)
    if err != nil {
        http.Error(w, err.String(), http.StatusInternalServerError)
    }
}

const lenPath = len("/view/")

var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        title := r.URL.Path[lenPath:]
        if !titleValidator.MatchString(title) {
            http.NotFound(w, r)
            return
        }
        fn(w, r, title)
    }
}

func main() {
    http.HandleFunc("/view/", makeHandler(viewHandler))
    http.HandleFunc("/edit/", makeHandler(editHandler))
    http.HandleFunc("/save/", makeHandler(saveHandler))
    http.ListenAndServe(":8080", nil)
}
代码语言:javascript
代码运行次数:0
运行
复制

运行测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ 8g wiki.go
$ 8l wiki.8
$ ./8.out
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
在地址栏输入地址:http://localhost:8080/view/aNewPage

效果图:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL 中的反斜杠 \\,真是太坑了!!
在MySQL中有很多特殊符号都是相当恶心的,比如字符串中有单引号(')、双引号(")、反斜杠(\)等等,同学们可以先脑补一下可能会出现啥问题?
程序猿DD
2021/07/13
3.3K0
MySQL 中的反斜杠 \\,真是太坑了!!
在MySQL中有很多特殊符号都是相当恶心的,比如字符串中有单引号(')、双引号(")、反斜杠(\)等等,同学们可以先脑补一下可能会出现啥问题?
Java技术栈
2021/06/16
3.3K0
这MySQL里的反斜杠(\\)也太坑了吧!!真是醉了
  后来发现,原因其实很简单,在MySQL中,反斜杠在字符串中是属于转义字符,经过语法解析器解析时会进行一次转义,所以当我们insert反斜杠(\)字符时,如 insert “\” 在数据库中最终只会存储"",第一个反斜杠(\)被当做转义字符处理。
陈哈哈
2021/10/13
4.6K0
MySQL 之 JSON 支持(一)—— JSON 数据类型
MySQL 支持由 RFC 7159 所定义的原生 JSON 数据类型,通过该类型能够有效访问 JSON(JavaScript 对象表示法)文档中的数据。与将 JSON 格式字符串存储在字符串列中相比,JSON 数据类型提供了以下优点:
用户1148526
2024/06/06
3.9K0
MySQL 快速入门(一)
ps:char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符,超出报错
HammerZe
2022/03/24
1.6K0
MySQL 快速入门(一)
Python : 反斜杠
使用python写字符串常量时,raw string是个很好用的东东,比如在C里我要写一个Windows下的路径,得这么
py3study
2020/01/07
4K0
MySQL安装
在任何版本的 Windows 默认安装是现在比以前要容易得多,MySQL巧妙地打包安装程序。只需下载安装包,随地把它解压缩,并运行 mysql.exe. 下载地址:http://dev.mysql.com/downloads/ 页面如下图所示:
botkenni
2022/01/10
11.5K0
MySQL安装
MySQL或者MariaDB里面sql_mode的设置详解
地址:http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html
保持热爱奔赴山海
2019/09/18
2.5K0
MySQL数据类型
注意:尽量不使用unsigned,对于int类型可能存放不下的数据,int unsigned同样可能存放不 下,与其如此,还不如设计时,将int类型提升为bigint类型。
用户11316056
2025/02/17
1290
MySQL数据类型
学习 MySQL 需要知道的 28 个小技巧
无论是运维、开发、测试,还是架构师,数据库技术都是一个 必备加薪神器,那么,一直说学习数据库、学 MySQL,到底是要学习它的哪些东西呢?
Lucifer三思而后行
2021/11/29
1K0
Mysql系列 - 第2天:详解mysql数据类型(重点)
上面表格中有符号和无符号写反了,[]包含的内容是可选的,默认是无符号类型的,无符号的需要在类型后面跟上unsigned
路人甲Java
2019/09/16
1.1K0
Mysql系列 - 第2天:详解mysql数据类型(重点)
MySQL从删库到恢复,还用跑路吗?
误删数据库应该如何恢复操作?怎样才能做好数据库的备份、恢复、容灾、HA?如果你身处数据库行业,最近可能会比较关注这几个问题
搜云库技术团队
2019/10/17
1.3K0
MyBatis踩坑之SQLProvider转义字符被删除问题
使用MyBatis作为ORM框架,jdbc驱动使用的是mariadb-java-client。
编程随笔
2019/11/23
1.7K0
《MySQL核心知识》第3章:MySQL中的运算符
今天是《MySQL核心知识》专栏的第3章,今天跟大家一起聊聊MySQL中的运算符。好了,开始今天的正题。
冰河
2022/08/05
7480
《MySQL核心知识》第3章:MySQL中的运算符
【mysql】比较运算符
比较运算符 = <=> <> != < <= > >= 比较运算符用来对表达式左边的操作数和右边的操作数进行比较,比较的结果为真则返回1,比较的结果为假则返回0,其他情况则返回NULL。 比较运算符经常被用来作为SELECT查询语句的条件来使用,返回符合条件的结果记录。 [请添加图片描述] [请添加图片描述]1. 等号运算符(=) 等号运算符(=)判断等号两边的值、字符串或表达式是否相等,如果相等则返回1,不相等则返回0。 在使用等号运算符时,遵循如下规则: 如果等号两边的值、字符串或表达式都
兮动人
2022/03/02
2.6K0
MySQL数据库数据类型
在MySQL数据库中,MySQL数据类型分有四大类:数值类型、文本/二进制类型、时间日期和String类型。以下是这四大类的具体类型:
二肥是只大懒蓝猫
2023/10/13
3620
MySQL数据库数据类型
路径中 斜杠/和反斜杠\ 的区别
路径中使用斜杠/和反斜杠\的区别到底是什么。查阅了一些资料后可知。 Unix使用斜杆/ 作为路径分隔符,而web应用最新使用在Unix系统上面,所以目前所有的网络地址都采用 斜杆/ 作为分隔符。 Windows由于使用 斜杆/ 作为DOS命令提示符的参数标志了,为了不混淆,所以采用 反斜杠\ 作为路径分隔符。所以目前windows系统上的文件浏览器都是用 反斜杠\ 作为路径分隔符。随着发展,DOS系统已经被淘汰了,命令提示符也用的很少,斜杆和反斜杠在大多数情况下可以互换,没有影响。 知道这个背景后,可以总结一下结论: (1)浏览器地址栏网址使用 斜杆/ ; (2)windows文件浏览器上使用 反斜杠\ ; (3)出现在html url() 属性中的路径,指定的路径是网络路径,所以必须用 斜杆/ ;
全栈程序员站长
2022/07/07
2.9K0
MySQL定时任务(EVENT|事件)如何配置,必会技能!
  自MySQL5.1.6起,增加了一个非常有特色的功能 - 事件调度器(Event Scheduler),可以用做定时执行某些特定任务(例如:删除记录、数据统计报告、数据备份等等),来取代原先只能由操作系统的计划任务来执行的工作。   值得一提的是MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux的cron)只能精确到每分钟执行一次。对于一些对数据实时性要求比较高的应用(例如:股票、赔率、比分等)就非常适合。
陈哈哈
2021/10/13
7.8K0
MySQL数据类型
总结: 如果插入的数据超过MySQL数据类型的范围,那么MySQL就不让你插入,直接拦截,不让做对应的操作。这点和C/C++一样,但是编译器不会报错,语言上给你发生截断,编译器内部可能会隐式转换。 如果已经有数据被成功插入到MySQL中,那么插入的时候一定是合法的。 因此,MySQL中,一般而言,数据类型本身也是一种约束。这种约束倒逼程序员,让程序员尽可能正确插入,如果不正确插入,MySQL也能保证插入的数据合法性。这样就能保证数据库中的数据是可预期完整的。
南桥
2024/07/26
1610
MySQL数据类型
【MySQL 系列】MySQL 语句篇_DML 语句
DML(Data Manipulation Language),即数据操作语言,用于操作数据库对象中所包含的数据。常用关键字包括:插入(INSERT)、更新(UPDATE)、删除(DELETE)。
栗筝i
2024/03/19
8940
【MySQL 系列】MySQL 语句篇_DML 语句
相关推荐
MySQL 中的反斜杠 \\,真是太坑了!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档