运行效果图








项目初始化

初始化项目结构

  1. 新建app.js

  2. npm init -y:快速初始化项目依赖

  3. 安装express:npm install --save express

  4. 把服务器跑起来
    ① 初始代码

    const express = require('express');
    const  app = express();app.get('/', (req, res)=>{res.end('hello, itLike');
    });app.listen(3000, ()=>{console.log('server is running');
    });
    

    ② git运行
    node app.js

配置babel

目的:转化高阶语法

  1. 新建.babelrc

    {"presets": ["env"]
    }
    

    npm install babel-preset-env --save-dev
    为什么要用–save-dev
    生产环境中不需要
    上线部署的时候

  2. 安装babel-register
    ① 概念:babel-register可以理解成一个小插件,将es6的东西转成es5
    ② 命令:npm i babel-register --save-dev

新建main.js

  1. 中间过渡

    require('babel-register');
    require('./app');
    
  2. app.js

    // const express = require('express');
    import express from 'express'
    
  3. 运行
    node main.js

babel高阶语法转化演示

  1. 安装
    npm install -g babel-cli
    npm install babel-cli --save-dev
  2. 转化1
    babel ./app.js
    图示
  3. 转化2
    babel src -d dist
    图示
  4. 开发和生产分离
    ① package.json

    ② 分别测试

    1. 开发环境
      npm run dev
    2. 生产环境
      npm run build
      npm start

配置项目依赖

新建public,views文件夹, 引入静态资源

集成静态资源文件

配置全局路径

  1. 新建config.js

  2. 路径配置
    config.js

     viewPath: join(__dirname, '../views'),publicPath: join(__dirname, '../public')
    

    app.js

    app.use(express.static(config.publicPath));
    

配置新的模板引擎

  1. 概念
    nunjucks:火狐开源
    https://nunjucks.bootcss.com/

  2. 删除ejs配置nunjucks
    npm uninstall --save ejs
    npm install nunjucks --save

  3. 页面操作
    app.js

    import nunjucks from 'nunjucks';
    nunjucks.configure(config.viewPath, {autoescape: true,express: app,noCache: true
    });
    

    nunjucks模板引擎没有对模板文件名的后缀做特定限制
    如果文件名是a.html 则渲染是就需要传递 a.html

配置全局路由

  1. app.js

    import indexRouter from './../routes/index';
    app.use(indexRouter);
    
  2. 新建routes文件夹
    index.js

    let express = require('express');
    let router = express.Router({});router.get('/back', function(req, res, next) {res.render('back/index.html');
    });module.exports = router;
    

配置nodemon

  1. 概念:在开发环境下,往往需要一个工具来自动重启项目工程
  2. 安装: npm install -g nodemon
    开发依赖

    “dev”: “nodemon main.js”

配置公共代码模板

前提

一般后端项目头部、侧边和尾部都是一样的代码
借助Nunjucks可以配置一个基础模板

配置基础模板文件

base.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>撩课-后台管理系统</title><link rel="shortcut icon" href="public/images/favicon.ico" type="image/x-icon"><link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"><link rel="stylesheet" href="node_modules/font-awesome/css/font-awesome.css"><link rel="stylesheet" href="node_modules/nprogress/nprogress.css"><link rel="stylesheet" href="public/less/index.css"><!--留个插槽-用于放置其它的引入文件-->{% block style %}{% endblock%}
</head>
<body><!--引入头部版块-->{% include "header.html" %}<!-- 主体 --><div class="main"><!--引入侧边版块-->{% include "aside.html" %}<!--留出插槽, 放置其它内容-->{% block body %}{% endblock %}</div><script src="node_modules/jquery/dist/jquery.js"></script><script src="node_modules/bootstrap/dist/js/bootstrap.js"></script><script src="node_modules/nprogress/nprogress.js"></script><script src="public/js/common.js"></script><!--留出插槽, 放置其它尾部引入-->{% block script %}{% endblock %}
</body>
</html>

