Node.js项目总结—Express框架


项目要实现的功能: 使用Express实现一个简单的数据管理系统

1.项目构建

1.1 使用npm初始化项目

npm init提供了项目初始化的功能,也解决了多个包的管理问题。

终端命令:npm init

初始化后的json文件

{
  "name": "chaldea",//项目名
  "version": "1.1.10",//版本号
  "description": "人理存续保障机构菲尼斯·迦勒底,简称人理保障机构迦勒底或迦勒底。",//项目描述信息
  "main": "index.js",//入口文件
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {//git地址
    "type": "git",
    "url": "https://github.com/Sherlock-Homles?tab=repositories"
  },
  "keywords": [//关键字
    "servant"
  ],
  "author": "竹川夏目",//作者
  "license": "ISC",//当前项目的协议
  "dependencies": {//引入的第三方模块管理
    "art-template": "^4.13.2",
    "cookie-session": "^2.0.0-beta.3",
    "express": "^4.16.4",
    "express-art-template": "^1.0.1",
    "formidable": "^1.2.1",
    "jquery": "^3.3.1",
    "moment": "^2.23.0",
    "mysql": "^2.16.0"
  }
}

注意:package.jsonpackage-lock.json 文件

如果后期开发过程中,需要项目迁移,我们只需要将package.json文件迁移即可,在新项目下执行

npm install ,所有第三方包会自动安装。

1.2 第三方模块的加载

使用npm install+模块名 进行安装

1.3 项目目录

Node.js项目总结---Express框架

node_modules:安装的第三方模块目录

public:公共文件目录,包括静态页面引用的css,js,images文件等,其中upload为上传文件的保存目录

views:静态页面(HTML)目录

http.js:服务器模块

route.js:路由模块

business.js:业务处理模块,相当于PHP中控制器(controller)模块

db.js:数据库处理模块,相当于PHP中的模型(model)模块

#####1.4 数据表设计

servant表,存放所有的展示数据

Node.js项目总结---Express框架

master表,存放登录账号信息

Node.js项目总结---Express框架

2.具体功能实现

2.1 整合所有接口后的服务器模块和路由模块

服务器模块:http.js

//服务器模块
var express = require('express');
//引入文件操作模块
var fs = require('fs');
var app = express();
var route = require('./route');
//加载中间件
var cookieSession = require('cookie-session');
//托管静态文件
app.use(express.static('public'));
app.engine('html', require('express-art-template'));
//注册中间件---session设置
app.use(cookieSession({
    name: 'user_key', //客户端cookie的名称
    keys: ['sherlock'] //用于加密的关键字
}));
//使用导入的路由模块
app.use(route);
//设置监听接口
app.listen('2060', () => {
    console.log('请打开浏览器访问 http://localhost:2060');
});

路由模块:route.js

//设置外置路由
var express = require('express');
//引入业务模块
var business = require('./business');
var router = express.Router();
//优化路由模块
router
    .get('/', business.getall) //列表页
    .get('/getservant', business.getone) //从者信息页面
    .get('/editservant', business.upuser_get) //修改信息页面
    .post('/editpost', business.upuser_post) //修改数据到数据库
    .get('/creat', business.creat) //添加信息页面
    .post('/saveservant', business.save_post) //添加数据到数据库
    .get('/deleteservant', business.delete) //从数据库中删除数据
    .get('/login', business.login) //登录页面
    .post('/dologin', business.dologin) //登录验证数据库方法
    .get('/register', business.register) //注册页面
    .post('/doregister', business.doregister) //注册写入数据库
    .get('/logout',business.logout);// 退出登录并清除session
module.exports = router;
2.2 登录功能

实现思想: 接收html接收到的username和password,通过where(username=" "&&password=" ")在数据表中查询,查询到数据则判断登录成功,将登录信息保存到session中,未查询到则判断登录失败。

业务模块business.js

