2.5万字详细讲解个人网站的开发过程和项目的部署

Posted Talisman丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2.5万字详细讲解个人网站的开发过程和项目的部署相关的知识,希望对你有一定的参考价值。

简介

博客介绍: 第一个前后端分离的项目,想做个好的个人博客是很久之前的事,算上这个博客我一共做过三个,第一个是用jsp做的,因为没有设计感页面简直不能直视。第二个是跟着B站上的做的,用thymeleaf模板做的博客,那时候才学SpringBoot没多久,算是为了熟练SpringBoot才做的。这次是想做一个能长期维护的博客(就是一直会用这个,就算要改的话,整体架构也不会怎么变的),所以我打算就用vue来做,做前后端分离的项目。

技术讲解: 这篇博客会详细讲解整个环境配置、开发流程、项目部署这些内容,比如说某些重要的内容,哪里容易出错,哪一方面要注意一下。一些简单的CURD操作就不会详细讲解了。

关于界面: 有些页面是参照别人的做,例如首页我是参照这个做的,并在基础上修改了一下。https://xiaoyou66.com/

个人网站: 附上部署好的网站,可以更好的阅读下面的文章http://liaojiale.com/


1 技术介绍

1.1 个人博客功能


1.2 技术组合

  1. 前端:vue + Semantic-ui框架
  2. 后端:SpringBoot + MyBatis-plus
  3. 数据库: mysql + Redis
  4. 运维:docker + nginx

1.3 工具与坏境

  1. IDEA
  2. Navicat
  3. Xshell
  4. Xftp
  5. Maven3.6
  6. JDK 8

2 项目的环境配置

2.1 vue的环境配置

首先进到放vue代码的文件下,在地址栏上输入CMD就会跳到当前的目录下,然后根据以下步骤去创建vue项目

vue init webpack 文件名

# 进入工程目录
cd 创建完的vue项目
# 安装 vue-router
cnpm install vue-router --save-dev
# 安装 element-ui
cnpm install element-ui --save-dev
# 安装依赖
cnpm install
# 安装 SASS 加载器
cnpm install sass-loader node-sass --save-dev
# 启动测试
npm run dev

npm isntall vue-router --save
npm install storage --save-dev
npm install semantic-ui  --save-dev
npm install vue-jsonp --save
cnpm install axios --save-dev
cnpm install vue-axios --save-dev

1.环境配置好后首先进到main.js把安装好的依赖到进去

  1. 配置路由
  2. 然后通过npm run dev进行访问,访问成功则环境配置好了,之后就可以进行前端页面的操作啦~~~

2.2 解决跨域问题

在获取后端数据时都会有一个跨域的问题要解决,所以我们去找到config目录下的index.js的文件进行如下的操作

下面的是以/api/代替了http://localhost:8081/这个ip和端口,这样就能解决跨域的问题。

this.axios({
     url: "/api/layer/getLayerInfo",
     method: "get",
 })

2.3 关于图标的获取

可以通过阿里巴巴矢量图标库获取图标(个人比较推荐,因为这个是真的很简单方便)

步骤

  1. 先进入阿里巴巴矢量图标库
  2. 搜索你需要的图标
  3. 找到喜欢的图标并收藏
  4. 新建项目并添加至项目中
  5. 在Font Class里点击更新代码便会出现链接,然后打开链接并复制里面的内容
  6. 在vue项目里创建一个css文件并复制进去,最后引用这个css文件
  7. 在添加图标的标签里的class里面加入iconfont 图标的class。例如:
 <strong class="iconfont icon-shouye"></strong>

3 前端技术

3.1 element-ui的分页使用介绍

<el-col>
  <el-pagination
     background
     layout="prev, pager, next"
     @current-change="selectPage()"
     :total="blogsCount * 10 / size">
   </el-pagination>
</el-col>

current-change当前页面发生改变时会触发

blogsCount是博客的数量,通过blogsCount * 10 / size就可以获取到页数

通过获取active这个class获取页面发生改变时的值,再把这个值传给后台便可以获取下一页的数据

selectPage(){
      let current = document.getElementsByClassName('active')[0].innerhtml
      this.axios({
        url:"/api/{{请求地址}}",
        method:"get",
        params:{
          current:current - 1,
          size:this.size
        }
      }).then(res => {
        this.blogs = res.data.blog
      })
    },

3.2 发布博客

个人博客最核心的是什么,那当然是写博客啊,要说写博客首选的编辑器当然是markdown,功能多样却操作容易方便。有一个基于vue的markdow编辑插件mavon-edtior

步骤

  1. npm install mavon-editor --save
  2. 在main.js上引用
// 全局注册
    // import with ES6
    import Vue from 'vue'
    import mavonEditor from 'mavon-editor'
    import 'mavon-editor/dist/css/index.css'
    // use
    Vue.use(mavonEditor)
    new Vue({
        'el': '#main',
        data() {
            return { value: '' }
        }
    })
  1. maven-editor配置