header.html
aside.html
index.html

<!--继承base.html基础模板-->
{% extends "base.html" %}<!--新增的样式文件-->
{% block style %}
{% endblock%}<!--主题内容-->
{% block body %}
<div class="container-fluid"><!-- 个人资料 --><div class="body teacher-profile"><div class="profile"><div class="row c1"><div class="col-md-4"><div class="cell s1"><i class="fa fa-users"></i><h4>登录用户</h4><h5>13,000</h5></div></div><div class="col-md-4"><div class="cell s2"><i class="fa fa-registered"></i><h4>新增注册</h4><h5>12,00</h5></div></div><div class="col-md-4"><div class="cell s3"><i class="fa fa-camera"></i><h4>课程新增学员</h4><h5>123</h5></div></div></div><div class="row c1"><div class="col-md-4"><div class="cell s4"><i class="fa fa-safari"></i><h4>班级新增学员</h4><h5>666</h5></div></div><div class="col-md-4"><div class="cell s5"><i class="fa fa-opera"></i><h4>新增会员</h4><h5>1122</h5></div></div><div class="col-md-4"><div class="cell s6"><i class="fa fa-question"></i><h4>未回复问答</h4><h5>236</h5></div></div></div><div class="lk-chart"><div class="chart"><div id="main1" style="height:400px;"></div></div><div class="chart"><div id="main2" style="height:400px;"></div></div></div></div></div>
</div>
{% endblock %}<!--新增尾部引入-->
{% block script %}
<script src="node_modules/echarts/dist/echarts.js"></script>
<script>let main1 = echarts.init(document.getElementById('main1'));let option = {title: {text: '订单统计'},tooltip: {},legend: {data:['购买数量']},xAxis: {data: ["Web全栈","JavaEE","Python","React实战","Vue实战","Node实战"]},yAxis: {},series: [{name: '销量',type: 'bar',data: [45, 10, 26, 29, 23, 33]}]};main1.setOption(option);let main2 = echarts.init(document.getElementById('main2'));let option2 = {title : {text: '付费订单统计',subtext: '最近7天',x:'right',y:'bottom'},tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},legend: {orient : 'vertical',x : 'left',data:['Chrome','Firefox','Safari','IE9+','IE8-']},toolbox: {show : true,feature : {mark : {show: true},dataView : {show: true, readOnly: false},restore : {show: true},saveAsImage : {show: true}}},calculable : false,series : (function (){let series = [];for (let i = 0; i < 30; i++) {series.push({name:'付费订单统计',type:'pie',itemStyle : {normal : {label : {show : i > 28},labelLine : {show : i > 28, length:20}}},radius : [i * 4 + 40, i * 4 + 43],data:[{value: i * 128 + 80,  name:'Java'},{value: i * 64  + 160,  name:'Web'},{value: i * 32  + 320,  name:'Python'},{value: i * 16  + 640,  name:'Node'},{value: i * 8  + 1280, name:'大数据+'}]})}series[0].markPoint = {symbol:'emptyCircle',symbolSize:series[0].radius[0],effect:{show:true,scaleSize:12,color:'rgba(250,225,50,0.8)',shadowBlur:10,period:30},data:[{x:'50%',y:'50%'}]};return series;})()};main2.setOption(option2);
</script>
{% endblock %}

配置404界面

配置前台界面

轮播图版块

接口处理

新增一张轮播图

  1. 路径:/sowing/api/add
  2. 参数
    图片的标题:image_title
    图片的地址:image_url
    图片的链接:image_link
    上架时间:s_time
    下架时间:e_time
    添加时间:c_time
    最后编辑:l_time
  3. 方法:POST

获取轮播图数据

  1. 路径:/sowing/api/list
  2. 方法:GET

查询一条轮播图数据

  1. 路径:/sowing/api/single/:sowingId
  2. 参数:轮播图ID:sowingId
  3. 方法:GET

