1. npm init -y
2. git init
3. npm i express mongoose
4. app.js
var express = require('express')
var path = require('path')
var bodyParser = require('body-parser')
var session = require('express-session')
var router = require('./router')
var app = express()
app.use('/public/', express.static(path.join(__dirname, './public/')))
app.use('/node_modules/', express.static(path.join(__dirname, './node_modules/')))
//path.join 进行路径拼接
node每个模块中 除了require exports 等模块相关的API之外还有两个特殊成员
—dirname 可以用来获取当前文件模块所书目录的绝对路径
-filename 可以用来获取当前文件的的绝对路径
文件操作中 使用相对路径是不靠谱的 因为在node中文件操作的路径被设计为相对于执行node命令所处的路径
解决这个问题只需把相对路径变为绝对路径 使用—dirname和-filename
app.engine('html', require('express-art-template'))
app.set('views', path.join(__dirname, './views/')) // 默认就是 ./views 目录
// 配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// 在 Express 这个框架中,默认不支持 Session 和 Cookie
// 但是我们可以使用第三方中间件:express-session 来解决
// 1. npm install express-session
// 2. 配置 (一定要在 app.use(router) 之前)
// 3. 使用
// 当把这个插件配置好之后,我们就可以通过 req.session 来发访问和设置 Session 成员了
// 添加 Session 数据:req.session.foo = 'bar'
// 访问 Session 数据:req.session.foo
app.use(session({
// 配置加密字符串,它会在原有加密基础之上和这个字符串拼起来去加密
// 目的是为了增加安全性,防止客户端恶意伪造
secret: 'itcast',
resave: false,
saveUninitialized: false // 无论你是否使用 Session ,我都默认直接给你分配一把钥匙
}))
// 把路由挂载到 app 中
app.use(router)
app.listen(5000, function () {
console.log('running...')
})
5. 模版引擎 npm i art-template express-art-template
6.index.html
_layouts/home.html: 母版页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{block 'title'}}默认标题{{/block}}</title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
{{block 'head'}}{{/block}} //让子页有自己的样式
</head>
<body>
{{include '../_partials/header.html'}}
{{block 'body'}}{{/block}}
{{include '../_partials/footer.html'}}
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.js"></script>
{{block 'script'}}{{/block}}
</body>
</html>
继承:
{{extend './_layouts/home.html'}}
{{block 'title'}}{{'多人博客 - 首页'}}{{/block}}
{{block 'body'}}
7. nodemon app.js 启动
8. npm i bootstrap jquery
9.npm install --save body-parser 配置解析表单post请求体插件
10. 设计用户数据模型
user.js
var mongoose = require('mongoose')
// 连接数据库
mongoose.connect('mongodb://localhost/test', { useMongoClient: true })
var Schema = mongoose.Schema
var userSchema = new Schema({
email: {
type: String,
required: true
},
nickname: {
type: String,
required: true
},
password: {
type: String,
required: true
},
created_time: {
type: Date,
// 注意:这里不要写 Date.now() 因为会即刻调用
// 这里直接给了一个方法:Date.now
// 当你去 new Model 的时候,如果你没有传递 create_time ,则 mongoose 就会调用 default 指定的Date.now 方法,使用其返回值作为默认值
default: Date.now
},
last_modified_time: {
type: Date,
default: Date.now
},
avatar: {
type: String,
default: '/public/img/avatar-default.png'
},
bio: {
type: String,
default: ''
},
gender: {
type: Number,
enum: [-1, 0, 1],
default: -1
},
birthday: {
type: Date
},
status: {
type: Number,
// 0 没有权限限制
// 1 不可以评论
// 2 不可以登录
enum: [0, 1, 2],
default: 0
}
})
module.exports = mongoose.model('User', userSchema)
11. router.js
var express = require('express')
var User = require('./models/user')
var md5 = require('blueimp-md5')
var router = express.Router()
router.get('/', function (req, res) {
// console.log(req.session.user)
res.render('index.html', {
user: req.session.user
})
})
router.get('/login', function (req, res) {
res.render('login.html')
})
router.post('/login', function (req, res) {
// 1. 获取表单数据
// 2. 查询数据库用户名密码是否正确
// 3. 发送响应数据
var body = req.body
User.findOne({
email: body.email,
password: md5(md5(body.password))
}, function (err, user) {
if (err) {
return res.status(500).json({
err_code: 500,
message: err.message
})
}
// 如果邮箱和密码匹配,则 user 是查询到的用户对象,否则就是 null
if (!user) {
return res.status(200).json({
err_code: 1,
message: 'Email or password is invalid.'
})
}
// 用户存在,登陆成功,通过 Session 记录登陆状态
req.session.user = user
res.status(200).json({
err_code: 0,
message: 'OK'
})
})
})
router.get('/register', function (req, res) {
res.render('register.html')
})
router.post('/register', function (req, res) {
// 1. 获取表单提交的数据
// req.body
// 2. 操作数据库
// 判断改用户是否存在
// 如果已存在,不允许注册
// 如果不存在,注册新建用户
// 3. 发送响应
var body = req.body
User.findOne({
$or: [{
email: body.email
},
{
nickname: body.nickname
}
]
}, function (err, data) {
if (err) {
return res.status(500).json({
success: false,
message: '服务端错误'
})
}
// console.log(data)
if (data) {
// 邮箱或者昵称已存在
return res.status(200).json({
err_code: 1,
message: 'Email or nickname aleady exists.'
})
return res.send(`邮箱或者密码已存在,请重试`)
}
// 对密码进行 md5 重复加密
body.password = md5(md5(body.password))
new User(body).save(function (err, user) {
if (err) {
return res.status(500).json({
err_code: 500,
message: 'Internal error.'
})
}
// 注册成功,使用 Session 记录用户的登陆状态
req.session.user = user
// Express 提供了一个响应方法:json
// 该方法接收一个对象作为参数,它会自动帮你把对象转为字符串再发送给浏览器
res.status(200).json({
err_code: 0,
message: 'OK'
})
// 服务端重定向只针对同步请求才有效,异步请求无效
// res.redirect('/')
})
})
})
router.get('/logout', function (req, res) {
// 清除登陆状态
req.session.user = null
// 重定向到登录页
res.redirect('/login')
})
// router.post('/register', async function (req, res) {
// var body = req.body
// try {
// if (await User.findOne({ email: body.email })) {
// return res.status(200).json({
// err_code: 1,
// message: '邮箱已存在'
// })
// }
// if (await User.findOne({ nickname: body.nickname })) {
// return res.status(200).json({
// err_code: 2,
// message: '昵称已存在'
// })
// }
// // 对密码进行 md5 重复加密
// body.password = md5(md5(body.password))
// // 创建用户,执行注册
// await new User(body).save()
// res.status(200).json({
// err_code: 0,
// message: 'OK'
// })
// } catch (err) {
// res.status(500).json({
// err_code: 500,
// message: err.message
// })
// }
// })
module.exports = router
12.服务端重定向 只针对同步请求才有效 对异步请求无效