04_02.用node做增,查,删的项目

1. 模块化

模块化

2. 第三方包

第三方包

npm i -S art-template
npm i -S bootstrap
npm i -S formidable
npm i -S jquery

3. 代码区

app.js

/*
 * @Author: Robyn 
 * @Date: 2017-10-31 19:43:28 
 * @Last Modified by:   Robyn 
 * @Last Modified time: 2017-10-31 19:43:28 
 */

//开启服务器
//核心 
var http = require("http");


//自定义
var render = require("./render.js");
var router = require("./router.js");

var server = http.createServer();

server.on("request",function(req,res){
    
    //在res中注册一个render方法
    render(res);

    //为下面代码的执行铺路:下面需要接收路径,根据不同的路径作出不同的处理,我们使用一个单独的模块来完成这个功能
    //这个模块我们取名叫做路由
    router(req,res);
});

server.listen(3000,function(){
    console.log("running");
});

handler.js

/*
 * @Author: Robyn 
 * @Date: 2017-10-31 19:44:19 
 * @Last Modified by:   Robyn 
 * @Last Modified time: 2017-10-31 19:44:19 
 */


//负责处理具体的事物

var fs = require("fs");
var url = require("url");

//第三方
var formidable = require("formidable");

//自定义模块
var modules = require("./modules.js");


module.exports.getIndex = function(req,res){
    //封装读取静态文件的代码
    // fs.readFile("./data.json",function(err,herosData){
    //     if(err) {
    //         return res.end("失败");
    //     }
    //     res.render("index.html",JSON.parse(herosData.toString()),function(err,html){
    //         if(err) {
    //             return res.end("失败");
    //         } 
    //         res.end(html);
    //     });
    // });
    
    modules.getAll(function(err,herosData){
        if(err) {
            return res.end("失败");
        }
        //渲染
        res.render("index.html",herosData,function(err1,html){
            if(err1) {
                return res.end("失败");
            }
            res.end(html);
        });
    });
}

module.exports.getAdd = function(req,res){
    res.render("add.html",null,function(err,data){
        if(err) {
            return res.end(err);
        } 
        res.end(data);
    });
}

module.exports.postAdd = function(req,res){
    res.writeHead(200,{
        "content-type": "text/html;charset=utf-8"
    });
    // 将原来通过data和end事件接收到的参数 改为通过第三方包formidable来接收
    //创建一个formidable对象
    var form = new formidable.IncomingForm();
    // //调用parse方法
    // //回调函数的三个参数:
    // //  参数一:err:错误信息
    // //  参数二:fields  字段  从浏览器端提交到服务器的一些属性
    // //  参数三:files   文件  从浏览器端上传过来的文件
    // //  由于formidable会将图片自动保存到一个临时目录下,而我们需要将图片保存到img下,所以需要设置一个图片的保存路径
    // form.uploadDir = "./img";
    // //  由于formidable默认不会保存文件的后缀名,所以我们需要将图片留后缀名
    // form.keepExtensions = true;
    form.parse(req, function(err, fields, files) {
        if(err) {
            return res.end(retMsg(1,"失败"));
        }
        //新增对象
        modules.add(fields,function(err){
            res.end(retMsg());
        });
        
        // fs.readFile("./data.json",function(err,herosData){
        //     var heros = JSON.parse(herosData.toString());
            
        //     //根据得到的参数创建一个对象
        //     var obj = {};
        //     obj.name = fields.name;
        //     obj.gender = fields.gender;
        //     //得到heros中最后一条数据的id
        //     var id = heros.heros[heros.heros.length - 1].id + 1;
        //     obj.id = id;
        //     // obj.img = "/" + files.img.path;
        //     obj.img = fields.img;
        //     //将对象重新追倒hero中
        //     heros.heros.push(obj);
        //     //重新将对象写入到data.json中
        //     fs.writeFile("./data.json",JSON.stringify(heros,null,"  "),function(err){
        //         if(err) {
        //             return res.end(retMsg(1,"失败"));
        //         }
        //         // res.end("<script>alert('新增成功');window.location='/'</script>");
        //         //返回的数据是交给浏览器中的异步对象的,而异步对象需要的一个json格式的字符串
        //         //将retobj对象作为返回给浏览器的数据,有这么几属性:
        //         //  statu: 表示的是当前操作的状态码:  0 成功  1 失败
        //         //  msg: 表示当前操作的 文本信息
        //         // var retObj = {
        //         //     statu: 0,
        //         //     msg: "操作成功"
        //         // };
        //         // res.end(JSON.stringify(retObj));
        //         res.end(retMsg());
        //     });
        // });
        
    })
}