修改轮播图

  1. 路径:/sowing/api/edit
  2. 参数:轮播图ID:id
  3. 方法:POST

根据id删除一条录播图记录

  1. 路径:/sowing/api/remove/:sowingId
  2. 参数:轮播图ID:id
  3. 方法:GET

添加轮播图处理

后台

后台添加轮播图

  1. 页面路由配置
    1)加载轮播图的列表页面/back/s_list
    2)加载添加轮播图的页面/back/s_add

  2. 页面细节修改

  3. 文件上传处理:formidable
    ① 概述
    1)node.js在处理客户端以POST方式提交的数据时,比较复杂,要写两个监听,并且要处理上传的图片、文件也比较艰难
    2)常用第三方模块包formidable来处理客户端以POST方式提交的表单、文件、图片等
    ② 使用npm install formidable

    const formidable = require('formidable');
    

    详情见文档:https://github.com/felixge/node-formidable
    ③ 使用注意
    1)表单提交的过程中涉及文件或图片上传,则一定要设置表单头,即在form标签上加上固定写法的属性为enctype=“multipart/form-data”,否则文件或图片会上传失败
    2),当中的name属性一定要赋值
    详情见文档:https://github.com/felixge/node-formidable

  4. 模板引擎渲染界面

后台修改轮播图

  1. 页面路由配置
    加载修改轮播图的页面/back/s_edit
  2. 页面细节修改
  3. 文件上传处理
    formidable
  4. 模板引擎渲染界面

后台删除轮播图

  1. 页面路由配置/sowing/api/remove/
  2. 页面细节修改

formData

  1. 主要作用
    ① 将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率
    ② 异步上传文件
  2. 常用操作
    //通过FormData构造函数创建一个空对象
    var formdata=new FormData();
    //可以通过append()方法来追加数据
    formdata.append("name","撩课");
    //通过get方法对值进行读取
    console.log(formdata.get("name"));//撩课
    //通过set方法对值进行设置
    formdata.set(“name”,“小撩”);
    console.log(formdata.get("name"));//小撩

前台

用户中心版块

用户模型

// 姓名
real_name: {type: String, required: false},
// 用户名
user_name: {type: String, required: true},
// 密码
user_pwd: {type: String, required: true},
// 头像
icon_url: {type: String, required: false},
// 性别
sex: {type: String, required: false},
// 手机号码
phone: {type: String, required: false},
// 邮箱
e_mail: {type: String, required: false},
// 加入日期
join_time: {type: String, required: false},
// 自我介绍
intro_self: {type: String, required: false},
// 当前编辑的时间
c_time: {type: Date, default: Date.now},
// 最后编辑时间
l_time: {type: Date, default: Date.now},

接口处理

后台管理员生成

  1. 路径/user/api/add
  2. 参数
    后端登录用户名user_name
    后端登录密码user_pwd
  3. 方法POST

