当前位置: 首页 > news >正文

一家专门做原型的网站mysql创建WordPress

一家专门做原型的网站,mysql创建WordPress,科技网站设计公司有哪些,最有效的线下推广方式文章目录 模块化路由前缀树路由 前情提示#xff1a; 【Golang学习笔记】从零开始搭建一个Web框架#xff08;一#xff09;-CSDN博客 模块化路由 路由在kilon.go文件中导致路由和引擎交织在一起#xff0c;如果要实现路由功能的拓展增强#xff0c;那将会非常麻烦… 文章目录 模块化路由前缀树路由 前情提示 【Golang学习笔记】从零开始搭建一个Web框架一-CSDN博客 模块化路由 路由在kilon.go文件中导致路由和引擎交织在一起如果要实现路由功能的拓展增强那将会非常麻烦这无疑降低了代码的可读性和可维护性。现在的工作是将路由从引擎里剥离出来引擎中仅对路由进行包装。 新建文件router.go当前目录结构为 myframe/├── kilon/│ ├── context.go│ ├── go.mod [1]│ ├── kilon.go│ ├── router.go├── go.mod [2]├── main.go在router中添加下面内容 package kilonimport (net/http )type router struct {Handlers map[string]HandlerFunc } // 创建router对象 func newRouter() *router {return router{make(map[string]HandlerFunc)} } // 剥离路由注册的具体实现 func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {key : method - patternr.Handlers[key] handler } // 剥离SeverHTTP中路由处理的具体实现 func (r *router) handle(ctx *Context) {key : ctx.Method - ctx.Pathif handler, ok : r.Handlers[key]; ok {handler(ctx)} else {ctx.String(http.StatusNotFound, 404 NOT FOUND: %s\n, ctx.Path)} }修改kilon.go文件 package kilonimport (net/http )type HandlerFunc func(*Context)type Origin struct {router *router // 修改路由 }func New() *Origin {return Origin{router: newRouter()} // 修改构造函数 }func (origin *Origin) addRoute(method string, pattern string, handler HandlerFunc) {origin.router.addRoute(method, pattern, handler) // 修改调用 }func (origin *Origin) GET(pattern string, hander HandlerFunc) {origin.addRoute(GET, pattern, hander) }func (origin *Origin) POST(pattern string, hander HandlerFunc) {origin.addRoute(POST, pattern, hander) }func (origin *Origin) ServeHTTP(w http.ResponseWriter, req *http.Request) {ctx : newContext(w, req)origin.router.handle(ctx) // 调用router.go中的处理方法 }func (origin *Origin) Run(addr string) (err error) {return http.ListenAndServe(addr, origin) }至此实现了路由的模块化后续路由功能的增强将不会改动kilon.go文件。 前缀树路由 目前的路由表使用map存储键值对索引非常高效但是有一个弊端键值对的存储的方式只能用来索引静态路由而无法实现动态路由。在实际的应用中可能需要使用正则表达式或者其他匹配规则来实现更复杂的路由匹配而 map 无法提供这种功能。接下来将使用前缀树Tire树实现动态路由主要实现两个功能 参数匹配:。例如 /p/:name/doc可以匹配 /p/zhangsan/doc 和 /p/lisi/doc。通配*仅允许最后一个有*号。例如 /static/*filepath可以匹配/static/fav.ico和/static/js/jQuery.js。 新建文件trie.go当前文件目录结构为 myframe/├── kilon/│ ├── context.go│ ├── go.mod [1]│ ├── kilon.go│ ├── router.go│ ├── tire.go├── go.mod [2]├── main.go在trie.go中创建前缀树的节点: type node struct {patten string // 待匹配路由part string // 路由当前部分children []*node // 孩子节点isWild bool // 是否为模糊搜索当含有:和通配符*时为true }当注册路由/p/:name/doc、“/p/:name/png”、“/p/:lang/doc”、/p/:lang/png后树中内容如下 可以看到pattern只有在插入最后一个子节点后才会设置这是为了在查询路由信息时可以根据 pattern来判断改路由是否注册。isWaild的作用在于当part不匹配时如果isWaild为true可以继续搜索这样就实现了模糊匹配。 先实现路由注册时的前缀树插入逻辑 func (n *node) insert(pattern string, parts[]string, index int)pattern是注册路由地址parts是解析pattern后的字符串数组使用方法strings.Split(pattern, /)进行解析如/p/:name/doc对应 [“p”,“:name”,“doc”]parts[index]是当前需要插入的part。可以通过index判断是否退出。疑问如果只用Split解析那pattren/的时候不就无法注册了吗答开始时树的根节点的part为空不会匹配“p一定会插入到根节点的子节点切片中。而当pattern为”/“时解析字符串切片为空进入根节点的时候len(parts) index 0,会将根节点的pattern设置为”/“也可以实现路由”/的注册。 代码如下 func (n *node) insert(pattern string, parts[]string, index int){// 进来的时候说明 n.part parts[index-1] 即最后一个 part 则直接设置 pattenif len(parts) index {n.patten patternreturn}// 还需匹配 part// 先在 n.children 切片中匹配 partpart : parts[index]child : n.matchChild(part)// 如果没有找到则构建一个 child 并插入 n.children 切片中if child nil {child node{part: part,// 含有:或者通配符*时为 trueisWild: part[0] : || part[0] *,}// 插入 n.children 切片n.children append(n.children, child)}// 递归插入child.insert(pattern, parts, index 1) } // 查找匹配 child func (n *node) matchChild(part string) *node {// 遍历 n.children 查找 part 相同的 childfor _, child : range n.children {// 如果找到匹配返回 child 当 isWild 为 true 时视为匹配实现模糊搜索if child.part part || child.isWild true {return child}} // 没找到返回nilreturn nil }接下来实现接受请求时查询路由信息时的前缀树搜索逻辑 func (n *node) search(parts []string, index int) *nodeparts是路由地址的解析数组index指向当前part索引 代码如下: // 搜索 func (n *node) search(parts []string, index int) *node {// 如果匹配将节点返回if len(parts) index || strings.HasPrefix(n.part, *) {if n.pattern {return nil}return n}part : parts[index]// 获取匹配的所有孩子节点nodes : n.matchChildren(part)// 递归搜索匹配的child节点for _, child : range nodes {result : child.search(parts, index1)if result ! nil {return result}}return nil } // 查找匹配的孩子节点由于有:和*所以可能会有多个匹配因此返回一个节点切片 func (n *node) matchChildren(part string) []*node {nodes : make([]*node, 0)for _, child : range n.children {if child.part part || child.isWild true {nodes append(nodes, child) // 将符合的孩子节点添入返回切片}}return nodes }至此trie.go暂时写完现在在路由中进行应用回到router.go文件。为了区分不同的方法如GET和POST为每一个Method建立一颗前缀树并以键值对的形式存储在一个map中map[Method] tire。修改router结构体与构造方法 type router struct {roots map[string]*node // 前缀树mapHandlers map[string]HandlerFunc // 将pattern作为key获取/注册方法 } func newRouter() *router {return router{make(map[string]*node),make(map[string]HandlerFunc),} }将pattern插入前缀树之前要先解析成字符串切片现在需要实现一个解析函数。 func parsePattern(pattern string) []string {temp : strings.Split(pattern, /)parts : make([]string, 0)for _, item : range temp {if item ! {parts append(parts, item)if item[0] * {break}} }return parts }修改注册路由的逻辑 func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {parts : parsePattern(pattern) // 解析patternkey : method - patternif _, ok : r.roots[key]; !ok {r.roots[method] node{} // 如果没有则创建一个节点}r.roots[method].insert(pattern, parts, 0) // 前缀树插入patternr.Handlers[key] handler // 注册方法 }当接受请求时需要对请求中携带的路由信息解析并获取匹配的节点以及:“,”*匹配到的参数现在需要写一个路由获取方法 func (r *router) getRoute(method string, path string) (*node, map[string]string) {searchParts : parsePattern(path) // 解析路由信息params : make(map[string]string) // 参数字典root, ok : r.roots[method]if !ok {return nil, nil}// 搜索匹配节点n : root.search(searchParts, 0)if n! nil {parts : parsePattern(n.pattern) // 解析pattern// 寻找*和:,找到对应的参数。for index, part : range parts {if part[0] : {params[part[1:]] searchParts[index]}if part[0] * len(part) 1 {// 将*后切片内容拼接成路径params[part[1:]] strings.Join(searchParts[index:],/)break // 仅允许一个通配符*}return n, params}}return nil, nil }路径中的参数应该交给上下文对象让用户便捷获取。在Context结构体中添加Params属性,并包装获取方法 type Context struct {Writer http.ResponseWriterReq *http.RequestPath stringMethod stringParams map[string]string // 路由参数属性StatusCode int } // 获取路径参数 func (c *Context) Param(key string) string {value : c.Params[key]return value }在router.go中的handle中应用路由获取方法并将路径参数提交给上下文对象。 func (r *router) handle(ctx *Context) {n, params : r.getRoute(ctx.Method, ctx.Path) // 获取路由节点及参数字典ctx.Params paramsif n ! nil {key : ctx.Method - n.pattern // key为n的patternr.Handlers[key](ctx) // 调用注册函数} else {ctx.String(http.StatusNotFound, 404 NOT FOUND: %s\n, ctx.Path)} }现在router.go内容为 package kilonimport (net/httpstrings )type router struct {roots map[string]*nodeHandlers map[string]HandlerFunc }func newRouter() *router {return router{make(map[string]*node),make(map[string]HandlerFunc),} }func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {parts : parsePattern(pattern)key : method - pattern_, ok : r.roots[method]if !ok {r.roots[method] node{}}r.roots[method].insert(pattern, parts, 0)r.Handlers[key] handler }func (r *router) handle(ctx *Context) {n, params : r.getRoute(ctx.Method, ctx.Path)ctx.Params paramsif n ! nil {key : ctx.Method - n.patternr.Handlers[key](ctx)} else {ctx.String(http.StatusNotFound, 404 NOT FOUND: %s\n, ctx.Path)} }func parsePattern(pattern string) []string {temp : strings.Split(pattern, /)parts : make([]string, 0)for _, item : range temp {if item ! {parts append(parts, item)if item[0] * {break}}}return parts }func (r *router) getRoute(method string, path string) (*node, map[string]string) {searchParts : parsePattern(path)params : make(map[string]string)root, ok : r.roots[method]if !ok {return nil, nil}n : root.search(searchParts, 0)if n ! nil {parts : parsePattern(n.pattern)for index, part : range parts {if part[0] : {params[part[1:]] searchParts[index]}if part[0] * len(part) 1 {params[part[1:]] strings.Join(searchParts[index:], /)break}}return n, params}return nil, nil }在main.go测试一下 package mainimport (kilonnet/http )func main() {r : kilon.New()r.GET(/hello, func(ctx *kilon.Context) {ctx.JSON(http.StatusOK, kilon.H{message: Hello World,})})r.GET(/hello/:username, func(ctx *kilon.Context) {ctx.JSON(http.StatusOK, kilon.H{message: ctx.Param(username),})})r.GET(/hello/:username/*filename, func(ctx *kilon.Context) {ctx.JSON(http.StatusOK, kilon.H{username: ctx.Param(username),filename: ctx.Param(filename),})})r.Run(:8080) }分别访问下面地址都可以看到响应信息 127.0.0.1:8080/hello 127.0.0.1:8080/hello/zhangsan 127.0.0.1:8080/hello/zhangsan/photo.png
http://www.hkea.cn/news/14325261/