module.exports.getDel = function(req,res){
    //del?id=2
    var path = req.url;
    var id =  url.parse(path,true).query.id;
    
    //得到id
    modules.del(id,function(err){
        if(err) {
            return res.end(retMsg(1,"失败"));
        }
        res.end(retMsg());
    });
}

module.exports.postUpload = function(req,res){
    var form = new formidable.IncomingForm();
    form.uploadDir = "./img";
    form.keepExtensions = true;
    form.parse(req, function(err, fields, files) {
        if(err) {
            return res.end(retMsg(1,"失败"));
        }
        var imgName = "/" + files.img.path;
        res.end(retMsg(0,"成功",imgName));
    });
}

module.exports.getStatic = function(req,res) {
    var path = "." + req.url;
    fs.readFile(path,function(err,data){
        if(err) {
            return res.end("失败");
        }
        res.end(data);
    });
}

//设置一个统一的返回对象
//  statu:返回对象的状态  0成功 1失败
//  msg:返回对象信息
//  imgName: 返回对象的图片名称
function retMsg(statu,msg,imgName) {
    var obj = {};
    obj.statu = statu || 0;
    obj.msg = msg || "成功";
    obj.imgName = imgName || "";
    //将对象转为字符串返回
    return JSON.stringify(obj);
}

modules.js

/*
 * @Author: Robyn 
 * @Date: 2017-10-31 19:45:16 
 * @Last Modified by:   Robyn 
 * @Last Modified time: 2017-10-31 19:45:16 
 */


var fs = require("fs");

//四种类型的方式:

var path =  "./data.json";

//查
//得到data.json中所有的数据
// 回调函数
//  两个参数:err,data
module.exports.getAll = function(callback){
    fs.readFile(path,function(err,data){
        if(err) {
            return callback(err);
        }
        callback(null,JSON.parse(data.toString()));
    });
}

//增
//  两个参数:
//      obj:要新增的对象(这个对象中没有id属性)
//      回调函数:
//          只有一个参数:当出现错误时的参数,如果没有错误,则没有参数
module.exports.add = function(obj,callback) {
    //1.0 先读取出data.json中的所有的数据
    this.getAll(function(err,herosData){
        if(err) {
            return callback(err);
        }
        //2.0 得到要新增的对象
        //一般新增的对象都是没有id的,所以我们需要得到id,给这个对象赋值
        var id =  herosData.heros[herosData.heros.length -1].id + 1;
        obj.id = id;
        //3.0 将新增的对象添加到对象的数组中
        herosData.heros.push(obj);
        //4.0重新将数据写入到data.json中
        fs.writeFile(path,JSON.stringify(herosData,null,"  "),function(err){
            if(err) {
                return callback(err);
            }
            callback(null);
        });
    });



}

//改


//删
module.exports.del = function(id,callback){
    //要得到要删除数据的id
    //得到所有的数据
    this.getAll(function(err,herosData){
        if(err) {
            return callback(err);
        }
        for(var i = 0 ; i < herosData.heros.length; i ++) {
            //根据id得到要删除的数据
            if(herosData.heros[i].id == id) {
                herosData.heros.splice(i,1);
                break;
            }
        }
        //重新将内容写入到data.json中
        fs.writeFile(path, JSON.stringify(herosData,null,"  "),function(err1){
            if(err1) {
                return callback(err1);
            }
            callback();
        });
    });
    
    
}

