# blog2205
**Repository Path**: xiaozhangxuegis/blog2205
## Basic Information
- **Project Name**: blog2205
- **Description**: 团队开发的第一个博客项目
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2023-02-20
- **Last Updated**: 2025-07-06
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 一、整体功能流程图
##

## 二、需求分析
### 2.1前台
#### 2.1.1 首页
> 导航栏
- 点击tab栏按钮,相应的按钮显示高亮颜色
- 点击`首页`,可以进入首页
- 点击`搜索`,可以搜索相关文章
- 点击`分类`/`简介`/`留言`/等分类进入相应的页面
> 页面
- 显示欢迎界面,向下滑动显示推荐的文章(`默认展示首页`),
")
#### 1.2 分类页面
> 导航栏
- 同上
> 页面
- 中间显示分类的标签
- 点击`标签`下面显示对相应的文章简介
- 点击对应的文章,可以跳转到文章详情页

#### 1.3 简介页面
> 导航栏
- 同上
> 页面
- 简介显示小组成员相关的简介
- 点击简介跳转到相应的成员简介

#### 1.4 留言板
> 导航栏
- 同上
> 页面
- 中间显示`留言框` 留言框下方显示已存在的留言
- 游客点击留言框`跳出`这登录页面
- 未登录游客只能浏览留言板,不能发表评论:
- 已登录的游客可以`发表`留言,`删除`自己的留言
- 管理员拥有所有的权限

#### 1.5 关于页面
> 导航栏
- 同上
> 页面
- 简介`显示`小组成员的作品
- 展示最近相关的六个作品
- 点击简介跳转到相应的项目
- 右侧显示作品,打赏,b站、知乎
- 点击打赏 弹出收款二维码

### 2. 后台
#### 2.1 登录页面
- 输入用户名和密码后进行表单校验
- 点击登录,进入管理员页面
- 点击退出登录即可返回登录页面

#### 2.2 后台首页
**左侧导航栏**
**首页内容**
- e-charts饼图:分类名称和分类文章数量统计图
- e-charts柱状图:文章创建时间及文章数量统计图
**原型图**

#### 2.3 分类管理
管理文章分类标签
1)显示所有分类
2)点击添加分类按钮添加新的分类
3)点击删除选中按钮删除选中分类
4)搜索分类框可以用关键字搜索分类名
5)点击删除按钮删除选中分类
6)点击编辑按钮修改分类
7)数据提供给文章管理分类标签使用
原型图

添加、删除分类原型图

删除分类原型图

###
#### 2.4 文章管理
文章管理下有二级菜单
##### 2.4.1文章列表
- 显示所有文章
- 点击编辑按钮可以重新编辑文章
原型图

编辑弹框

##### 2.4.2 添加文章
- 集成富文本编辑器
- 设置文章标题
- 文章分类
- 文章图片
- 文章内容
原型图

#### 2.5 用户管理
对用户进行新增、删除、查找、修改。
- 添加用户
- 删除用户
- 编辑用户
- 查找用户——搜索功能
- 分页
**原型图**




#### 2.6 留言管理
- 显示所有留言
- 可以管理留言的显示和隐藏
- 可以删除留言
- 可以设置精选留言
原型图

## 三、数据库设计