//加载模板引擎
var template = require('art-template');
var querystring = require('querystring');
//图片上传模块
var formidable = require('formidable');
var fs = require('fs');
//连接数据库模块
var db = require('./db');
template.defaults.root = './';
module.exports = {
    //加载登录页面
    login: function(req, res) {
        res.render('login.html');
    },
    //登录验证
    dologin: function(req, res) {
        var form = new formidable.IncomingForm();
        form.parse(req, function(err, fields, files) {
            //获取用户提交的数据,判断用户名密码是否正确
            //获取用户提交的数据,判断用户名密码是否正确
            //判断字段要加引号,以防止数据类型不同
            db.where('email= "' + fields.username + '" and password= "' + fields.password + '"').select_login(function(data) {
                console.log(data);
                //判断数据库中是否存在数据,存在则data为查询到的完整信息,不存在则为空。
                if (data != "") {
                    //数据正确,写入session
                    req.session.user_data = data;
                    res.send("<script>alert('登录成功!');window.location.href='/'</script>")
                } else {
                    //数据验证失败,跳转回归登录页面
                    res.send("<script>alert('登录失败,请检查用户名或密码,重新登录!');window.location.href='/login'</script>")
                }
            });
        });
    },
}

数据库模块db.js

//数据库连接模块
var mysql = require('mysql');
var connection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'root',
    password: 'root',
    port: '3306',
    database: 'chaldea'
});
module.exports = {
    that: this,
    where: function(wh) {
        this.whe = wh;
        return this;
    },
    //自定义的select_login函数,判断数据库中是否存在用户信息
    select_login: function(callback) {
        console.log(this.tables);
        if (this.whe == undefined) {
            var sql = 'select * from master';
        } else {
            var sql = 'select * from master where ' + this.whe;
        }
        console.log(sql);
        this.tables='';
        //用完后重置where条件,以免后续操作的数据重复
        this.whe = undefined;
        connection.query(sql, function(error, results, fields) {
            if (error) {
                console.log(sql);
                callback(error);
                return;
            }
            callback(results);
        });
    }
}
2.3 注册用户

**实现思想:**将html页面接收到的email和password保存到数据库数据表中。

业务模块:business.js 模块引入代码在2.2中已经写入了,接下来的代码只有具体功能实现代码。

    //加载注册页面
    register: function(req, res) {
        res.render('register.html')
    },
    //注册写入数据库
    doregister: function(req, res) {
        var data = '';
        req.on('data', function(save) {
            data += save;
        })
        //绑定post传输的数据,监听接收完成
        req.on('end', function() {
            //获取post传输的数据
            var post_data = querystring.parse(data);
            //调用数据模块保存从者信息
            db.save_register(post_data, function(data) {
                if (data != 0) {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('添加成功!');location.href='http://localhost:2060';</script>");
                } else {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('添加失败!');window.history.back(-1);</script>");
                }
            })
        })
    },

数据库模块:db.js 模块引入代码在2.2中已经写入了,接下来的代码只有具体功能实现代码。

    //自定义的save_register函数,将注册信息保存到数据库中
    save_register: function(data,callback) {
        //组装SQL语句:接收过来的为对象数据{name:'xx',rank:'xx'}
        //循环遍历对象
        var set = '';
        var key = '';
        for (k in data) {
            set += "'" + data[k] + "',";
            key += k + ",";
        }
        //去掉最后一个逗号
        set = set.slice(0, set.length - 1);
        key = key.slice(0, key.length - 1);
        var sql = 'INSERT INTO master (' + key + ') VALUES (' + set + ');';
        console.log(sql);
        connection.query(sql, function(error, sql_data) {
            console.log(sql_data);
            callback(sql_data.insertId);
        });
    }
2.3.10 注册优化:如果数据库中存在相同email字段,则提示去登陆

**优化思想:**将要注册的邮箱数据作为条件去查询数据表,如果有相同记录,则不予许注册,提示跳转登录;如果没有相同记录,则允许注册。

