(三)项目功能的实现之新增用户BLOG -- 源码目录 └── model -- 数据库操作 └── user.js --用户管理 ├── public -- 静态资源 └── route -- 路由 └── admin --博客管理 ├── user-edit-fn.js --用户添加页面路由 └── user-edit.js --用户编辑页面路由 └── admin.js --博客管理页面路由 └── views -- 模板 └── admin --博客管理页面art模板 ├── user-edit.art --用户编辑页面 └── user.art --用户列表页 ├── app.js -- 创建网站服务 └──joi.js -- JavaScript对象的规则描述语言和验证器1.user.art为新增用户添加跳转链接到user-edit.art{{extend './common/layout.art'}}{{block 'main'}} <!-- 子模板的相对路径相对的就是当前文件 因为它是由模板引擎解析的 而不是浏览器 --> {{include './common/header.art'}} <!-- 主体内容 --> <div class="content"> {{include './common/aside.art'}} <div class="main"> <!-- 分类标题 --> <div class="title"> <h4>用户</h4> <span>找到1个用户</span> <a href="/admin/user-edit" class="btn btn-primary new">新增用户</a> </div> {{/block}}2.user-edit.art为新增用户表单指定请求地址、请求方式、为表单项添加name属性(method\value\name\action)<p class="tips">{{message}}</p>表示用户提交的错误信息的显示{{extend './common/layout.art'}}{{block 'main'}} {{include './common/header.art'}} <!-- /头部 --> <!-- 主体内容 --> <div class="content"> {{include './common/aside.art'}} <div class="main"> <!-- 分类标题 --> <div class="title"> <h4 style="display: {{button == '修改' ? 'block' : 'none'}}">{{@user && user._id}}</h4> <p class="tips">{{message}}</p> </div> <!-- /分类标题 --> <form class="form-container" action="{{link}}" method="post"> <div class="form-group"> <label>用户名</label> <input name="username" type="text" class="form-control" placeholder="请输入用户名" value="{{user && user.username}}"> </div> <div class="form-group"> <label>邮箱</label> <input type="email" class="form-control" placeholder="请输入邮箱地址" name="email" value="{{user && user.email}}"> </div> <div class="form-group"> <label>密码</label> <input type="password" class="form-control" placeholder="请输入密码" name="password"> </div> <div class="form-group"> <label>角色</label> <select class="form-control" name="role"> <option value="normal" {{user && user.role == 'normal' ? 'selected' : ''}}>普通用户</option> <option value="admin" {{user && user.role == 'admin' ? 'selected' : ''}}>超级管理员</option> </select> </div> <div class="form-group"> <label>状态</label> <select class="form-control" name="state"> <option value="0" {{user && user.state == '0' ? 'selected' : ''}}>启用</option> <option value="1" {{user && user.state == '1' ? 'selected' : ''}}>禁用</option> </select> </div> <div class="buttons"> <input type="submit" class="btn btn-primary" value="{{button}}"> </div> </form> </div> </div>{{/block}} admin.js创建用户编辑页面路由,渲染user-edit增加实现添加用户的功能路由,user-edit-fn// 引用expess框架const express = require('express');// 创建博客展示页面路由const admin = express.Router();// 渲染登录页面admin.get('/login', require('./admin/loginPage'));// 实现登录功能admin.post('/login', require('./admin/login'));// 创建用户列表路由admin.get('/user', require('./admin/userPage'));// 实现退出功能admin.get('/logout', require('./admin/logout'));// 创建用户编辑页面路由admin.get('/user-edit', require('./admin/user-edit'));// 创建实现用户添加功能路由admin.post('/user-edit', require('./admin/user-edit-fn'));// 将路由对象做为模块成员进行导出module.exports = admin;user.js引入joi模块,定义验证规则,将模块对象抛出// 创建用户集合// 引入mongoose第三方模块const mongoose = require('mongoose');// 导入bcryptconst bcrypt = require('bcrypt');// 引入joi模块const Joi = require('joi');// 创建用户集合规则const userSchema = new mongoose.Schema({ username: { type: String, required: true, minlength: 2, maxlength: 20 }, email: { type: String, // 保证邮箱地址在插入数据库时不重复 unique: true, required: true }, password: { type: String, required: true }, // admin 超级管理员 // normal 普通用户 role: { type: String, required: true }, // 0 启用状态 // 1 禁用状态 state: { type: Number, default: 0 }});// 创建集合const User = mongoose.model('User', userSchema);async function createUser () { const salt = await bcrypt.genSalt(10); const pass = await bcrypt.hash('123456', salt); const user = await User.create({ username: 'iteheima', email: 'itheima@itcast.cn', password: pass, role: 'admin', state: 0 });}// createUser();// 验证用户信息const validateUser = user => { // 定义对象的验证规则 const schema = { username: Joi.string().min(2).max(12).required().error(new Error('用户名不符合验证规则')), email: Joi.string().email().required().error(new Error('邮箱格式不符合要求')), password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required().error(new Error('密码格式不符合要求')), role: Joi.string().valid('normal', 'admin').required().error(new Error('角色值非法')), state: Joi.number().valid(0, 1).required().error(new Error('状态值非法')) }; // 实施验证 return Joi.validate(user, schema);}// 将用户集合做为模块成员进行导出module.exports = { User, validateUser}5.joi.jsJavaScript对象的规则描述语言和验证器 npm install joi// 引入joi模块const Joi = require('joi');// 定义对象的验证规则const schema = { username: Joi.string().min(2).max(5).required().error(new Error('username属性没有通过验证')), birth: Joi.number().min(1900).max(2020).error(new Error('birth没有通过验证'))};async function run () { try { // 实施验证 await Joi.validate({username: 'ab', birth: 1800}, schema); }catch (ex) { console.log(ex.message); return; } console.log('验证通过') }run();7、user-edit.js通过req.query获取message并渲染到user-edit.art中module.exports = async (req, res) => { // 获取到地址栏中的id参数 const { message } = req.query; //进行渲染res.render('admin/user-edit', { message: message, });8、user-edit-fn.js通过引入validateUser构造函数,验证没有通过,获取e.message并重定向回用户添加页面根据邮箱地址查询用户是否存在,如果用户已经存在 邮箱地址已经被别人占用重定向回用户添加页面如果都没有问题,说明可以添加用户,则进行密码加密,引入bcrypt,将用户信息添加到数据库中,完成用户添加后重定向回用户列表页面// 引入用户集合的构造函数const { User, validateUser } = require('../../model/user');// 引入加密模块const bcrypt = require('bcrypt');module.exports = async (req, res, next) => { try { await validateUser(req.body) }catch (e) { // 验证没有通过 // e.message // 重定向回用户添加页面 // return res.redirect(`/admin/user-edit?message=${e.message}`); // JSON.stringify() 将对象数据类型转换为字符串数据类型 return next(JSON.stringify({path: '/admin/user-edit', message: e.message})) } // 根据邮箱地址查询用户是否存在 let user = await User.findOne({email: req.body.email}); // 如果用户已经存在 邮箱地址已经被别人占用 if (user) { // 重定向回用户添加页面 // return res.redirect(`/admin/user-edit?message=邮箱地址已经被占用`); return next(JSON.stringify({path: '/admin/user-edit', message: '邮箱地址已经被占用'})) } // 对密码进行加密处理 // 生成随机字符串 const salt = await bcrypt.genSalt(10); // 加密 const password = await bcrypt.hash(req.body.password, salt); // 替换密码 req.body.password = password; // 将用户信息添加到数据库中 await User.create(req.body); // 将页面重定向到用户列表页面 res.redirect('/admin/user');}
