前言
五一闲来无事,也不是特别想打ctf,啧,最近感觉打ctf的体验越来越不对了,热爱好像变质了?搓个项目玩吧。在这里复盘一下
整体框架
前端vue3
,好久没搓vue了,还挺怀念去年暑假学vue的。
后端nodejs+expres
,本来想用fastify
,但是掌握度不高,还是稳一点吧,别给自己写恶心了。
项目挺老套的,新闻+产品管理/发布项目,两套前端(admin&web),一个后端(server)。管理又分为管理员和编辑员。
前端
初期配置
vue create admin
创建后台管理项目,在8080端口运行
vue create web
创建企业门户页面,在8081端口运行
因为用的一套后端在3000端口,上来直接配置vue.config.js
,利用反向代理和后端通讯
1
2
3
4
5
6
7
8
9
10
11
12
|
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
"api阿巴阿巴": {
target: "http://localhost:3000",
changeOrigin: true
}
}
}
})
|
不过让我最好奇的他这个居然不是es6写法
模板组件
为了前端不那么丑,我大量使用了element-plus
的组件,使用方法照抄官网的就行,值得注意的是参数调整和自己灵活应用组件
关于时间处理
时间规范化处理可以使用moment
,可以参考他们的官方文档,一般常用的方法是
1
2
3
4
5
6
7
8
9
10
|
import moment from 'moment'
moment.locale("zh-cn");
const formatTime = {
getTime: (data) => {
return moment(data).format('YYYY/MM/DD')
}
}
export default formatTime
|
关于文件上传
因为传新闻和产品的时候总会用到的,虽然写好一个复制粘贴过去就行,但是又长又臭非常的影响我心情,这种时候可以利用封装的思想,把这个单独封装成一个组件去使用
关于路由配置
路由配置又麻烦又简单的,创建的时候就有一个router/index.js
,因为admin
项目的左侧栏会放很多的子选项,就会加一堆路由,用子路由实现是合理的,但是就会有一些问题,比如权限性问题,我又不想在后端实现,所以我专门写了个router/config.js
去实现动态路由,并在里面实现权限管理requireAdmin
,感觉比较简陋,就是对编辑员隐藏这个路由
关于拦截器
这里直接使用axios
,直接把官网的拉过来用了,写了个util/axios.config.js
,去实现拦截器
关于富文本编辑器
现在用的还是wangeditor
的v4,为什么呢?因为很简单,可以直接导入,不像v5需要自己再重新配置,但是还是过时了,后面再换成v5或者是其他的markdown编辑器吧,咕咕咕
关于样式
经典常用<style lang="scss" scoped>
,但是如果Element Plus 的子组件,它的 DOM 结构并不在当前组件的模板中,我就不能加效果了,那么就可以用::v-deep
去穿透,比如
1
2
3
4
5
6
7
|
.avatar-uploader .el-upload { ... }
编译后
.avatar-uploader .el-upload[data-v-xxxxxx] { ... }
::v-deep .avatar-uploader .el-upload { ... }
编译后
[data-v-xxxxxx] .avatar-uploader .el-upload { ... }
|
这样就可以作用进去了
后端
初期配置
express
默认创建时commonjs模式,不喜欢,先全部重构成es6,再规划一下
经典的nodejs+MVC.routes路由是纯接口==>controllers数据处理=>models层数据操作==>数据库==>返回数据
数据库
这里用的mongo
,nodejs里面用mongoose
去创建模型,可视化用的是vsc的插件Database Client
关于token
这里使用jsonwebtoken
去实现,方便好用放心,同时结合前端的身份区分去进行完善,因为是自己写的小项目,key也就随便输入了一个常用的,例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
import jsonwebtoken from 'jsonwebtoken'
const secret = 'abab'
export class JWT {
generate(value, expries) {
return jsonwebtoken.sign(value, secret, { expiresIn: expries })
}
verify(token) {
try {
return jsonwebtoken.verify(token, secret)
} catch (error) {
return false
}
}
}
//验证token
app.use((req, res, next) => {
//如果token有效,next(),如果无效,返回401给前端
if (req.url === '/adminapi/user/login') {
next()
return;
}
const token = req.headers["authorization"].split(" ")[1]
if (token) {
const payload = jwt.verify(token)
if (payload) {
const newToken = jwt.generate({
_id: payload._id,
username: payload.username
}, '1d')
res.header("Authorization", newToken)
next()
} else {
res.status(401).send({
errCode: "-1",
errorInfo: "token过期"
})
}
}
})
|
关于MVC&数据库
nodejs的MVC是要自己手动实现的,就像上面所写的一样,需要创建三个文件夹,分别去实现不同的功能,这点就没springboot好。
同时创建之后,再在下面创建admin和web文件夹,分别去处理管理页面和门户页面,以免写的api太乱。
关于数据库本地docker去搭mango并且关联到db
这个文件夹,同时一套模型对应两套前端,方便调用,也没有同步的问题,比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import mongoose from 'mongoose'
const { Schema } = mongoose
const NewsSchema = new Schema({
title: String,
content: String,
category: Number, // 123
cover: String, // 封面
isPublish: Number, // 发布状态
editTime: Date, // 编辑时间
})
// 注册并导出模型
const NewsModel = mongoose.model("news", NewsSchema)
export default NewsModel
|
config文件里面去写关于数据库的东西
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import mongoose from "mongoose";
mongoose.connect("mongodb://127.0.0.1:27017/company-system", {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on("error", (err) => {
console.error("❌ MongoDB connection error:", err);
});
db.once("open", () => {
console.log("✅ MongoDB connected successfully!");
});
export default db;
|
那么该如何使用呢,server
文件夹下的直接对数据库模型进行调用,在XXserver.js
里面写入api,比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import NewsModel from '../../models/NewsModel.js'
const NewsService = {
add: async ({ title, content, category, isPublish, cover, editTime }) => {
return NewsModel.create({
title, content, category, isPublish, cover, editTime
})
},
getList: async ({ _id }) => {
return _id ? NewsModel.find({ _id }) : NewsModel.find({})
},
publish: async ({ _id, isPublish, editTime }) => {
return NewsModel.updateOne({
_id
}, {
isPublish,
editTime
})
},
delList: async ({ _id }) => {
return NewsModel.deleteOne(
{
_id
}
)
},
updateList: async ({ _id, title, content, category, isPublish, cover, editTime }) => {
if (cover) {
return NewsModel.updateOne({ _id }, {
title, content, category, isPublish, cover, editTime
})
} else {
return NewsModel.updateOne({ _id }, {
title, content, category, isPublish, editTime
})
}
}
}
export default NewsService
|
然后Controller文件再去调用server文件,最后合并到路由里面,这样就算是封装好了
个人感受
这个项目很简单,主要就是练手的,前后端交互和调试占了好多时间,还是写的太少了,和其他的对比的话,和spring不同,nodejs让我感觉更加组件化,个人写的更加舒服和享受。但是现在写进去的东西太少了,比如前面study
系列的单点登录,orm等知识点都没用,并且小项目也凸显不出nodejs最大的优势,后面可能会改善这个,把这个复杂化,技术化,或者是直接去写一个更大的(或者是咕咕咕)