实战Node—幼教平台
运行效果图
项目初始化
初始化项目结构
新建app.js
npm init -y
:快速初始化项目依赖安装express:
npm install --save express
把服务器跑起来
① 初始代码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
目的:转化高阶语法
- 新建.babelrc
{"presets": ["env"] }
npm install babel-preset-env --save-dev
为什么要用–save-dev
生产环境中不需要
上线部署的时候 - 安装babel-register
① 概念:babel-register可以理解成一个小插件,将es6的东西转成es5
② 命令:npm i babel-register --save-dev
新建main.js
中间过渡
require('babel-register'); require('./app');
app.js
// const express = require('express'); import express from 'express'
运行
node main.js
babel高阶语法转化演示
- 安装
npm install -g babel-cli
npm install babel-cli --save-dev
- 转化1
babel ./app.js
图示
- 转化2
babel src -d dist
图示
- 开发和生产分离
① package.json
② 分别测试- 开发环境
npm run dev
- 生产环境
npm run build
npm start
- 开发环境
配置项目依赖
新建public,views文件夹, 引入静态资源
集成静态资源文件
配置全局路径
新建config.js
路径配置
config.jsviewPath: join(__dirname, '../views'),publicPath: join(__dirname, '../public')
app.js
app.use(express.static(config.publicPath));
配置新的模板引擎
概念
nunjucks:火狐开源
https://nunjucks.bootcss.com/删除ejs配置nunjucks
npm uninstall --save ejs
npm install nunjucks --save
页面操作
app.jsimport nunjucks from 'nunjucks'; nunjucks.configure(config.viewPath, {autoescape: true,express: app,noCache: true });
nunjucks模板引擎没有对模板文件名的后缀做特定限制
如果文件名是a.html 则渲染是就需要传递 a.html
配置全局路由
app.js
import indexRouter from './../routes/index'; app.use(indexRouter);
新建routes文件夹
index.jslet express = require('express'); let router = express.Router({});router.get('/back', function(req, res, next) {res.render('back/index.html'); });module.exports = router;
配置nodemon
- 概念:在开发环境下,往往需要一个工具来自动重启项目工程
- 安装:
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界面
配置前台界面
轮播图版块
接口处理
新增一张轮播图
- 路径:
/sowing/api/add
- 参数
图片的标题:image_title
图片的地址:image_url
图片的链接:image_link
上架时间:s_time
下架时间:e_time
添加时间:c_time
最后编辑:l_time - 方法:POST
获取轮播图数据
- 路径:
/sowing/api/list
- 方法:GET
查询一条轮播图数据
- 路径:
/sowing/api/single/:sowingId
- 参数:轮播图ID:sowingId
- 方法:GET
修改轮播图
- 路径:
/sowing/api/edit
- 参数:轮播图ID:id
- 方法:POST
根据id删除一条录播图记录
- 路径:
/sowing/api/remove/:sowingId
- 参数:轮播图ID:id
- 方法:GET
添加轮播图处理
后台
后台添加轮播图
页面路由配置
1)加载轮播图的列表页面/back/s_list
2)加载添加轮播图的页面/back/s_add
页面细节修改
文件上传处理:
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模板引擎渲染界面
后台修改轮播图
- 页面路由配置
加载修改轮播图的页面/back/s_edit
- 页面细节修改
- 文件上传处理
formidable - 模板引擎渲染界面
后台删除轮播图
- 页面路由配置
/sowing/api/remove/
- 页面细节修改
formData
- 主要作用
① 将form表单元素的name与value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率
② 异步上传文件 - 常用操作
//通过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},
接口处理
后台管理员生成
- 路径
/user/api/add
- 参数
后端登录用户名user_name
后端登录密码user_pwd
- 方法
POST
用户名和密码登录
- 路径
/user/api/login
- 方法
POST
- 参数
user_name
user_pwd
- 配置session
- 概念
Session用于记录客户状态的一种机制,不同于Cookie的是,Cookie存储在客户端,而Session则将数据存储在服务器上 - Session 的用途
session 运行在服务器端,当客户端第一次访问服务器时,可以将客户的登录信息保存
当客户访问其他页面时,可以判断客户的登录状态,做出提示,相当于登录拦截
session 可以和 Redis 或者数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)丢失 - 工作原理
① 当浏览器访问服务器并发送第一次请求时,服务器端会创建一个 session 对象,生成一个类似于key,value 的键值对
② 将 key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)
③ 最后将存在session中的信息返回到页面上 - 使用
① 项目中安装express-session
和connect-mongo
npm install express-session --save
npm install connect-mongo --save
② 代码中使用引入express-session
var session = require('express-session');
引入connect-mongo用于express连接数据库存储session
var mongoStore = require('connect-mongo')(session);
中间件使用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 //多长时间往数据库中更新存储一次,除了在会话数据上更改了某些数据除外 }) }));
获取session
req.session.token = 'itlike'
设置session
req.session.token
- 概念
- 注意事项:md5
- 概念
MD5(Message-Digest Algorithm)是计算机安全领域广泛使用的散列函数(又称哈希算法、摘要算法),主要用来确保消息的完整和一致性
常见的应用场景有密码保护、下载文件校验等 - 应用场景
- 文件完整性校验
比如从网上下载一个软件,一般网站都会将软件的md5值附在网页上,用户下载完软件后,可对下载到本地的软件进行md5运算,然后跟网站上的md5值进行对比,确保下载的软件是完整的(或正确的) - 密码保护
将md5后的密码保存到数据库,而不是保存明文密码,避免拖库等事件发生后,明文密码外泄 - 防篡改
比如数字证书的防篡改,就用到了摘要算法。(当然还要结合数字签名等手段)
- 文件完整性校验
- 密码保护
- 安全性
将明文密码保存到数据库是很不安全的,最起码也要进行md5后进行保存
比如用户密码是123456,md5运行后,得到输出:e10adc3949ba59abbe56e057f20f883e - 好处
- 防内部攻击
网站主人也不知道用户的明文密码,避免网站主人拿着用户明文密码干坏事 - 防外部攻击
如果网站被黑客入侵,黑客也只能拿到md5后的密码,而不是用户的明文密码
- 防内部攻击
- 安全性
- 单纯对密码进行md5不安全
- 当攻击者知道算法是md5, 可以将事先准备好的常见明文密码的md5值来进行匹配暴力破解
- 密码加盐
在密码特定位置插入特定字符串后,再对修改后的字符串进行md5运算
注意- 同样的密码,当“盐”值不一样时,md5值的差异非常大
- 通过密码加盐,可以防止最初级的暴力破解,如果攻击者事先不知道”盐“值,破解的难度就会非常大
- 密码加盐增强: 随机盐值
- 使用
blueimp-md5
- 概念
退出登录
- 路径
/back/user/api/logout
- 注意事项:销毁session
① 方法一:将cookie的时间设置为0,只有cookie中携带的信息通过客户端请求传到服务器,由对应的session接收session才起作用,cookie没了session自然而然的将不起作用
② 方法二req.session.destroy((err) => {console.log(err) });
权限控制
中间件
分页插件:twbsPagination
实战Node—幼教平台相关推荐
- 【.NET Core项目实战-统一认证平台】第四章 网关篇-数据库存储配置(2)
[.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) 原文:[.NET Core项目实战-统一认证平台]第四章 网关篇-数据库存储配置(2) [.NET Core项目实战- ...
- 【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1)
[.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) 原文:[.NET Core项目实战-统一认证平台]第三章 网关篇-数据库存储配置(1) [.NET Core项目实战- ...
- 【.NET Core项目实战-统一认证平台】第十四章 授权篇-自定义授权方式
上篇文章我介绍了如何强制令牌过期的实现,相信大家对IdentityServer4的验证流程有了更深的了解,本篇我将介绍如何使用自定义的授权方式集成老的业务系统验证,然后根据不同的客户端使用不同的认证方 ...
- 【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程...
上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成acce ...
- 【.NET Core项目实战-统一认证平台】第十一章 授权篇-密码授权模式
上篇文章介绍了基于Ids4客户端授权的原理及如何实现自定义的客户端授权,并配合网关实现了统一的授权异常返回值和权限配置等相关功能,本篇将介绍密码授权模式,从使用场景.源码剖析到具体实现详细讲解密码授权 ...
- 【.NET Core项目实战-统一认证平台】第十章 授权篇-客户端授权
上篇文章介绍了如何使用Dapper持久化IdentityServer4(以下简称ids4)的信息,并实现了sqlserver和mysql两种方式存储,本篇将介绍如何使用ids4进行客户端授权. .ne ...
- 【.NET Core项目实战-统一认证平台】第九章 授权篇-使用Dapper持久化IdentityServer4...
上篇文章介绍了IdentityServer4的源码分析的内容,让我们知道了IdentityServer4的一些运行原理,这篇将介绍如何使用dapper来持久化Identityserver4,让我们对I ...
- 【.NET Core项目实战-统一认证平台】第八章 授权篇-IdentityServer4源码分析
上篇文章我介绍了如何在网关上实现客户端自定义限流功能,基本完成了关于网关的一些自定义扩展需求,后面几篇将介绍基于IdentityServer4(后面简称Ids4)的认证相关知识,在具体介绍ids4实现 ...
- 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流
上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们将介绍如何实现自定义客户端的限流功能,来进一步完善网关的基础 ...
- 【.NET Core项目实战-统一认证平台】第六章 网关篇-自定义客户端授权
上篇文章[.NET Core项目实战-统一认证平台]第五章 网关篇-自定义缓存Redis 我们介绍了网关使用Redis进行缓存,并介绍了如何进行缓存实现,缓存信息清理接口的使用.本篇我们将介绍如何实现 ...
最新文章
- 有奖话题讨论:你的互联网从业故事
- asp.net 域名欺骗式开发
- 使用Consul做服务发现的若干姿势
- vue-preview动态获取图片宽高并增加旋转功能
- php博客详情页怎么做,简书仿站报告(四):如何制作文章详情页
- android发送短信指定收件人,android-发送短信给收件人
- iOS 端容器之 WKWebView 那些事
- 多路RTSP-RTMP转RTMP定制版
- 女生学电气or计算机,8个女生可以学习的工科专业,高三毕业生了解一下,值得报考...
- 算法-查找数组两个数据相加等于目标值
- skyline 系列 1 - 简介、下载
- 花之语第十四期:萱草花
- 内存拷贝函数memcpy相关解析(C语言)
- c语言中余数恒等于1,费马小定理_KANGMANG201102_新浪博客
- 跨平台应用 Qt 对决 HTML5
- 如何使网站图标Icon显示在浏览器地址前面
- 手机端页面测试神器--Browsersync
- 201671010402-陈靖 实验十四 团队项目评审课程学习总结
- 合并报表软件怎么完成表格合并?
- Linux 文件管理 : patch 命令详解
热门文章
- 16.卷2(进程间通信)---Sun RPC
- 30. Element parentNode 属性
- 15. Magento路由分发过程解析(四):请求重写
- 15. 从远程库克隆
- oracle+导入导出教程,oracle导入导出整理(一)
- js中addEventLister()函数的用法
- js中的fromCharCode() charCodeAt() charAt()
- [洛谷P4183][USACO18JAN]Cow at Large P
- Kubernetes实战阅读笔记--1、介绍
- 全局异常捕捉用法解析