【12】博客项目:01-项目环境搭建、项目功能实现、数据分页、开发环境与生产环境、第三方模块config、密码加密bcrypt、cookie与session、Joi、formidable、文件读取

博客项目

1. 项目环境搭建

1.1 项目介绍

多人博客管理系统

  1. 博客内容展示
  2. 博客管理功能

在这里插入图片描述
在这里插入图片描述

1.2 案例初始化

1.建立项目所需文件夹

  • public 静态资源
  • model 数据库操作
  • route 路由
  • views 模板

2.初始化项目描述文件

  • npm init -y

3.下载项目所需第三方模块

  • npm install express mongoose art-template express-art-template

4.创建网站服务器
5.构建模块化路由
6.构建博客管理页面模板

静态资源的外链文件是由浏览器解析的,其中的相对路径不是相对于当前文件,而是相对浏览器中的请求路径
在这里插入图片描述
改为:
在这里插入图片描述
其他类似
模板的路径是由模板引擎解析的,其中的相对路径是相对当前文件
在这里插入图片描述


主要代码
在这里插入图片描述
app.js

// 引用express框架
const express = require('express');
// 处理路径
const path = require('path');
// 创建网站服务器
const app=express();

// 告诉express框架模板所在的位置
app.set('views', path.join(__dirname, 'views'));
// 告诉express框架模板的默认后缀是什么
app.set('view engine', 'art');
// 当渲染后缀为art的模板时 所使用的模板引擎是什么
app.engine('art', require('express-art-template'));


// 开放静态资源文件
app.use(express.static(path.join(__dirname,'public')));
// 引入路由模块
const home =require('./route/home');
const admin = require('./route/admin');

// 为路由匹配请求路径
app.use('/home',home);
app.use('/admin',admin);
// 监听端口 开发的时候一般监听3000端口
app.listen(80);
console.log('网站服务器启动成功,请访问localhost');

home.js

// 引用express框架
const express = require('express');
// 创建博客展示页面路由
const home = express.Router();

home.get('/', (req, res) => {
    res.send('欢迎来到博客首页');
});

// 将路由对象做为模块成员进行导出
module.exports = home;

admin.js

// 引用express框架
const express = require('express');
// 创建博客展示页面路由
const admin = express.Router();

admin.get('/login', (req, res) => {
    res.render('admin/login');
});

// 创建用户列表路由
admin.get('/user',(req, res) => {
    res.render('admin/user');
})
// 将路由对象做为模块成员进行导出
module.exports = admin;

layout.art

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>Blog - Content Manager</title>
    <link rel="stylesheet" href="/admin/lib/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="/admin/css/base.css">
    {{block 'link'}}{{/block}}
</head>

<body>
    {{block 'main'}} {{/block}}
    <script src="/admin/lib/jquery/dist/jquery.min.js"></script>
    <script src="/admin/lib/bootstrap/js/bootstrap.min.js"></script>
    {{block 'script'}} {{/block}}
</body>

</html>

header.art

<!-- 头部 -->
<div class="header">
    <!-- 网站标志 -->
    <div class="logo fl">
      黑马程序员 <i>ITHEIMA</i>
    </div>
    <!-- /网站标志 -->
    <!-- 用户信息 -->
    <div class="info">
        <div class="profile dropdown fr">
            <span class="btn dropdown-toggle" data-toggle="dropdown">
                admin
                <span class="caret"></span>
            </span>
            <ul class="dropdown-menu">
                <li><a href="user-edit.html">个人资料</a></li>
                <li><a href="#">退出登录</a></li>
            </ul>
        </div>
    </div>
    <!-- /用户信息 -->
</div>
<!-- /头部 -->

aside.art

<!-- 侧边栏 -->
<div class="aside fl">
    <ul class="menu list-unstyled">
        <li>
            <a class="item active" href="user.html">
                <span class="glyphicon glyphicon-user"></span>
                用户管理
            </a>
        </li>
        <li>
            <a class="item" href="article.html">
                <span class="glyphicon glyphicon-th-list"></span>
                文章管理
            </a>
        </li>
    </ul>
    <div class="cprt">
        Powered by <a href="http://www.itheima.com/" target="_blank">黑马程序员</a>
    </div>
</div>
<!-- 侧边栏 -->