### 1.文章管理数据列表(blog_article)
| 字段名 | 类型 | 字属性 | 备注 |
| --- | --- | --- | --- |
| id | int(11) | 主键,自增,非空,无符号 | ID编号 |
| title | varchar(80) | 非空 | 博客标题 |
| content | varchar(255) | 非空 | 博客内容 |
| updataTime | datetime | CURRENT_TIMESTAMP | 修改时间 |
| type | varchar(80) | / | 所属分类 |
| pictureUrl | varchar(255) | CURRENT_TIMESTAMP | 首图地址 |
| isRecommend | tinyint | 长度1,默认0 | 是否开启推荐 |
| createTime | datetime | CURRENT_TIMESTAMP | 创建时间 |
### 2.分类管理数据表(blog_categories)
| 字段名 | 类型 | 字属性 | 备注 |
| --- | --- | --- | --- |
| categories_id | int(100) | 主键,自增,非空,无符号 | 编号ID |
| typename | varchar(255) | 非空 | 文章类型名称 |
### 3.用户信息表(blog_users)
| 字段名 | 类型 | 字属性 | 备注 |
| --- | --- | --- | --- |
| id | int | 主键,自增,非空,无符号 | 用户ID |
| username | varchar | 非空, 默认值'' | 用户名 |
| password | varchar | 非空, 默认值'' | 用户密码 |
| role | tinyint | 非空, 默认值'' | 用户权限 |
### 4.留言表(blog_message)
| 字段名 | 类型 | 字属性 | 备注 |
| --- | --- | --- | --- |
| id | int(255) | 主键,自增,非空,无符号 | 编号ID |
| name | varchar(30) | 非空 | 发表留言的用户名称 |
| time | datetime | CURRENT_TIMESTAMP | 发布时间 |
| content | varchar(255) | 非空 | 留言内容 |
## 四、接口设计
### 1.API接口说明
basURL:[http://localhost:3000](http://localhost:3000)
使用code 标识状态
数据返回格式统一使用 JSON
**支持请求的方法**
GET(SELECT):从服务器`获取`资源(一项或多项)。
POST(CREATE):在服务器`新建`一个资源。
PUT(UPDATE):在服务器`更新`资源(客户端提供改变后的完整资源)。
DELETE(DELETE):从服务器`删除`资源。
**返回状态码**
| _**状态码**_ | _**说明**_ |
| --- | --- |
| 0 | 请求成功 |
| 1 | 请求失败 |
### 2.功能设计
#### 2.1 文章管理API
1. 获取文章列表
- 请求
- 请求方式:GET
- 请求路径:/articles?
- 请求参数
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| 空 | 获取所有文章 | -- |
| page=page&size=size | 获取分页数据,page当前页数,size每页显示条数 | 不能为空 |
| isRecommend=isRecommend | 获取推荐文章,1为推荐,0为不推荐 | 不能为空 |
请求示例
```javascript
//获取所有文章
GET http://localhost:3000/article
//获取分页文章
GET http://localhost:3000/article?page=1&size=3
//获取推荐文章
GET http://localhost:3000/article?isRecommend=1
```
响应
```javascript
所有文章数据
{
"code": 0,
"message": "获取所有文章成功",
"result": {
"total": 9,
"data": [
{
"id": 1,
"title": "test-new",
"content": "test-new",
"updataTime": "2023-02-08 20:07:35",
"type": null,
"pictureUrl": null,
"isRecommend": 1,
"createTime": "2023-02-08 20:02:23"
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}
]
}
}
文章分页数据
{
"code": 0,
"message": "获取所有文章成功",
"result": {
"total": 9,
"data": [
{
"id": 1,
"title": "test-new",
"content": "test-new",
"updataTime": "2023-02-08 20:07:35",
"type": null,
"pictureUrl": null,
"isRecommend": 1,
"createTime": "2023-02-08 20:02:23"
},
{
"id": 3,
"title": "对对对",
"content": "测试4",
"updataTime": "2023-02-08 19:52:52",
"type": null,
"pictureUrl": null,
"isRecommend": 1,
"createTime": "2023-02-08 20:02:23"
},
{
"id": 5,
"title": "test",
"content": "test",
"updataTime": "2023-02-08 20:27:22",
"type": "css",
"pictureUrl": "test",
"isRecommend": 0,
"createTime": "2023-02-08 20:02:23"
}
]
}
}
推荐文章数据
{
"code": 0,
"message": "获取推荐文章成功",
"result": {
"isRecommendCount": 1,
"data": [
{
"id": 9,
"title": "test",
"content": "test",
"updataTime": "2023-02-08 20:28:10",
"type": "1",
"pictureUrl": "test",
"isRecommend": 1,
"createTime": "2023-02-08 20:28:10"
}
]
}
}
```
2.根据id获取文章
- 请求
- 请求方式:GET
- 请求路径:/article/:id
- 请求参数
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| id | 文章id | 不能为空 |
请求示例
```javascript
###
GET http://localhost:3000/article/6
```
响应
```javascript
{
"code": 0,
"message": "根据id获取文章成功",
"result": {
"data": {
"id": 6,
"title": "test",
"content": "test",
"updataTime": "2023-02-08 20:27:10",
"type": "javascript",
"pictureUrl": "test",
"isRecommend": 0,
"createTime": "2023-02-08 20:02:23"
}
}
}
```
3.添加文章
- 请求
- 请求方式:POST
- 请求url:/article
- 请求示例
```javascript
###
POST http://localhost:3000/article
Content-Type: application/json
{
"title": "test",//必传
"content": "test",//必传
"type":"aaaa",//必传
"isRecommend":1 //必传
}
```
- 响应
```javascript
{
"code": 0,
"message": "新增文章成功",
"result": {
"id": 27 //插入文章的id
}
}
```
4.修改文章
- 请求
- 请求方式:PUT
- 请求url:/article /:id
- 请求参数
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| id | 文章id | 不能为空 |
- 请求示例
```javascript
PUT http://localhost:3000/article/4
Content-Type: application/json
{
"content": "test-new",//可选
"title": "test-new",//可选
"type": "test-new",//可选
"isRecommend":0//可选
}
```
- 响应
```javascript
{
"code": 0,
"message": "更新文章成功",
"result": {
"id": "4",
"content": "test-new",
"title": "test-new",
"type": "test-new",
"isRecommend": 0
}
}
```
5.删除文章
- 请求
- 请求方式:DELETE
- 请求url: /article/:id
- 请求参数
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| id | 文章id | 不能为空 |
- 请求示例
```javascript
###
DELETE http://localhost:3000/article/24
```
- 响应
```javascript
{
"code": 0,
"message": "删除成功",
"result": ""
}
```
#### 2.2 分类管理API
- 增加用户——新增(post)
- 编辑用户——修改(put)
- 删除用户——删除(delete)
- 查找用户——获取(get)
- 分页接口——获取(get)
##### 2.2.1 获取所有分类列表
允许已授权的用户通过此接口查询自己的信息。
:::tips
- **URL**:`/api/category`
- **Method**:`GET`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
:::info
💡 注意,categories_id 和 typename 字段目前是只读属性,不允许通过此接口进行修改。
:::
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将数据库的分类信息数据全部返回
:::
```json
{
"code": 0,
"message": "获取所有分类成功",
"result": [
{
"categories_id": 1,
"typename": "测试更改-test"
},
{
"categories_id": 2,
"typename": "测试2"
},
{
"categories_id": 3,
"typename": "测试3"
},
{
"categories_id": 5,
"typename": "测试5"
},
{
"categories_id": 6,
"typename": "测试6"
},
{
"categories_id": 7,
"typename": "测试7"
},
{
"categories_id": 8,
"typename": "测试-test"
}
]
}
```
##### 2.2.2 获取分页分类信息
允许已授权的用户通过此接口查询自己的信息。
:::tips
- **URL**:`/api/category?page&size`
- **Method**:`GET`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
:::info
💡 注意,categories_id 和 typename 字段目前是只读属性,不允许通过此接口进行修改。
:::
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将数据库的分类信息数据全部返回
:::
```json
{
"code": 0,
"message": "获取所有分页分类成功",
"result": {
"total": 7,
"data": [
{
"categories_id": 1,
"typename": "测试更改-test"
},
{
"categories_id": 2,
"typename": "测试2"
},
{
"categories_id": 3,
"typename": "测试3"
},
{
"categories_id": 5,
"typename": "测试5"
}
]
}
}
```
##### 2.2.3 获取单个分类信息
允许已授权的用户通过此接口获取自己的信息。
:::tips
- **URL**:`/api/categories/`categories_id
- **Method**:`GET`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
:::info
💡 注意,categories_id 和 typename 字段目前是只读属性,不允许通过此接口进行修改。
:::
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 1234 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "获取单个分类成功",
"result": {
"categories_id": 1,
"typename": "测试更改-test"
}
}
```
##### 2.2.4 添加分类信息
允许已授权的用户通过此接口更改自己的信息。
:::tips
- **URL**:`/api/categories`
- **Method**:`POST`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 1234 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "添加分类成功",
"result": {
"categories_id": 9,
"typename": "测试-test"
}
}
```
##### 2.2.5 修改分类信息
允许已授权的用户通过此接口更改自己的信息。
:::tips
- **URL**:`/api/categories`
- **Method**:`PUT`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 1234 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "更新分类成功",
"result": {
"categories_id": "1",
"typename": "测试更改-test"
}
}
```
##### 2.2.6 删除分类信息
允许已授权的用户通过此接口更改自己的信息。
:::tips
- **URL**:`/api/categories/categories_id`
- **Method**:`DELETE`
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数 | 类型 | 约束 |
| --- | --- | --- |
| categories_id | Number | 不能为空 |
| `typename` | String | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 1234 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "删除分类成功",
"result": ""
}
```
#### 2.3 用户管理API
- 增加用户——新增(post)
- 编辑用户——修改(put)
- 删除用户——删除(delete)
- 查找用户——获取(get)
- 分页接口——获取(get)
##### 2.3.1 获取用户列表
允许已授权的用户通过此接口更新自己的信息。
:::tips
- **URL**:`/api/users`
- **请求方式**:GET
- **需要登录**:是
- **需要鉴权**:是
:::
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 1234 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "获取所有用户成功",
"result": {
"total": 6,
"data": [
{
"id": 2,
"username": "test",
"role": 1
},
{
"id": 3,
"username": "test",
"role": 1
}
]
}
}
```
##### 2.3.2 根据id获取用户信息
- 允许已授权的用户通过此接口更新自己的信息。
:::tips
- **URL**:`/api/users/2`
- **请求方式**:GET
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数名 | 参数说明 | 约束 |
| --- | --- | --- |
| id | 用户id | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 2 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "获取用户成功",
"result": {
"id": 2,
"username": "test",
"password": "123456",
"role": 1
}
}
```
##### 2.3.3 添加用户
- 允许已授权的用户通过此接口更新自己的信息。
:::tips
- **URL**:`/api/users`
- **请求方式**:POST
- **需要登录**:是
- **需要鉴权**:是
:::
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 2 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "添加用户成功",
"result": {
"username": "test",
"password": "123456",
"role": "0"
}
}
```
##### 2.3.4 修改用户
- 允许已授权的用户通过此接口更新自己的信息。
:::tips
- **URL**:`/api/users/2`
- **请求方式**:PUT
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数名 | 参数说明 | 约束 |
| --- | --- | --- |
| id | 用户id | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 2 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "修改用户成功",
"result": {
"id": "6",
"username": "lxj",
"password": "123456",
"role": "1"
}
}
```
##### 2.3.5 删除用户
- 允许已授权的用户通过此接口更新自己的信息。
:::tips
- **URL**:`/api/users/2`
- **请求方式**:DELETE
- **需要登录**:是
- **需要鉴权**:是
:::
**请求参数**
| 参数名 | 参数说明 | 约束 |
| --- | --- | --- |
| id | 用户id | 不能为空 |
**成功响应**
:::tips
**条件**:请求参数合法,并且用户身份校验通过。
**状态码:**`200 OK`
**响应示例**:响应会将修改后的用户信息数据返回,一个`id`为 2 的用户设置他们的姓名后将会返回:
:::
```json
{
"code": 0,
"message": "删除用户成功"
}
```
#### 2.4 留言管理API
1.获取所有留言
- 请求路径:/message
- 请求方式:GET
```javascript
router.get('/', async (req, res) => {
const data = await getAll('select * from blog_message');
res.send({
code: 0,
message: '获取所有留言成功',
result: data,
});
});
```
2.获取分页留言信息
- 请求路径:/message
- 请求方式:GET
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| page | 当前页数 | 不能为空 |
| size | 每页显示条数 | 不能为空 |
```javascript
router.get('/', async (req, res, next) => {
const { page = 1, size = 2 } = req.query;
const offset = (page - 1) * size;
const data = await getAll(
`select * from blog_message limit ${offset} , ${size}`
);
const { total } = await getOne(`select cont(*) as total from blog_message`);
res.send({
code: 0,
message: '获取分页成功',
require: {
data,
total,
},
});
});
```
3.新增留言
- 请求路径:/message
- 请求方式:post
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| name | 用户昵称 | 不能为空 |
| content | 留言内容 | 不能为空 |
```javascript
router.post('/', async (req,res) => {
const {name , content } = req.body
let sql = `insert into blog_message (name, content) values ('${name}','${content}')`
const data = await exec(`insert into blog_message (name, content) values ('${name}','${content}')`)
console.log(sql)
res.send({
code:0,
message:'添加留言成功',
result:{
id: data.insertId,
name,
content,
}
})
})
```
4.删除留言
- 请求路径:/message
- 请求方式:delete
| 参数名 | 参数说明 | 备注 |
| --- | --- | --- |
| id | 用户id | 不能为空 |
```javascript
router.delete('/:id', async (req , res ) => {
const { id } = req.params
let sql = `delete from blog_message where id=${id}`
let a = await exec(sql)
console.log(a)
res.send({
code: 0,
message: '删除成功',
result:''
})
})
```
####
## 五、模块流程图
### 1.文章管理流程图

