zoukankan      html  css  js  c++  java
  • 项目:个人博客网站


    typora-copy-images-to: media

    使用到的技术:node、express、swig、mongoose、模块化设计、中间件(body-parser、cookies)、bootstrap

    第三方模块、中间件

    • express
    • bodyParser
    • cookies
    • swig: 模板引擎
    • mongoose:操作mongodb数据库
    • markdown:markdown语法解析生成模块
    • jquery
    • bootstrap

    项目初始化

    生成package.json文件

    npm init -y
    

    安装上面的插件

    npm install express body-parser...
    

    配置、使用模板引擎

    配置

    const swig = require('swig');
    ...
    app.engine('html', swig.renderFile);	// 定义当前应用所使用的模板引擎。 参数1:模板引擎后缀;参数2:用于解析处理模块内容的方法
    app.set('views', './views');	// 设置模板文件寸法的目录。 参数1:必须是views;参数2:模板文件存放的目录
    app.set('view engine', 'html');	// 注册所使用的模板引擎。 参数1:必须是view engine;参数2:和上面的模板引擎后缀必须一致(html)
    
    // 开发过程中,取消模板缓存,方便调试
    swig.setDefaults({cache: false});
    

    使用

    app.get('/', function(req, res, next){
      // 读取views目录下的指定文件,解析并返回给客户端
      res.render('index', {});	// 参数1:模板文件(可以忽略后缀,可以忽略views/);参数2:传递给模板使用的数据
    });
    

    静态文件的托管

    配置

    // 当用户访问的url以 /public 开始,直接返回 path.join(__dirname, 'node_modules') 对应的文件
    app.use('/node_modules', express.static(path.join(__dirname, 'node_modules')));
    app.use('/public', express.static(path.join(__dirname, 'public')));
    

    加载中间件

    body-parser

    const bodyParser = require('body-parser');
    ...
    // 设置body-parser
    app.use(bodyParser.urlencoded({extended: true}));
    app.use( bodyParser.json() );
    

    cookies

    // app.js
    const Cookies = require('cookie');
    ...
    // 设置cookie
    app.use(function(req, res, next){
      req.cookies = new Cookies(req, res);
      next();
    });
    
    // api.js
    req.cookies.set( 'userInfo', JSON.stringify(resData.userInfo) );	// 添加cookies
    req.cookies.get('userInfo');	// 获取cookies
    

    模块划分

    使用app.use()进行模块划分

    app.use('/admin', require('./routers/admin'));
    app.use('/api', require('./routers/api'));
    app.use('/', require('./routers/main'));
    

    路由

    前台

    • main模块

      路径 方法 get参数 post参数 备注
      / get 首页
      /view get 内容页
    • api模块

      路径 方法 get参数 post参数 备注
      / get 首页
      /register 用户注册
      /login 用户登录
      /comment 评论获取
      /comment/post 评论提交

    后台

    • admin模块

      路径 方法 get参数 post参数 备注
      / 首页
      用户管理
      /user 用户列表
      分类管理
      /category 分类列表
      /category/add 分类添加
      /category/edit 分类修改
      /category/delete 分类删除
      文章内容管理
      /article 文章列表
      /article/add 文章添加
      /article/edit 文章修改
      /article/delete 文章删除
      评论内容管理
      /comment 评论列表
      /comment/delete 评论删除

    数据库连接

    启动mongodb数据库服务

    将mongodb数据库存放到“D:00web20workw02_blogdb”目录下

    mongod --dbpath=D:00web20workw02_blogdb
    

    连接数据库

    // app.js
    const mongoose = require('mongoose');
    ...
    // 连接数据库
    mongoose.connect('mongodb://127.0.0.1:27017/blog', {useNewUrlParser: true, useUnifiedTopology: true}, function(err){
        if( err ){
            console.log('数据库连接失败!');
        }else{
            console.log('数据库连接成功!');
            // 监听http端口
            app.listen(5000);
        }
    });
    

    数据库设计

    • 用户表

      • schemas/users.js - 表结构对象

        const mongoose = require('mongoose');
        // 用户表结构对象
        module.exports = new mongoose.Schema({
          username: String,
          password: String
        });
        

      • models/User.js - 模型类

        const mongoose = require('mongoose');
        const userSchema = require('../schemas/users');
        // 创建用户表的模型类
        module.exports = mongoose.model('User', userSchema);
        

    • 分类表

      • schemas/categories.js - 表结构对象

        
        

      • model/Category.js - 模型类

        
        

    用户

    用户注册

    • 前端

      • 注册页面渲染 - 用户注册、登录面板切换
      • 注册功能实现 - ajax提交到api.js - /api/user/register
    • 后端

      • 注册功能(错误码:1xx)
        • 前端验证
          • 1、用户名不能为空
          • 2、密码不能为空
          • 3、两次密码必须一致
        • 数据库验证
          • 1、用户是否已经存在
        • 注册成功
          • 保存用户注册信息到数据库中
    // index.js    
    	$userInfo = $('#userInfo');
        $loginBox = $('#loginBox');
        $registerBox = $('#registerBox');
    
        // 注册切换到登录
        $registerBox.find('.colMint').on('click', function(){
            $registerBox.hide();
            $loginBox.show();
        });
    
        // 登录切换到注册
        $loginBox.find('.colMint').on('click', function(){
            $loginBox.hide();
            $registerBox.show();
        });;
    
        // 注册功能实现
        $registerBox.find('button').on('click', function(){
            $.ajax({
                type: 'post',
                url: '/api/user/register',
                data: {
                    username: $registerBox.find('[name="username"]').val(),
                    password: $registerBox.find('[name="password"]').val(),
                    repassword: $registerBox.find('[name="repassword"]').val()
                },
                dataType: 'json',
                success: function(result){
                    console.log(result);
                }
            });
        });
    
    // api.js
    /* 
    用户注册
        前端验证
            1、用户名不能为空
            2、密码不能为空
            3、两次密码必须一致
        数据库验证
            1、用户是否已经存在
                1、用户不存在 - 保存用户注册信息到数据库中
    */
    router.post('/user/register', function(req, res, next){
        // 接收前端数据
        var username = req.body.username;
        var password = req.body.password;
        var repassword = req.body.repassword;
    
        // 用户名不能为空
        if( username == '' ){
            resData.code = 101;
            resData.msg = '用户名不能为空';
            res.json(resData);
            return;
        }
    
        // 密码不能为空
        if( password == '' ){
            resData.code = 102;
            resData.msg = '密码不能为空';
            res.json(resData);
            return;
        }
    
        // 两次密码必须一致
        if( password != repassword ){
            resData.code = 103;
            resData.msg = '两次密码必须一致';
            res.json(resData);
            return;
        }
    
        // 用户是否已经存在
        User.findOne({
            username: username
        }).then(function(userInfo){
            if( userInfo ){
                resData.code = 104;
                resData.msg = '用户已被注册';
                res.json(resData);
                return;
            }
            // 保存用户注册信息到数据库中
            return new User({
                username: username,
                password: password
            }).save();
    
        }).then(function(newUserInfo){
            console.log(newUserInfo);
            resData.msg = '注册成功';
            res.json(resData);
        });
    });
    

    用户登录

    • 前端

      • 登录页面渲染 - 用户注册、登录面板切换
      • 登录功能实现 - ajax提交到api.js - /api/user/login
      • 登录成功 - 显示用户信息标签
    • 后端

      • 登录功能(错误码:2xx)
        • 前端验证

          • 1、用户名不能为空
          • 2、密码不能为空
        • 数据库验证

          • 1、用户名和密码是否正确
          • 2、验证是否是管理员 - 在app.js页面中验证
        • 登录成功

          • 返回登录成功信息到前端
          • 保存登录cookie信息

    用户退出

    • 前端
      • 点击“退出” - 返送ajax - /api/user/logout
      • 退出成功 - 重新刷新页面
    • 后端
      • 删除cookie

    后台管理

    首页

    • 前端
      • 使用bootstrap搭建后台管理首页
    • 后端
      • 验证是否是管理员用户

    用户管理

    • 数据库

    • 前端

      • 使用bootstrap搭建用户列表
    • 后端

      • 用户 - 列表
        • 路由 - /user
        • 渲染 - 用户列表
          • 从数据库中获取用户数据
          • 分页

    分类管理

    • 数据库

    • 前端

      • 使用bootstrap搭建分类列表
    • 后端

      • 分类 - 列表
        • 路由 - /category
        • 渲染 - 分类列表
          • 从数据库获取分类数据
          • 分页
      • 分类 - 添加
        • 路由 - /category/add
        • 渲染 - 分类添加
        • 处理 - 分类添加
          • 接收前端数据
          • 前端验证
            • 1、分类名是否为空
          • 后端验证
            • 1、分类名是否存在
              • 存在: 跳转错误提示【问题:Promise.reject(),卡在这里了】
              • 不存在:添加分类名到数据库中
      • 分类 - 修改
        • 路由 - /category/edit
        • 渲染 - 分类修改页面
          • 1、 获取分类ID
          • 2、查询 categories 数据库,显示该ID对应的内容
          • 3、 render页面
        • 处理 - 分类修改
          • 前端验证
            • 1、 分类ID不能为空
            • 2、 分类名不能为空
          • 数据库验证
            • 1、 新分类名不能存在
          • 更新 updateOne 新分类名到数据库中
      • 分类 - 删除
        • 路由 - /category/delete
        • 处理 - 分类删除
          • 获取分类ID
          • 操作数据库,执行删除语句- remove()

    文章管理

    • 数据库

    • 文章 - 列表

      • 路由 - /article
      • 渲染 - 文章列表页面
        • 查询 articles 数据库
    • 文章 - 添加

      • 路由 - /article/add
      • 渲染 - 文章添加页面
        • 1、 查询categoires数据库,渲染分类
        • 2、 渲染页面
      • 处理 - 添加文章
        • 1、 获取前端传递的数据
        • 2、前端验证
          • cateId是否为空
          • title是否为空
        • 3、 数据库验证
          • cateId是否存在
        • 4、 保存文章到数据库中
    • 文章 - 修改

      • 路由 - /article/edit

      • 渲染 - 文章修改页面

        • 1、获取文章id
        • 2、数据库验证
          • 文章id是否存在
          • 根据id,查询 article数据表
        • 3、查询所有的分类数据
        • 4、渲染查询到的文章信息(附带分类数据、文章数据)
      • 处理 - 添加文章

        • 1、获取前端传递的文章数据

        • 2、前端验证

          • cateId是否为空

          • title是否为空

        • 3、 数据库验证【问题:此处在接收前端post数据的同时也get了url中的id参数数据,导致出现 CastError: Cast to ObjectId failed 错误】

          • article的id是否存在

          • cateId是否存在

        • 4、 更新文章

    • 文章 - 删除

      • 路由 - /article/delete
      • 处理 - 文章删除
        • 1、获取文章id
        • 2、数据库验证
          • 文章id是否存在
        • 3、根据id删除文章

    前台

    首页

    • 首页 - 渲染
      • 1、渲染导航分类标签
        • 获取分类ID - category
        • 获取数据库中的分类数据
      • 2、渲染文章列表
        • 获取数据库中总行数
        • 计算分页所需要的参数
        • 根据以上参数获取文章数据(分页、关联categories和users表)
        • 统一渲染index.html
      • 3、根据导航分类显示不同分类的文章
        • category是否为空
          • 为空:where为空对象
          • 不为空:where条件根据cateId分类文章

    详情页

    • 详情页 - 渲染
      • 1、获取URL参数:articleId
        • 验证是否存在articleId
      • 2、根据articleId查询数据库,获取该文章的所有信息
      • 3、阅读数的自增
      • 4、渲染该文章

    评论

    • 数据库
    • 前端
      • 初始化就显示评论
      • 点击提交按钮,提交评论
      • 点击上一页、下一页,实现评论翻页
      • 渲染评论,带分页
      • 格式化时间
    • 后端
      • 评论 - 显示
        • 1、获取文章id
        • 2、查询articles数据表
        • 3、通过json返回前端
      • 评论 - 添加
        • 1、获取文章id
        • 2、生成一条评论对象
        • 3、查询articles数据表
        • 4、将生成的评论push到返回的数据中
        • 5、保存新的article数据到表中,并返回新的article数据
        • 6、通过json返回新的article数据到前端
  • 相关阅读:
    javascript异步编程学习及实例
    通过调试vue-cli 构建代码学习vue项目构建运行过程
    web技术栈开发原生应用-多端共用一套代码
    vuejs应用开发前后端分离
    web前端跨域解决方案JSONP,CORS,NGINX反向代理
    js script 加载顺序
    js 百度地图
    layui-table 样式
    css 排版 test
    layui table
  • 原文地址:https://www.cnblogs.com/pikachu/p/14710402.html
Copyright © 2011-2022 走看看