article-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>5b9a716cb2d2bf17706bcc0a</h4>
            </div>
            <!-- /分类标题 -->
            <form class="form-container">
                <div class="form-group">
                    <label>标题</label>
                    <input type="text" class="form-control" placeholder="请输入文章标题">
                </div>
                <div class="form-group">
                    <label>作者</label>
                    <input type="text" class="form-control" readonly>
                </div>
                <div class="form-group">
                    <label>发布时间</label>
                    <input type="date" class="form-control">
                </div>
                
                <div class="form-group">
                   <label for="exampleInputFile">文章封面</label>
                   <input type="file">
                   <div class="thumbnail-waper">
                       <img class="img-thumbnail" src="">
                   </div>
                </div>
                <div class="form-group">
                    <label>内容</label>
                    <textarea class="form-control" id="editor"></textarea>
                </div>
                <div class="buttons">
                    <input type="submit" class="btn btn-primary">
                </div>
            </form>
            
        </div>
    </div>
    <!-- /主体内容 -->
{{/block}}

{{block 'script'}}
    <script src="/admin/lib/ckeditor5/ckeditor.js"></script>
    <script type="/admin/text/javascript">
    
        let editor;

        ClassicEditor
                .create( document.querySelector('#editor'))
                .then(newEditor => {
                    editor = newEditor;
                })
                .catch( error => {
                    console.error( error );
                });

        // 获取数据
        // const editorData = editor.getData();
    </script>
{{/block}}

其余类似

2. 项目功能实现

2.1 登录

  1. 创建用户集合,初始化用户
    • 连接数据库
    • 创建用户集合
    • 初始化用户
  2. 为登录表单项设置请求地址、请求方式以及表单项name属性
  3. 当用户点击登录按钮时,客户端验证用户是否填写了登录表单
  4. 如果其中一项没有输入,阻止表单提交
  5. 服务器端接收请求参数,验证用户是否填写了登录表单
  6. 如果其中一项没有输入,为客户端做出响应,阻止程序向下执行
  7. 根据邮箱地址查询用户信息
  8. 如果用户不存在,为客户端做出响应,阻止程序向下执行
  9. 如果用户存在,将用户名和密码进行比对
  10. 比对成功,用户登录成功
  11. 比对失败,用户登录失败
  12. 保存登录状态
  13. 密码加密处理

在这里插入图片描述

2.2 新增用户

  1. 为用户列表页面的新增用户按钮添加链接
  2. 添加一个连接对应的路由,在路由处理函数中渲染新增用户模板
  3. 为新增用户表单指定请求地址、请求方式、为表单项添加name属性
  4. 增加实现添加用户的功能路由
  5. 接收到客户端传递过来的请求参数
  6. 对请求参数的格式进行验证
  7. 验证当前要注册的邮箱地址是否已经注册过
  8. 对密码进行加密处理
  9. 将用户信息添加到数据库中
  10. 重定向页面到用户列表页面

2.3 数据分页

当数据库中的数据非常多是,数据需要分批次显示,这时就需要用到数据分页功能。
在这里插入图片描述
分页功能核心要素:

  1. 当前页,用户通过点击上一页或者下一页或者页码产生,客户端通过get参数方式传递到服务器端
  2. 总页数,根据总页数判断当前页是否为最后一页,根据判断结果做响应操作

在这里插入图片描述
总页数:Math.ceil(总数据条数 / 每页显示数据条数)

limit(2) // limit 限制查询数量  传入每页显示的数据数量
skip(1) // skip 跳过多少条数据  传入显示数据的开始位置

数据开始查询位置=(当前页-1)* 每页显示的数据条数

2.4 用户信息修改

  1. 将要修改的用户ID传递到服务器端
  2. 建立用户信息修改功能对应的路由
  3. 接收客户端表单传递过来的请求参数
  4. 根据id查询用户信息,并将客户端传递过来的密码和数据库中的密码进行比对
  5. 如果比对失败,对客户端做出响应
  6. 如果密码对比成功,将用户信息更新到数据库中

2.5 用户信息删除

  1. 在确认删除框中添加隐藏域用以存储要删除用户的ID值
  2. 为删除按钮添自定义属性用以存储要删除用户的ID值
  3. 为删除按钮添加点击事件,在点击事件处理函数中获取自定义属性中存储的ID值并将ID值存储在表单的隐藏域中
  4. 为删除表单添加提交地址以及提交方式
  5. 在服务器端建立删除功能路由
  6. 接收客户端传递过来的id参数
  7. 根据id删除用户

2.6 开发环境与生产环境

什么是开发环境与生产环境
环境,就是指项目运行的地方,当项目处于开发阶段,项目运行在开发人员的电脑上,项目所处的环境就是开发环境。当项目开发完成以后,要将项目放到真实的网站服务器电脑中运行,项目所处的环境就是生产环境。

