1.准备工作:
新建一个文件夹mybook
准备一个入口文件:index.js
初始化该项目:npm init -y
安装需要的依赖的包:
npm install express --save npm install art-template --save //第三方中间件:模板引擎 npm install body-parser --save //对参数的处理,主要用于处理post参数 npm install express-art-template --save
2.功能模块:
主要功能为:
*添加图书
*修改图书
*删除图书
将数据存储在json文件中,通过路由的路径分发功能实现对不同页面的处理
目录结构如下:
前端页面都存放在views目录下,注意views目录下的文件后缀都要改成(.art)取决于你设置模板引擎时的后缀。
index.js是入口文件。
data.json用来存放图书的数据。
router.js是将路由模块的功能单独抽取出来作为一个独立的功能模块。
services.js是将router.js中的回调函数功能全部抽取出来作为业务处理的功能模块。
test目录下的功能是将data.json的数据转换为sql的insert语句,方便以后将数据转移到数据库中使用。
入口文件index.js:
/** * 图书管理功能-入口文件 */ const express = require('express'); const tempalte = require('art-template'); const bodyParser = require('body-parser'); const path = require('path'); const router = require('./router.js'); const app = express(); //启动静态啊资源服务 app.use('/www',express.static('./public')); //设置模板引擎 //1.设置模板的路径:设定views变量,意为视图存放的目录 app.set('views',path.join(__dirname,'views')); //2.设置模板引擎:后缀名为art app.set('view engine','art'); //3.使express兼容art-template app.engine('art',require('express-art-template')); //处理请求参数 //挂载参数处理中间件 app.use(bodyParser.urlencoded({extended:false})); //处理json格式的参数 app.use(bodyParser.json()); //启动服务器功能:1.配置路由 2.监听端口 //配置路由 app.use(router); //监听端口 app.listen(3000,()=>{ console.log('running...'); });
路由模块router.js:
/** * 路由模块 */ const express = require('express'); const router = express.Router(); const service = require('./service.js'); //路由处理:通过路由绑定路径 //渲染主页 //'/'表示根目录 router.get('/',service.showIndex); //添加图书:跳转到添加图书的页面 //跳转到虚拟路径:http://localhost:3000/toAddBook router.get('/toAddBook',service.toAddBook); //添加图书:提交表单 router.post('/addBook',service.addBook); //跳转到编辑图书信息页面:跳转页面用get就可以 router.get('/toEditBook',service.toEditBook); //编辑图书提交表单:修改页面用post提交 router.post('/editBook',service.editBook); //删除图书信息 router.get('/deleteBook',service.deleteBook); //必须导出,否则在index页面使用不了 module.exports = router;
业务模块services.js:
/** * 业务模块 */ const data = require('./data.json'); const path = require('path'); const fs = require('fs'); //自动生成图书编号(自增) let maxBookCode = () => { let arr = []; data.forEach(item => { arr.push(item.id); }); return Math.max.apply(null,arr); } //把内存数据写入到文件 let writeDataFile = (res) => { //需要把内存中的数据写入文件 //JSON.stringify(data)仅传data一个参数的话,data.json文件是压缩形式的 fs.writeFile(path.join(__dirname,'data.json'),JSON.stringify(data,null,4),(err) => { if(err){ res.send('server err'); } //文件写入成功之后重新跳转到主页面 res.redirect('/'); }); } //渲染主页面 exports.showIndex = (req,res) => { res.render('index',{list:data}); } //跳转到添加图书的页面 exports.toAddBook = (req,res) => { //render将会根据views中的模板文件进行渲染,渲染的是空对象{} res.render('addBook',{}); } //添加图书保存数据 exports.addBook = (req,res) => { //获取表单数据 let info = req.body; let book = {}; for (const key in info) { book[key] = info[key]; } book.id = maxBookCode()+1; data.push(book); //需要把内存中的数据写入文件 writeDataFile(res); } //跳转到编辑页面 exports.toEditBook = (req,res) => { let id = req.query.id; let book = null; data.forEach((item)=>{ if(id == item.id){ book = item; //break; //forEach循环中不能有break,用return终结即可 return; } }); //render将会根据views中的模板文件进行渲染,渲染的是对应图书的完整信息 res.render('editBook',book); } //编辑图书更新数据: //1.先查询出对应的数据并渲染到页面上 //2.然后再提交表单,再重新保存,写入文件 //编辑的时候要告诉服务器编辑的是哪条数据 exports.editBook = (req,res) => { //获取表单的数据 let info = req.body; data.forEach((item)=>{ if(info.id == item.id){ for (const key in infp) { item[key] = info[key]; } return; } }); //需要把内存中的数据写入文件 writeDataFile(res); } //删除图书信息 exports.deleteBook = (req,res) => { //先获取到传过来的id let id = req.query.id; data.forEach((item,index)=>{ if(item.id == id){ //删除数组的一项数据 data.splice(index,1); } return; }); //需要把内存中的数据写入文件 writeDataFile(res); }
数据文件data.json:
[ { "id": "1", "name": "三国演义", "author": "罗贯中", "category": "文学", "desc": "一个杀伐纷争的年代" }, { "id": "2", "name": "水浒传", "author": "施耐庵", "category": "文学", "desc": "108条好汉的故事" }, { "id": "3", "name": "西游记", "author": "吴承恩", "category": "文学", "desc": "佛教与道教的斗争" }, { "id": "4", "name": "红楼梦", "author": "曹雪芹", "category": "文学", "desc": "一个封建王朝的缩影" }, { "name": "明朝那些事", "author": "当年明月", "category": "文学", "desc": "明朝的历史", "id": 5 } ]
图书管理页面index.art:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>图书管理功能</title> <link rel="stylesheet" type="text/css" href="/www/style.css"> </head> <body> <div class="title">图书管理功能<a href="/toAddBook">添加图书</a></div> <div class="content"> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th>编号</th> <th>名称</th> <th>作者</th> <th>分类</th> <th>描述</th> <th>操作</th> </tr> </thead> <tbody> {{each list}} <tr> <td>{{$value.id}}</td> <td>{{$value.name}}</td> <td>{{$value.author}}</td> <td>{{$value.category}}</td> <td>{{$value.desc}}</td> <td><a href="/toEditBook?id={{$value.id}}">修改</a>|<a href="/deleteBook?id={{$value.id}}">删除</a></td> </tr> {{/each}} </tbody> </table> </div> </body> </html>
添加图书页面addBook.art:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>添加图书</title> </head> <body> <form action="/addBook" method="post"> 名称:<input type="text" name="name"><br> 作者:<input type="text" name="author"><br> 分类:<input type="text" name="category"><br> 描述:<input type="text" name="desc"><br> <input type="submit" value="提交"><br> </form> </body> </html>
修改图书页面editBook.art:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>修改图书</title> </head> <body> <form action="/addBook" method="post"> <input type="hidden" name="id" value="{{id}}"> 名称:<input type="text" name="name" value="{{name}}"><br> 作者:<input type="text" name="author" value="{{author}}"><br> 分类:<input type="text" name="category" value="{{category}}"><br> 描述:<input type="text" name="desc" value="{{desc}}"><br> <input type="submit" value="提交"><br> </form> </body> </html>
样式表:style.css
.title{ text-align: center; background-color: lightblue; height: 50px; line-height: 50px; font-size: 24px; } .content{ background-color: lightgray; border-right: 1px solid blanchedalmond; border-bottom: 1px solid blanchedalmond; } .content table{ width: 100%; text-align: center; } .content th,td{ border-left: 1px solid blanchedalmond; border-top: 1px solid blanchedalmond; height: 40px; line-height: 40px; }
初始化sql语句文件initsql.js:
/** * 把data.js文件中的数据拼接成insert语句 */ const path = require('path'); const fs = require('fs'); fs.readFile(path.join(__dirname,'../data.json'),'utf8',(err,content) => { if(err) return; let list = JSON.parse(content); let arr = []; list.forEach(item => { //字符串拼接,用反引号 let sql = `insert into book(name,author,category,description) VALUES('${item.name}','${item.author}','${item.category}','${item.desc}');` //获取的只是一条sql语句,依此将sql语句存入数组中 arr.push(sql); }); fs.writeFile(path.join(__dirname,'data.sql'),arr.join(' '),'utf8',(err) => { console.log('init data finished!'); }); });
3.功能展示: