Node.js + Express + MongoDB 实战 TodoList 基础入门
视频地址
常用链接
看视频整理要点笔记:
express
快速开始
npm init -y
默认模式生成 package.json
npm install --save express
安装框架npm install -g nodemon
方便调试,nodemon xxx
启动应用var express = require('express') var app = express() app.get('/', function (req, res) { res.send('this is homepage') }) app.listen(3000)
res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('<p>some html</p>'); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' }); res.json({ user: 'tobi' }); res.status(500).json({ error: 'message' }); req.ip // => "127.0.0.1" // GET /search?q=tobi+ferret req.query.q // => "tobi ferret" // example.com/users?sort=desc req.path // => "/users"
// http://127.0.0.1:3000/profile/1/user/able app.get('/profile/:id/user/:name', function (req, res) { console.dir(req.params) // 显示属性 { id: '1', name: 'able' } res.send("You requested " + req.params.id + req.params.name) })
app.get('/ab?cd', function (req, res) { res.send('ab?cd') })
// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order // => "desc" req.query.shoe.color // => "blue" req.query.shoe.type // => "converse"
// http://127.0.0.1:3000/?find=hot app.get('/', function (req, res) { console.dir(req.query) // => { find: 'hot' } res.send('home page: ' + req.query.find) })
使用 body-parser 包,处理 post 请求
npm install body-parser --save
安装postman 工具,用来图形化模拟浏览器发送各种请求
var bodyParser = require('body-parser') // create application/json parser var jsonParser = bodyParser.json() // 使用中间件,在请求和响应中间处理 create application/x-www-form-urlencoded parser var urlencodedParser = bodyParser.urlencoded({ extended: false }) app.post('/', urlencodedParser, function (req, res) { console.dir(req.body) res.send('ok') }) app.post('/upload', jsonParser, function (req, res) { console.dir(req.body) res.send('ok') })
Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files.
安装 npm install --save multer
上传文件的表单需要指定 enctype="multipart/form-data"
postman 上传文件,post body form-data
// form.html <form action="/upload" method="post" enctype="multipart/form-data"> <h2>上传logo图片</h2> <input type="file" name="logo"> <input type="submit" value="提交"> </form>
// 创建目录,上传文件 var createFolder = function (folder) { try { fs.accessSync(folder); } catch (e) { fs.mkdirSync(folder); } }; var uploadFolder = './upload/'; createFolder(uploadFolder); var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, uploadFolder); }, filename: function (req, file, cb) { cb(null, file.originalname); } }); var upload = multer({ storage: storage }); app.get('/form', function (req, res) { var form = fs.readFileSync('./form.html', { encoding: "utf8" }) res.send(form) }) app.post('/upload', upload.single('logo'), function (req, res) { console.dir(req.file); // 列出文件的所有属性 res.send({ 'ret_code': 0 }) })
res.sendFile(__dirname + '/form.html')
响应网页app.get('/form', function (req, res) { // var form = fs.readFileSync('./form.html', { encoding: "utf8" }) // res.send(form) res.sendFile(__dirname + '/form.html') })
npm install ejs --save
.ejs
%> Plain ending tag
app.get('/form/:name', function (req, res) { var person = req.params.name res.render('form', { person: person }) }) // views/form.ejs <h1><%= person %></h1> // http://127.0.0.1:3000/form/able // 输出 able
app.get('/form/:name', function (req, res) { // var person = req.params.name var person = { age: 29, job: 'CEO', hobbies: ['eating', 'coding', 'finshing']} res.render('form', { person: person }) }) app.get('/about', function (req, res) { // var person = req.params.name res.render('about') })
<%- include('particals/header.ejs') -%> // 引用模版 <h1><%= person %></h1> <h1><%= person.age %></h1> <h2>hobbies</h2> <ul> //遍历数组 <% person.hobbies.forEach(function(item){ %> <li> <%= item %> </li> <% }) %> </ul>
中间件作用
// 没有路径的中间件函数, 每次收到请求时执行该函数。 app.use(function (req, res, next) { console.log('first middleware') next() // 没有响应请求,需要将控制权传递给下一个中间件函数 console.log('first middleware after next') }) // 安装在某个路径的中间件函数 app.use('/m', function (req, res, next) { console.log('second middleware') res.send('ok') }) // app.get('/m', function (req, res, next) { // res.send('ok') // })
app.use(express.static('public'));
指定静态资源根目录app.use('static', express.static('public'));
前缀目录static/a.png// server.js var indexRouter = require('./routes/index') var usersRouter = require('./routes/users') app.use('/', indexRouter) app.use('/users', usersRouter) // users.js var express = require('express') var router = express.Router() // 这里注意,因为前面路由匹配到/users了,这里直接时根即可,二级目录 router.get('/', function (req, res, next) { res.send('users') }) module.exports = router
npm init -y
初始化 package.jsonnpm install --save express body-parser ejs
安装包controllers
文件夹,单独存放控制器//app.js var express = require('express') var todoController = require('./controllers/todoController') var app = express() app.set('view engine', 'ejs') // 指定public目录下为静态文件根目录 app.use(express.static('public')) todoController(app) app.listen(3000) console.log('listening to port 3000') // todoController.js module.exports = function (app) { app.get('/todo', function (req, res) { }) app.post('/todo', function (req, res) { }) app.delete('/todo', function (req, res) { }) }
新建 views
文件夹,存放模版页面,todo.ejs
使用 BootCDN 在线免费 jQuery 库
https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js
body-parser
处理 post 请求ajax
异步处理提交和删除// 显示添加表单和取出内容 <div id="todo-table"> <form action=""> <input type="text" name="item" placeholder="Add new item..." required /> <button type="submit">ADD Item</button> </form> <ul> <% todos.forEach(function (todo) { %> <li><%= todo.item %></li> <% }) %> </ul> </div>
var bodyParser = require('body-parser') var urlencodeParser = bodyParser.urlencoded({ extended: false}) var data = [{item: 'get milk'}, {item: 'walk dog'}, {item: 'coding a'}] module.exports = function (app) { app.get('/todo', function (req, res) { res.render('todo', { todos: data }) }) app.post('/todo', urlencodeParser, function (req, res) { data.push(req.body) res.json(data) // 回复结束响应,可以回复其它的 }) app.delete('/todo/:item', function (req, res) { data = data.filter(function (todo) { // 返回为true的内容 return todo.item.replace(/ /g, "-") !== req.params.item }) res.json(data) console.log(data) }) }
// ajax 处理点击提交 和 删除,异步处理 $(document).ready(function() { $('form').on('submit', function(event) { event.preventDefault(); var item = $('form input'); var todo = { item: item.val().trim() }; $.ajax({ type: 'POST', url: '/todo', data: todo, success: function(data) { //do something with the data via front-end framework location.reload(); } }); return false; }); $('li').on('click', function() { var item = $(this).text().trim().replace(/ /g, "-"); $.ajax({ type: 'DELETE', url: '/todo/' + item, success: function(data) { //do something with the data via front-end framework location.reload(); } }); }); });
使用 MongoDB 持久化数据
使用线上免费 MongoDB 数据库 mLab
mongo ds020208.mlab.com:20208/todos -u <dbuser> -p <dbpassword>
mongodb://<dbuser>:<dbpassword>@ds020208.mlab.com:20208/todos
npm install mongoose --save
const mongoose = require('mongoose') mongoose.connect('mongodb://able8:xx@ds020208.mlab.com:20208/todos') // Schema 模式,规定数据类型 var todoSchema = new mongoose.Schema({ item: String // 字段名,字符串 }) //对应数据库中的表 var Todo = mongoose.model('Todo', todoSchema) // 添加一条数据 var itemOne = Todo({ item: 'buy flowers'}).save(function (err) { if (err) throw err console.log('item saved') })
app.get('/todo', function (req, res) { Todo.find({}, function (err, data) { if (err) throw err res.render('todo', { todos: data }) }) }) app.post('/todo', urlencodeParser, function (req, res) { var itemOne = Todo(req.body).save(function (err, data) { if (err) throw err res.json(data) }) }) app.delete('/todo/:item', function (req, res) { // data = data.filter(function (todo) { // 返回为true的内容 // return todo.item.replace(/ /g, "-") !== req.params.item // }) Todo.find({item: req.params.item.replace(/ /g, '-')}).remove(function (err, data) { if (err) throw err res.json(data) }) })