为什么要区分开发环境与生产环境
因为在不同的环境中,项目的配置是不一样的,需要在项目代码中判断当前项目运行的环境,根据不同的环境应用不同的项目配置。

如何区分开发环境与生产环境
通过电脑操作系统中的系统环境变量区分当前是开发环境还是生产环境。
在这里插入图片描述
在这里插入图片描述

 if (process.env.NODE_ENV == 'development') {
     // 开发环境
 } else {
     // 生产环境
 }

2.7 第三方模块config

作用:允许开发人员将不同运行环境下的应用配置信息抽离到单独的文件中,模块内部自动判断当前应用的运行环境,
并读取对应的配置信息,极大提供应用配置信息的维护成本,避免了当运行环境重复的多次切换时,手动到项目代码
中修改配置信息

使用步骤

  1. 使用npm install config命令下载模块
  2. 在项目的根目录下新建config文件夹
  3. 在config文件夹下面新建default.json、development.json、production.json文件
  4. 在项目中通过require方法,将模块进行导入
  5. 使用模块内部提供的get方法获取配置信息

将敏感配置信息存储在环境变量中
6. 在config文件夹中建立custom-environment-variables.json文件
7. 配置项属性的值填写系统环境变量的名字
8. 项目运行时config模块查找系统环境变量,并读取其值作为当前配置项属于的值

 { 
     "db": {
           "pwd": "APP_PWD"
     }
 }

在这里插入图片描述

2.8 文章评论

  1. 创建评论集合
  2. 判断用户是否登录,如果用户登录,再允许用户提交评论表单
  3. 在服务器端创建文章评论功能对应的路由
  4. 在路由请求处理函数中接收客户端传递过来的评论信息
  5. 将评论信息存储在评论集合中
  6. 将页面重定向回文章详情页面
  7. 在文章详情页面路由中获取文章评论信息并展示在页面中

3. 项目包含的知识点

3.1 密码加密 bcrypt

哈希加密是单程加密方式:1234 => abcd
在加密的密码中加入随机字符串可以增加密码被破解的难度。

// 导入bcrypt模块
const bcrypt = require('bcrypt');
// 生成随机字符串 gen => generate 生成 salt 盐
let salt = await bcrypt.genSalt(10);
// 使用随机字符串对密码进行加密
let pass = await bcrypt.hash('明文密码', salt);
// 密码比对
let isEqual = await bcrypt.compare('明文密码', '加密密码');

bcrypt依赖的其他环境

  1. python 2.x
  2. node-gyp
    npm install node-gyp -g
  3. windows-build-tools
    npm install --global --production windows-build-tools

最后npm install bcrypt

注意:

  1. 安装所有模块时最好以管理员身份运行Windows PowerShell
  2. 最好每安装完一个模块后重启Windows PowerShell(环境变量貌似改变)
  3. 在最后一步npm install bcrypt时安装太慢,本人挂了TZ才行(原因不明)

3.2 cookie与session

cookie:浏览器在电脑硬盘中开辟的一块空间,主要供服务器端存储数据。

  • cookie中的数据是以域名的形式进行区分的。
  • cookie中的数据是有过期时间的,超过时间数据会被浏览器自动删除。
  • cookie中的数据会随着请求被自动发送到服务器端。

在这里插入图片描述
session:实际上就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识。
在这里插入图片描述
在node.js中需要借助express-session实现session功能。

const session = require('express-session');
app.use(session({ secret: 'secret key' }));

3.3 Joi

JavaScript对象的规则描述语言和验证器。

const Joi = require('joi');
const schema = {
    username: Joi.string().alphanum().min(3).max(30).required().error(new Error(‘错误信息’)),
    password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
    access_token: [Joi.string(), Joi.number()],
    birthyear: Joi.number().integer().min(1900).max(2013),
    email: Joi.string().email()
};
Joi.validate({ username: 'abc', birthyear: 1994 }, schema);

3.4 formidable

作用:解析表单,支持get请求参数,post请求参数、文件上传。

 // 引入formidable模块
 const formidable = require('formidable');
 // 创建表单解析对象
 const form = new formidable.IncomingForm();
 // 设置文件上传路径
 form.uploadDir = "/my/dir";
 // 是否保留表单上传文件的扩展名
 form.keepExtensions = false;
 // 对表单进行解析
 form.parse(req, (err, fields, files) => {
     // fields 存储普通请求参数
         // files 存储上传的文件信息
 });

3.5 文件读取 FileReader

 var reader = new FileReader();
 reader.readAsDataURL('文件');
 reader.onload = function () {
     console.log(reader.result); 
 }

在这里插入图片描述

