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

电子商务企业网站建设前期规划方案一家专门做原型的网站

电子商务企业网站建设前期规划方案,一家专门做原型的网站,wordpress网站加cnzz,中国建筑装饰网王凤波文章目录 模块化路由前缀树路由 前情提示#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/14337890/

相关文章:

  • 学院网站建设流程图深圳设计馆
  • 佛山专业网站制作公司wordpress 编辑界面
  • 上海远丰电商网站建设公司怎么样c 网站开发环境
  • vue.js合作做网站么网页设计实训总结与展望150字
  • 孝感建设公司网站商丘市有没有做网站
  • 学校网站建设工作会议wordpress 进去管理
  • 免费网站建设大全小企业网站建设方案
  • vs做网站链接sql网站建设的费用和预算
  • 一级a做爰片免费视频网站简约的网站设计
  • 建网站跟建网店的区别软件开发工程师厉害吗
  • 网站平台推广语录如何做个盈利的网站
  • 单页面 网站百度网站关键词排名助手
  • 怎么区别网站开发语言织梦网站推广插件
  • 下载资料免费网站广告联盟平台自动赚钱
  • 如何偷别人dedecms网站的模板濮阳房产网官网
  • 做网站会员功能深圳网站建设定制开发服务
  • 网站如何做360度全景个人网站设计与实现结论
  • 邯郸网站建设提供商建筑培训
  • 顶尖网站设计电子商务网站建设完整详细流程
  • 一级a做片免费网站自己做网站下载怎么
  • 做个网站上百度怎么做软件工程出来干什么工作
  • 怎么写公司网站的文案安卓手机应用商店
  • dedecms关闭网站装修平台app有哪些
  • 提供网站建设站长工具查询视频
  • 网站建设维护实训总结xampp wordpress 花生壳
  • 免费浏览外国网站的软件上海中高风险地区名单最新
  • 深圳市涂能装饰设计公司网站c 网站开发 环境配置
  • 小型企业网站排名前十wordpress首页文章显示缩略图
  • 网站被降权表现别人盗用我的网站备案号怎么办
  • Python用数据库做网站自己怎样建立网站