## 引言
> 简单说下本章的重点
* 1、抽离路由
* 2、将writer和request封装成Context,以方便后续扩展,封装了返回类型
* 3、优化框架源码,抽离封装了handleHTTPRequest方法
* 4、[代码地址 https://github.com/18211167516/go-Ebb/tree/master/day2-context](https://github.com/18211167516/go-Ebb/tree/master/day2-context)
## 抽离路由
* 新建router.go
```golang
package ebb
type router struct{
handlers map[string]HandlerFunc
}
func newRouter() *router{
return &router{handlers:make(map[string]HandlerFunc)}
}
func (r *router) addRoute(method string,pattern string,handler HandlerFunc){
key := method+"-"+pattern
r.handlers[key] = handler
}
```
> 设计Context的必要性
* 对外接口简化调用 (封装了writer和request)
* 提供了扩展性(比如支持动态参数、支持中间件等等)
```golang
package ebb
import (
"net/http"
"fmt"
"encoding/json"
)
type H map[string]interface{}
type Context struct{
//write and request
Writer http.ResponseWriter
Request *http.Request
//request info
Method string
Path string
//response
HttpCode int
}
func newContext(w http.ResponseWriter,r *http.Request) *Context{
context := &Context{
Writer:w,
Request:r,
Path: r.URL.Path,
Method: r.Method,
}
return context
}
func (c *Context) PostForm(key string) string {
return c.Request.FormValue(key)
}
func (c *Context) Query(key string) string {
return c.Request.URL.Query().Get(key)
}
func (c *Context) Status(code int) {
c.HttpCode = code
c.Writer.WriteHeader(code)
}
func (c *Context) SetHeader(key string, value string) {
c.Writer.Header().Set(key, value)
}
func (c *Context) Write(data []byte){
c.Writer.Write(data)
}
func (c *Context) String(code int,message string,v ...interface{}){
c.SetHeader("Content-Type", "text/plain")
c.Status(code)
c.Write([]byte(fmt.Sprintf(message, v...)))
}
func (c *Context) JSON(code int, obj interface{}) {
c.SetHeader("Content-Type", "application/json")
c.Status(code)
data,err:= json.Marshal(obj)
if err!=nil {
http.Error(c.Writer, err.Error(), 500)
}
c.Write(data)
}
func (c *Context) HTML(code int,html string){
c.SetHeader("Content-Type", "text/html")
c.Status(code)
c.Write([]byte(html))
}
```
* 修改ebb.go
```golang
package ebb
import (
"net/http"
)
//重新定义框架请求处理方法
type HandlerFunc func(*Context)
//核心结构体
type Engine struct{
router *router
}
//实例化结构体
func New() *Engine{
engine := &Engine{
router : newRouter(),
}
return engine
}
//添加到结构体路由
func (engine *Engine) addRoute(mothod string,pattern string,handler HandlerFunc){
engine.router.addRoute(mothod,pattern,handler)
}
func (engine *Engine) GET(pattern string,handler HandlerFunc){
engine.addRoute("GET",pattern,handler)
}
func (engine *Engine) POST(pattern string,handler HandlerFunc){
engine.addRoute("POST",pattern,handler)
}
//启动服务
func (engine *Engine) Run(addr string) (err error){
return http.ListenAndServe(addr,engine)
}
//engine 实现ServeHTTP接口(所有的请求都会走到这)
//查找是否路由映射表存在,如果存在则调用,否则返回404
func (engine *Engine) ServeHTTP(w http.ResponseWriter,req *http.Request){
c := newContext(w, req)
engine.handleHTTPRequest(c)
}
//v2 新增
func (engine *Engine) handleHTTPRequest(c *Context){
key := c.Method + "-" + c.Path
if handler, ok := engine.router.handlers[key]; ok {
handler(c)
} else {
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
}
}
```
> 入口文件应用
```golang
package main
import (
"ebb"
)
func main(){
r := ebb.New()
r.GET("/", func(c *ebb.Context) {
c.HTML(200, "<h1>Hello ebb</h1>")
})
r.GET("/hello", func(c *ebb.Context) {
c.String(200, "hello %s, you from %s\n", c.Query("name"), c.Path)
})
r.POST("/login", func(c *ebb.Context) {
c.JSON(200, ebb.H{
"name": c.PostForm("name"),
})
})
r.Run(":8080")
}
```
有疑问加站长微信联系(非本文作者))