一、express 框架
express是什么?
express是node的一个框架,使用框架可以快速开发服务端程序,处理客户端请求;让后端代码更加清晰
使用 express
1. 安装express
npm install express --save
2. 导入express
let express = require('express');let bodyParser = require('body-parser');
3. 使用express创建server
let app = express();
4. 使用中间件
app.use(express.static(__dirname)); // 静态资源服务app.use(bodyParser.json()); // 解析POST请求的数据,并且挂载到req的body上
5 配置路由 (接口)
- get请求
 
app.get('/login', function (req, res) {console.log(req.query);res.send(req.headers);});
- post请求
 
app.post('/register', function (req, res) {console.log(req.body);res.send({code: 0,data: {},msg: 'ok'})});
- 无论get还是post请求都会执行
 
app.all('/api/xyz', function (req, res) {console.log('请求来了');});
5. 监听端口号
app.listen(8000, () => console.log('启动成功'));
二、CRM系统
需求:
- 该系统有一个列表页,列表中每一行是一条数据;该列表需要从服务端动态获取,然后渲染到页面中;
 - 在列表上方有一个新增按钮,点击新增跳转到新增页面,在新增页面输入表单中的值,点击保存会自动把数据存到数据库中,如果保存成功则跳回列表页,失败alert提示;
 - 在列表中每一行都有一个修改按钮,点击修改跳到修改页面,进入修改页面后要回填原有的数据;点击保存后,把修改后的数据保存到数据库中,如果保存成功则跳转到首页,如果失败则alert提示;
 - 列表中每一行有一个删除按钮,点击删除时弹出confirme框,如果点击确定时则删除这条数据,点击取消则不动作;删除成功后刷新列表;
 