获取md格式和html格式,md的格式内容是在修改博客时用的,html格式的内容是博客展示是用的。这样就能把数据发到后台在存进数据库啦。记得两种格式都要存进数据库

updateDoc(markdown, render) {
      this.html = render;
      this.markdown = markdown;
},
saveDoc(markdown, render) {
      this.html = render;
      this.markdown = markdown;
},
  1. 图片上传
 $imgAdd (pos, $file) {
      // 第一步.将图片上传到服务器.
      var formdata = new FormData()
      formdata.append('image', $file)
      this.img_file[pos] = $file
      this.$http({
        url: '/api/{{地址}}',
        method: 'post',
        data: formdata,
        headers: { 'Content-Type': 'multipart/form-data' }
      }).then((res) => {
        let _res = res.data
        // 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url)
        this.$refs.md.$img2Url(pos, _res.data)
      })
    },
  1. 图片删除
    下面的请求主要是删除图片,删除服务器上的图片
$imgDel (pos) {
      delete this.img_file[pos]
      var p = pos[0]
      this.axios({
        url:"/api/{{地址}}",
        method:"get",
        params:{
          pos:p
        }
      })
    }
  1. 代码高亮
    通过npm引入以下的三个插件,并在mavon-editor标签上加入这段代码 :ishljs = "true"

highlight.js
github-markdown-css
katex(v2.4.7)

小提示:如果你觉得这些高亮的颜色、字体大小不好看,可以通过f12查看这个高亮的代码的class,然后通过权重(!important)对属性进行自己喜欢的样式修改。

  1. 展示博客的内容
    通过以下代码让博客内容进行展示
    content是从后台请求到的博客内容,也就是html格式的内容
<div id="content" class="markdown-body" v-html="content">
  1. mavon-editor官方文档

3.3 点赞功能的实现

点赞功能通常都是一个人只能点赞一次,不可以重复点赞,因为这个博客主要是个人博客,个人所有的,没有其他用户,所以在数据库上没有建用户表,但要有点赞功能且不能重复点赞,我第一个想到的技术就是本地储存技术也就是cookie,当你点赞时会在你的浏览器上加上一个cookie,例如:我在id为3的博客里点赞了就会在浏览器上储存一个blogId:3这样的一个cookie意思是你在id为3的博客里点赞了,如果识别到你本地上有这个cookie那你就不能继续点赞了。
步骤

  1. 先建一个工具包把这个工具类放进去
var storage = {
  /**
   对本地数据进行操作的相关方法,如localStorage,sessionStorage的封装
   */
  setStorage: function(key, value, duration) {
    var data = {
      value: value,
      expiryTime: !duration || isNaN(duration) ? 0 : this.getCurrentTimeStamp() + parseInt(duration)
    };
    localStorage[key] = JSON.stringify(data);
  },
  getStorage: function(key) {
    var data = localStorage[key];
    if (!data || data === "null") {
      return null;
    }
    var now = this.getCurrentTimeStamp();
    var obj;
    try {
      obj = JSON.parse(data);
    } catch (e) {
      return null;
    }
    if (obj.expiryTime === 0 || obj.expiryTime > now) {
      return obj.value;
    }
    return null;
  },
  removeStorage: function(key){
    localStorage.removeItem(key);
  },
  getSession: function(key) {
    var data = sessionStorage[key];
    if (!data || data === "null") {
      return null;
    }
    return JSON.parse(data).value;

  },
  setSession: function(key, value) {
    var data = {
      value: value
    }
    sessionStorage[key] = JSON.stringify(data);
  },
  getCurrentTimeStamp: function() {
    return Date.parse(new Date());
  }
};
export default storage;

  1. 在main.js如下配置
import mavonEditor from "mavon-editor";
Vue.prototype.$storage=storage;

使用方法

this.$storage.setStorage(key,value) //设置cookie
this.$storage.getStorage(key)       //获取cookie

代码如下

if (this.$storage.getStorage("good"+this.blogId)==this.blogId){
        this.$message.warning("你已经点过赞了")
        return
}
this.axios({
  url:"/api/{{地址}}",
  method:"get",
  params:{blogId:this.blogId}
}).then(res=>{
   if (res.data){
     this.$message.success("点赞成功")
     this.$storage.setStorage("good"+this.blogId,this.blogId)
   }
})

3.4 评论

说到评论。几乎每个博客都会加上这一点,毕竟这个能增加和别人的互动性。这个评论的难点是数据库的设计,如果数据库设计的不好,做出来是比较困难的。
评论的结构设计

思路: 根据这个设计,我们如何去设计呢?如果是建一张表如何设计才能做出楼和层的结构,他们的关系是怎样表现的出来的?我想过用一张表设计,但这样设计会很麻烦。所以我建了两张表,一张是floor(楼)表和layer(层)表。如下:

floor表是专门放楼的评论的数据,而层表是专门放层评论的数据,层的数据是绑定楼的id来获取你是在哪一楼发言,这样就能确定楼层之间的关系啦~~~

要展示哪一些层对应哪一楼这个最简单不过了只要用v-if将绑定在层的楼id等于楼的id就可。如下:

