手把手和你一起实现一个Web框架实战——EzWeb框架(二)[Go语言笔记]Go项目实战
手把手和你一起实现一个Web框架实战——EzWeb框架(二)[Go语言笔记]Go项目实战
代码仓库:
github
gitee
中文注释,非常详尽,可以配合食用
上一篇文章我们实现了框架的雏形,基本地实现了将原来的处理方法和监听处理的实例指向我们自定义的实例。封装出了GET,POST处理方法。完成了框架雏形。
本篇文章,我们将原本的handler方法中的参数 w http.ResponseWriter, req *http.Request 封装到一个新的结构体Context中,同时替代掉原来的参数,并在该结构体提供响应的一些简单的请求数据查询功能和响应处理方法。能够让我们快速获取数据以及构造响应。

一、设计这个Context
/*
@Time : 2021/8/17 下午1:46
@Author : Mrxuexi
@File : context.go
@Software: GoLand
*/
package Ez
import (
"encoding/json"
"net/http"
)
// H 为map[string]interface{}结构体起个别名,方便用户在代码中构建JSON
type H map[string]interface{}
// Context 结构体,内部封装了 http.ResponseWriter, *http.Request
type Context struct {
Writer http.ResponseWriter
Req *http.Request
//请求的信息,包括路由和方法
Path string
Method string
//响应的状态码
StatusCode int
}
//Context构造方法
func newContext(w http.ResponseWriter, req *http.Request) *Context {
return &Context{
Writer: w,
Req: req,
Path: req.URL.Path,
Method: req.Method,
}
}
// 访问参数的处理方法PostForm和Query
// PostForm 根据key拿到请求中的表单内容
func (c Context) PostForm(key string) string {
return c.Req.FormValue(key)
}
// Query 根据key获取请求中的参数
func (c Context) Query(key string) string {
return c.Req.URL.Query().Get(key)
}
//一些服用的前值方法Status处理响应状态码 SetHeader处理响应消息头
// Status 将状态码写入context,同时将通过封装起来的http.ResponseWriter方法,将状态码写入响应头
func (c Context) Status(code int) {
c.StatusCode = code
c.Writer.WriteHeader(code)
}
// SetHeader 构造响应的消息头
func (c Context) SetHeader(key string,value string) {
c.Writer.Header().Set(key,value)
}
// String 调用我们的 SetHeader和Status 方法,构造string类型响应的状态码和消息头,然后将字符串转换成byte写入到响应头
func (c Context) String(code int,values ...interface{}) {
c.SetHeader("Content-Type","text/plain")
c.Status(code)
var str = ""
for _, value := range values {
str += value.(string)
}
c.Writer.Write([]byte(str))
}
// JSON 调用我们的 SetHeader和Status 方法,构造JSON类型响应的状态码和消息头,根据我们传入的对象来构造json数据写入
func (c Context) JSON(code int,obj interface{}) {
c.SetHeader("Content-Type","application/json")
c.Status(code)
encoder := json.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
http.Error(c.Writer, err.Error(),http.StatusInternalServerError)
}
}
// Data 同上 ,但是直接写入字节数组,不再构建消息头
func (c Context) Data(code int,data []byte) {
c.Status(code)
c.Writer.Write(data)
}
// HTML 模版渲染 同上,消息体传入的是html文件
func (c Context) HTML(code int, html string) {
c.SetHeader("Content-Type","text/html")
c.Status(code)
c.Writer.Write([]byte(html))
}
我们将这些内容全部封装到了Context中,能够让我们快速获取数据以及构造响应。
如果我们没有进行封装,构造一个Json响应是十分麻烦的:
1、构造一个消息对象
//新建obj存储信息
obj := map[string]interface{}{
"name" : "Mrxuexi",
"password" : "password",
}
2、构造相应的消息头
//构造响应的消息头
w.Header().Set("Content-Type","application/json")
3、写入响应的状态码
//w写入状态码
w.WriteHeader(http.StatusOK)
4、根据已经做好的响应writer构建一个json编码器
//根据w建立一个json编码器
encoder := json.NewEncoder(w)
5、根据obj构建响应的消息体
//将obj放入消息体,处理报错
if err := encoder.Encode(obj); err != nil {
http.Error(w, err.Error(), 500)
}
如果我们进行了封装,我们只需要这样,省去了许多繁杂的工作:
c.JSON(http.StatusOK, context.H{
"name" : "Mrxuexi",
"password" : "password",
})
二、重新调整封装入口
我们将原来的Ez.go进行重构,将原来的路由表router map 封装到router.go。
HandlerFunc传入的参数改为 *Context
type HandlerFunc func(*Context)
将原来的ServeHTTP 方法作为入口,将请求传入构造context。
在router.go中进行addRoute路由注册处理和对应的请求处理。
/*
@Time : 2021/8/16 下午4:03
@Author : Mrxuexi
@File : Ez
@Software: GoLand
*/
package Ez
import (
"net/http"
)
// HandlerFunc 是Ez框架中定义的对请求的响应处理方法,传入*Context针对http请求处理
type HandlerFunc func(*Context)
// Engine 实现了"net/http"标准库中的 Handler 接口中的ServeHTTP方法
type Engine struct {
//用于存储路由处理方法
//key是方法类型加路径,value是用户的处理方法
router *router
}
// ServeHTTP 方法的实现,用于实现处理HTTP请求
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
//根据req和w实例一个context
c := newContext(w, req)
//传入开始执行处理
engine.router.handle(c)
}
// New 路由存储结构的构造函数
func New() *Engine {
return &Engine{router: newRouter()}
}
// addRoute 方法封装在router中,在 router map[string]HandlerFunc 中存入对应处理方法
func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
engine.router.addRoute(method, path, handler)
}
// GET 实现的是注册GET请求的路径和对应方法,调用了addRoute,存入了route 结构体的handler中
func (engine *Engine) GET(path string, handler HandlerFunc) {
engine.addRoute("GET", path, handler)
}
// POST 同上
func (engine *Engine) POST(path string, handler HandlerFunc) {
engine.addRoute("POST", path, handler)
}
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
三、重新调整封装router,路由注册处理和请求处理
所有的路由注册处理和请求处理都从入口拿到这一层来处理。
/*
@Time : 2021/8/16 下午4:03
@Author : Mrxuexi
@File : Ez
@Software: GoLand
*/
package Ez
import (
"net/http"
)
// HandlerFunc 是Ez框架中定义的对请求的响应处理方法,传入*Context针对http请求处理
type HandlerFunc func(*Context)
// Engine 实现了"net/http"标准库中的 Handler 接口中的ServeHTTP方法
type Engine struct {
//用于存储路由处理方法
//key是方法类型加路径,value是用户的处理方法
router *router
}
// ServeHTTP 方法的实现,用于实现处理HTTP请求
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
//根据req和w实例一个context
c := newContext(w, req)
//传入开始执行处理
engine.router.handle(c)
}
// New 路由存储结构的构造函数
func New() *Engine {
return &Engine{router: newRouter()}
}
// addRoute 方法封装在router中,在 router map[string]HandlerFunc 中存入对应处理方法
func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
engine.router.addRoute(method, path, handler)
}
// GET 实现的是注册GET请求的路径和对应方法,调用了addRoute,存入了route 结构体的handler中
func (engine *Engine) GET(path string, handler HandlerFunc) {
engine.addRoute("GET", path, handler)
}
// POST 同上
func (engine *Engine) POST(path string, handler HandlerFunc) {
engine.addRoute("POST", path, handler)
}
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
测试:
/*
@Time : 2021/8/16 下午4:01
@Author : mrxuexi
@File : main
@Software: GoLand
*/
package main
import (
"Ez"
"net/http"
)
func main() {
r := Ez.New()
r.GET("/", func(c *Ez.Context) {
c.HTML(http.StatusOK,"<h1>This is the index</h1>")
})
r.GET("/hello", func(c *Ez.Context) {
c.String(http.StatusOK, "hello")
})
r.POST("/message", func(c *Ez.Context) {
c.JSON(http.StatusOK,Ez.H{
"name" : c.PostForm("name"),
"age" : c.PostForm("age"),
})
})
r.Run(":9090")
}
index:

