本文最后更新于 2024-02-24,文章内容可能已经过时。

前言:一路走来,迈出了转型的好多个第一步,从第一个 Java swing 点餐程序的磕磕绊绊,再到现在自己纯手写的这个博客网站的搭建,中间收获了很多,也经历过最枯燥的日子,感谢教导我的老师们和陪我一路走来的好朋友。

关于个人博客网站的搭建

一、博客搭建的初衷

1、巩固自己半年内的前端技术学习成果。从去年八月份(2021年8月份)开始,发现自己的知识体系太过片面,对于前端一窍不通,只是停留在 HTML 阶段,这样对于以后的学习肯定会出现知识断层。于是网上找课程进行系统的学习,方便以后和前端的同学好沟通。

2、分享自己平时学习过程中的一些心得总结和感悟。我个人认为检验一个人掌握知识的最好方法就是---通过自己的分享把复杂的知识点简易化的讲解出来,即输入输出。所以分享总结在学习编程的过程中是很重要的。

二、技术选型

1、前端技术:vue2element-uivuex

2、服务端:Node.jsexpressmongoodbmongoose

3、对于服务端的技术选型,当时很纠结,本来计划是使用 mysqlssm 框架,于是打算提前看springspringMvc,但是后边听从了一个大佬的建议,便选用了 Node.js 作为服务端,虽然使用的还是 mvc 模式,但是总感觉写起来没有 Java 的三层架构舒服吧,只是搭建服务的方式比较简单吧,使用 express 框架,直接几行代码就可以跑起来一个服务。

三、设计思路

1、这个博客系统主要由用户端和后台管理组成,这儿只展示部分页面。
1646146413831-1643529050359-网页.jpg

1646314776476-admin2.png

1646314728609-admin1.png
2、功能需求分析

1646146543169-1643706192123-后台管理功能需求分析.png

1646146574871-1643706515403-个人博客功能需求.png

3、数据库表设计。

1646146607108-1643708017964-数据库表设计.png

四、关于使用 vue2 的心得总结

1、前端项目结构

1646297999524-vue项目结构图.png

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&gt;
<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请求,启动定时器,因为这时候datamethods中的数据已经被初始化了,而且已经挂载到页面上了,所以我们才可以调用methods中的方法给data中的数据赋值。beforeDestory函数,离开该组件前触发,这时候组件中的 datamethodscomputed中的数据都是可用状态,一般用于清除一些数据,销毁一些资源。详见下图:

1646301198898-vue生命周期.png

  • 对于从服务端请求到的图片,我推荐使用图片懒加载。具体用法如下:

    1. 安装
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 请求,尽量使用 asyncawait来进行处理,代码结构比较清晰,当然你也可以使用.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
        }
   }
}
//组件中使用
&lt;router-link
     :to="{
             name: 'Detail',
             query: {
                indexof: item._id,
             },
          }"
&gt;{{ item.title }}&lt;/router-link&gt;
//接收值
 props: ["indexof"],

五、使用node.js作为服务端的总结

1、目录结构

1646305739638-node.png

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这种套模板的技术(仅仅依靠htmlcssjsjq等技术的堆积来完成一个复杂的页面展示也变得非常繁杂)再也无法高效的开发。**究其本质原因:前端开发没有像后端开发那样实现工程化、模块化、可复用化的思想。所以就会出现前后端开发不协调、效率低、扯皮的问题,这很不利于项目开发。因此项目管理者就想办法来解决这种问题,如何解决?→解耦。**在软件领域,任何复杂的问题面前,高内聚、低耦合这种原则几乎总是能见效。所以前后端分离开发出现了,把前端开发的责任从后端开发人员身上拿掉,给前端开发工程师一个单独的岗位和责任领域,将前端也工程化、模块化、项目化。这才是前后端分离开发最开始的来源。这些与vuereact框架没有什么关系,它们充其量只是一种具体实现方式而已。从本质上来看,前后端分离并不是一个技术问题,而是一个工程化考量和项目管理的问题。

2、前后端分离的核心

前后端分离核心思想是前端HTML页面通过AJAX调用后端的API接口并使用JSON数据进行交互。

3、如何做到前后端分离:

我这里以vuenode.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效果等都是由后台驱动,即前端都是塞到后端中,然后项目部署。当前端人员需要修改、发版本的时候就需要去求着后端人员帮忙)。前后端分离之后,就不再这样了,前后端发布上线可以完全独立,互相透明。这次项目部署的时候,我使用了前后端分离部署,感觉特别方便,尤其是在修改网页文件的时候,不需要考虑服务端。

博客迁移声明:

后来随着个人写博客的一个需求,发现自己原有开发的博客网站满足不了我当下的需求,于是开始重构博客,后边感觉没必要浪费这个时间,应该把精力专注于博客写作和内容输出上,所以便果断放弃了以前开发的博客,通过一些流行博客框架进行搭建,因此,现在看到的博客站点可能和文章描述的博客站点是不一样的。