关于个人博客网站的搭建
本文最后更新于 2024-02-24,文章内容可能已经过时。
前言:一路走来,迈出了转型的好多个第一步,从第一个 Java swing 点餐程序的磕磕绊绊,再到现在自己纯手写的这个博客网站的搭建,中间收获了很多,也经历过最枯燥的日子,感谢教导我的老师们和陪我一路走来的好朋友。
关于个人博客网站的搭建
一、博客搭建的初衷
1、巩固自己半年内的前端技术学习成果。从去年八月份(2021年8月份)开始,发现自己的知识体系太过片面,对于前端一窍不通,只是停留在 HTML 阶段,这样对于以后的学习肯定会出现知识断层。于是网上找课程进行系统的学习,方便以后和前端的同学好沟通。
2、分享自己平时学习过程中的一些心得总结和感悟。我个人认为检验一个人掌握知识的最好方法就是---通过自己的分享把复杂的知识点简易化的讲解出来,即输入输出。所以分享总结在学习编程的过程中是很重要的。
二、技术选型
1、前端技术:vue2、element-ui、vuex
2、服务端:Node.js、express、mongoodb、mongoose
3、对于服务端的技术选型,当时很纠结,本来计划是使用 mysql 和 ssm 框架,于是打算提前看spring和springMvc,但是后边听从了一个大佬的建议,便选用了 Node.js 作为服务端,虽然使用的还是 mvc 模式,但是总感觉写起来没有 Java 的三层架构舒服吧,只是搭建服务的方式比较简单吧,使用 express 框架,直接几行代码就可以跑起来一个服务。
三、设计思路
1、这个博客系统主要由用户端和后台管理组成,这儿只展示部分页面。
2、功能需求分析
3、数据库表设计。
四、关于使用 vue2 的心得总结
1、前端项目结构
2、使用时关于项目结构的心得总结
-
这是我使用
vue-cli
创建的项目结构,由于第一次使用,我对项目的结构把握的不是很好,在组件里边我的结构不是很清晰,而且我对所有的请求没有进行一个统一的封装
,这样后期项目部署后,运行时请求太多,可能会造成504
错误,所以在今后的项目中,可以在src
目录下创建一个api
目录用来封装所有的请求,同时全局创建一个request.js文件来处理请求和响应的公共逻辑。 -
views 文件夹下放置你所有的路由页面,这个项目中我也使用了
vuex
,但是官方的说法是小型应用不需要vuex
,我为了熟悉vuex
用法,便在开始项目创建的时候勾选了vuex
。这个项目中我把需要用到的vuex
单独抽离出来一个js
文件进行使用。 -
assets 是我的存储静态资源的目录,但是我不建议直接使用
img
元素的src
属性直接引入,最好的做法就是通过vue
语法中的reqruie
把他引入,作为一个变量绑定在src
上,这样后期加载 图片的时候效率比较高;例如:
<template>;
<!--使用v-bind动态绑定-->
<img :src="image"/>
</template>
<script>
export default{
data(){
return{
image:require("@/assets/image.jpg");
}
}
}
</script>;
或者使用import
引入
<template>
<!--使用v-bind动态绑定-->
<img :src="image"/>
</template>;
<script>
import img from "@/assets/image.jpg"
export default{
data(){
return{
image:img;
}
}
}
</script>
3、vue
语法使用的总结
- 规范使用
vue
的语法,尽量不要出现原生的JavaScript
,这些规则能够在绝大多数工程中改善可读性和开发体验。即使你违反了,代码还是能照常运行,但例外应该尽可能少且有合理的理由。 - 注意组件命名规范,最好是见名知意,不能与现有的
HTML
元素产生冲突,可以由一个单词或者多个单词构成。多个单词构成的时候可以使用连接符或者驼峰命名法。如:
app-about
驼峰命名的时候主要要和vue-cli搭配,不然无法识别组件
AppAbout
- **组件的
data
必须是一个函数。**尽量不要使用对象(除了new Vue
外的任何地方)。data的值必须是返回一个对象的函数。
data(){
return{
value:"info",
}
}
- 必须深刻理解
vue
的生命周期,很重要!很重要!很重要!我在这儿就只介绍项目中经常用到的生命周期函数。mountd
函数一般用于数据的请求,发送axios
请求,启动定时器,因为这时候data
和methods
中的数据已经被初始化了,而且已经挂载到页面上了,所以我们才可以调用methods
中的方法给data
中的数据赋值。beforeDestory
函数,离开该组件前触发,这时候组件中的data
、methods
、computed
中的数据都是可用状态,一般用于清除一些数据,销毁一些资源。详见下图:
-
对于从服务端请求到的图片,我推荐使用图片懒加载。具体用法如下:
- 安装
npm install vue-lazyload --save
2.main.js
中引入全局使用
import VueLazyload from "vue-lazyload"
//自己映入加载时的图片和加载失败的图片
const loadingImg = require("./assets/img/loadingImg.gif")
const errorImage = require("./assets/img/errorImage.jpg")
Vue.use(VueLazyload, {
//加载时图片的展示高度
preLoad: 1,
error: errorImage,
loading: loadingImg,
attempt: 1
})
3.在img
元素中使用v-lazy
指令代替src
绑定图片,建议加一个key,这个key可以是图片的地址,不然会出现页面刷新了,但是图片不刷新的情况,因为key可能会相同,但是页面不刷新。
- 全局使用到的一些指令和
npm
包,可以在main.js
中进行全局绑定。这样在各个组件中使用的时候便不需要单独引入了。例:使用了一个时间处理工具库
import dayjs from "dayjs";
//在main.js文件中绑定dayjs
Vue.prototype.$dayjs = dayjs;
//在其他组件中使用
const time = new Date();
this.$dayjs(time).format("YYYY-MM-DD");
- 对于
axios
请求,尽量使用async
和await
来进行处理,代码结构比较清晰,当然你也可以使用.then
和.catch
来处理结果。此外,得到结果的时候进行解构赋值,这样你在使用数据的时候可以不用在对象.属性了。例:
async findAllComments() {
let { data } = await this.$axios.post("/node/blog/findComment", {
id: this.blogData._id,
});
this.commentDatas = data.comments.reverse();
},
- 使用路由的时候,最好使用路由懒加载,它可以在你需要用到这个路由的时候才加载这个路由组件。如:
{
path: "/personal",
name: "Personal",
component: () => import("../components/resourcePage/ResourcePage.vue")
}
- vuex 单独抽离的写法
export default {
namespaced: true,
state: {
userInfo: {
userDate: "",
userIcon: "/vue_img/hot5.png",
userName: "",
userPass: "",
id: "",
}
},
actions: {
changeuserinfo(content, value) {
content.commit("CHANGEUSERINFO", value)
}
},
mutations: {
CHANGEUSERINFO(state, value) {
state.userInfo = value
}
}
}
import Vue from 'vue'
import Vuex from 'vuex'
import userInfo from "./moudleStore/userInfo"
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
userInfo
}
})
- 路由传值,可以用
query
或者params
,params
是动态路由。两者的区别是query
传递的值在页面刷新后还存在,但是params
中传递的数据会消失。示例:
//在router文件下的index.js中的写法,这样写直接可以使用props接收值,不在使用$router.query.indexof获取
{
path: "/detail",
name: "Detail",
component: () => import("../components/article/Detail.vue"),
props(route) {
return {
indexof: route.query.indexof
}
}
}
//组件中使用
<router-link
:to="{
name: 'Detail',
query: {
indexof: item._id,
},
}"
>{{ item.title }}</router-link>
//接收值
props: ["indexof"],
五、使用node.js作为服务端的总结
1、目录结构
2、总结
- 项目层次尽量分明,降低代码耦合度,能够抽离出来使用的模块,最好抽离出来,这样无论你是在修改
bug
还是维护的时候,都比较方便。处理数据库中得到的数据的js
文件你可以放在module
里边,处理业务逻辑的一些js文件也可以放在module里边,连接MongooDB
数据库的文件放在单独在module底下新建一个目录进行统一管理,管理路由的文件放置在router
目录下,app.js
文件是你的启动文件,我们可以使用express
框架建立一个服务。代码如下:
const express = require("express");
const app = express();
const history = require("connect-history-api-fallback")
// 配置静态
app.use(express.static("./public"))
// 解析post请求数据
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
// 链接数据库
require("./module/mongoose/mongoose")
//引入session
app.use(require("./module/plugin_vue/session"))
// 设置博客界面的子路由 ---------前台展示界面路由的引入
app.use("/blog", require("./router/blogVue.js"))
//设置管理端界面的路由-------后台管理
app.use("/adminUser", require("./router/amdinUser"))
app.use(history)
app.listen("9001", () => {
console.log("9001端口启动成功");
})
- 子路由配置方法:这里我已
/blog
的子路由举例,这时候前端发送请求的时候,他的请求路径就是:https://localhost:9001/blog/getLink
const express = require("express");
const router = express.Router();
//引入处理相应数据的函数
const { getTypeLink } = require("../module/admin-link/link");
router.post("/getLink", async (req, res) => {
let { value } = req.body;
let data = await getTypeLink(value);
res.send(data)
})
- 统一约束你的
数据返回格式
。例如使用上边的函数getTypeLink
函数返回数据后得到的结果:
//引入你需使用的MongoDB数据库里的集合
const dbLink = require("../mongoose/mongoLink");
const getTypeLink = async (val) => {
let data = await dbLink.find({ type: val });
let result = data;
if (data) return { code: 1, value: "查找成功", result }
return { code: 0, value: "查找失败" }
}
- mongooDB数据库的连接方法
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/blog")
.then(() => {
console.log("数据库连接成功");
})
.catch(() => {
console.log("链接失败");
})
- 在
mongooDB
数据库中创建集合的方法
const mongoose = require("mongoose");
module.exports = mongoose.model(
"blog",
new mongoose.Schema(
{
title: {
type: String,
required: true
},
summary: String,
type: String,
content: String,
date: {
type: Date,
required: true
},
views: {
type: Number,
default: 6
},
pictureUrl: String,
property: String,
state: {
type: String,
default: "草稿"
}
},
{
versionKey: false
}
)
);
六、关于前后端分离项目的搭建总结:
1、为什么需要前后端分离:
在以往的很长一段时间里,后端开发才是开发团队里的核心,前端开发往往仅由一小撮人甚至交给后端人员兼任。比如JSP
开发,它是一个典型的前后端高耦合的技术案例,前后端代码放在一起写,各种繁琐的套模板。这种开发方式在以前互联网服务不那么繁荣,web化趋势还不那么明显的年代发挥着巨大作用。随着各种社会服务的信息化程度加深,前端需要展示的内容越来越复杂(比如淘宝页面),JSP
这种套模板的技术(仅仅依靠html
、css
、js
、jq
等技术的堆积来完成一个复杂的页面展示也变得非常繁杂)再也无法高效的开发。**究其本质原因:前端开发没有像后端开发那样实现工程化、模块化、可复用化的思想。所以就会出现前后端开发不协调、效率低、扯皮的问题,这很不利于项目开发。因此项目管理者就想办法来解决这种问题,如何解决?→解耦。**在软件领域,任何复杂的问题面前,高内聚、低耦合这种原则几乎总是能见效。所以前后端分离开发出现了,把前端开发的责任从后端开发人员身上拿掉,给前端开发工程师一个单独的岗位和责任领域,将前端也工程化、模块化、项目化。这才是前后端分离开发最开始的来源。这些与vue
、react
框架没有什么关系,它们充其量只是一种具体实现方式而已。从本质上来看,前后端分离并不是一个技术问题,而是一个工程化考量和项目管理的问题。
2、前后端分离的核心
前后端分离核心思想是前端HTML页面通过AJAX调用后端的API
接口并使用JSON
数据进行交互。
3、如何做到前后端分离:
我这里以vue
和node.js
作为前端和服务端示例,其实不必太在意前后端使用的是什么技术,原理其实一样,不同点在于其配置,我们需要学习的是这样的开发模式和思维。
vue
项目中在配置文件 vue.config.js
中进行如下配置:就是进行一个代理
module.exports = {
devServer: {
proxy: {
"/node": {
target: 'https://127.0.0.1:9001',
ws: true,
changeOrigin: true,
pathRewrite: {
'^/node': ''
}
}
}
}
}
此后,使用前缀 /node
进行 axios
请求:
import axios from "axios";
export const addBlog = async (ruleform) => {
let { data } = await axios.post("/node/adminUser/addBlog", { data: ruleform });
return data;
}
服务端通过相应的接口接收数据:
const { addBlog } = require("../module/adminBlog/blog")
router.post("/addBlog", async (req, res) => {
let { data } = req.body;
let result = await addBlog(data)
res.send(result)
})
这便是最简单的前后端分离,然而在正式开发中,并不是如此简洁。这便要从软件开发的四大步说起:设计
、开发
、测试
、部署
,真正的前后端分离需要渗透到以上的每一步中。
- 首先说第一个阶段:设计阶段。设计阶段的第一个层面是系统设计,后端系统设计包括后端架构:数据库、中间件、缓存等架构的设计,主要是考虑性能、容量、扩展性、可维护性。前端也应该如此,尤其是当一个网站页面多、复杂的时候,前端架构就也需要做好充分的规划和准备,以满足长期可演进、可迭代的目标。设计阶段的第二个层面是接口设计,前后端交互是通过接口来实现的,所以model层面上的接口约定也就极其重要,包括:接口的请求方式、数据类型、返回数据格式等。接口设计一定要评审到位,避免前后端开发人员因为某个没有约定好的接口扯来扯去。
- 其次是第二个阶段:开发阶段。前后端开发人员按照先前约定好的接口独立开发,互相透明(一旦出现扯皮现象,那就不算是严格独立的前后端开发,因为必定会有一方需要被迫妥协,去修改代码,这就算是还未完全实现解耦)。前端开发用来测试的数据都是从
mock
(mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。)中模拟出来的,并不是从后端拿的;而后端开发仅提供一套接口,按照先前提供的评审好的接口约定来提供数据,这一套接口可以提供给很多的前端使用,比如web网``页
、h5
页面、app
、微信小程序
等。 - 然后是第三个阶段:测试阶段。要保证前后端独立可测试,前端测试包括:页面、跳转、展示、输入、传参、响应等;后端则包括:数据接口的提供、数据格式、校验、异常、数据一致性、权限问题等。
- 最后是第四个阶段:部署阶段。要保证前后端独立可部署。(
JSP
时代前端html
页面、css
样式、js
效果等都是由后台驱动,即前端都是塞到后端中,然后项目部署。当前端人员需要修改、发版本的时候就需要去求着后端人员帮忙)。前后端分离之后,就不再这样了,前后端发布上线可以完全独立,互相透明。这次项目部署的时候,我使用了前后端分离部署,感觉特别方便,尤其是在修改网页文件的时候,不需要考虑服务端。
博客迁移声明:
后来随着个人写博客的一个需求,发现自己原有开发的博客网站满足不了我当下的需求,于是开始重构博客,后边感觉没必要浪费这个时间,应该把精力专注于博客写作和内容输出上,所以便果断放弃了以前开发的博客,通过一些流行博客框架进行搭建,因此,现在看到的博客站点可能和文章描述的博客站点是不一样的。
- 感谢你赐予我前进的力量