完成前台文章操作接口
This commit is contained in:
parent
d05f9c61f7
commit
95415eedb2
270
README.md
Normal file
270
README.md
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
## 九、项目 - 个人网站管理
|
||||||
|
|
||||||
|
### 9.1 介绍
|
||||||
|
|
||||||
|
### 9.2 功能模块
|
||||||
|
|
||||||
|
#### 整体采用前后端分离
|
||||||
|
|
||||||
|
后端: nodejs + expressjs + mysql 完成数据存取,如何验证是否已经登录(session、cookie)
|
||||||
|
|
||||||
|
前端:vue + element-ui
|
||||||
|
|
||||||
|
#### 模块
|
||||||
|
|
||||||
|
**用户模块**:管理用户的登录、退出、信息修改等
|
||||||
|
|
||||||
|
**文章模块**:添加文章、修改文章、查询文章、删除文章、文件的上传等 -
|
||||||
|
|
||||||
|
**前台模块** : 查询文章列表(分页|搜索)、查询文章的详情、更新文章的数据、文章的搜索、
|
||||||
|
|
||||||
|
**评论模块**:添加评论、查询评论、删除评论(管理员)
|
||||||
|
|
||||||
|
### 9.3 快速开始 - 搭建项目框架
|
||||||
|
|
||||||
|
1、使用npm初始化项目
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir pro-blog
|
||||||
|
cd pro-blog
|
||||||
|
# 使用npm初始化项目
|
||||||
|
npm init -y
|
||||||
|
```
|
||||||
|
|
||||||
|
2、安装项目所需的依赖
|
||||||
|
|
||||||
|
```shell
|
||||||
|
npm i express mysql vue element-ui
|
||||||
|
npm i -D nodemon
|
||||||
|
```
|
||||||
|
|
||||||
|
3、package.json - 项目的信息
|
||||||
|
|
||||||
|
提交项目时不要提交node_modules,只需要有package.json文件,执行`npm i`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "pro-blog",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "nodemon index.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"element-ui": "^2.15.8",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"vue": "^3.2.33"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.16"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4、入口文件 - index.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const express = require("express")
|
||||||
|
const user = require('./modules/user') // 用户模块
|
||||||
|
const article = require('./modules/article') // 文章
|
||||||
|
|
||||||
|
const app = express(); // 创建express应用
|
||||||
|
|
||||||
|
app.use(express.static('public')) // 设置静态文件路径
|
||||||
|
// 使用路由模块
|
||||||
|
app.use('/api/user',user)
|
||||||
|
app.use('/api/article',article)
|
||||||
|
|
||||||
|
app.listen(3000); // 监听端口
|
||||||
|
console.log('server run success! http://localhost:3000')
|
||||||
|
```
|
||||||
|
|
||||||
|
5、user 与 article 模块
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// article.js
|
||||||
|
const router = require('express').Router(); // 创建一个路由对象
|
||||||
|
// 实现相应路由功能
|
||||||
|
// ....
|
||||||
|
module.exports = router // 暴露路由对象
|
||||||
|
|
||||||
|
// user.js
|
||||||
|
const router = require('express').Router();
|
||||||
|
module.exports = router
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 数据库结构
|
||||||
|
|
||||||
|
用户登录表: 登录信息ID、登录时间、登录IP、客户端标识、有效期
|
||||||
|
|
||||||
|
文章表: 文章ID、标题、封面、发布时间、描述(一部分的文章内容)、文章内容、分类、阅读量、评论数、状态
|
||||||
|
|
||||||
|
评论表: 评论ID、文章ID、评论内容、发布时间、评论者IP
|
||||||
|
|
||||||
|
```sql
|
||||||
|
create DATABASE pro_blog;
|
||||||
|
use pro_blog;
|
||||||
|
|
||||||
|
-- 用户登录表: 登录信息ID、登录时间、登录IP、客户端标识、有效期
|
||||||
|
create table login(
|
||||||
|
id int(10) PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
login_time datetime not null,
|
||||||
|
BIGINT -- xxx.xxx.xxx.xx -> ipv4
|
||||||
|
-- xxxx:xxxx:xxxx::xxxx -> ipv6
|
||||||
|
ip varchar(40) not null,
|
||||||
|
client varchar(200) null,
|
||||||
|
expire_time datetime null
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 文章表: 文章ID、标题、封面、发布时间、描述(一部分的文章内容)、文章内容、分类、阅读量、评论数、状态
|
||||||
|
create table article(
|
||||||
|
id int(10) PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
title varchar(50) not null,
|
||||||
|
cover varchar(200) null,
|
||||||
|
publish_time datetime null,
|
||||||
|
description varchar(500) null,
|
||||||
|
content text not null,
|
||||||
|
category varchar(20) not null,
|
||||||
|
view_count int default 0,
|
||||||
|
comment_count int default 0,
|
||||||
|
status tinyint(1) default 1 -- 状态 1标识草稿 2表示已发布 0表示已删除
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 评论表: 评论ID、文章ID、评论内容、发布时间、评论者IP
|
||||||
|
create table comment
|
||||||
|
(
|
||||||
|
id int(10) PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
article_id int(10) not null,
|
||||||
|
content varchar(500) not null,
|
||||||
|
publish_time datetime not null,
|
||||||
|
ip varchar(40) not null
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 9.6 功能实现
|
||||||
|
|
||||||
|
#### 9.6.1 文章模块
|
||||||
|
|
||||||
|
##### 1、公共数据库查询工具模块
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 数据查询工具封装
|
||||||
|
const mysql = require('mysql')
|
||||||
|
// 创建数据库连接池
|
||||||
|
const pool = mysql.createPool({
|
||||||
|
user: 'root',
|
||||||
|
password: '123',
|
||||||
|
database: 'pro_blog',
|
||||||
|
timezone: 'Asia/Shanghai'
|
||||||
|
});
|
||||||
|
// 执行查询操作 返回Promise对象
|
||||||
|
function query(sql, values = []) {
|
||||||
|
return new Promise(function (resolve, reject) { // resolve是成功的回调函数 reject是错误的回调函数
|
||||||
|
pool.query(sql, values, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
reject(err) // 有错误 直接回调错误的函数
|
||||||
|
} else {
|
||||||
|
resolve(result) // 直接正常的回调
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 暴露接口
|
||||||
|
module.exports = {
|
||||||
|
pool,
|
||||||
|
createConnection: pool.getConnection,
|
||||||
|
query
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 2、实现分页查询文章列表
|
||||||
|
|
||||||
|
article.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const db = require('./db'); //
|
||||||
|
// 文章模块
|
||||||
|
const router = require('express').Router();
|
||||||
|
|
||||||
|
// 1.查询文章列表(分页)
|
||||||
|
router.get("/web/list",async function (req, res) {
|
||||||
|
const page = req.query['page'] || 1; // 获取页码
|
||||||
|
// 默认每页5条
|
||||||
|
const start = (page - 1) * 5;
|
||||||
|
try{
|
||||||
|
const listResult = await db.query("select * from article limit ?,5", [start]); // 执行查询语句并等待结果出来后赋值给变量
|
||||||
|
const totalCount = await db.query('select count(*) as total from article'); // 执行获取总条数
|
||||||
|
res.send({count:totalCount[0]['total'],list:listResult,size:5});
|
||||||
|
}catch(e){
|
||||||
|
console.log(err)
|
||||||
|
res.send({count:0,list:[]});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module.exports = router
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 3、实现关键字查询
|
||||||
|
|
||||||
|
article.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
router.get("/web/list", async function (req, res) {
|
||||||
|
const page = parseInt(req.query['page'] || 1); // 获取页码
|
||||||
|
const size = parseInt(req.query['size'] || 5); // 每天条数
|
||||||
|
// 默认每页5条
|
||||||
|
const start = (page - 1) * size;
|
||||||
|
const search = '%' + (req.query['search'] || '') + '%'; // 搜索关键字
|
||||||
|
try {
|
||||||
|
const listResult = await db.query(
|
||||||
|
`select id,title,category,publish_time,cover,description,view_count,comment_count
|
||||||
|
from article where title like ? or content like ? limit ?,?`,
|
||||||
|
[search, search, start, size]); // 执行查询语句并等待结果出来后赋值给变量
|
||||||
|
const totalCount = await db.query(
|
||||||
|
`select count(*) as total from article where title like ? or content like ?`, [search, search]); // 执行获取总条数
|
||||||
|
res.send({ total: totalCount[0]['total'], list: listResult, size: size });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
res.send({ count: 0, list: [] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 4、实现查询文章详情
|
||||||
|
|
||||||
|
article.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 2.查询单个文章详情
|
||||||
|
router.all('/web/detail',async (req,res)=>{
|
||||||
|
let id = req.query['id'];
|
||||||
|
if(!id || id <1){
|
||||||
|
res.send([])
|
||||||
|
}else{
|
||||||
|
const article = await db.query('select * from article where id =?',[id]);
|
||||||
|
res.send(article)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 5、实现更新文章阅读数
|
||||||
|
|
||||||
|
article.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
router.all('/web/update',async (req,res)=>{
|
||||||
|
let id = req.query['id'];
|
||||||
|
if(!id || id <1){
|
||||||
|
res.send("参数不对")
|
||||||
|
}else{
|
||||||
|
const article = await db.query('update article set view_count=view_count + 1 where id =?',[id]);
|
||||||
|
res.send("true")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
42
callback-promise-test.js
Normal file
42
callback-promise-test.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 实现暂停功能
|
||||||
|
function sleep(time){
|
||||||
|
let start = Date.now();
|
||||||
|
let i = 0;
|
||||||
|
while(true){
|
||||||
|
let currentTime = Date.now();
|
||||||
|
if(currentTime - start >= time){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(Date.now());
|
||||||
|
// sleep(2000);
|
||||||
|
// console.log(Date.now());
|
||||||
|
|
||||||
|
function sleep1(time,callback){
|
||||||
|
setTimeout(callback,time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(Date.now());
|
||||||
|
// sleep1(2000,function(){
|
||||||
|
// console.log(Date.now());
|
||||||
|
// })
|
||||||
|
function sleep2(time){
|
||||||
|
return new Promise((resovle)=>{
|
||||||
|
setTimeout(resovle,time);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// console.log(Date.now());
|
||||||
|
sleep2(2000).then(()=>{
|
||||||
|
sleep2(2000).then(()=>{
|
||||||
|
console.log(Date.now());
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function test(){
|
||||||
|
console.log(Date.now());
|
||||||
|
await sleep2(2000);
|
||||||
|
await sleep2(2000);
|
||||||
|
console.log(Date.now());
|
||||||
|
}
|
||||||
|
test();
|
3
db.sql
3
db.sql
@ -52,3 +52,6 @@ select * from article limit 2,2; -- 第2页
|
|||||||
select * from article limit 4,2; -- 第3页
|
select * from article limit 4,2; -- 第3页
|
||||||
-- 假设条数位:size 页码为: page
|
-- 假设条数位:size 页码为: page
|
||||||
-- 那么分页的起始位置为: (page - 1) * size
|
-- 那么分页的起始位置为: (page - 1) * size
|
||||||
|
-- 搜索文章
|
||||||
|
select id,title,category,publish_time,cover,description,view_count,comment_count
|
||||||
|
from article where title like '%测试%' or content like '%测试%';
|
@ -3,37 +3,46 @@ const db = require('./db'); //
|
|||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
// 用户网站模块
|
// 用户网站模块
|
||||||
|
|
||||||
// 1.查询文章列表(分页)
|
// 1.查询文章列表(分页|搜索)
|
||||||
router.get("/web/list",async function (req, res) {
|
router.get("/web/list", async function (req, res) {
|
||||||
const page = req.query['page'] || 1; // 获取页码
|
const page = parseInt(req.query['page'] || 1); // 获取页码
|
||||||
|
const size = parseInt(req.query['size'] || 5); // 每天条数
|
||||||
// 默认每页5条
|
// 默认每页5条
|
||||||
const start = (page - 1) * 5;
|
const start = (page - 1) * size;
|
||||||
// db.pool.query("select * from article limit ?,5", [start], (err, listResult) => {
|
const search = '%' + (req.query['search'] || '') + '%'; // 搜索关键字
|
||||||
// if (err) {
|
try {
|
||||||
// console.log(err)
|
const listResult = await db.query(
|
||||||
// res.send([]);
|
`select id,title,category,publish_time,cover,description,view_count,comment_count
|
||||||
// }
|
from article where title like ? or content like ? limit ?,?`,
|
||||||
// else{
|
[search, search, start, size]); // 执行查询语句并等待结果出来后赋值给变量
|
||||||
// // res.send(result);
|
const totalCount = await db.query(
|
||||||
// db.pool.query('select count(*) as total from article',(err,result)=>{
|
`select count(*) as total from article where title like ? or content like ?`, [search, search]); // 执行获取总条数
|
||||||
// res.send({
|
res.send({ total: totalCount[0]['total'], list: listResult, size: size });
|
||||||
// count:result,
|
} catch (e) {
|
||||||
// list:listResult
|
console.log(e)
|
||||||
// });
|
res.send({ count: 0, list: [] });
|
||||||
// })
|
}
|
||||||
// }
|
});
|
||||||
// });
|
// 2.查询单个文章详情
|
||||||
|
router.all('/web/detail',async (req,res)=>{
|
||||||
try{
|
let id = req.query['id'];
|
||||||
const listResult = await db.query("select * from article limit ?,5", [start]); // 执行查询语句并等待结果出来后赋值给变量
|
if(!id || id <1){
|
||||||
const totalCount = await db.query('select count(*) as total from article'); // 执行获取总条数
|
res.send([])
|
||||||
res.send({count:totalCount[0]['total'],list:listResult,size:5});
|
}else{
|
||||||
}catch(e){
|
const article = await db.query('select * from article where id =?',[id]);
|
||||||
console.log(err)
|
res.send(article)
|
||||||
res.send({count:0,list:[]});
|
}
|
||||||
|
});
|
||||||
|
// 3.更新阅读数量
|
||||||
|
router.all('/web/update',async (req,res)=>{
|
||||||
|
let id = req.query['id'];
|
||||||
|
if(!id || id <1){
|
||||||
|
res.send("参数不对")
|
||||||
|
}else{
|
||||||
|
const article = await db.query('update article set view_count=view_count + 1 where id =?',[id]);
|
||||||
|
res.send("true")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 管理后台模块
|
// 管理后台模块
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
Loading…
x
Reference in New Issue
Block a user