node实现基于文件管理的增删改实例

要点:

       1、初步体会node基于模块化的编程思想,在node中,模块之间的互不影响,模块与模块之间只有通过module.exports(node为了减少开发人员代码,默认添加一句 var exports = module.export)才能实现数据的共享。

      2、自定义模块时,尽量做到一个模块处理一个功能,同时写的鲁棒性越强,越好。

      3、最重要的:在函数进行异步操作时,想要获取函数中的值,必须通过回调函数才能获取到。如果想要对函数中的方法的值进行操作,在回调函数中处理。在这个例子中如果回调函数发生错误直接返回错误对象,也不需要进行数据类型的转变,如果正确获取到数据,前一个参数设置为null,后一个参数是返回的数据,既可与错误的返回做区分,也可以返回数据,中间通过逗号隔开,这是现阶段第一种理解。

            另外在一种理解是,函数作为参数使用,在调用时输入了一个函数,这个函数就是需要拿到回调函数进行处理的函数,对函数相关的异步操作成功或者失败两种不同的结果,调用两次回调函数传入不同的数据,一种是错误对象,另一种是(null,data)两个参数,第一个参数返回null的错误对象。

           这里去掉过第一个参数null,程序运行失败,第二种理解的null的理解不太正确。另外,将正确的callback回调函数前添加return是正确执行的,第一种的理解应该较正确但是不透彻。

      4、为了使路由更加简洁直观,通过 express.Router()创建一个路由容器,再将路由挂载到路由容器对象上,最后通过 server.use(router)将路由容器挂载到node创建的服务上。

效果:

依赖:

{
  "name": "crub-expre",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "art-template": "^4.13.2",
    "body-parser": "^1.18.3",
    "bootstrap": "^3.3.7",
    "express": "^4.16.4",
    "express-art-template": "^1.0.1"
  }
}

node入口:

var express = require('express')
var fs = require('fs')
var bodyParser = require('body-parser')

var router = require('./router.js')
// 引入自定义的将路由模块化的包

var app = express()

app.use('/node_modules/',express.static('./node_modules/'))
// 开放固定文件夹资源,前一项参数是监听的url,是否有这段字符,后一个参数是监听对应的文件夹
app.use('/public/',express.static('./public/'))

app.engine('html',require('express-art-template'))

app.use(bodyParser.urlencoded({ extended:false }))
app.use(bodyParser.json())
// 模板引擎的配置和body-parser一定要在将路由模块挂载到服务之前


app.use(router)
// 将router容器挂载到node创建的服务器上

app.listen(3000,function(){
	console.log('succeed')
})

路由模块:

var fs = require('fs')
// 核心模块只要在所在的模块中被使用了,就需要重新引入

var express = require('express')
var Shuaiges = require('./shuaiges.js')
// 引入帅哥文件夹的操作模块

var router = express.Router()
// 创建一个express的路由容器


router.get('/',function(req,res){

	Shuaiges.find(function(err,shuaiges){
		if(err){
			return res.status(500).send('not find file')
			// 返回的状态码500,表示出错
		}
		res.render('index.html',{
			// 在express框架中,默认在views中寻找文件
			shuaiges:shuaiges
		})
	})
})
// 将路由都挂载到router容器上

router.get('/shuaiges/new',function(req,res){
	res.render('new.html')
	
})

router.post('/shuaiges/new',function(req,res){
    Shuaiges.save(req.body,function(err){
    	if(err){
    		return res.status(500).send('save fail')
    	}
    	res.redirect('/')
    	// 成功跳到首页
    })
})
router.get('/shuaiges/edit',function(req,res){
	Shuaiges.findById(parseInt(req.query.id),function(err,shuaige){
		// query中的查询字符串需要转换成数字类型,跟定义的时候相同
		if(err){
           return res.status(500).send('can not edit file')
		}
		res.render('edit.html',{
			shuaige:shuaige
		})

	})

})
router.post('/shuaiges/edit',function(req,res){

    Shuaiges.updata(req.body,function(err){
    	if(err){
    		return res.status(500).send('updata fail')
    	}
    	res.redirect('/')
    })
})

router.get('/shuaiges/delete',function(req,res){

	Shuaiges.delete(req.query.id,function(err){
		if(err){
			return res.status(500).send('delete fail')
		}
		res.redirect('/')
	})

})

module.exports = router




帅哥文件操作模块:

var fs = require('fs')
// 引入文件读取核心模块,这个自定义文件模块,封装操作shuaiges.json的方法,做到类似数据库

filePath = './shuaiDb.json'
// 这里路径就是用来存放帅哥的文件夹

exports.find = function(callback){
	fs.readFile(filePath,function(err,data){
		if(err){
			return callback(err)
			// 读取失败,中止代码执行,并返回错误对象
		}
        callback(null,JSON.parse(data).shuaiges)
        // 当错误时,返回错误对象,正确时错误返回null,并且返回数据数组两个信息

        // callback回调函数是自定义的,需要区分回调函数返回的数据还是错误信息,如果直接传入
        // data无法与前面的err作区分,这里还是需要前面定义一个参数null,既可以作区分,又没有实际数值
	})
}