列表首页 index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="/static/css/index.css"></head><body><div class="box1"><a href="/modify.html">增加新客户</a><h4 class="head"><span class="w50">编号</span><span class="w150">姓名</span><span class="w50">年龄</span><span class="w200">电话</span><span class="w200">地址</span><span class="w150">操作</span></h4><ul class="list" id="list"><li><span class="w50">1</span><span class="w150">2</span><span class="w50">3</span><span class="w200">电话</span><span class="w200">地址</span><span class="w150"><a href="/modify.html">修改</a><a href="javascript: void 0;">删除</a></span></li><li><span class="w50">1</span><span class="w150">2</span><span class="w50">3</span><span class="w200">电话</span><span class="w200">地址</span><span class="w150">操作</span></li><li><span class="w50">1</span><span class="w150">2</span><span class="w50">3</span><span class="w200">电话</span><span class="w200">地址</span><span class="w150">操作</span></li></ul></div><script src="/static/js/axios.js"></script><script src="/static/js/index.js"></script></body></html>
新增、修改页面 modify.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="static/css/modify.css"></head><body><div class="box2"><div><span>姓名</span><input type="text" id="username"></div><div><span>年龄</span><input type="text" id="age"></div><div><span>电话</span><input type="text" id="phone"></div><div><span>地址</span><input type="text" id="address"></div><div class="submit" id="submit">提交</div></div><script src="/static/js/axios.js"></script><script src="/static/js/modify.js"></script></body></html>
客户端index.js
let list = document.getElementById('list');function bindHTML(data) {let str = ``;data.forEach(({id, name, age, phone, address}) => {str += `<li><span class="w50">${id}</span><span class="w150">${name}</span><span class="w50">${age}</span><span class="w200">${phone}</span><span class="w200">${address}</span><span class="w150"><a href="/modify.html?id=${id}">修改</a><a href="javascript: void 0;" type="del" data-id="${id}">删除</a></span></li>`});list.innerHTML = str;}axios.get('/api/getList').then(({data}) => {if (data.code === 0) {bindHTML(data.data)}});list.onclick = function (e) {if (e.target.nodeName.toUpperCase() === 'A' && e.target.getAttribute('type') === 'del') {let id = e.target.getAttribute('data-id');let isDel =confirm(`您要删除id为${id}的用户吗`)if (isDel) {axios.get(`/api/removeInfo?id=${id}`).then(({data}) => {if (data.code === 0) {window.location.href = '/'}})}}};
修改/新增 modify.js
let isModify = /\?id=(\d+)/.exec(location.search);let $ = selector => document.querySelector(selector);let submit = $('.submit');let name = $('#username');let age = $('#age');let phone = $('#phone');let address = $('#address');// 如果是修改,首先根据id获取数据if (isModify) {let [,id] = isModify;axios.get(`/api/getInfo?id=${id}`).then(({data}) => {if (data.code === 0) {name.value = data.data.name;age.value = data.data.age;phone.value = data.data.phone;address.value = data.data.address;} else {alert(data.msg)}});}submit.onclick = function () {let params = {name: name.value,age: age.value,phone: phone.value,address: address.value};let api = ''if (isModify) {let [,id] = isModify;params.id = +id;api = '/api/updateInfo'} else {api = '/api/addInfo'}axios.post(api, params).then(({data}) => {if (data.code === 0) {window.location.href = '/'} else {alert(data.msg)}});};
服务器端 server.js
let http = require('http');let fs = require('fs');let url = require('url');let mime = require('mime');let server = http.createServer((req, res) => {let urlObj = url.parse(req.url, true);let {pathname, query} = urlObj;// 静态资源服务if (pathname === '/' || /(\.\w+)$/.test(pathname)) {let filePath = '';let contentType = '';if (pathname === '/') {filePath = __dirname + '/index.html';contentType = 'text/html';} else {filePath = __dirname + pathname;contentType = mime.getType(pathname)}fs.readFile(filePath, (err, data) => {if (err) {res.statusCode = 404;res.end(`${pathname} is not found`)} else {res.end(data);}})} else {// 处理ajax接口res.setHeader('Content-Type', 'application/json;charset=UTF-8;');let database = __dirname + '/database/custom.json'; // 数据文件路径let response = {code: 0,data: null,msg: 'ok'};// 获取列表if (pathname === '/api/getList') {let con = JSON.parse(fs.readFileSync(database, 'utf8'));response.data = con;res.end(JSON.stringify(response)); // 服务端不能直接把对象直接响应去,需要对象转成json格式的字符串;}// 2. 删除数据if (pathname === '/api/removeInfo') {let arr = JSON.parse(fs.readFileSync(database, 'utf8'));let result = arr.find(item => +item.id === +query.id);if (result) {arr = arr.filter(item => +item.id !== +query.id);fs.writeFileSync(database, JSON.stringify(arr));res.end(JSON.stringify(response));} else {response.code = 1;response.msg = `id为${query.id}的客户不存在`;res.end(JSON.stringify(response))}}// 3. 新增客户if (pathname === '/api/addInfo') {// 接收客户端post过来的数据// 如何接收POST的数据呢?// POST的请求数据量一般比较大,客户端会把数据切段,然后一段一段的传过来,每传过来一次就会触发一次data事件,当最后一段发送完会触发一次end事件let str = '';req.on('data', (chunk) => {// 监听data事件,接收数据str += chunk;});req.on('end', () => {let curCustom = JSON.parse(str);// 先读取出来,然后写入;let con = JSON.parse(fs.readFileSync(database, 'utf8'));// 为新增的数据生成一个id,如果之前的数据为空,那么这个id为1,如果不为空,那么这个id应该为数据的之前最后一条数据的id + 1con.length? curCustom.id = con[con.length - 1].id + 1: curCustom.id = 1;con.push(curCustom);fs.writeFileSync(database, JSON.stringify(con), 'utf8');res.end(JSON.stringify(response));})}// 4. 获取某个客户的信息if (pathname === '/api/getInfo') {// 根据客户端传递的id,从数据库中查出指定id的用户的信息let con = JSON.parse(fs.readFileSync(database, 'utf8'));let result = con.find(item => +item.id === +query.id);if (result) {response.data = result;res.end(JSON.stringify(response))} else {response.code = 1;response.msg = `id为${query.id}的用户不存在`;res.end(JSON.stringify(response))}}// 5. 修改客户信息if (pathname === '/api/updateInfo') {let str = '';req.on('data', (chunk) => str += chunk);req.on('end', () => {let curData = JSON.parse(str);let con = JSON.parse(fs.readFileSync(database, 'utf8'));let curIndex = con.findIndex(item => +item.id === +curData.id);console.log(curIndex);if (curIndex > -1) {con[curIndex] = curData;fs.writeFileSync(database, JSON.stringify(con), 'utf8');res.end(JSON.stringify(response))} else {response.code = 1;response.msg = `id为${curData.id}用户不存在`;res.end(JSON.stringify(response));}})}}});server.listen(8001, () => console.log('port 8001 is on'));
package.json
{"name": "crm","version": "1.0.0","description": "","main": "server.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "node server.js"},"author": "","license": "ISC","dependencies": {"axios": "^0.19.0","mime": "^2.4.4"}}
【发上等愿,结中等缘,享下等福,择高处立,寻平处住,向宽处行】