业务模块:business.js 只需要在业务模块添加一部分查询判断代码即可

    //注册写入数据库
    doregister: function(req, res) {
        var data = '';
        req.on('data', function(save) {
            data += save;
        })
        //绑定post传输的数据,监听接收完成
        req.on('end', function() {
            //获取post传输的数据
            var post_data = querystring.parse(data);
            //查询数据库中是否已经存在这个email
            db.where('email= "' + post_data.email + '"').select_login(function(date) {
                if (date != '') {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('电邮地址已存在,前去登录!');location.href='/login';</script>");
                } else {
                    //调用数据模块保存从者信息
                    db.save_register(post_data, function(data) {
                        if (data != 0) {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('注册成功!');location.href='/login';</script>");
                        } else {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('注册失败!');window.history.back(-1);</script>");
                        }
                    })
                }
            });
        })
    },

#####2.4 退出登录

实现思想: 点击退出按钮是,销毁session,并回到登录页面,不需要对数据库进行操作。

业务模块:buiness.js

    //退出登录,并清除session
    logout: function(req, res) {
        req.session = null;
        //清除cookie:要销毁session,只需将其设置为null。
        console.log('退出成功!');
        //跳转回登录页面
        res.send("<script>alert('成功退出迦勒底!');window.location.href='/login'</script>");
    }
2.5 展示主页

实现思路:

1.查询session中是否存在登录信息,不存在则提示登录并跳转到登录页

2.存在session信息,则展示首页

业务模块:business.js

    //获取全部数据
    getall: function(req, res) {
        //判断是否登录
        //获取并判断session
        if (req.session.user_data) {
            console.log(req.session.user_data);
            console.log(req.session.user_data[0].name);
            //利用db模块导出的方法
            db.select(function(data) {
                //利用回调函数获取数据
                res.render('servant.html', { data: data, username: req.session.user_data[0].name });
            });
        } else {
            //没有session信息,跳转到登录页
            res.send('<script>alert("请登录后查看!");window.location.href="/login";</script>')
        }

    },

数据库模块:db.js·

    //判断是否有条件传过来
	where: function(wh) {
        this.whe = wh;
        return this;
    },
	//自定义的select函数
    select: function(callback) {
        if (this.whe == undefined) {
            var sql = 'select * from servant';
        } else {
            var sql = 'select * from servant where ' + this.whe;
        }
        this.table='';
        //用完后重置where条件,以免后续操作的数据重复
        this.whe = undefined;
        connection.query(sql, function(error, results, fields) {
            if (error) {
                callback(error);
                return;
            }
            callback(results);
        });
    },
2.6 展示单个从者信息页

业务模块:business.js

    //获取单条数据
    getone: function(req, res) {
        db.where('id=' + req.query.id).select(function(data) {
            res.render('./servant_check.html', { data: data });
        });
    },

数据库模块:db.js 与展示页面的select方法相同,通过db.where方法获取到要查询的id条件,然后查询单条数据。

2.7 向数据库中添加一条从者信息

**实现思路:**这里针对图片上传,有两种实现方法:

1.没有图片上传模块:则就是简单的接受post数据并存入数据库

2.有图片上传模块:因为formidable图片上传模块可以接受表单传过来的所有数据,所以不必额外再写接收post数据的代码。

formidablenpm上的介绍:A Node.js module for parsing form data, especially file uploads.[Node.js模块,用于解析表单数据,尤其是文件上载。]

业务模块:business.js

1.没有图片上传模块时:

    //加载添加页面
    creat: function(req, res) {
        res.render('servant_creat.html');
    },
    //添加数据到数据库
    save_post: function(req, res) {
        var data = '';
        req.on('data', function(save) {
            data += save;
        })
        //绑定post传输的数据,监听接收完成
        req.on('end', function() {
            //获取post传输的数据
            var post_data = querystring.parse(data);
            //调用数据模块保存从者信息
            db.save(post_data, function(data) {
                if (data != 0) {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('添加成功!');location.href='http://localhost:2060';</script>");
                } else {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('添加失败!');window.history.back(-1);</script>");
                }
            })
        })
    },