render.js

/*
 * @Author: Robyn 
 * @Date: 2017-10-31 19:45:58 
 * @Last Modified by:   Robyn 
 * @Last Modified time: 2017-10-31 19:45:58 
 */


var fs = require("fs");
var template = require("art-template");

//用来给res对象动态添加一个渲染方法
module.exports = function (res) {
    //作用:读取views下面的静态文件
    //参数一:url要读取的静态文件的名称  index.html  add.html
    //参数二:obj 要通过模板引擎渲染的数据
    //参数三:callback 给将来调用者设置一个回调函数,读取出数据以后怎么操作由调用者来决定
    //  现在callback中有两个参数:第一个参数是err,第二个参数是html
    //      由于我们将来对读取出来数据无非作这么几种处理:
    //          1)直接返回给浏览器,2)得到一个数据,将数据通过模板引擎进行渲染,渲染以后再返回给浏览器 
    res.render = function (url,obj,callback) {
        //将url转换为可以读取内容的路径
        var path = "./views/" + url;
        fs.readFile(path,function(err,data){
            if(err) {
                return callback(err);
            }
            //将数据进行渲染,并且响应到浏览器中
            var html = template.compile(data.toString())(obj || {});
            callback(null,html);
        });
    } 
}

router.js

/*
 * @Author: Robyn 
 * @Date: 2017-10-31 19:46:29 
 * @Last Modified by:   Robyn 
 * @Last Modified time: 2017-10-31 19:46:29 
 */


var handler = require("./handler.js");

//路由只是用来分发请求,得到请求的路径,并且判断路径,具体做什么事情,这个文件也不管
module.exports = function(req,res){
    //先拿到不同的请求
    var url = req.url;
    var method = req.method;
    //判断
    if(url == "/" && method == "GET") {
       handler.getIndex(req,res);
    } else if( url == "/add" && method == "GET") {
        handler.getAdd(req,res);
    } else if(url =="/upload" && method == "POST") {
        handler.postUpload(req,res);
    } else if( url == "/add" && method == "POST"){
       handler.postAdd(req,res);
    } else if( url.indexOf("/del") == 0 && method == "GET"){
        handler.getDel(req,res);
    } else if (url.indexOf("/node_modules") == 0 || url.indexOf("/img") == 0) {
        handler.getStatic(req,res);
    }
}

views下index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Hero - Admin</title>
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
  <style>
    .hero-list img {
      width: 50px;
    }
  </style>
</head>

<body>
  <header>
    <div class="page-header container">
      <h1>王者荣耀 <small>英雄管理器</small></h1>
    </div>
  </header>
  <div class="container hero-list">
    <a class="btn btn-success pull-right" href="/add">添加英雄</a>
    <table class="table table-hover">
      <thead>
        <th>编号</th>
        <th>名称</th>
        <th>性别</th>
        <th>头像</th>
        <th>操作</th>
      </thead>
      <tbody id="tbody"> 
        {{each heros}}
          <tr>
            <td>{{$value.id}}</td>
            <td>{{$value.name}}</td>
            <td>{{$value.gender}}</td>
            <td>![]({{$value.img}})</td>
            <td><a href="#">查看</a> <a href="#">修改</a> <a onclick="del({{$value.id}})" href="javascript:void(0)">删除</a></td>
          </tr>
        {{/each}}
      </tbody>
    </table>
  </div>
</body>
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script>
  function del(id) {
    if(confirm("您确定删除吗?")) {
      $.ajax({
        url: "/del",
        type: "get",
        data: "id=" + id,
        dataType: "JSON",
        success: function(result){
          if(result.statu == 0) {
             alert(result.msg);
             window.location = "/";
          } else {
            alert(result.msg);
          }
        }
      });
    }
  }
</script>
</html>

views下add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        table {
            margin: 0 auto;
            width: 500px;
            min-height: 300px;
        }
    </style>
