• 何为框架:
框架一直是敏捷开发中的利器,能让开发者很快的上手并做出应用,甚至有的时候,脱离了框架,一些开发者都不会写程序了。成长总不会一蹴而就,从写出程序获取成就感,再到精通框架,快速构造应用,当这些方面都得心应手的时候,可以尝试改造一些框架,或是自己创造一个。
Gin是一个golang的微框架,封装比较优雅,API友好,源码注释比较明确,已经发布了1.0版本。具有快速灵活,容错方便等特点。其实对于golang而言,web框架的依赖要远比Python,Java之类的要小。自身的net/http足够简单,性能也非常不错。框架更像是一些常用函数或者工具的集合。借助框架开发,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。
(1)首先需要安装,安装比较简单,使用go get即可
go get github.com/gin-gonic/gin
如果安装失败,直接去Github clone下来,放置到对应的目录即可。
(2)代码中使用:
下面是一个使用Gin的简单例子:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
router.Run(":8080") // listen and serve on 0.0.0.0:8080
}
简单几行代码,就能实现一个web服务。使用gin的Default方法创建一个路由handler。然后通过HTTP方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到gin.Context的上下文环境。最后是启动路由的Run方法监听端口。麻雀虽小,五脏俱全。当然,除了GET方法,gin也支持POST,PUT,DELETE,OPTION等常用的restful方法。
Gin可以很方便的支持各种HTTP请求方法以及返回各种类型的数据,详情可以前往查看。
2.1 匹配参数
我们可以使用Gin框架快速的匹配参数,如下代码所示:
冒号:加上一个参数名组成路由参数。可以使用c.Param的方法读取其值。当然这个值是字串string。诸如/user/rsj217,和/user/hello都可以匹配,而/user/和/user/rsj217/不会被匹配。
浏览器输入以下测试:
返回结果为:
其中c.String是gin.Context下提供的方法,用来返回字符串。
其中c.Json是gin.Context下提供的方法,用来返回Json。
下面我们使用以下gin提供的Group函数,方便的为不同的API进行分类。
我们创建了一个gin的默认路由,并为其分配了一个组 v1,监听hello请求并将其路由到视图函数HelloPage,最后绑定到 0.0.0.0:8000
C.JSON是Gin实现的返回json数据的内置方法,包含了2个参数,状态码和返回的内容。http.StatusOK代表返回状态码为200,正文为{"message": “welcome"}。
注:Gin还包含更多的返回方法如c.String, c.HTML, c.XML等,请自行了解。可以方便的返回HTML数据
我们在之前的组v1路由下新定义一个路由:
下面我们访问
可以看到,通过c.Param(“key”)方法,Gin成功捕获了url请求路径中的参数。同理,gin也可以捕获常规参数,如下代码所示:
在浏览器输入以下代码:
通过c.Query(“key”)可以成功接收到url参数,c.DefaultQuery在参数不存在的情况下,会由其默认值代替。
我们还可以为Gin定义一些默认路由:
这时候,我们访问一个不存在的页面:
返回如下所示:
下面我们测试在Gin里面使用Post
在测试端输入:
附带发送的数据,测试即可。记住需要使用POST方法.
继续修改,将PostHandler的函数修改如下
测试工具输入:
发送的内容输入:
返回结果如下:
备注:此处需要指定Content-Type为application/x-www-form-urlencoded,否则识别不出来。
一定要选择对应的PUT或者DELETE方法。
Gin框架快速的创建路由
能够方便的创建分组
支持url正则表达式
支持参数查找(c.Param c.Query c.PostForm)
请求方法精准匹配
支持404处理
快速的返回给客户端数据,常用的c.String c.JSON c.Data
JSON传值的时候,如果有回车符就会挂的。我们可以使用正则来去掉回车符:
1 $str = preg_replace("'([\r\n])[\s]+'", "", $str);
2
3 // 不用正则
4 $str = str_replace("\n","",$str);
转出来的字符串就没有回车符的困扰了。
顺便记录一个PHP过滤脚本:
01 ?php
02 // $document 应包含一个 HTML 文档。
03 // 本例将去掉 HTML 标记,javascript 代码
04 // 和空白字符。还会将一些通用的
05 // HTML 实体转换成相应的文本。
06
07 $search = array ("'script[^]*?.*?/script'si", // 去掉 javascript
08 "'[\/\!]*?[^]*?'si", // 去掉 HTML 标记
09 "'([\r\n])[\s]+'", /
你的这一条正则表达式是要匹配“双引号之间除换行之外的所有字符,并以名称为first为名进行捕获 但是,这里却使用了貌似只有Python支持的P
先介绍几种常用的方法:
1、使用MatchString函数或Match函数
regexp.MatchString(pattern string, s string) pattern为正则表达式,s为需要校验的字符串
regexp.Match(pattern string, b []byte) pattern为正则表达式,s为需要校验的字符串
它们的作用都是匹配,区别在于参数为字符串和切片
实例如下:
2、使用 Compile函数或MustCompile函数
它们的区别是Compile返回两个参数 Regexp,error类型,而MustCompile只返回 Regexp类型
它们的作用是将正则表达式进行编译,返回优化的 Regexp 结构体,该结构体有需多方法。
实例如下:
3、查找正则匹配字串( 注:函数名包含string的所传参数为string 其他的均为[]byte 带All是所有)
查找正则匹配的字符串位置( 注:函数名包含string的所传参数为string 其他的均为[]byte 带All是所有)
4、替换
正则替换
按原文替换
函数处理替换源字串
5、Regexp结构体中一些常用的方法
正则中有分组这个功能,在golang中也可以使用命名分组。
一次匹配的情况
场景还原如下:
有一行文本,格式为:姓名 年龄 邮箱地址
请将其转换为一个map
代码实现如下:
str := `Alice 20 alice@gmail.com`
// 使用命名分组,显得更清晰
re := regexp.MustCompile(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\w+@\w+(?:\.\w+)+)`)
match := re.FindStringSubmatch(str)
groupNames := re.SubexpNames()
fmt.Printf("%v, %v, %d, %d\n", match, groupNames, len(match), len(groupNames))
result := make(map[string]string)
// 转换为map
for i, name := range groupNames {
if i != 0 name != "" { // 第一个分组为空(也就是整个匹配)
result[name] = match[i]
}
}
prettyResult, _ := json.MarshalIndent(result, "", " ")
fmt.Printf("%s\n", prettyResult)
输出为:
[Alice 20 alice@gmail.com Alice 20 alice@gmail.com], [ name age email], 4, 4
{
"age": "20",
"email": "alice@gmail.com",
"name": "Alice"
}
注意 [ name age email]有4个元素, 第一个为""。
多次匹配的情况
接上面的例子,实现一个更贴近现实的需求:
有一个文件, 内容大致如下:
Alice 20 alice@gmail.com
Bob 25 bob@outlook.com
gerrylon 26 gerrylon@github.com
...
更多内容
和上面一样, 不过这次转出来是一个slice of map, 也就是多个map。
代码如下:
// 文件内容直接用字符串表示
usersStr := `
Alice 20 alice@gmail.com
Bob 25 bob@outlook.com
gerrylon 26 gerrylon@github.com
`
userRe := regexp.MustCompile(`(?Pname[a-zA-Z]+)\s+(?Page\d+)\s+(?Pemail\w+@\w+(?:\.\w+)+)`)
// 这里要用FindAllStringSubmatch,找到所有的匹配
users := userRe.FindAllStringSubmatch(usersStr, -1)
groupNames := userRe.SubexpNames()
var result []map[string]string // slice of map
// 循环所有行
for _, user := range users {
m := make(map[string]string)
// 对每一行生成一个map
for j, name := range groupNames {
if j != 0 name != "" {
m[name] = strings.TrimSpace(user[j])
}
}
result = append(result, m)
}
prettyResult, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(prettyResult))
输出为:
[
{
"age": "20",
"email": "alice@gmail.com",
"name": "Alice"
},
{
"age": "25",
"email": "bob@outlook.com",
"name": "Bob"
},
{
"age": "26",
"email": "gerrylon@github.com",
"name": "gerrylon"
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
总结
使用命名分组可以使正则表示的意义更清晰。
转换为map更加符合人类的阅读习惯,不过比一般的根据索引取分组值麻烦一些。
————————————————
版权声明:本文为CSDN博主「butterfly5211314」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
本文链接:http://task.lmcjl.com/news/1480.html