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页面功能,则按如下逻辑返回:
如果Request的http header "accept"包含"text/html",先找public路径下的404.html,如果存在则返回404.html的内容。
如果启用View引擎,并且views目录下存在404.html,则解析模板404.html返回。
如果Request的http header "accept"包含"text/plain",并且public路径下存在的404.txt,则返回404.txt的内容。
如果上面的情况都不成立,则返回http.StatusNotFound。
开启了自定义404页面功能的方法是设置config的NotFoundPageEnable为true。设置方式见"配置"章节。
ErrorResult
func Error(message string) *ErrorResult {
return &ErrorResult{
Message: message,
}
}
ErrorResult顾名思义返回错误信息,默认返回http.StatusInternalServerError,如果你开启了自定义错误页面功能,则按如下逻辑返回:
如果Request的http header "accept"包含"text/html",先找public路径下的error.html,如果存在则返回error.html的内容。
如果启用View引擎,并且views目录下存在error.html,则解析模板error.html返回。
如果Request的http header "accept"包含"text/plain",并且public路径下存在的error.txt,则返回error.txt的内容。
如果上面的情况都不成立,则返回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\nb\nc" }}</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: 将字符串中的"\n"替换为
"<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语言Web框架gwk介绍2的更多相关文章
- Go语言Web框架gwk介绍4
Go语言Web框架gwk介绍 (四) 事件 gwk支持事件系统,但并没有硬编码有哪些事件,而是采用了比较松散的定义方式. 订阅事件有两种方式: 调用On函数或者OnFunc函数 func On(m ...
- Go语言Web框架gwk介绍 3
Go语言Web框架gwk介绍 (三) 上一篇忘了ChanResult ChanResult 可以用来模拟BigPipe,定义如下 type ChanResult struct { Wait syn ...
- Go语言Web框架gwk介绍 1
Go语言Web框架gwk介绍 (一) 今天看到Golang排名到前30名了,看来关注的人越来越多了,接下来几天详细介绍Golang一个web开发框架GWK. 现在博客园支持markdown格式发布 ...
- Go语言Web框架gwk介绍 (一)
今天看到Golang排名到前30名了,看来关注的人越来越多了,接下来几天详细介绍Golang一个web开发框架GWK. 现在博客园支持markdown格式发布文章么?后台的编辑器不太好用嘛. GWK ...
- Go语言Web框架gwk介绍 (五)
Session Go的net/http本身不带session的机制,需要开发人员自行实现,gwk实现了内存中的session存储机制,如果需要将session存在其他地方比如redis或者memcac ...
- Go语言Web框架gwk介绍 (四)
事件 gwk支持事件系统,但并没有硬编码有哪些事件,而是采用了比较松散的定义方式. 订阅事件有两种方式: 调用On函数或者OnFunc函数 func On(moudle, name string, h ...
- Go语言Web框架gwk介绍 (二)
HttpResult 凡是实现了HttpResult接口的对象,都可以作为gwk返回Web客户端的内容.HttpResult接口定义非常简单,只有一个方法: type HttpResult inter ...
- Go语言Web框架gwk介绍 (三)
上一篇忘了ChanResult ChanResult 可以用来模拟BigPipe,定义如下 type ChanResult struct { Wait sync.WaitGroup Chan chan ...
- 最好的6个Go语言Web框架
原文:Top 6 web frameworks for Go as of 2017 作者:Edward Marinescu 译者:roy 译者注:本文介绍截至目前(2017年)最好的6个Go语言Web ...
随机推荐
- c/c++ 基金会(七) 功能覆盖,虚函数,纯虚函数控制
1.功能覆盖 ClassA , ClassB ,其中ClassB继承ClassA 类的定义如下面的: #ifndef _CLASSA_H #define _CLASSA_H #include < ...
- Java数据结构与算法(3) - ch04栈(栈和转置)
栈的基本特性是后进先出,最简单的用途是用于转置,还有其他诸如括号匹配,中序表达式(A+B*(C-D/(E+F)) --> ABCDEF+/-*+)和后续表达式(345+*612+/- --> ...
- java中文件的相对路径以及jar中文件的读取
Java中File类的构造函数需要我们传入一个pathname,当我们传入以"/"开头的pathname表示绝对路径,其他均表示相对路径. 一:绝对路径名:是完整的路径名,不需要任 ...
- uploadfiy 动态传递Form 参数
参见 百度 http://jingyan.baidu.com/article/a3a3f8118b1c4d8da3eb8a60.html @{ ViewBag.Title = "Ind ...
- Asp.net MVC + EF + Spring.Net 项目实践(二)
这一篇主要介绍数据库和entity framework集成 1. 先创建数据库,很简单的几张表,但也涉及了一些主外键关系.联合主键等,关系图如下(DB脚本在最后) 2. 打开VS,现在建立Model实 ...
- MVC验证12-使用DataAnnotationsExtensions对整型、邮件、最小值、文件类型、Url地址等验证
原文:MVC验证12-使用DataAnnotationsExtensions对整型.邮件.最小值.文件类型.Url地址等验证 本文体验来自http://dataannotationsextension ...
- 认识ASP.NET MVC6
认识ASP.NET MVC6 这篇文章说明下如何在普通编辑器下面开发mvc6应用程序. 上篇文章: 十分钟轻松让你认识ASP.NET 5(MVC6) 首先安装mvc6的nuget包: 可以看到在pro ...
- [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)
原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日 ...
- css中字符换行的一些问题
-------我们在处理文章的内容的过程中由于文章内容混杂有中文.英文.数字等其他字符,而我们常见的英文和数字是无法在包裹元素中自动换行,这往往会导致元素被撑破,如下图所示: css中word-bre ...
- PCL点云库中怎样读取指定的PCD文件,又一次命名,处理后保存到指定目录
我一直想把处理后的pcd文件重命名,然后放到指定的目录,尝试了好久最终做到了: 比方我想读取 "table_scene_lms400.pcd" 把它进行滤波处理,重命名为 &qu ...