### 2.分类管理流程图

### 3.用户管理流程图

### 4.留言管理流程图

## 六、具体开发
## 七、关键技术
### 7.1.jwt的使用
##### 7.1.1JWT概念:
JWT (Json Web Token)
JWT由3部分组成:标头(Header)、有效载荷(Payload)、 签名(Signature);
#### 7.1.2.JWT组成:
JWT由3部分组成:标头(Header)、有效载荷(Payload)、 签名(Signature);
####
| | **描述** | **属性名/字段** |
| --- | --- | --- |
| **标头(Header)** | 描述JWT数据的json对象
Base64 URL算法将JSON对象转换为字符串保存 | **属性**
alg: 签名使用的算法
用来说明JWT签发时所使用的签名和摘要算法
typ: JWT令牌的类型,统一写为JWT
标识整个token字符串是一个JWT字符串 |
| **载荷(Payload)** | JWT的主体内容部分
用来承载要传递的数据(容器)
本质: **JSON对象**
** --**包含需要传递的数据
Base64 URL算法将JSON对象转换为字符串保存 | **默认字段**
iss: 发行人
exp: 到期时间
sub: 主体
aub: 用户
nbf: 在此之前不可用
iat: 发布时间
jti: JWT ID (用于标识此jwt)
**自定义字段**
**包含用户信息的数据-payload**
username
注:password不放置在JWT中 |
| **签名(Signature)** | 1.签名: 把header(头部)和payload(载荷)对应的json结构进行base64url编码之后得到的两个串用英文句点号拼接起来,然后根据header里面alg指定的签名算法生成出来的。
2.算法不同,签名结果不同
**3.**秘钥保存在服务器中,不向用户公开; | **生成哈希过程**
1.创建秘钥
2.通过headers中指定的签名算法,根据公式生成签名 |
####