<div v-for="layer in allLayer" v-if="layer.floorId == floor.id">

3.5 获取B站用户信息

既然做评论,当然要知道是谁评论,可这是个人博客诶,又没有建用户表,所以我想到获取B站的个人信息作为评论的前提。
步骤

  1. 打开在用户信息那里工具栏抓包,你会发现有一个请求是获取个人信息的,接口如下:

https://api.bilibili.com/x/space/acc/infomid={{B站的UID}}&jsonp=jsonp

  1. 通过键盘输入每一个字母就去请求一次接口
  2. 通过以下代码展示图片,不然展示不了
if( res.data.data.face !== undefined ){
          let _u = res.data.data.face.substring( 7 );
          this.BPhoto = res.data.data.face = 'https://images.weserv.nl/?url=' + _u;
}

这是完成后的样子~

3.6 相册的设计

相册是用了不少的时间去做的,但仔细想想其实很多都是CURD操作和一下逻辑上的操作,其实没有什么可以说的,我相信多人都是会做的,所以就不说了,但花费了这么多时间还是要讲一下不说的原因的哈哈哈哈哈。
这个是相册的链接可以点进去看一下哈------相册链接

3.7 图片上传

vue提供的图片上传真的太容易了,只要贴上如下代码就可了,详细的介绍就看vue官方。

<el-upload
    class="upload-demo"
    drag
    :action="'/api/{{请求地址}}"
    list-type="picture"
    :on-preview="handlePreview"
    :on-remove="handleRemove"
    multiple>
    <i class="el-icon-upload"></i>
    <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>

3.8 时光轴设计详情

时光轴的设计结构

这个时光轴的设计难点就是sql语句和怎么展示出来。首先我们先写获取年份的sql语句,如下

SELECT DATE_FORMAT( b.createTime,'%Y') as years FROM blog b
        GROUP BY years
        ORDER BY years DESC;

然后获取该年份下的博客

SELECT DATE_FORMAT( b.createTime,'%Y') as years FROM blog b
        GROUP BY years
        ORDER BY years DESC;

通过在两条sql语句就能查询出来啦~
那我们该怎么去展示在页面呢?首先我们先把年份给遍历出来,然后遍历查询出来博客,也就是第二条sql语句的数据,最后我们遍历出该博客的信息,并等于当前年份的博客才能展示出来。所以我们用到了v-if语句,这样就完成了,如果有什么不明白可以在评论区问问我哈哈哈

<div v-for="year in allYears">
 <div v-for="info in blogYearInfo">
   <div v-for="i in info" v-if="i.createTime.split('-')[0]==year"></div>
 </div>
</div>	

关于前端的知识现在到这里已经结束了,接下来讲一下关于后端方面的知识!!!


4 后端技术

4.1 SpringBoot环境配置

mybatis-plus里面有一个代码自动生成,我们可以通过代码来生成无聊且没有意思的代码。

  1. 我们先导入需要的依赖包
<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.0.5</version>
</dependency>
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-generator</artifactId>
  <version>3.0.5</version>
  <scope>test</scope>
</dependency>
  1. 我可以通过以下代码生成
public static void main(String[] args) {

        // 需要构建一个 代码自动生成器 对象
        AutoGenerator mpg = new AutoGenerator();
        // 配置策略

        // 1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath+"/src/main/java");
        gc.setAuthor("Talisman");
        gc.setOpen(false);
        gc.setFileOverride(false); // 是否覆盖
        gc.setServiceName("%sService"); // 去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
//        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 2、 配置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/yingmublog?useSSL=true&characterEncoding=utf8&useUnicode=true&autoReconnect=true&failOverReadOnly=false");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("账号");
        dsc.setPassword("密码");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        
        // 3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("yingmublog");
        pc.setParent("com.jiale");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 配置策略
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("admin","blog","blog_tag","comment","tag","type","topic","animation",
                "friend","other","album_photo","album","floor","layer");// 设置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setLogicDeleteFieldName("deleted");
        
        // 自动填充配置
        TableFill createTime = new TableFill("createTime", FieldFill.INSERT);
        TableFill updateTime = new TableFill("updateTime", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);

        // 乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        mpg.execute();
    }

通过这些代码我们就能生成这样的目录结构


这段代码是映射你表里的字段,如果你每增加一个表可以写进去再运行代码,他就会生成对应的,这个真的很方便,大力推荐一下,它可以减少我们不必要浪费的时间。

 strategy.setInclude("admin","blog","blog_tag","comment","tag","type","topic","animation",
                "friend","other","album_photo","album","floor","layer"2.5 万字详解:23 种设计模式

基于python的种子搜索网站-项目部署

❤️爆肝万字整理的综合架构web服务之nginx详解❤️,附建议收藏

UG NX二次开发(C#)--详细讲述编程模板NXOpen_CS_Wizard的代码意义,帮你轻松进入NXOpen(C#)二次开发

基于python的种子搜索网站-开发过程

万字长文 Vue全家桶从入门到实战,超详细笔记整理 ( 三 ) (建议收藏)