用户名和密码登录

  1. 路径/user/api/login
  2. 方法POST
  3. 参数
    user_name
    user_pwd
  4. 配置session
    1. 概念
      Session用于记录客户状态的一种机制,不同于Cookie的是,Cookie存储在客户端,而Session则将数据存储在服务器上
    2. Session 的用途
      session 运行在服务器端,当客户端第一次访问服务器时,可以将客户的登录信息保存
      当客户访问其他页面时,可以判断客户的登录状态,做出提示,相当于登录拦截
      session 可以和 Redis 或者数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)丢失
    3. 工作原理
      ① 当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session 对象,生成一个类似于key,value 的键值对
      ② 将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)
      ③ 最后将存在session中的信息返回到页面上
    4. 使用
      ① 项目中安装express-sessionconnect-mongo
      npm install express-session --save
      npm install connect-mongo --save
      ② 代码中使用

      1. 引入express-session

        var session = require('express-session');
        
      2. 引入connect-mongo用于express连接数据库存储session

        var mongoStore  = require('connect-mongo')(session);
        
      3. 中间件使用session

        app.use(session({//参数配置
        secret:'itlike',//加密字符串
        name:'likeid',//返回客户端key的名称,默认为connect_sid
        resave:false,//强制保存session,即使它没有变化
        saveUninitialized:true,//强制将未初始化的session存储。当新建一个session且未设定属性或值时,它就处于未初始化状态。在设定cookie前,这对于登录验证,减轻服务器存储压力,权限控制是有帮助的,默认为true
        cookie:{maxAge:24*3600 },
        rolling:true, //在每次请求时进行设置cookie,将重置cookie过期时间
        store:new mongoStore({//将session数据存储到mongo数据库中
        url:'mongodb://127.0.0.1/college', //数据库地址
        touchAfter:24*3600  //多长时间往数据库中更新存储一次,除了在会话数据上更改了某些数据除外
        })
        }));
        
      4. 获取session

        req.session.token = 'itlike'
        
      5. 设置session

        req.session.token
        
  5. 注意事项:md5
    1. 概念
      MD5(Message-Digest Algorithm)是计算机安全领域广泛使用的散列函数(又称哈希算法、摘要算法),主要用来确保消息的完整和一致性
      常见的应用场景有密码保护、下载文件校验等
    2. 应用场景
      1. 文件完整性校验
        比如从网上下载一个软件,一般网站都会将软件的md5值附在网页上,用户下载完软件后,可对下载到本地的软件进行md5运算,然后跟网站上的md5值进行对比,确保下载的软件是完整的(或正确的)
      2. 密码保护
        将md5后的密码保存到数据库,而不是保存明文密码,避免拖库等事件发生后,明文密码外泄
      3. 防篡改
        比如数字证书的防篡改,就用到了摘要算法。(当然还要结合数字签名等手段)
    3. 密码保护
      1. 安全性
        将明文密码保存到数据库是很不安全的,最起码也要进行md5后进行保存
        比如用户密码是123456,md5运行后,得到输出:e10adc3949ba59abbe56e057f20f883e
      2. 好处
        1. 防内部攻击
          网站主人也不知道用户的明文密码,避免网站主人拿着用户明文密码干坏事
        2. 防外部攻击
          如果网站被黑客入侵,黑客也只能拿到md5后的密码,而不是用户的明文密码
    4. 单纯对密码进行md5不安全
      1. 当攻击者知道算法是md5, 可以将事先准备好的常见明文密码的md5值来进行匹配暴力破解
      2. 密码加盐
        在密码特定位置插入特定字符串后,再对修改后的字符串进行md5运算
        注意

        1. 同样的密码,当“盐”值不一样时,md5值的差异非常大
        2. 通过密码加盐,可以防止最初级的暴力破解,如果攻击者事先不知道”盐“值,破解的难度就会非常大
      3. 密码加盐增强: 随机盐值
    5. 使用blueimp-md5

退出登录

  1. 路径/back/user/api/logout
  2. 注意事项:销毁session
    ① 方法一:将cookie的时间设置为0,只有cookie中携带的信息通过客户端请求传到服务器,由对应的session接收session才起作用,cookie没了session自然而然的将不起作用
    ② 方法二

    req.session.destroy((err) => {console.log(err)
    });
    

权限控制

中间件

分页插件:twbsPagination