2.有图片上传模块:

    //加载添加页面
    creat: function(req, res) {
        res.render('servant_creat.html');
    },
    //添加数据到数据库
    save_post: function(req, res) {
        //图片上传
        var form = new formidable.IncomingForm();
        //解决 跨磁盘分区移动 或操作文件会有权限问题-->添加一个 form.uploadDir='tmp' 即可(写一个临时路径)
        form.uploadDir = 'public';
        form.parse(req, function(err, fields, files) {
            console.log(fields);
            var times = new Date().getTime();
            //组装上传路径
            var file_path = './public/upload/' + times + files.photo.name;
            //将缓存文件移动到指定的public目录下
            fs.rename(files.photo.path, file_path, (err) => {
                if (!err) {
                    //因为设置静态资源时,已经将public文件夹,写入数据库,不要加public
                    fields.photo = './upload/' + times + files.photo.name;
                    console.log(fields);
                    //调用数据模块保存从者信息
                    db.save(fields, function(data) {
                        if (data != 0) {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('添加成功!');location.href='http://localhost:2060';</script>");
                        } else {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('添加失败!');window.history.back(-1);</script>");
                        }
                    })
                } else {
                    console.log('文件上传失败!' + err);
                }
            });
        });
    },

数据库模块:db.js

    //自定义save方法,添加新数据到数据库
    save: function(data, callback) {
        //组装SQL语句:接收过来的为对象数据{name:'xx',rank:'xx'}
        //循环遍历对象
        var set = '';
        var key = '';
        for (k in data) {
            set += "'" + data[k] + "',";
            key += k + ",";
        }
        //去掉最后一个逗号
        set = set.slice(0, set.length - 1);
        key = key.slice(0, key.length - 1);
        var sql = 'INSERT INTO servant (' + key + ') VALUES (' + set + ');';
        console.log(sql);
        connection.query(sql, function(error, sql_data) {
            console.log(sql_data);
            callback(sql_data.insertId);
        });
    },
2.8 在页面上更新一条从者信息

实现思路:

1.先从数据库查询出要修改的那条数据,并展示到页面上。展示同样用的是db.select方法

2.保存修改后的数据到数据库:这里与添加相同,同样是分为有文件上传和没有文件上传的情况,这里就不再赘述无上传的情况了,直接就用formidable模块进行解析表单数据。

业务模块:business.js

    //获取要修改的数据
    upuser_get: function(req, res) {
        db.where('id=' + req.query.id).select(function(data) {
            res.render('./servant_edit.html', { data: data });
        });
    },
    //向数据库中保存要修改的数据
    upuser_post: function(req, res) {
        //图片上传
        var form = new formidable.IncomingForm();
        //解决 跨磁盘分区移动 或操作文件会有权限问题-->添加一个 form.uploadDir='tmp' 即可(写一个临时路径)
        form.uploadDir = 'public';
        form.parse(req, function(err, fields, files) {
            console.log(fields);
            var times = new Date().getTime();
            //组装上传路径
            var file_path = './public/upload/' + times + files.photo.name;
            //将缓存文件移动到指定的public目录下
            fs.rename(files.photo.path, file_path, (err) => {
                if (!err) {
                    //因为设置静态资源时,已经将public文件夹,写入数据库,不要加public
                    fields.photo = './upload/' + times + files.photo.name;
                    console.log(fields);
                    db.where('id=' + req.query.id).update(fields, function(changedRows) {
                        //http服务器相应的要求必须是字符串
                        if (changedRows == 1) {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('修改成功!');location.href='http://localhost:2060';</script>");
                        } else {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('修改失败!');window.history.back(-1);</script>");
                        }
                    })
                } else {
                    console.log('文件上传失败!' + err);
                }
            });
        });
    },

数据库模块:db.js

    //自定义update方法:更新数据
    update: function(data, callback) {
        if (this.where == undefined) {
            callback("修改时不能没有where条件!");
        } else {
            //组装SQL语句:接收过来的为对象数据{name:'xx',rank:'xx'}
            //循环遍历对象
            var set = '';
            for (k in data) { //k为键,data[k]为值
                set += k + "='" + data[k] + "',";
            }
            //去掉最后一个逗号
            set = set.slice(0, set.length - 1);
            var sql = 'update servant set ' + set + ' where ' + this.whe;
            //重置where条件
            this.whe = undefined;
            connection.query(sql, function(error, sql_data) {
                console.log(sql_data);
                callback(sql_data.changedRows);
            });
        }
    },