GET请求hello:

POST请求hello:

成功!
接上期灵魂画手环节:

参考:
[1]: https://github.com/geektutu/7days-golang/tree/master/gee-web ""gee""
[2]: https://github.com/gin-gonic/gin ""gin""
手把手和你一起实现一个Web框架实战——EzWeb框架(二)[Go语言笔记]Go项目实战的更多相关文章
- 手把手和你一起实现一个Web框架实战——EzWeb框架(三)[Go语言笔记]Go项目实战
手把手和你一起实现一个Web框架实战--EzWeb框架(三)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 本篇代码,请选择demo3 这一篇文章 ...
- 手把手和你一起实现一个Web框架实战——EzWeb框架(四)[Go语言笔记]Go项目实战
手把手和你一起实现一个Web框架实战--EzWeb框架(四)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 这一篇文章主要实现路由组功能.实现路由 ...
- 手把手和你一起实现一个Web框架实战——EzWeb框架(五)[Go语言笔记]Go项目实战
手把手和你一起实现一个Web框架实战--EzWeb框架(五)[Go语言笔记]Go项目实战 代码仓库: github gitee 中文注释,非常详尽,可以配合食用 本篇代码,请选择demo5 中间件实现 ...
- Go语言笔记[实现一个Web框架实战]——EzWeb框架(一)
Go语言笔记[实现一个Web框架实战]--EzWeb框架(一) 一.Golang中的net/http标准库如何处理一个请求 func main() { http.HandleFunc("/& ...
- 用C写一个web服务器(三) Linux下用GCC进行项目编译
.container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...
- MVC框架入门准备(二) - 语言包类与工厂模式
语言包类: 相关配置项 LANG_FOLDER : 语言包目录名,默认为Lang LANG_AUTO : 自动识别语言,默认为true DEFAULT_LANG : 默认语言,默认为zh-cn方法 取 ...
- Python之路,Day18 - 开发一个WEB聊天来撩妹吧
Python之路,Day18 - 开发一个WEB聊天来撩妹吧 本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个 ...
- 【转载】ASP.NET MVC Web API 学习笔记---第一个Web API程序
1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...
- ASP.NET MVC Web API 学习笔记---第一个Web API程序
http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...
随机推荐
- 资源:jenkins下载路径
Jenkins版本下载路径 所有版本:http://mirrors.jenkins.io/war/
- mongodb数据的导出导入
1.[导出]mongoexport -h (主机名) -d (库) -c (集合名) -o (路径) -u (账号) -p (密码)示例:mongoexport -h localhost -d jav ...
- 青蛙跳台阶问题(斐波那契数列) python
一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法 class Solution: def jump(self,n): if n ==0: return 0 el ...
- WPF教程十二:了解自定义控件的基础和自定义无外观控件
这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...
- postgresql安装及配置
目录 1. 安装 2. PostgrepSQL的简单配置 2.1 修改监听的ip和端口 2.2 修改数据库log相关的参数 2.3 内存参数 3. 数据库的基础操作 3.1 连接数据库控制台 3.2 ...
- SpringBoot自动装配原理之Configuration以及@Bean注解的使用
Configuration以及Bean注解的使用 该知识点在Spring中应该学过,没有学过或者遗忘的的朋友需要预习或温习前置知识点.SpringBoot其实就是Spring的进一步简化,所以前置知识 ...
- MySQL数据库性能优化该如何入手
今天小杨给大家分享一篇关于数据库查询优化,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情. ...
- Oracle-索引分裂研究
目录 索引分裂介绍 分类 索引分裂实验 基础环境准备 基础信息统计--之前 数据插入 基础信息统计--之后 Trace 数据统计 数据分析 索引PRI_ID之dba_extents视图 索引PRI_I ...
- python 爬取网络小说 清洗 并下载至txt文件
什么是爬虫 网络爬虫,也叫网络蜘蛛(spider),是一种用来自动浏览万维网的网络机器人.其目的一般为编纂网络索引. 网络搜索引擎等站点通过爬虫软件更新自身的网站内容或其对其他网站的索引.网络爬虫可以 ...
- [刘阳Java]_酷炫视频播放器制作_界面篇
今天开始分享一篇酷炫播放器制作,包括界面+JS.整个案例非常类似腾讯视频,优酷视频,爱奇艺视频.我们先看一下效果图,然后这篇文章主要界面篇 是不是效果比较酷炫,那么我接着来给大家说一下这个界面设计思路 ...