相关文章:

  • 印度网站域名wordpress跳转
  • 做药品网站有哪些大气手机企业网站
  • 网站布局教程百度推广合作
  • 网站优化顺义案例成都市建设局官方网站
  • 中徽园林建设有限公司网站栾城网站建设
  • 网站提速wordpress vip服务积分
  • 快递物流网站建设开发具备哪些功能韶关做网站的
  • 高级网站设计效果图app下载app开发公司
  • 富民网站建设电脑课程培训零基础
  • 莱州网站建设费用成都企业网站建设 四川冠辰科技
  • 网站建设收费明细网站建设安全方案
  • 长沙做网站要多少钱wordpress 百度文库
  • 做外包胡it网站网站打开很慢怎么回事啊
  • 如何用apache建设网站最新seo视频教程
  • 医院网站建设策划案模板住房和城乡建设部官网查询平台
  • 网站建设及管理工作岗位要求网络公司经营范围写电子商务
  • 用flash做的网站展示wordpress 小工具开发
  • 龙岗网站建设服务岳阳网站建设哪里有
  • 网站 短链接怎么做No商业网站建设
  • 如何做网站方案天津网站推广方法
  • 网站域名费用网店装修素材网站
  • 网站系统怎么做的青岛房产网新楼盘
  • 网站被k申述高端html5网站建设
  • 上海网站建设兴策重庆网站免费优化
  • 礼品网站设计wordpress商品多选
  • 重庆网站建设公司价钱wordpress博客文章怎么设置
  • 杭州绿城乐居建设管理有限公司网站装潢设计软件有哪些
  • 在电子商务网站建设中需要哪些知识桂林生活网租房信息
  • 网站建设有哪些模块上海专业网站制作设计
  • 跨境o2o网站建设方案给公司做企业网站