3.6 数据分页 mongoose-sex-page

const pagination = require('mongoose-sex-page');
pagination(集合构造函数).page(1) .size(20) .display(8) .exec();

3.7 mongoDB数据库添加账号

  1. 以系统管理员的方式运行powershell
  2. 连接数据库 mongo
  3. 查看数据库 show dbs
  4. 切换到admin数据库 use admin
  5. 创建超级管理员账户 db.createUser()
  6. 切换到blog数据 use blog
  7. 创建普通账号 db.createUser()
  8. 卸载mongodb服务
    1. 停止服务 net stop mongodb
    2. mongod --remove
  9. 创建mongodb服务
    mongod --logpath=“C:\Program Files\MongoDB\Server\4.1\log\mongod.log” --dbpath=“C:\Program Files\MongoDB\Server\4.1\data” --install –-auth
  10. 启动mongodb服务 net start mongodb
  11. 在项目中使用账号连接数据库
    mongoose.connect(‘mongodb://user:pass@localhost:port/database’)
免费个人博客系统(兼多用户博客系统)是支持一个空间2个网站的全能型网站管理系统,本免费个人博客系统通用和拓展性强,博客、文章系统、商城、企业网站、个性化论坛等类型网站都可以使用,将来网站无论如何转型或拓展,只需要修改模板就可以实现,无需重建网站。本系统不同于以往任何逻辑架构的网站程序。本软件开发者希望通过注重商业化开发,助力用户通过网络创业和赚钱,当然您也可以通过这个软件在互联网高效地展示自己。 详细说明: 1.本个人博客系统可以用于商业用途,本软件官方、开发者不收取任何授权费用; 2.本个人博客系统是支持一个空间2个网站的全能型博客系统; 3.本个人博客系统通用和拓展性强,博客、文章系统、商城、企业网站、个性化论坛等类型网站都可以使用; 4.本个人博客系统功能强大,代码少,运行效率更高,程序运行速度是其它主流同类软件的3~4倍,内存占用不到其它主流同类软件的五分之一; 5.开启和关闭会员注册,开启和关闭普通会员投稿功能; 6.会员功能拓展到了兼职专题功能,SEO设置和开放特约编辑的多用户不同权限管理功能等; 7.超级管理员可无密码一键登录任意会员后台,管理员用受限登录会员身份后台发布信息,也可让网站攻击者无法猜解密码; 8.自动生成手机版网站,系统默认带www的域名为PC模板站,不带www的顶级域名为手机站,不增加维护难度,就可以同时拥有2个网站; 9.博客程序还包含订单、秒杀、限时抢购和数量虚拟功能,助力用户互联网创业和商业化运营,就看脑洞大开的你怎么使用了; 10.本个人博客系统能够适应各种界面浏览器,后台可手机随时随地访问、管理和更新网站; 11.可一键切换成.shtml、.html、.htm、.asp、.aspx、.cgi、.php、.jsp、.cgi、/ 等网页后缀,模拟不同语言编程的网站程序; 12.前端页面精简,前端编码不用div标签,不用id、class规则的CSS样式,最大限度精简前端代码,鼓励用户抛弃div+CSS前端代码编写模式,我们这样做不是为了迎合HTML5,只是为了更合理的应用HTML标签; 13.安装程序自动识别和设置伪静态; 14.全站无死角SEO设置; 15.强大的内链逻辑,特别适应大数据类型网站使用; 16.强大的广告和精准广告设置; 17.数据缓存模式,不依赖外部服务器组件和其它插件,不额外占用服务器系统内存资源; 18.删除局部缓存和一键清除全部缓存; 19.可设置邮件实时通知新订单和访客留言; 20.可设置管理员回复留言可同时邮件通知留言者; 21.可查看和删除无用上传文件,为将来数据备份节省时间和空间; 22.特色的tag标签功能; 23.分类、tag标签、url表单填写自动补缺; 24.url表单可自动生成拼音,也可以用汉字,自动转码,有利于SEO搜索引擎排名; 25.开放式PHP原生态模板,用户任意修改、穿插内容或广告,无需花时间研究额外规则,模板修改成本更低; 26.可对模板备份,使用备份模板,并可对模板恢复系统初始状态; 27.模板修改全站页面秒更新; 28.可自定义SQL语句的图片展示页面; 29.后台可控制各个模块是否开启验证码、设置验证码长度,以及设置验证码破解难度; 30.访客留言关键词过滤; 31.可自定义导航; 32.可在线编辑js和CSS文件; 33.本免费个人博客系统(兼多用户博客系统)无后门。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值