Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx

上传人:b****1 文档编号:3313322 上传时间:2023-05-01 格式:DOCX 页数:13 大小:269.03KB
下载 相关 举报
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第1页
第1页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第2页
第2页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第3页
第3页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第4页
第4页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第5页
第5页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第6页
第6页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第7页
第7页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第8页
第8页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第9页
第9页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第10页
第10页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第11页
第11页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第12页
第12页 / 共13页
Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx

《Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx》由会员分享,可在线阅读,更多相关《Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx(13页珍藏版)》请在冰点文库上搜索。

Nodejs实现一个简单的WebMVC框架我要看明白的第一个mvcWord格式.docx

http.createServer(function(req,res){res.writeHead(200,{'

Content-Type'

:

'

text/plain'

});

res.end('

HelloWorld\n'

}).listen(8124,"

"

console.log('

Serverrunningat.1:

8124/'

  require类似于C#的using、Python的import,用于导入模块(module)。

node使用的是CommonJS的模块系统。

http.createServer的参数为一个函数,每当有新的请求进来的时候,就会触发这个函数。

最后就是绑定要监听的端口。

  怎么运行?

  当然,是先安装node.js啦。

到,支持Linux、Mac,也支持windows下的Cygwin。

具体的安装说明见:

装好node后,就可以运行我们的helloworld了:

  $nodehello_world.jsServerrunningat.1:

8124/

  编程习惯的改变?

  我们来写一个读取文件内容的脚本:

  //output_me.jsvarfs=require('

fs'

),fileContent='

nothing'

;

fs.readFile(__filename,"

utf-8"

function(err,file){if(err){console.log(err);

return;

}fileContent=file;

endreadfile\n'

});

doSomethingWithFile:

+fileContent+'

\n'

  这个脚本读取当前文件的内容并输出。

__filename是node的一个全局变量,值为当前文件的绝对路径。

我们执行这个脚本看一下:

  有没发现结果不对呢?

打印的fileContent并不是读取到的文件内容,而是初始化的时候赋值的nothing,并且‘endreadfile’最后才打印出来。

前面我们提到node的一个特性就是非阻塞IO,而readFile就是异步非阻塞读取文件内容的,所以后面的代码并不会等到文件内容读取完了再执行。

请谨记node的异步非阻塞IO特性。

所以我们需要将上面的代码修改为如下就能正常工作了:

//对于file的处理放到回调函数这里处理console.log('

我们先去喝杯茶\n'

  写个WebMVC框架试试

  下面我们用node来写一个小玩具:

一个WebMVC框架。

这个小玩具我称它为n2Mvc,它的代码结构看起来大概如下:

  和helloworld一样,我们需要一个http的服务器来处理所有进来的请求:

),querystring=require("

querystring"

exports.runServer=function(port){port=port||8080;

varserver=http.createServer(function(req,res){var_postData='

'

//on用于添加一个监听函数到一个特定的事件req.on('

data'

function(chunk){_postData+=chunk;

}).on('

end'

function(){req.post=querystring.parse(_postData);

handlerRequest(req,res);

}).listen(port);

+port+'

/'

};

  这里定义了一个runServer的方法来启动我们的n2Mvc的服务器。

有没注意到runServer前面有个exports?

这个exports相当于C#中的publish,在用require导入这个模块的时候,runServer可以被访问到。

我们写一个脚本来演示下node的模块导入系统:

  //moduleExample.jsvarmyPrivate='

艳照,藏着'

exports.myPublish='

冠西的相机'

this.myPublish2='

this也可以哦'

moduleExample.jsloaded\n'

  执行结果:

  从结果中我们可以看出exports和this下的变量在外部导入模块后,可以被外部访问到,而var定义的变量只能在脚本内部访问。

从结果我们还可以看出,第二次require导入moduleExample模块的时候,并没有打印“moduleExample.jsloaded”,因为require导入模块的时候,会先从require.cache中检查模块是否已经加载,如果没有加载,才会从硬盘中查找模块脚本并加载。

require支持相对路径查找模块,例如上面代码中require(‘./moduleExample’)中的“./”就代表在当前目录下查找。

如果不是相当路径,例如require(‘http’),node则会到require.paths中去查找,例如我的系统require.paths为:

  当require(‘http’)的时候,node的查找路径为:

  1、/home/qleelulu/.node_modules/http2、/home/qleelulu/.node_modules/http.js3、/home/qleelulu/.node_modules/http.node4、/home/qleelulu/.node_modules/http/index.js5、/home/qleelulu/.node_modules/http/index.node6、/home/qleelulu/.node_libraries/http7、/home/qleelulu/.node_libraries/http.js8、参考前面

  再看回前面的代码,http.createServer中的回调函数中的request注册了两个事件,前面提到过node的一个特点是事件驱动的,所以这种事件绑定你会到处看到(想想jQuery的事件绑定?

例如$(‘a’).click(fn))。

关于node的事件我们在后面再细说。

request对象的data事件会在接收客户端post上来的数据时候触发,而end事件则会在最后触发。

所以我们在data事件里面处理接收到的数据(例如post过来的form表单数据),在end事件里面通过handlerRequest函数来统一处理所有的请求并分发给相应的controlleraction处理。

handlerRequest的代码如下:

  varroute=require('

./route'

varhandlerRequest=function(req,res){//通过route来获取controller和action信息varactionInfo=route.getActionInfo(req.url,req.method);

//如果route中有匹配的action,则分发给对应的actionif(actionInfo.action){//假设controller都放到当前目录的controllers目录里面,还记得require是怎么搜索module的么?

varcontroller=require('

./controllers/'

+actionInfo.controller);

//./controllers/blogif(controller[actionInfo.action]){varct=newcontrollerContext(req,res);

//动态调用,动态语言就是方便啊//通过apply将controller的上下文对象传递给actioncontroller[actionInfo.action].apply(ct,actionInfo.args);

}else{handler500(req,res,'

Error:

controller"

+actionInfo.controller+'

withoutaction"

+actionInfo.action+'

)}}else{//如果route没有匹配到,则当作静态文件处理staticFileServer(req,res);

}};

  这里导入来一个route模块,route根据请求的url等信息去获取获取controller和action的信息,如果获取到,则通过动态调用调用action方法,如果没有匹配的action信息,则作为静态文件处理。

下面是route模块的代码:

  varparseURL=require('

url'

).parse;

//根据http请求的method来分别保存route规则varroutes={get:

[],post:

[],head:

[],put:

[],delete:

[]};

/***注册route规则*示例:

*route.map({*method:

post'

*url:

/\/blog\/post\/(\d+)\/?

$/i,*controller:

blog'

*action:

showBlogPost'

*})*/exports.map=function(dict){if(dict&

&

dict.url&

dict.controller){varmethod=dict.method?

:

get'

routes[method].push({u:

dict.url,//url匹配正则c:

dict.controller,a:

dict.action||'

index'

exports.getActionInfo=function(url,method){varr={controller:

null,action:

null,args:

null},method=method?

method.toLowerCase():

//url:

/blog/index?

page=1,则pathname为:

/blog/indexpathname=parseURL(url).pathname;

varm_routes=routes[method];

for(variinm_routes){//正则匹配r.args=m_routes[i].u.exec(pathname);

if(r.args){r.controller=m_routes[i].c;

r.action=m_routes[i].a;

;

//第一个值为匹配到的整个url,去掉break;

}}//如果匹配到route,r大概是{controller:

action:

args:

['

1'

]}returnr;

  map方法用于注册路由规则,我们新建一个config.js的文件,来配置route规则:

  //config.jsvarroute=require('

route.map({method:

url:

/\/blog\/?

$/i,controller:

  如果请求的url有匹配的route规则,则会返回controller和action信息。

例如上面的route配置,当访问/blog这个url的时候,则会调用./controllers/blog.js模块里面的index函数。

当调用action的时候,会传递controllerContext给acation:

  varct=newcontrollerContext(req,res);

  这里会通过apply将controllerContext作为action的this,并传递args作为action的参数来调用action。

ontrollerContext封装了一些action会用到的方法:

  //controller的上下文对象varcontrollerContext=function(req,res){this.req=req;

this.res=res;

this.handler404=handler404;

this.handler500=handler500;

=function(viewName,context){viewEngine.render(this.req,this.res,viewName,context);

=function(json){viewEngine.renderJson(this.req,this.res,json);

  在action中处理完逻辑获取获取到用户需要的数据后,就要呈现给用户。

这就需要viewEngine来处理了。

ViewEngine的代码如下:

  varviewEngine={render:

function(req,res,viewName,context){varfilename=path.join(__dirname,'

views'

viewName);

try{varoutput=Shotenjin.renderView(filename,context);

}catch(err){handler500(req,res,err);

}res.writeHead(200,{'

text/html'

res.end(output);

},renderJson:

function(res,json){//TODO:

  这里viewEngine主要负责模板解析。

node有很多的可用的模块,模板解析模块也有一大堆,不过这里我们是要“玩”,所以模板解析系统我们这里使用jstenjin来稍作修改:

  //shotenjin.js增加的代码//模板缓存,缓存解析后的模板Shotenjin.templateCatch={};

//读取模板内容//在模板中引用模板使用:

{#../layout.html#}Shotenjin.getTemplateStr=function(filename){//console.log('

gettemplate:

+filename);

vart='

//这里使用的是同步读取if(path.existsSync(filename)){t=fs.readFileSync(filename,'

utf-8'

}else{throw'

View:

+filename+'

notexists'

}t=t.replace(/\{#[\s]*([\.\/\w\-]+)[\s]*#\}/ig,function(m,g1){varfp=path.join(filename,g1.trim())returnShotenjin.getTemplateStr(fp);

returnt;

Shotenjin.renderView=function(viewPath,context){vartemplate=Shotenjin.templateCatch[viewPath];

if(!

template){vartemplate_str=Shotenjin.getTemplateStr(viewPath);

vartemplate=newShotenjin.Template();

template.convert(template_str);

//添加到缓存中Shotenjin.templateCatch[viewPath]=template;

}varoutput=template.render(context);

returnoutput;

global.Shotenjin=Shotenjin;

  增加的代码主要是读取模板的内容,并解析模板中类似{#../layout.html#}的标签,递归读取所有的模板内容,然后调用jstenjin的方法来解析模板。

这里读取文件内容使用的是fs.readFileSync,这是同步阻塞读取文件内容的,和我们平时使用的大多编程语言一样,而fs.readFile的非阻塞异步读。

这里的shotenjin.js原来是给客户端web浏览器javascript解析模板用的,现在拿到node.js来用,完全不用修改就正常工作。

GoogleV8真威武。

现在基本的东西都完成了,但是对于静态文件,例如js、css等我们需要一个静态文件服务器:

  varstaticFileServer=function(req,res,filePath){if(!

filePath){filePath=path.join(__dirname,config.staticFileDir,url.parse(req.url).pathname);

}path.exists(filePath,function(exists){if(!

exists){handler404(req,res);

}fs.readFile(filePath,"

binary"

function(err,file){if(err){handler500(req,res,err);

}varext=path.extname(filePath);

ext=ext?

ext.slice

(1):

html'

res.writeHead(200,{'

contentTypes[ext]||'

res.write(file,"

res.end();

varcontentTypes={"

aiff"

"

audio/x-aiff"

"

arj"

application/x-arj-compressed"

//省略}

  简单来说就是读取文件内容并写入到response中返回给客户端。

现在该有的都有了,我们写一个action:

  //./controllers/blog.jsexports.index=function(){this.render('

blog/index.html'

{msg:

HelloWorld'

  blog/index.html的内容为:

  {#../../header.html#}

n2MvcDemo

#{msg}

{#../../footer.html#}

  接着,就是写一个脚本来启动我们的n2Mvc了:

  //run.jsvarn2MvcServer=require('

./server'

n2MvcServer.runServer();

  ok,运行我们的启动脚本:

在浏览器访问看看:

  嗯嗯,一切正常。

好,接下来我们再写一个获取新浪微博最新微博的页面。

首先,我们在config.js中增加一个route配置:

  route.map({method:

/\/tweets\/?

tweets'

  然后开始写我们的cnotrolleraction:

),events=require("

events"

vartsina_client=http.createClient(80,"

vartweets_emitter=newevents.EventEmitter();

//action:

tweetsexports.tweets=function(blogType){var_t=this;

varlistener=tweets_emitter.once("

tweets"

function(tweets){_t.render('

blog/tweets.html'

{tweets:

tweets});

get_tw

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2