zoukankan      html  css  js  c++  java
  • Go语言Web框架gwk介绍2

    Go语言Web框架gwk介绍 (二)

    HttpResult

    凡是实现了HttpResult接口的对象,都可以作为gwk返回Web客户端的内容。HttpResult接口定义非常简单,只有一个方法:

    type HttpResult interface {
        Execute(ctx *HttpContext) error
    }
    

    func Execute(ctx *HttpContext) error 方法定义了应该怎么样将数据返回客户端,*HttpContext 是当前http请求的上下文对象,后文会详细介绍。

    gwk内置了支持几种常用的HttpResult。

    ContentResult

    type ContentResult struct {
        ContentType string
        Data interface{}
    }
    
    func Content(data interface{}, contentType string) *ContentResult {
        return &ContentResult{
            Data:        data,
            ContentType: contentType,
        }
    }
    

    ContentResult对应了raw html数据,直接将Data原样写入到http response中,如果你定义了ContentType参数,会在写Data之前先写http header:Content-Type。

    如果Data实现了WriterTo、Reader接口,或者Data是[]byte 或者string,直接将Data写入Response,如果不是的话,gwk调用fmt.Fprintln将Data写入Response。

    JsonResult

    func Json(a interface{}) *JsonResult 
    

    JsonResult顾名思义,先将数据序列化为json格式,再写入Response,默认会将http header的Content-Type设置为"application/json",你也可以先给Content-Type设置一个值来阻止gwk设置Content-Type。

    XmlResult

    func Xml(a interface{}) *XmlResult 
    

    XmlResult将数据序列化为xml格式再写入Response,默认会将Content-Type设置为"text/xml"。

    FileResult

    func File(path string) *FileResult
    

    FileResult对应静态文件,实际上就是调用http.ServeFile来输出静态文件。 FileResult的path支持两种方式:绝对路径和相对路径,例子如下:

    func FileAbsolute(ctx *wk.HttpContext) (result wk.HttpResult, err error) {
        return wk.File(path.Join(ctx.Server.Config.RootDir, "public/humans.txt")), nil
    }
    
    func FileRelative(ctx *wk.HttpContext) (result wk.HttpResult, err error) {
        return wk.File("~/public/humans.txt"), nil
    }
    

    如果path以~/开头则为相对路径,否则即为绝对路径。

    FileStreamResult

    func FileStream(contentType, downloadName string, reader io.Reader, modtime time.Time) *FileStreamResult {
        return &FileStreamResult{
            ContentType:  contentType,
            DownloadName: downloadName,
            Data:         reader,
            ModifyTime:   modtime,
        }
    }
    

    FileStreamResult对应一个Stream文件,如果设置了DownloadName参数,则将其作为浏览器保存文件的默认文件名,实际就是设置http header:"Content-Disposition"。

    FileStreamResult内部是调用ServeContent。一个简单的例子如下:

    // url: get /file/time.txt
    server.RouteTable.Get("/file/time.txt").To(FileHelloTime)
    
    func FileHelloTime(ctx *wk.HttpContext) (result wk.HttpResult, err error) {
        s := "hello, time is " + time.Now().String()
        reader := strings.NewReader(s)
        return wk.FileStream("", "hellotime.txt", reader, time.Now()), nil
    }
    

    BundleResult

    func FileJsBundling(ctx *wk.HttpContext) (result wk.HttpResult, err error) {
        files := []string{"xxx/js/main.js", "xxx/js/plugins.js"}    
        return &wk.BundleResult{Files: files}, nil
    }
    

    BundleResult是将若干相同类型的文件打包成一个文件返回,藉此提升响应速度。BundleResult原先是一个用来演示如何自定义HttpResult的demo,现在集成到gwk中。现在的版本还只支持绝对路径,后续的版本可能会支持相对路径。

    RedirectResult

    func Redirect(urlStr string, permanent bool) *RedirectResult 
    

    RedirectResult用来做http重定向,根据permanent参数决定返回 http.StatusMovedPermanently还是http.StatusFound。

    NotFoundResult

    NotFoundResult默认返回http.StatusNotFound,如果你开启了自定义404页面功能,则按如下逻辑返回:

    1. 如果Request的http header "accept"包含"text/html",先找public路径下的404.html,如果存在则返回404.html的内容。

    2. 如果启用View引擎,并且views目录下存在404.html,则解析模板404.html返回。

    3. 如果Request的http header "accept"包含"text/plain",并且public路径下存在的404.txt,则返回404.txt的内容。

    4. 如果上面的情况都不成立,则返回http.StatusNotFound。

    开启了自定义404页面功能的方法是设置config的NotFoundPageEnable为true。设置方式见"配置"章节。

    ErrorResult

    func Error(message string) *ErrorResult {
        return &ErrorResult{
            Message: message,
        }
    }
    

    ErrorResult顾名思义返回错误信息,默认返回http.StatusInternalServerError,如果你开启了自定义错误页面功能,则按如下逻辑返回:

    1. 如果Request的http header "accept"包含"text/html",先找public路径下的error.html,如果存在则返回error.html的内容。

    2. 如果启用View引擎,并且views目录下存在error.html,则解析模板error.html返回。

    3. 如果Request的http header "accept"包含"text/plain",并且public路径下存在的error.txt,则返回error.txt的内容。

    4. 如果上面的情况都不成立,则返回http.http.StatusInternalServerError。

    开启了自定义错误页面功能的方法是这是config的ErrorPageEnable为true。

    ViewResult

    func View(file string) *ViewResult {
        return &ViewResult{
            File: file,
        }
    }
    

    ViewResult解析html模板并且输出到Response,因为这一块内容比较多,在"View引擎"一节单独介绍。

    JsonpResult

    返回Jsonp格式的数据,目前还没有实现。

    NotModifiedResult

    返回http.StatusNotModified

    自定义HttpResult

    自定义HttpResult十分简单,只要实现Execute(ctx *HttpContext) error方法就可以了,Go的interface机制让使用第三方的HttpResult或者开发一个HttpResult给别人使用变得很简单。

    gwk的demo中包含一个自定义HttpResult的例子QrCodeResult,可以将文本转化为二维码显示,这个例子不兼容App Engine,只能在线下运行demo程序看效果。

    模板引擎

    作为Web Engine框架,模板引擎是必不可少的,gwk的模板引擎基于Go自带的Html Template,在此基础上添加了一些新的功能。

    • 内存中缓存编译的模板
    • 内置了一系列Template Func
    • 支持模板layout
    • 支持partial view

    先看几个具体的模板定义的例子,对gwk的模板有个直观的印象。

    layout文件:_layout.html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>{{.title}}</title>
    <script type="text/javascript">
    </script>
    <style>
    </style>
    {{template "head" .}}
    </head>
    
    <body>
    <div id="header">
    {{partial "nav.html" .user }}
    </div>
    
    {{/* a comment */}}
    
    {{template "body" .}}
    
    <div id="footer">
    build by gwk
    </div>
    
    <script type="text/javascript">
    </script>
    
    {{template "script" .}}
    
    </body>
    </html>
    

    模板文件:basic.html

    {{set . "title" "title demo" }}
    {{import "_layout.html" }}
    
    {{define "head" }}
    <script type="text/javascript">
    </script>
    <style>
    div{padding: 10px;}
    </style>
    {{end}}
    
    {{define "body" }}
    
    <h1>hello gwk!</h1>
    
    {{raw  "<!-- <script><style><html>  -->"}}
    
    <div>
    <lable for="selected">selected</lable>
    <select id="selected">
        <option value="" ></option>
        <option value="selected" {{selected true}}>selected</option>
    </select>
    <lable for="notselected">not selected</lable>
    <select id="notselected">
        <option value="" ></option>
        <option value="notselected" {{selected false}}>not selected</option>
    </select>
    </div>
    
    <div>
    <input id="checked" type="checkbox" {{checked true}}>checked</input>
    <input id="notchecked" type="checkbox" {{checked false}}>not checked</input>
    </div>
    
    <ul>
    <li id="eq">eq 123 123 = {{eq 123 123}}</li>
    <li id="eq">eqs "123" 123 = {{eqs "123" 123}}</li>
    <li id="gt">gt 3.14 3 = {{gt 3.14 3}}</li>
    <li id="le">le 1.1 2 = {{le 1.1 2}}</li>
    </ul>
    
    <div>{{nl2br "a
    b
    c" }}</div>
    
    <div id="settest-before">settest-before = {{.settest}}</div>
    {{set . "settest" "true"}}
    <div id="settest-after">settest-after = {{.settest}}</div>
    
    {{partial "user.html" .user}}
    
    {{end}}
    
    {{define "script" }}
    
    <script>
    {{jsvar "user" .user}}
    </script>
    
    {{end}}
    

    partial view文件:nav.html

    <div id="nav">Hi {{.Name}}</div>
    

    另外一个partial view文件:user.html

    <ul id="div-{{.Name}}">
    <li>name:{{.Name}} </li>
    <li>age:{{.Age}}</li>
    <li><a href="{{.Web}}">web</a></li>
    <li><a href="mailto:{{.Email}}">email</a></li>
    </ul>
    

    最后的输出应该类似下面的html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>title demo</title>
        <script type="text/javascript">
        </script>
        <style>
        </style>
        <script type="text/javascript">
        </script>
        <style>
            div{padding: 10px;}
        </style>
    </head>
    
    <body>
    
    <div id="header">
        <div id="nav">Hi Gopher</div>
    </div>
    
    <h1>hello gwk!</h1>
    
    <!-- <script><style><html>  -->
    
    <div>
        <lable for="selected">selected</lable>
        <select id="selected">
            <option value="" ></option>
            <option value="selected" selected>selected</option>
        </select>
        <lable for="notselected">not selected</lable>
        <select id="notselected">
            <option value="" ></option>
            <option value="notselected" >not selected</option>
        </select>
    </div>
    
    <div>
        <input id="checked" type="checkbox" checked>checked</input>
        <input id="notchecked" type="checkbox" >not checked</input>
    </div>
    
    <ul>
        <li id="eq">eq 123 123 = true</li>
        <li id="eq">eqs "123" 123 = true</li>
        <li id="gt">gt 3.14 3 = true</li>
        <li id="le">le 1.1 2 = true</li>
    </ul>
    
    <div>a<br/>b<br/>c</div>
    
    <div id="settest-before">settest-before = </div>
    <div id="settest-after">settest-after = true</div>
    
    <ul id="div-Gopher">
        <li>name:Gopher </li>
        <li>age:3</li>
        <li><a href="http://golang.org">web</a></li>
        <li><a href="mailto:gopher@golang.org">email</a></li>
    </ul>
    
    <div id="footer">
        build by gwk
    </div>
    
    <script type="text/javascript">
    </script>
    
    <script>
     var user = {"Name":"Gopher","Age":3,"Web":"http://golang.org","Email":"gopher@golang.org"};
    </script>
    
    </body>
    </html>
    

    更多模板的例子可以参考https://github.com/sdming/wk/tree/master/demo/basic/views/user

    Template Func

    gwk默认添加了若干Template Func

    • eq: 判断是否相等
    • eqs: 转化成字符串,再判断是否相等
    • gt: 大于
    • le: 小于
    • set: 设置map[string]interface{}元素的值
    • raw: 输出非转义的字符串
    • selected: 输出字符串"selected"或者""
    • checked: 输出字符串"checked"或者""
    • nl2br: 将字符串中的" "替换为"<br/>"
    • jsvar: 将Go的变量转化为javascript中的变量定义
    • import: 导入模板文件
    • fv: 调用*http.Request.FormValue
    • incl: 判断一个[]string中是否包含字符串v
    • partial: 调用一个partial view

    模板layout

    你gwk中你可以定义若干个模板layout,然后在每个具体的模板文件中调用函数"import"引用某个layout文件,layout文件的路径为相对于模板根目录的相对路径。

    {{import "_layout.html" }}
    

    需要注意的是,import要在模板输出具体内容之前调用才有效。

    调用另一个模板

    在gwk的模板文件中,可以通过函数partial调用另一个模板文件,这对于web服务端模块化开发来说很有用。在上面例子中定义了一个模板文件user.html来显示user对象的信息,在其他模板文件中就可以直接使用user.html了。

    {{partial "user.html" .user}}
    

    模板缓存

    默认配置下,gwk在第一次访问某个模板文件时会缓存编译后的模板*template.Template,后续访问这个模板时直接从缓存中读取*template.Template对象,如果模板的物理文件被修改,gwk会从缓存中删除对应的*template.Template对象。gwk使用fsnotify来监控物理文件,详细信息可以访问fsnotify的项目主页。

    需要注意的是fsnofity在App Engine上不起作用,其实App Engine的更新机制也决定了不需要物理文件变更监控这样的功能。

    你可以在plugin.conf关闭模板缓存功能,配置代码类似:

    #GoHtml config
    gohtml: {
        cache_enable:   true
    }
    # -->end GoHtml
    

    接下里介绍gwk的内部实现机制。

     
     
    分类: Go
    标签: golangWeb FrameworkGWKMVC
  • 相关阅读:
    Delphi系统变量:IsMultiThread对MM的影响
    Delphi7中 string, AnsiString, Utf8String,WideString的区别分析
    Delphi之TComponent类
    delphi -----(去掉窗口最大化,最小化、关闭),主窗口,和子窗口之间的设置
    Application.Title与Application.MainFormOnTaskbar之间的关系
    DELPHI用户登录窗口框架
    Element 1.2.7 发布,饿了么 Vue 2.0 组件库
    用Delphi实现网络视频编程
    甘超波:NLP是什么?
    OpenCV使用filter2D实现图像对比度提升
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3240851.html
Copyright © 2011-2022 走看看