项目目录结构
采用mvc的模式
|———ui(视图,放前端打包好的代码)
└───controller (控制器)
└───module (模型)
└───router (路由)
└───middleware (自定义的中间件)
└───utiles (自己封装的工具)
└───app.js (项目入口)
└───config.js (全局配置)
└───node_modules
└───package.json
package.json
我们需要用到的包
"dependencies": {
"body-parser": "^1.19.0", //用来解析请求体
"express": "^4.17.1",
"express-mysql-session": "^2.1.4", //将session存入数据库
"express-session": "^1.17.1", //设置cookie session的
"glob": "^7.1.6", // 获取文件路径
"multer": "^1.4.2", // 处理文件上传
"mysql": "^2.18.1" // 连接数据库
}
app.js (项目入口)
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const glob = require("glob");
const session = require('./middleware/session'); // 自定义的session中间件(后边会说)
const app = express();
// 处理静态资源
app.use('/public',app.static(path.join(__dirname,'./ui')));
// 解析post请求体 ->application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// 解析post请求体 ->application/json
app.use(bodyParser.json())
//跨域处理
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With,xtoken");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
app.use(session)// 使用session
// 注册所有 router
glob('./router/**/*',{},(err,files) => {
if (err) throw err;
// files => router下所有文件路径的集合
files.forEach(item => {
const router = require(item);
if (router instanceof Function) {
app.use(router)
}
})
// 最后加一个错误处理
app.use((errMsg,req,res,next) => {
res.state(200).send({
code:1,
msg:errMsg,
data:'操作失败'
})
})
})
// 如果URL中的内容不发生变化,这个etag就会保持不变,于是浏览器就会使用缓存。
// 禁用ETag =>不让浏览器使用缓存
app.disable('etag')
// 监听端口
app.listen(8080,() => {
console.log('Service running at:')
console.log('-Local :http://localhost:8081')
})
session中间件
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
const db = require('../utils/db'); // 数据库的配置 后边说
// 配置session 库
const sessionStore = new MySQLStore({
createDatabaseTable: true, //是否创建表,如果表不存在的话
schema: {//架构
tableName: 'session_tab', //表名
columnNames: { //列选项
session_id: 'session_id',
expires: 'expires',
data: 'data'
}
}
},bd)
// 导出session 在入口 使用
module.exports = session({
key: 'cookie',// cookie名
secret: "keyboard cat",
store: sessionStore, // 使用MySQLStore实例
resave: false, //重新保存
saveUninitialized: false,//强制将“未初始化”的会话保存到存储中(不登录也设置)
})
utiles-> db(用来连接数据库)
const mysql = require("mysql");
var pool = mysql.createPool({
connectionLimit : 10,// 连接池连接数
host : '127.0.0.1',// 数据库ip
port : '3306',// 数据库端口
user : 'root',// 数据库用户名
password : '123456789',// 数据库密码
database : 'chat', // 数据库名
})
module.exports = pool; // 导出给module模块和express-mysql-session使用
mvc使用 这里拿登录举例
router(处理所有路由请求)
const exporss = require('express');
const router = rexpress.Router();
const Clogin = require('../../constroller/login'); //一会要写的登录控制器
router
.post('/api/user/login',Clogin.login)// 登录
.get('/api/user/loginOut',Clogin.loginOut)// 退出登录
module.exports = router // 导出router 入口去使用
constroller(对应路由下的处理器)
const Mlogin = require('../model/login'); // 用来获取数据的model层
exports.login = function (req,res,next) {
/**
@param {string} userName 用户名
@param {string} pwd 密码
@param {boolean} autoLogin 自动登录
*/
const {userName,pwd,autoLogin} = req.body;
Mlogin.getUserInfo(userName,(err,ret) => {
if (err) return next(err);
if (ret.length === 0) {
return res.send({code : 1, msg:'当前用户不存在', data:''})
}
if (ret[0].pwd === pwd) {
req.session.userinfo = ret[0];// 设置cookie session
if(autoLogin) {// 自动登录
req.session.cookie.maxAge = 7 * 24 * 60 * 60 * 1000;// 设置cookie的有效时长
}
res.send({code : 0, msg:'success', data:''})
}else {
return res.send({code : 1, msg:'密码错误', data:''})
}
})
}
exports.loginOut = function (req,res,next) {
// 清空 session 中用户信息
try {
req.session.destroy(function (err) { //清除session
if(err) return next(err);
res.clearCookie('cookie');//清掉cookie
res.send({code:0,msg:'退出登录成功',data:''})
});
} catch (error) {
next(error)
}
}
model(和数据库交互获取数据)
const db = require('../utils/db.js');
exports.getUserInfo = (userName,callback) => {
db.query('SELECT * FROM `user` WHERE name = ?', [userName], (err,ret) => {
if (err) return callback(err)
callback(null,ret)
})
}
关于响应页面
- 前端采用单页面应用
- 在router目录下写一个router即可
- 在router下
const repress = require('repress');
const fs = require('fs');
const router = express.Router();
const path = require('path');
function indexHtml (req,res,next) {
const urlHeader = req.url.split('/')[1];
// 如果是访问接口或者静待资源
if (urlHeader === 'api' || urlHeader === 'public') return next();
fs.readFile(path.join(__dirName,'../ui/index.html'),'utf8',(err,data) => {
if(err) return next(err)
res.setHeader('Content-type','text-html');
res.send(data)
})
}
router.get('/',indexHtml).get('/index.html',indexHtml)
module.export= router