没有合适的资源?快使用搜索试试~ 我知道了~
第2节: Package选择与修改第3节: 依赖注入第2章: 永远的MVC第1节: 永远的MVC第2节: 常见的方法第3章: 面向对象和并发第1节: 面向对象第
资源详情
资源评论
资源推荐
![](https://csdnimg.cn/release/download_crawler_static/86286061/bg1.jpg)
(Martini版本版本)老版本点击这里
GoBlogInAction中文名Go语言博客实践语言博客实践.是对TypePress开发过程中的想法,方法,探讨等任何方面同步整理成的电子书.
作者:喻恒春
第1章: 选择Martini框架
第1节: 为什么是Martini
第2节: Package选择与修改
第3节: 依赖注入
第2章: 永远的MVC
第1节: 永远的MVC
第2节: 常见的方法
第3节: TypePress的方法
第3章: 面向对象和并发
第1节: 面向对象
第2节: 并发下维护上下文
第3节: Martini下的并发
第4章: 服务器裸奔
第1节: 配置基本参数
第2节: 基本功能
第3节: 模块化
第5章: 静态博客 未完待续,穿插解析器部分
第6章: 解析器与舞台剧
第1节: 汤姆的故事
第2节: PEG
第7章: 解析器与ABNF
第1节: ABNF
第2节: 四则运算表达式
第3节: 解析器
第4节: 手工至上
第8章: Rivet
第1节: Router
第2节: Rivet
第3节: Module
除特别声明外,本书使用CCBY-SA3.0License(创作共用署名-相同方式共享3.0许可协议)授权。
===============
在上一版Go语言博客实践中,作者提到不使用框架来完成一个Blog系统.现在选择Martini作为基础框架确实和Martini设计的
独特性有关.Martini的核心Injector实现了依赖注入(参见控制反转).
这里有两篇博客可供参考Martini的工作方式和Martini中的Handler.
简单的说Injector通过reflect削弱了合作对象间引用依赖.
对于Martini的使用可以简单总结为:
Martini对象方法Map/MapTo/Use/Handlers/Action非并发安全,服务器运行前使用.
Router对象也是非并发安全的,服务器运行前使用.
Go语言博客实践语言博客实践
目录目录
授权许可授权许可
![](https://csdnimg.cn/release/download_crawler_static/86286061/bg2.jpg)
Context对象是在httpRequest时动态创建的.
所有要使用的对象必须先Map/MapTo.
对http.ResponseWriter任何的Write都会完结响应.内部方法是终止了响应Handler.
善用Context对象的Next方法会产生奇效.
上一版本因为不能找到“解耦”的框架而放弃使用框架.Martini在Injector的支持下为”解耦”提供了可能.这正是笔者希望的.
Martini社区martini-contrib
Martini社区贡献的package,可能会使用一些.如果您研究了Martini和这些contribpackage,您会发现真的解耦了.
角色控制accessflags
角色控制是应用中的常见需求,accessflags基于Martini实现了一个通过interger标记值控制Martini.Handler是否允许
访问.可以用于角色控制.(已被社区收录)
配置文件支持tom-toml
笔者重新写了一个TOML解析器tom-toml,参见文章有关tom-toml的一些事儿,和第六章的内容.
数据库操作typepress/db
upper.io/db是gosexy/db的重构版本.代码质量很高.但是包路径问题同样给import造成了问题.为方便,笔者fork了一个
github版本typepress/db.
upper.io/db为常见的SQL/NoSQL数据库提供了统一的调用接口,这是非常难能可贵的.
日志支持typepress/log
typepress/log学习了uniqush/log的一些好想法重新构建的.
typepress/log支持日志分割,并实现了一个file日志,一个email日志.
template模板
可能会有几个备选版本martini-contrib中有render,笔者写有template.
国际化支持i18n
这是一个简洁的i18n支持接口,仿照fmt.Sprint,fmt.Sprintf的形式.
在使用中即便暂时没有国际化支持的需求,使用i18n所带来的消耗也是极小的.完全可以当作fmt.Sprint,fmt.Sprintf使用.
Martini的核心就是实现依赖注入,高度解耦.依据依赖注入的思路,上述的package被替换掉应该不是一件复杂的事情.随时引入
依赖注入也应该很容易.也许吧,实践中我会关注这个事情.
========
MVC是对软件软件系统三个基础部分的描述,就好像冯·诺伊曼结构或者哈佛结构对计算机体系结构的定义.MVC是客观存在的,是
事实.
无论你的代码中是否显示的使用了MVC的方法,她都存在.
无论你的代码是否显示的遵循MVC的方法,她都存在.
无论你的代码是否违背了公认的MVC方法,她都存在.
总之只要你写代码,无论你怎么写,她都存在.
对于一个运算表达式:
a:=b+c
又或者对于一个函数:
Package选择与修改选择与修改
依赖注入依赖注入
![](https://csdnimg.cn/release/download_crawler_static/86286061/bg3.jpg)
funcFoo(b,cinterface{})(ainterface{}){
//函数主体,完成的就是控制了
}
a就是view
”+”就是controller
b,c就是model
MVC在心中在心中
开发者通常会这么做:
类型声明,包含 Controller 这个词
文件名,包含 Controller 这个词
目录名,包含 Controller 这个词
在名称上显示出来是好方法.这增强了代码可读性,一目了然.
当然如果目录名已经用了 Controller 了,目录之下的文件或者类型声明是否有必要再加上 Controller ,语言不同,习惯不同,并没有定
式.Go语言一向提倡能省则省能省则省.
依据MVC目录看起来是这个样子
├───conf
├───controllers//这里面因归属关系又嵌套了N层
│└───something
├───models
└───views
├───login
└───signup
典型的树状结构树状结构增强了代码可读性,是常见MVC目录组织形式.
能保有树状代码目录结构无疑有助于管理维护.基于MartiniInjector风格下,对象间的依赖被降低,对象依赖关系不必遵循树状结
构,目录结构也不必保持树状.这在很多时候会更灵活,同时这也是一种不常见的方法,TypePress将尝试使用一些.
意思是尽量降低目录曾经深度,视觉上不显示依赖关系.事实上这类似于组件独立化.
如果代码是辅助性的,例如服务器端的Handler,那就表现为独立的Rep.如果可以分组,例如浏览器前端组件,那就在同一个Rep下
做扁平目录.
实验性实验性想法,目的是给应用生成工具提供基础支持.
对于具体应用,比如博客,业务层面的控制器,多具有层级关系.其中还涉及角色控制和httpRequestMethod.用
martini.Router写起来像这样
router.Get("/profile",roleAllow("Admin"),youHandler)
如果用自动注册路由写起来像这样
常见的方法常见的方法
TypePress的方法的方法
扁平目录扁平目录
自动注册路由自动注册路由
![](https://csdnimg.cn/release/download_crawler_static/86286061/bg4.jpg)
core.AutoRouter(youHandler)
前提是要把path,method,role写到文件路径里.对应上面的例子,完整的运行期路径写起来有这样几种
github.com/UserName/RepName/Admin/GET/profile.go
github.com/UserName/RepName/Admin/GET.profile.go
github.com/UserName/RepName/Admin.GET.profile.go
都是能被识别的写法,依据大小写和”/“,”.“作为分割符号实现自动注册路由是可能的.
由此设计出自动构建/装配工具就有了基础.TypePress将尝试这种方式将尝试这种方式.
========
OOP的思想,无疑是非常实用有效的.事实是,无论语言是否直接支持面向对象的编程.程序员在写代码的时候常常会应用OOP的思
想.
Go语言下没有类(Class),没有构造函数,没有 this 指针,没有多态,只有复合对象(或匿名属性).复合对象和继承是完全不同的.在
以后的文字中,继承这个词不再代表一般OOP下的继承,指的是复合对象.
应用OOP的思想,WEB应用下控制器常见形式祖先类型的示意写法(现实中没有太大意义).
//定义基础控制器结构
typeBaseControllerstruct{
Datainterface{}//应用要维护的数据
Req*http.Request//请求对象
Reshttp.ResponseWriter//响应对象
}
//官方net/http包要求实现的接口
func(p*BaseController)ServeHTTP(whttp.ResponseWriter,r*http.Request){
p.Req=r//保存起来供实例使用
p.Res=w
ifr.Method=="POST"{
p.Post()
}
}
//对应httpPOST方式
func(p*BaseController)Post(){
//继承者必须覆盖这个方法,否则认为不允许POST访问
//BaseController是不可能知道继承者要做什么,那就只能返回403拒绝访问
p.Res.WriteHeader(403)
}
//Login控制器
typeLoginstruct{
BaseController//匿名复合
}
//这里必须覆盖BaseController.Post,以实现Login的具体行为
func(p*Login)Post(){
ifp.Req.Form.Get("login_name")==""{
p.Data="无效的登录名"
return
}
//这里省略登录成功的过程
p.Data="登录成功"
}
//把这些行为定义成接口
typeControllerinterface{
ServeHTTP(http.ResponseWriter,*http.Request)
Post()
}
用例
http.Handle("/login",&Login{})
![](https://csdnimg.cn/release/download_crawler_static/86286061/bg5.jpg)
但是这有并发问题但是这有并发问题
很明显现实中这样的用法是错误的,因为WEB的请求是并发并发的,这样写所有并发的请求都由同一个 &Login{} 去处理响应,
Req , Res , Data 在并发中都被指向相同的对象.这是无法正常工作的.这就是常说的维护上下文,Context.
并发环境每一个请求都要有维护独占数据的能力并发环境每一个请求都要有维护独占数据的能力.除非没有独占数据要维护.
先重新审视官方包server.go中的代码
typeHandlerinterface{
ServeHTTP(ResponseWriter,*Request)
}
funcHandle(patternstring,handlerHandler){DefaultServeMux.Handle(pattern,handler)}
funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
DefaultServeMux.HandleFunc(pattern,handler)
}
func(mux*ServeMux)HandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
mux.Handle(pattern,HandlerFunc(handler))//进行了转换,只是为了符合接口要求
}
typeHandlerFuncfunc(ResponseWriter,*Request)//确实没有独占数据要维护
//ServeHTTPcallsf(w,r).
func(fHandlerFunc)ServeHTTP(wResponseWriter,r*Request){
f(w,r)
}
这个 http.Handler 接口其实只是被当作一个函数使用了.并发问题留给使用者自己解决.
可以这样做
http.HandleFunc("/login",func(whttp.ResponseWriter,r*http.Request){
p:=&Login{}
p.ServeHTTP(w,r)
})
每次请求都有新的 Login 对象产生.当然这个写法很生硬,如果有100个控制器,难道还要写100个不同的写法?!可以采用下面的方
法.
不用结构体直接使用函数,所有上下文维护都在函数内部定义成局部变量,局部变量在函数内部是独占的.
funcmain(){
http.HandleFunc("/login",login)
}
funclogin(whttp.ResponseWriter,r*http.Request){
//维护的数据是局部变量
vardatainterface{}
varpost=func(){//用闭包函数访问局部变量
ifr.Form.Get("login_name")==""{
data="无效的登录名"
return
}
data="登录成功"
}
post()
}
并发下维护上下文并发下维护上下文
函数法函数法
剩余20页未读,继续阅读
![7z](https://img-home.csdnimg.cn/images/20210720083312.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pptx](https://img-home.csdnimg.cn/images/20210720083543.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![docx](https://img-home.csdnimg.cn/images/20210720083331.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![avatar](https://profile-avatar.csdnimg.cn/8ff05e040e0d4ecd83ad77ebfb8904ca_weixin_35817939.jpg!1)
咖啡碎冰冰
- 粉丝: 14
- 资源: 292
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![voice](https://csdnimg.cn/release/downloadcmsfe/public/img/voice.245cc511.png)
![center-task](https://csdnimg.cn/release/downloadcmsfe/public/img/center-task.c2eda91a.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![dialog-icon](https://csdnimg.cn/release/downloadcmsfe/public/img/green-success.6a4acb44.png)
评论0