exports.findById = function(id,callback){
	fs.readFile(filePath,function(err,data){
		if(err){
			return callback(err)
		}

		var shuaiges = JSON.parse(data).shuaiges

        var shuaige = shuaiges.find(function(item){
        	return item.id === parseInt(id)
        	// .find()是es6方法,遍历数组并返回符合find内传入方法的条件的值
        })
		callback(null,shuaige)
	})
}

exports.save = function(shuaige,callback){
	fs.readFile(filePath,function(err,data){
		if(err){
			return callback(err)
		}
		var shuaiges = JSON.parse(data).shuaiges
		// 将二进制数据转为对象,并操作内部的shuaiges数组

        shuaige.id = shuaiges[shuaiges.length -1].id + 1
        // 为每个添加进来的帅哥添加一个不重复的id

		shuaiges.push(shuaige)
		// 将post提交过来的shuaige对象,添加进对象之中数组

		var strData = JSON.stringify({
			shuaiges:shuaiges
		})
		// 将shuaiges对象再转换成字符串类型,为了写入文件

		fs.writeFile(filePath,strData,function(err){
            if(err){
            	return callback(err)
            	// 写入文件失败,返回错误对象
            }
            callback(null)
            // 写入成功,返回空的错误对象
		})
	})

}

exports.updata = function(shuaige,callback){
	fs.readFile(filePath,function(err,data){
		if(err){
			return callback(err)
		}

		var shuaiges = JSON.parse(data).shuaiges

		shuaige.id = parseInt(shuaige.id)
		// 存入时,将存入string形式的id改为data类型,防止数据类型不一致造成的问题

		var shuaigeOld = shuaiges.find(function(item){
			return item.id === parseInt(shuaige.id)
		})
		// .find()是es6方法,遍历数组并返回符合find内传入方法的条件的值

		for(var key in shuaige){
            shuaigeOld[key] = shuaige[key]
            // 将查询到的shuaige对象替换成新的对象
		}

	    var strData = JSON.stringify({
			shuaiges:shuaiges
		})
		// 将shuaiges对象再转换成字符串类型,为了写入文件

		fs.writeFile(filePath,strData,function(err){
            if(err){
            	return callback(err)
            }
            callback(null)
		})
	})
}

exports.delete = function(id,callback){
	fs.readFile(filePath,function(err,data){
		if(err){
			return callback(err)
		}
		
		var shuaiges = JSON.parse(data).shuaiges

		var deleteId = shuaiges.findIndex (function(item){
			return item.id === parseInt(id)
		})

		shuaiges.splice(deleteId,1)
		// es6语法,前一位指定开始的位置,后一位指定删除的长度

        var strData = JSON.stringify({
			shuaiges:shuaiges
		})

		fs.writeFile(filePath,strData,function(err){
			if(err){
				return callback(err)
			}
			callback(null)
		})


	})

}

主页:


<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../favicon.ico">

    <title>Dashboard Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link href="/public/css/dashboard.css" rel="stylesheet">

  </head>

  <body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Project name</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Dashboard</a></li>
            <li><a href="#">Settings</a></li>
            <li><a href="#">Profile</a></li>
            <li><a href="#">Help</a></li>
          </ul>
          <form class="navbar-form navbar-right">
            <input type="text" class="form-control" placeholder="Search...">
          </form>
        </div>
      </div>
    </nav>

    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Reports</a></li>
            <li><a href="#">Analytics</a></li>
            <li><a href="#">Export</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item</a></li>
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
            <li><a href="">More navigation</a></li>
          </ul>
          <ul class="nav nav-sidebar">
            <li><a href="">Nav item again</a></li>
            <li><a href="">One more nav</a></li>
            <li><a href="">Another nav item</a></li>
          </ul>
        </div>
     
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
          <h1 class="page-header">Dashboard</h1>
          <div class="row placeholders">
            {{ each fruits }}
            <div class="col-xs-6 col-sm-3 placeholder">
              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
              <h4>{{ $value }}</h4>
              <span class="text-muted">Something else</span>
            </div>
            {{ /each }}
          </div>
          <h2 class="sub-header">Section title</h2>
          <a class="btn btn-success" href="/shuaiges/new">添加学生</a>
          <div class="table-responsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>#</th>
                  <th>姓名</th>
                  <th>qq</th>
                </tr>
              </thead>
              <tbody>
                {{ each shuaiges }}
                <tr>
                  <td>{{ $value.id }}</td>
                  <td>{{ $value.name }}</td>
                  <td>{{ $value.qq }}</td>
                  <td>
                    <a href="/shuaiges/edit?id={{ $value.id }}">修改</a>
                    <a href="/shuaiges/delete?id={{ $value.id }}">删除</a>
                    <!-- url的路径,发出get方式的请求,结合模板引擎 -->
                  </td>
                </tr>
                {{ /each }}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