2.9 删除一条数据

实现思路:接收get传过来的id,使用db.delete()方法删除数据表中的数据。

业务模块:business.js

    //删除数据库中的信息
    delete: function(req, res) {
        req.on('data', function() {
            //必须要有这一步,否则不进入end中
            //req.on(data)指每次发送的数据;
            //req.on(end)数据发送完成;
        })
        req.on('end', function() {
            db.where('id=' + req.query.id).delete(function(data) {
                if (data == '') {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('删除成功!');location.href='http://localhost:2060';</script>");
                } else {
                    res.setHeader('Content-type', 'text/html;charset=utf-8');
                    res.end("<script>alert('删除失败!');window.history.back(-1);</script>");
                }
            });
        })
    },

数据库模块:db.js

    //自定义删除方法,删除数据库中的数据
    delete: function(callback) {
        var sql = 'DELETE FROM servant WHERE ' + this.whe;
        console.log(sql);
        //重置where条件
        this.whe = undefined;
        connection.query(sql, function(error, sql_data) {
            console.log(error);
            console.log(sql_data);
            callback(sql_data.message);
        });
    },

3. 补充

#####3.1 Destroying a session[销毁session]

To destroy a session simply set it to null:

要销毁session,只需将其设置为null:

req.session = null

#####3.2 判断浏览器的cookie是否开启,需要用到浏览器Navigator对象

cookieEnabled 属性可返回一个布尔值,如果浏览器启用了
cookie,该属性值为 true。如果禁用了 cookie,则值为 false。

使用方法:

document.write("是否启用 Cookie: " + navigator.cookieEnabled);
//是否开启cookie:true
结果 : 是否启用 Cookie: true

#####3.3 图片上传

图片上传模块

var formidable = require('formidable');

代码实现

//向数据库中保存要修改的数据
    upuser_post: function(req, res) {
        //图片上传
        var form = new formidable.IncomingForm();
        //解决 跨磁盘分区移动 或 操作文件 会有权限问题-->添加一个 form.uploadDir='public' 即可(写一个临时路径)
        form.uploadDir = 'public';//设置上传路径
        form.parse(req, function(err, fields, files) {
            console.log(fields);
            var times = new Date().getTime();
            //组装上传路径
            var file_path = './public/upload/' + times + files.photo.name;
            //将缓存文件移动到指定的public目录下
            fs.rename(files.photo.path, file_path, (err) => {
                if (!err) {
                    //因为设置静态资源时,已经将public文件夹,写入数据库,不要加public
                    fields.photo = './upload/' + times + files.photo.name;
                    console.log(fields);
                    db.where('id=' + req.query.id).update(fields, function(changedRows) {
                        //http服务器相应的要求必须是字符串
                        if (changedRows == 1) {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('修改成功!');location.href='http://localhost:2060';</script>");
                        } else {
                            res.setHeader('Content-type', 'text/html;charset=utf-8');
                            res.end("<script>alert('修改失败!');window.history.back(-1);</script>");
                        }
                    })
                } else {
                    console.log('文件上传失败!' + err);
                }
            });
        });
    }

文件操作权限问题

解决 跨磁盘分区移动 或 操作文件 会有权限问题–>添加一个form.uploadDir='public'即可(写一个临时路径)。

4.结果展示

Node.js项目总结---Express框架

Node.js项目总结---Express框架

Node.js项目总结---Express框架

Node.js项目总结---Express框架

相关文章:

  • 2022-12-23
  • 2021-09-30
  • 2022-12-23
  • 2022-01-22
  • 2021-12-24
  • 2021-06-20
  • 2021-07-30
猜你喜欢
  • 2021-11-15
相关资源
相似解决方案