一,index.js页面
//模块一(服务模块):负责启动服务
//模块二(扩展模块):负责扩展req和res对象,为req和res增加以下更方便好用的API
//模块三(路由模块):负责路由判断
//模块四(业务模块):负责具体路由的业务代码
//模块五(数据操作模块):负责进行数据库操作
//模块六(配置模块):负责保存各种项目中用到的配置信息
//步骤:1:思考该模块要封装什么代码?2:思考这些代码有用到外部的数据吗,
//如果用到了,是否需要参数传入到模块中。3:当前模块对外需要暴露的东西(module.exports的值)
// 引入模板
var http=require('http');
var context=require('./context.js');
var router=require('./router.js');
var config=require('./config.js');
http.createServer(function(req,res){
//调用context模块,为req和res加方法。
context(req,res);
router(req,res);
}).listen(8080,function(){
console.log('服务器启动了,请访问:http://localhost:'+config.port);
});
二,contex.js页面
相关知识补充:
//核心模块,,文件模块.json .js .node ,,自定义模块(第三方)
//情况一,参数是路径 require('./index.js') ./表示js当前所在的目录 require('./index')先找js,没有找json,没有找node,
//没有然后找文件(package.json -> main入口文件app.js ->.js,.json,.node )
//情况二,参数不是路径是模块名称,先查找是否有该核心模块,若没有则找js文件所在目录下查找,若没有则一层一层往上找父目录里找
//直到磁盘根目录。
/**
// 声明一段代码的HTML文档
var html='<h2><%= name %></h2>';
//template() 函数的返回依然是个函数
var fn=_.template(html);
//fn接受一个数据对象,并用其替换html中的模板内容
html=fn({name:'达达'});
console.log(html);
**/
//模块二(扩展模块):负责扩展req和res对象,为req和res增加以下更方便好用的API
var url=require('url');
var fs=require('fs');
var mime=require('mime');
var _=require('underscore');
//让当前模块对外暴露一个函数,通过这个函数将index.js的req和res传递到当前这个模块。
module.exports=function(req,res){
var urlObj=url.parse(req.url.toLowerCase(),true);
req.method=req.method.toLowerCase();
req.query=urlObj.query;
res.pathname=urlObj.pathname;
console.log("res.pathname=urlObj.pathname:"+res.pathname);
console.log("res.method:"+res.method);
res.render=function(filename,tplData){
fs.readFile(filename,function(err,data){
if(err){
res.writeHead(404,'Not Found',{'Content-Type':'text/html;charset=utf-8'});
res.end('404,Not Found.');
return;
}
//如果用户传递了模板数据,则进行替换。
if(tplData){
var fn=_.template(data.toString('utf8'));
data=fn(tplData);
}
res.setHeader('Content-Type',mime.getType(require.url));
// 把读到的数据发送
//res 是http.ServerResponse对象
res.end(data);
});
}
}
三,router.js页面
//模块三(路由模块):负责路由判断
var url=require('url');
var path=require('path');
var handler=require('./handler.js');
module.exports=function(req,res){
if(req.url==='/' || req.url.startsWith('/index') && req.method==='get'){
handler.index(req,res);
}else if( req.url.startsWith('/list') && req.method==='get'){
handler.list(req,res);
}else if(req.url.startsWith('/login') && req.method==='get'){
handler.loginGet(req,res);
}else if(req.url.startsWith('/login') && req.method==='post'){
handler.loginPost(req,res);
}else{
handler.elseurl(req,res);
}
}
四,handler.js页面
//模块四(业务模块):负责具体路由的业务代码
var fs=require('fs');
var path=require('path');
var querystring=require('querystring');
var config=require('./config.js');
//这里的代码第一次加载该模块时会执行
//console.log(1);
//该模块负责最具体业务进行处理
module.exports.index=function(req,res){
//这里的代码每次调用该方法时会被执行
//console.log(1);
//调用函数
readNewsData(function(list_news){
res.render(path.join(__dirname,'index.html'),{list:list_news});
});
}
module.exports.list=function(req,res){
//读取相应id的内容
readNewsData(function(list_item){
for(var i=0;i<list_item.length;i++){
if(list_item[i].id.toString()=== req.query.id){
var model=list_item[i];
break;
}
}
if(model){
res.render(path.join(__dirname,'list.html'),{item:model});
}else{
res.end('No Such Item');
}
});
}
module.exports.loginGet=function(req,res){
//获取用户提交的数据,用url模块
//防止data.json文件覆盖
readNewsData(function(list){
//添加ID属性
// urlObj.query.id=list.length;
list.push(req.query);
//把数据保存到data.json文件中
writeNewsData(JSON.stringify(list),function(){
//设置响应报文头告诉浏览器进行跳转
res.statusCode=302;
res.statusMessage='Found';
res.setHeader('Location','/');
res.end();
});
});
}
module.exports.loginPost=function(req,res){
readNewsData(function(list){
postBodyData(req,function(postBody){
//添加ID属性
postBody.id=list.length+1;
list.push(postBody);
writeNewsData(JSON.stringify(list),function(){
//设置响应报文头告诉浏览器进行跳转
res.statusCode=302;
res.statusMessage='Found';
res.setHeader('Location','/');
res.end();
});
});
});
}
module.exports.elseurl=function(req,res){
//当url没有query请求字符串,可以直接跳转
res.render(path.join(__dirname,req.url));
}
//封装一个写入data.json文件的函数
function writeNewsData(data,callback){
fs.writeFile(config.dataPath,data,function(err){
if(err){
throw err;
}
//调用callback来执行当写入数据完毕后的操作,可能不同
callback();
});
}
//封装一个读取data.json文件的函数
function readNewsData(callback){
fs.readFile(config.dataPath,'utf8',function(err,data){
//第一次读取文件不存在,则排除报错ENOENT
if(err && err.code!= 'ENOENT'){throw err;}
var list=JSON.parse(data || '[]');
callback(list);
//函数内部有异步函数,需要本函数有一个回掉函数callback参数,来读取异步数据,然后传递出去
});
}
//封装一个获取用户post提交的数据的方法
function postBodyData(req,callback){
//把数据保存到data.json文件中
// post提交数据会分多次,因此需要监听request事件的data事件,当request的end事件被调用
// 表示数据提交接受完成。监听事件用on
var array=[];//保存用户每次提交的数据
req.on('data',function(chunk){
//chunk 参数,是浏览器提交的一部分数据,类型为Buffer
array.push(chunk);
});
req.on('end',function(){
//监听end事件,把array中的数据汇总,并转换为字符串
var postBody=Buffer.concat(array).toString('utf8');
// 把查询字符串转换为JSON对象eg:title=fffff&url=ndskjc&text=fcdsv
//如果是JSON类型的字符串(eg:{title:'fffff',url:'ndskjc',text:'fcdsv'})转为JSON对象用JSON.parse()方法
postBody=querystring.parse(postBody);
callback(postBody);
});
}
五,config.js页面
//模块六(配置模块):负责保存各种项目中用到的配置信息
var path=require('path');
module.exports={
"port":8080,
"dataPath":path.json(__dirname,'data','data.json')
};