编辑:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
  <meta name="description" content="">
  <meta name="author" content="">
  <link rel="icon" href="../../favicon.ico">
  <title>Dashboard Template for Bootstrap</title>
  <!-- Bootstrap core CSS -->
  <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Custom styles for this template -->
  <link href="/public/css/main.css" rel="stylesheet">
</head>

<body>
  <nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="#">Project name</a>
      </div>
      <div id="navbar" class="navbar-collapse collapse">
        <ul class="nav navbar-nav navbar-right">
          <li><a href="#">Dashboard</a></li>
          <li><a href="#">Settings</a></li>
          <li><a href="#">Profile</a></li>
          <li><a href="#">Help</a></li>
        </ul>
        <form class="navbar-form navbar-right">
          <input type="text" class="form-control" placeholder="Search...">
        </form>
      </div>
    </div>
  </nav>
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-3 col-md-2 sidebar">
        <ul class="nav nav-sidebar">
          <li class="active"><a href="/shuaiges">学生管理 <span class="sr-only">(current)</span></a></li>
          <li><a href="#">Reports</a></li>
          <li><a href="#">Analytics</a></li>
          <li><a href="#">Export</a></li>
        </ul>
        <ul class="nav nav-sidebar">
          <li><a href="">Nav item</a></li>
          <li><a href="">Nav item again</a></li>
          <li><a href="">One more nav</a></li>
          <li><a href="">Another nav item</a></li>
          <li><a href="">More navigation</a></li>
        </ul>
        <ul class="nav nav-sidebar">
          <li><a href="">Nav item again</a></li>
          <li><a href="">One more nav</a></li>
          <li><a href="">Another nav item</a></li>
        </ul>
      </div>
      <div class="col-sm-offset-3 col-md-offset-2 main">
        <h2 class="sub-header">添加学生</h2>
        <form action="/shuaiges/edit" method="post">
          <!-- 
            用来放一些不希望被用户看见,但是需要被提交到服务端的数据
           -->
          <input type="hidden" name="id" value="{{ shuaige.id }}">
          <div class="form-group">
            <label for="">姓名</label>
            <input type="text" class="form-control" id="" name="name" required minlength="2" maxlength="10" value="{{ shuaige.name }}">
          </div>
          <div class="form-group">
            <label for="">qq</label>
            <input class="form-control" type="number" id="" name="qq" value="{{ shuaige.qq }}" required minlength="2" maxlength="10">
          </div>
          <button type="submit" class="btn btn-default">提交</button>
        </form>
      </div>
    </div>
  </div>
</body>

</html>

添加:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
  <meta name="description" content="">
  <title>Dashboard Template for Bootstrap</title>
  <!-- Bootstrap core CSS -->
  <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Custom styles for this template -->
  <link href="/public/css/main.css" rel="stylesheet">
</head>

<body>
  <nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="#">Project name</a>
      </div>
      <div id="navbar" class="navbar-collapse collapse">
        <ul class="nav navbar-nav navbar-right">
          <li><a href="#">Dashboard</a></li>
          <li><a href="#">Settings</a></li>
          <li><a href="#">Profile</a></li>
          <li><a href="#">Help</a></li>
        </ul>
        <form class="navbar-form navbar-right">
          <input type="text" class="form-control" placeholder="Search...">
        </form>
      </div>
    </div>
  </nav>
  <div class="container-fluid">
    <div class="row">
      <div class="col-sm-3 col-md-2 sidebar">
        <!-- <ul class="nav nav-sidebar">
          <li class="active"><a href="/shuaiges">学生管理 <span class="sr-only">(current)</span></a></li>
          <li><a href="#">Reports</a></li>
          <li><a href="#">Analytics</a></li>
          <li><a href="#">Export</a></li>
        </ul> -->
        <ul class="nav nav-sidebar">
          <li><a href="">Nav item</a></li>
          <li><a href="">Nav item again</a></li>
          <li><a href="">One more nav</a></li>
          <li><a href="">Another nav item</a></li>
          <li><a href="">More navigation</a></li>
        </ul>
        <ul class="nav nav-sidebar">
          <li><a href="">Nav item again</a></li>
          <li><a href="">One more nav</a></li>
          <li><a href="">Another nav item</a></li>
        </ul>
      </div>
      <div class=" col-sm-offset-3  col-md-offset-2 main">
        <h2 class="sub-header">添加帅仔</h2>
        <form action="/shuaiges/new" method="post">
          <div class="form-group">
            <label for="">姓名</label>
            <input type="text" class="form-control" name="name" required minlength="2" maxlength="10">
          </div>
          <div class="form-group">
            <label for="">qq</label>
            <input class="form-control" type="number" id="" name="qq" required minlength="5" minlength="15">
          </div>
          <button type="submit" class="btn btn-default">提交</button>
        </form>
      </div>
    </div>
  </div>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/qq_42036616/article/details/84886652
今日推荐