# 一、项目开发流程
把前端给的文件一一归类。
1、html页面放在views文件夹
2、静态资源放在static或public
3、配置一些post中间件(因为要接收post传递过来的参数)
4、配置开放静态资源的中间件
# 二、文件上传
## 2.1 前端
**注意:**当表单中含有<input type="file">文件上传的表单项,则要把表单的编码设置为流媒体格式才能把用户选择的要上传的文件内容上传到服务器上
```html
<body>
<!--
注意:当表单中含有<input type="file">文件上传的表单项,则要把表单的编码设置为流媒体格式才能把用户选择的要上传的文件内容上传到服务器上
-->
<form action="/zhuce" method="post" enctype="multipart/form-data">
<div>帐号:<input type="text" name="username"></div>
<div>密码:<input type="password" name="password"></div>
<div>密码:<input type="password" name="repassword"></div>
<div>头像:<input accept=".gif,.png,.jpg,.jpeg" type="file" name="logo"></div>
<div><input type="submit" value="注册"></div>
</form>
</body>
```
## 2.2 后端
第三方formidable包用来处理含有文件上传的表单。
在项目根目录中安装formidable包: npm i formidable
```javascript
const express = require('express');
const path = require('path');
const fs = require('fs');
//引入formidable包处理含有文件上传的表单
const formidable = require('formidable');
const app = express();
app.listen(3000, () => {
console.log('3000端口');
});
//显示文件上传的界面
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'zhuce.html'));
});
//处理文件上传:
app.post('/zhuce', (req, res) => {
let curPaths = path.join(__dirname, 'uploads');
if (!fs.existsSync(curPaths)) {
//创建目录:
fs.mkdirSync(curPaths);
}
//uploadDir:设置文件上传成功的存放位置
let form = formidable({ multiples: true, uploadDir: curPaths });
form.parse(req, (err, fields, files) => {
// console.log(err,fields, files);
//获取用户输入的帐号、密码、确认密码
let { username, password, repassword } = fields;
console.log(username, password, repassword);
// path.extname(files.logo.originalFilename) ;
//获取文件扩展名:
let nameArr = files.logo.originalFilename.split('.');
let extName = nameArr[nameArr.length - 1];
//完整文件名:
let fullname = `${files.logo.newFilename}.${extName}`;
// console.log(err, fields, files);
fs.renameSync(files.logo.filepath, `${curPaths}/${fullname}`);
});
res.send('处理注册');
});
```
## 2.3 服务器处理完毕响应结果
生成一个唯一的上传成功后的新文件名的算法:
1)年月日时分秒 + 8位随机数
2)使用第三方模块uuid,使用方法:https://www.npmjs.com/package/uuid。
# 三、cookie
因为http协议是无状态(没有记忆功能)的协议,当我们的系统使用了cookie或session技术后可以让我们的系统有记忆功能。
## 3.1 介绍
Cookie的产生也是HTTP的特点所决定的。HTTP协议有一个非常重要的特点是无状态的,也就是说当客户端请求服务器,每一个请求和响应结束以后,这次的连接是马上断开的(也是为了释放资源)。同时服务器是不保留连接者相关的信息。这就说明了,Cookie要解决HTTP无状态的问题。
![](img\3-7cookie的现实场景.jpg)
## 3.2 cookie与session的区别:【重点】
- cookie存储在客户端、相对不安全,session存储在服务端、相对安全;
- cookie默认有效时间为整个有效会话期间,但设置有效时间,session不能设置有效时间,session默认有效时间为整个有效会话期间;
有效会话期间指打开浏览器开始访问某个系统到关闭整个浏览器之前的这段时间。
- cookie有大小限制(在4KB左右)及个数限制(每个域名可以存放的个数在20个至50个之间),session没有限制
- 浏览器可以禁用cookie,但session没有这方面的限制;
- 不同的浏览器之间不共享Cookie、session;
- 存储Cookie、session后在整个项目中有效(页面之间共享)
**cookie与session的联系:**【重点】
session依赖cookie,因为session的id存放在客户端的cookie中;
## 3.3 应用场景
## 3.4 cookie实现原理
![](img\3-8Cookie实现流程.jpg)
## 3.5 cookie-parser
### 3.5.1 下载
```
npm install cookie-parser
```
### 3.5.2 引入并开启cookie功能
```js
const cookieParser = require("cookie-parser"); // 引入cookieparser中间件
app.use(cookieParser()); // 使用cookie-parser中间件 全局开启cookie功用
```
### 3.5.3 设置cookie
中文文档参考地址: https://www.expressjs.com.cn/4x/api.html#res.cookie
```js
res.cookie(key,value[,option])
```
参数说明:
option:可选参数,{ maxAge : ms} 过期时间,表示多长时间后过期。以毫秒为单位
### 3.5.4 获取cookie
**要使用第三方中间件cookie-parser来获取cookie:**
中文文档参考地址: https://www.expressjs.com.cn/resources/middleware/cookie-parser.html
**在项目根目录下安装cookie-parser**: npm i cookie-parser
```js
req.cookies
```
### 3.5.5 案例
```javascript
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.listen(3000, () => {
console.log('3000端口');
});
//使用第三方cookie-parser中间件来获取cookie:
app.use(cookieParser());
//设置cookie:res.cookie('cookie名称','值'[,选项]);
app.get('/setcookie', (req, res) => {
//maxAge:设置cookie的有效时间,时间单位为:毫秒
//如果不设置cookie的有效时间则cookie的默认有效时间为整个有效会话期间
res.cookie('unames', '张三', { maxAge: 8 * 1000 });
res.cookie('tel', 110);
res.cookie('test', { x: 11, y: 99 });
res.send(`<script>alert('cookie设置成功');location.href='/getcookie';</script>`);
});
//获取cookie:
app.get('/getcookie', (req, res) => {
console.log(req.cookies);
let { unames, tel } = req.cookies;
res.send(`获取cookie:${unames} ${tel}`);
});
```
# 四、session
## 4.1 介绍
Session是另一种记录用户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。当服务端使用Session后,那么服务器会把Session信息存储在服务器上,同时Session标识也会记录在对应客户端上。
![](img\3-12session的现实场景.jpg)
## 4.2 特点
- Session存储在服务器
- 依赖cookie
- 可以存储任意类型
- 通过客户端的sessionid标识符区分Session
- Session没有大小限制
## 4.3 应用场景
## 4.4. 实现原理
![session](img/session.png)
![](img\3-14Session实现流程.jpg)
## 4.5 cookie-session
### 4.5.1 下载
不管是设置session还是获取session都要使用第三方中间件cookie-session:
在项目根目录下安装cookie-session:
中文文档参考地址: https://www.expressjs.com.cn/resources/middleware/cookie-session.html
```
npm i cookie-session
```
### 4.5.2 引入并开启session功能
```js
const cookieSession = require("cookie-session"); // 引入cookieSession中间件
// 使用cookieSession 中间件
app.use(cookieSession({
name: 'sessionids',//sessionid的名称,默认可以省略
keys: ['secret1','secret2','secret3'], //密钥锁
// Cookie Options
//maxAge: 24 * 60 * 60 * 1000 // 24 hours , session的有效期
}))
```
### 4.5.3 设置Session数据
```js
req.session[key] = value
```
### 4.5.4 访问Session数据
```js
req.session
```
express操作session的代码实例,如下:
```javascript
const express = require('express');
const cookieSession = require('cookie-session');
const app = express();
app.listen(4000, () => {
console.log('4000端口');
});
//使用第三方中间件cookie-session来操作session:
app.use(cookieSession({
name: 'cursession', //cookie名称
keys: ['sadfdsa&^%$%%', '79sadf#@@@'] //密钥
}));
//设置session:req.session.session名称=值
app.get('/setsession', (req, res) => {
req.session.usr = 'lisi';
req.session.email = 'lisi@qq.com';
res.send(`<script>alert('session设置成功');location.href='/getsession';</script>`);
});
//获取session:
app.get('/getsession', (req, res) => {
// console.log(req.session);
let { usr, email } = req.session;
res.send(`获取session: ${usr} ${email}`);
});
```
# 五、ejs模板引擎
## 5.1 ejs简介
使用ejs模板引擎可以让界面与数据分离(比如:有1000条新闻在展示时界面(风格)都是一致的,这时我们可以只发一个界面文件(模板文件),而要展示的新闻内容则为动态的),可以提高开发效率及降低后期维护成本。
## 5.2 使用步骤
1.下载ejs
在项目根目录安装ejs:
```
npm i ejs
```
2. 在项目中设置ejs模板引擎 【重点】
```js
//设置ejs:
app.set('view engine', 'ejs'); //设置模板引擎为ejs
app.set('views', [`${path.join(__dirname,'moban')}`, `${path.join(__dirname,'views')}`]); //设置模板文件的存放位置
app.engine('html', require('ejs').__express); //将html文件作为ejs模板文件来解析
```
3.在项目根目录下创建views文件夹
4.在views文件夹下创建模板文件
**注意:**ejs模板文件默认是以 .ejs为后缀名
## 5.3 ejs语法
### 5.3.1 渲染模板文件语法
```js
res.render('模板名称' [, data ])
```
参数说明:
参数1为模板名称不需要添加后缀,会自动寻找对应名称的.ejs文件
参数2为可选参数,向模板中传递的数据,必须是一个对象
### 5.3.2 模板语法
#### 5.3.2.1 数据渲染
```ejs
<%=变量名 %>
```
#### 5.3.2.2 分支
```ejs
<% if( 条件 ){%>
<% }else{ %>
<% } %>
```
#### 5.3.2.3 循环
```ejs
<% for(let i=0;i<数组.length;i++){ %>
循环项
<% }%>
```
#### 5.3.2.4 包含文件
说明:包含文件也是.ejs文件,无需携带后缀名
```ejs
<%- include('公共文件路径') %>
```
**使用ejs模板引擎的代码实例**:
```javascript
const express = require('express');
const path = require('path');
const app = express();
app.listen(3000, () => {
console.log('3000端口');
});
//设置ejs:
app.set('view engine', 'ejs'); //设置模板引擎为ejs
app.set('views', [`${path.join(__dirname,'moban')}`, `${path.join(__dirname,'views')}`]); //设置模板文件的存放位置
app.engine('html', require('ejs').__express); //将html文件作为ejs模板文件来解析
//新闻详情页面:
app.get('/newsdetail', (req, res) => {
let stuObj = [{ "names": "李四", "age": 20, "email": "lisi@qq.com" }, { "names": "张三", "age": 21, "email": "zs@qq.com" }, { "names": "小明", "age": 17, "email": "ming@163.com" }];
let title = '中公教育软件培训举行2021新生军训结训典礼';
let content = '中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人中公教育携手腾讯教育,深化产学合作加快“双元”育人';
res.render('newsdetail.html', { title, content, stuObj }); //渲染模板文件
// res.render('demo'); //渲染模板文件
});
```
newsdetail.html模板文件代码如下:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>
<h2>标题:
<%=title %>
</h2>
</p>
<div>内容:
<%=content %>
</div>
<div>
<table width="70%" border="1" cellspacing="0">
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>邮箱</td>
</tr>
<% for(let i=0;i<stuObj.length;i++){ %>
<tr>
<td>
<%=i+1 %>
</td>
<td>
<%=stuObj[i].names %>
</td>
<td>
<%=stuObj[i].age %>
<% if(stuObj[i].age >= 18){ %>
成年人
<% }else{ %>
未成年
<% } %>
</td>
<td>
<%=stuObj[i].email %>
</td>
</tr>
<% } %>
</table>
</div>
</body>
</html>