实战Node—幼教平台相关推荐

  1. 【.NET Core项目实战-统一认证平台】第四章 网关篇-数据库存储配置(2)

    [.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) 原文:[.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) [.NET Core项目实战- ...

  2. 【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1)

    [.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) 原文:[.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) [.NET Core项目实战- ...

  3. 【.NET Core项目实战-统一认证平台】第十四章 授权篇-自定义授权方式

    上篇文章我介绍了如何强制令牌过期的实现,相信大家对IdentityServer4的验证流程有了更深的了解,本篇我将介绍如何使用自定义的授权方式集成老的业务系统验证,然后根据不同的客户端使用不同的认证方 ...

  4. 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程...

    上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成acce ...

  5. 【.NET Core项目实战-统一认证平台】第十一章 授权篇-密码授权模式

    上篇文章介绍了基于Ids4客户端授权的原理及如何实现自定义的客户端授权,并配合网关实现了统一的授权异常返回值和权限配置等相关功能,本篇将介绍密码授权模式,从使用场景.源码剖析到具体实现详细讲解密码授权 ...

  6. 【.NET Core项目实战-统一认证平台】第十章 授权篇-客户端授权

    上篇文章介绍了如何使用Dapper持久化IdentityServer4(以下简称ids4)的信息,并实现了sqlserver和mysql两种方式存储,本篇将介绍如何使用ids4进行客户端授权. .ne ...

  7. 【.NET Core项目实战-统一认证平台】第九章 授权篇-使用Dapper持久化IdentityServer4...

    上篇文章介绍了IdentityServer4的源码分析的内容,让我们知道了IdentityServer4的一些运行原理,这篇将介绍如何使用dapper来持久化Identityserver4,让我们对I ...

  8. 【.NET Core项目实战-统一认证平台】第八章 授权篇-IdentityServer4源码分析

    上篇文章我介绍了如何在网关上实现客户端自定义限流功能,基本完成了关于网关的一些自定义扩展需求,后面几篇将介绍基于IdentityServer4(后面简称Ids4)的认证相关知识,在具体介绍ids4实现 ...

  9. 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流

    上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们将介绍如何实现自定义客户端的限流功能,来进一步完善网关的基础 ...

  10. 【.NET Core项目实战-统一认证平台】第六章 网关篇-自定义客户端授权

    上篇文章[.NET Core项目实战-统一认证平台]第五章 网关篇-自定义缓存Redis 我们介绍了网关使用Redis进行缓存,并介绍了如何进行缓存实现,缓存信息清理接口的使用.本篇我们将介绍如何实现 ...

最新文章

  1. 有奖话题讨论:你的互联网从业故事
  2. asp.net 域名欺骗式开发
  3. 使用Consul做服务发现的若干姿势
  4. vue-preview动态获取图片宽高并增加旋转功能
  5. php博客详情页怎么做,简书仿站报告(四):如何制作文章详情页
  6. android发送短信指定收件人,android-发送短信给收件人
  7. iOS 端容器之 WKWebView 那些事
  8. 多路RTSP-RTMP转RTMP定制版
  9. 女生学电气or计算机,8个女生可以学习的工科专业,高三毕业生了解一下,值得报考...
  10. 算法-查找数组两个数据相加等于目标值
  11. skyline 系列 1 - 简介、下载
  12. 花之语第十四期:萱草花
  13. 内存拷贝函数memcpy相关解析(C语言)
  14. c语言中余数恒等于1,费马小定理_KANGMANG201102_新浪博客
  15. 跨平台应用 Qt 对决 HTML5
  16. 如何使网站图标Icon显示在浏览器地址前面
  17. 手机端页面测试神器--Browsersync
  18. 201671010402-陈靖 实验十四 团队项目评审课程学习总结
  19. 合并报表软件怎么完成表格合并?
  20. Linux 文件管理 : patch 命令详解

热门文章

  1. 16.卷2(进程间通信)---Sun RPC
  2. 30. Element parentNode 属性
  3. 15. Magento路由分发过程解析(四):请求重写
  4. 15. 从远程库克隆
  5. oracle+导入导出教程,oracle导入导出整理(一)
  6. js中addEventLister()函数的用法
  7. js中的fromCharCode() charCodeAt() charAt()
  8. [洛谷P4183][USACO18JAN]Cow at Large P
  9. Kubernetes实战阅读笔记--1、介绍
  10. 全局异常捕捉用法解析