</head>
<body>
    <form id="form" action="/add" method="POST" enctype="multipart/form-data">
        <table>
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name" id="name"></td>
                </tr>
                <tr>
                    <td>性别</td>
                    <td><input id="man" type="radio" name="gender" value="男"><label for="man">男</label> <input type="radio"  name="gender" id="woman" value="女"><label for="woman">女</label></td>
                </tr>
                <tr>
                    <td>图片</td>
                    <td><img alt="" id="preImg"><input type="file" name="img" id="img"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" id="btn" value="新增"></td>
                </tr>
            </table>
    </form>
</body>
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script>
    //实现预览功能
    $("#img").on("change",function(){
        //1.0创建一个formData对象
        var fd = new FormData();
        //2.0提供参数:
        fd.append("img",document.getElementById("img").files[0]);

        //一旦选择了图片,我们需要将图片上传到服务器
        //为了不影响页面的正常运行,需要异步上传
        $.ajax({
            url: "/upload",
            type: "POST",
            data: fd,
            //告诉jquery不要验证我们fd中的参数的类型
            contentType: false,  
            //告诉jquery不要检查fd中提交的参数
            processData: false,  
            dataType: "JSON",
            success: function(result){
                if(result.statu == "0") {
                    //将返回的图片名称设置给img标签
                    $("#preImg").attr("src",result.imgName);
                } else {
                    alert(result.msg);
                    window.location = window.location;
                }
            }
        });
    });


    // 如果使用异步方式来提交新增的数据,jquery中的ajax方法会默认将提交数据的方式设置为
    // 与:enctype="application/x-www-form-urlencoded"      
    $("#btn").on("click",function(e){
        //在h5中为了能够更好的提交上传的参数,所以不能够使用form的serialize方法来序列化参数
        //可以用formdata来帮助我们上传参数
        //1.0创建一个formData对象
        var fd = new FormData();
        //2.0将要提交到服务器的参数添加到formData对象
        //append方法要传入两个参数:键值对象
        fd.append("name",$("#name").val());
        fd.append("gender",$("input[type=radio]:checked").val());
        // //document.getElementById("img").files[0]:得到上传过来的图片文件
        // fd.append("img",document.getElementById("img").files[0]);
        fd.append("img",$("#preImg").attr("src"));

        //阻止默认事件
        e.preventDefault();
        $.ajax({
            url: "add",
            type: "POST",
            // data: $("#form").serialize(),
            //关闭jquery内容的检查功能
            //告诉jquery不要验证我们fd中的参数的类型
            contentType: false,  
            //告诉jquery不要检查fd中提交的参数
            processData: false,  
            data: fd,
            dataType: "JSON",
            success: function(result){
                if(result.statu == 0) {
                    alert(result.msg);
                    window.location = "/";//跳转到/
                } else {
                    alert(result.msg);
                    window.location = window.location;//表示刷新当前页面
                }
            }
        });
    })
</script>
</html>

add-同步上传.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        table {
            margin: 0 auto;
            width: 500px;
            height: 300px;
        }
    </style>
</head>
<body>
    <form action="/add" method="POST" enctype="multipart/form-data">
        <table>
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name"></td>
                </tr>
                <tr>
                    <td>性别</td>
                    <td><input id="man" type="radio" name="gender" value="男"><label for="man">男</label> <input type="radio"  name="gender" id="woman" value="女"><label for="woman">女</label></td>
                </tr>
                <tr>
                    <td>图片</td>
                    <td><input type="file" name="img"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="新增"></td>
                </tr>
            </table>
    </form>
</body>
</html>

data.json

{
  "heros": [
    {
      "id": 3,
      "name": "安奇拉",
      "gender": "女",
      "img": "/img/3.jpg"
    },
    {
      "id": 4,
      "name": "虞姬",
      "gender": "女",
      "img": "/img/4.jpg"
    },
    {
      "name": "李白",
      "gender": "女",
      "id": 5,
      "img": "/img\\upload_b1ec223563a3a4691e3835e5695bd412.JPG"
    }
  ]
}

node app.js

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容