# 简而美的个人博客系统 **Repository Path**: mdqc/myblog ## Basic Information - **Project Name**: 简而美的个人博客系统 - **Description**: 该项目为个人博客系统,采用SpringBoot,SSM,thymeleaf,semantic UI技术,对于一些想学习SpringBoot,SSM,thymeleaf,semantic UI的人来说,这应该是个很好的练手项目,而且我也写了相应的配套博文来介绍项目,所以还是比较好上手的。不过需要注意的是此项目并非原创,项目原型是李仁密老师的作品,具体的教学视频来自b站https://www.bilibili.com/video/BV1nE411r7TF,不过up主貌似也是搬运的。此个人博客前端是模仿李仁密老师的,其中,我根据自身需求做出了部分修改。因为我是主后端的,所以想借此机会来锻炼自己,所以后端部分完全由自己来设计编写(不过异常的控制器和博客内容转html这部分是借鉴了李仁密老师的)。介绍此项目的个人博文地址:https://blog.csdn.net/qq_46101869/article/details/107582966 欢迎各位提出自己意见和建议 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: http://dreamchaser.net.cn - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 61 - **Created**: 2022-10-29 - **Last Updated**: 2022-10-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 一、前言 ### 1.项目背景 此项目并非原创,项目原型是李仁密老师的作品,具体的教学视频来自b站https://www.bilibili.com/video/BV1nE411r7TF,不过up主貌似也是搬运的。 此个人博客前端是模仿李仁密老师的,其中,我根据自身需求做出了部分修改。 因为我是主后端的,所以想借此机会来锻炼自己,所以后端部分完全由自己来设计编写(不过异常的控制器和博客内容转html这部分是借鉴了李仁密老师的)。 为此在完成项目并测试之后我写了这篇博文来记录我的项目思路和遇到的一些问题,对于一些想学习SpringBoot,SSM,thymeleaf,semantic UI的人来说,这应该是个很好的练手项目。 ### 2.部分效果图展示 话不多说,先放几张效果图展示一下项目 ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101821672.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101819147.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101819826.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101819953.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101820787.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![请添加图片描述](https://img-blog.csdnimg.cn/20200726101822443.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ## 二、项目总述 ### 1.项目总述 此项目为个人博客系统,分前台和后台。前台负责展示你的博客,且页面适配移动端(不过不是我的功劳,是老师lirenmi的功劳)。管理员可以登录后台来对博客、分类、评论等进行管理。 ### 2.技术栈选择 前端:Semantic UI、thymeleaf 后端:SpringBoot、Spring、SpringMVC、Mybatis ### 3.环境介绍 数据库:mysql8.0 数据库连接池:Druid 前端框架:Semantic UI、thymeleaf模板引擎 后端框架:SpringBoot、SSM 语言:Java jdk版本:11.0.5(我个人是没怎么用语法糖的,按理来说jdk8以上都可以运行) 编写的IDE:IDEA 2020.1 插件引用: lombok(简化部分代码插件)、animate.css-master(动画效果)、editor.md-master(markdown插件)、prism(代码高亮)、tocbot-master(目录生成)、typo.css-master(网页排版)、logback(日志记录) ## 三、设计思路 接下来,我来讲讲我是如何一步一步来设计后台,当然过程仅供参考,勿喷。 ### 1.根据实际背景制定相应的策略 首先开始设计的时候我已经完成了前端页面的制作 以下当时完成的前端页面: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726104104678.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072610422915.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726104318836.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 2.总览项目,抽象功能,化为实体,画出设计图 这时候我还并没有开始写代码,而是把接下来要怎么做写个粗略的文档并画出相应的设计图(不过这也是我的习惯,我喜欢在写代码前先把思路写好,再去写代码,虽然写文档的时候确实会花一些时间,不过写代码的时候思路会很清晰,这会省下不少时间,并且能让你的代码结构清晰不少) 因为我写完前端的页面(不过后台只写了两张),所以先把所需的前端页面画出,再把这些页面汇总得到我第一张设计图——前端页面设计图 ![前端页面设计](https://img-blog.csdnimg.cn/2020072610523927.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 然后我就根据页面来分析我需要的功能,由此我画出了第二张设计图 ![根据页面写出功能](https://img-blog.csdnimg.cn/20200726105055808.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)随后我根据这些功能抽象分离,并划分所需的类,由此我得到了第三张设计图——UML图 ![UML图](https://img-blog.csdnimg.cn/20200726105525456.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 3.建库建表 至此,项目结构大致清晰了。根据这个类的划分我利用Navicat开始建表(当然PowerDeigner是个很好用的工具,可以让你在一边设计的同时完成建表的工作,但无奈我不太会用,所以采取原始的方式)。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726105853285.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 4.搭建框架结构 建完表后我开始搭建框架,先把最基础的那些建出来,分出最基本的Mapper(Dao)层、Service层、Controller层,pojo层(实体类),然后把写好的前端页面给搬过来,再配置所需要的依赖。经过一系列操作后,最基础的框架搭成了(SpringBoot已经简化了很多很多,这个操作还是蛮快的)。 然后再借助tablego神器,直接生成实体类和相应的mapper文件(当然接口还是要自己写的) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726110633679.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 然后再对接口加些基本的增删改查操作。 到此基本的框架已经出来了,接下来的不过是根据页面实现相应的功能。 ### 5.接口设计 唯一值得一提的是接口的设计,这是一门大学问,我原先的想法是采用restful风格来设计接口,但是实际操作中还是遇到了些问题。因为这个项目并不是正宗的前后端分离项目,后端实际上还承担了一部分渲染的工作,对于一些前端页面的变化都需要后端来完成,这样**后端接口数量会因这些变化急速增长,接口设计巧不巧秒就成了至关重要的一环,因为如果接口设计少了,那么就无法应对前端错综复杂的变化,设计多了那么后端系统将会变得极其复杂,不便于后期维护。** 举个例子,比如前端有个分页查询的需求,后端需根据查询的条件和分页来返回数据,如果说将这个查询和分页分开成为多个接口,那么系统将很繁杂,尤其是restful风格,难道你要对同一个资源针对不同情况命名多次?这显然不现实,所以你要解决的问题就是如何做到一个接口应对多种不同情况。 我的解决思路是采用map来接收前端数据,如果map中有相应的数据则做相应的处理。当然这需要前端的配合,不过前后端都是我写的,规矩自然由我来定。**前后端不分离好处就在于此,但坏处也显而易见,后端承担前端的部分工作,那么系统复杂度会极度攀升。** 说完设计接口,接下来要注意的就是一些细节的地方,比如前端没有传回相应的数据,但是如果将实体类传入做增删改查,那么没有数据的部分就是为null,而你又想要默认值,那么你要么在实体类中加默认值,要么别用实体类,用map传值。再比如null的处理,String和Integer的处理。这些都是细节,但往往出bug的都是这些细节!!! 等我做了大部分功能后,忽然发现架构的时候comment实体类和blog实体类少了个别属性,唉,无奈只能慢慢改。 **所以你需要记住架构的时候千万要架构好,不然等你写代码的时候再来改,那改的成本就不是一星半点儿了。** 后来针对页面做出了点调整和优化,将修改页和新增页合为一体,随后修改了我的设计图 ![前端设计图(修改后)](https://img-blog.csdnimg.cn/20200726113411208.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![根据页面写出功能(修改后)](https://img-blog.csdnimg.cn/20200726113417168.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)再往后,就是一步一步写相应页面的代码了,一开始遇到很多问题,写了两个页面就花了我四天,不过解决了相应的问题后,后面的页面就写的很快了,前前后后花了半个月时间,终于完成。在这个过程中我查了无数的博客,学到了很多很多,**不得不说做项目是最好的提升方式**。 哦,对了,跟你们分享一下我的习惯,我写代码的时候一般都会把遇到的问题记录下来,做出总结,前一天没有完成的任务我也会记录下来,以便第二天工作的开展,以下是我制作博客的文件夹 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726121956120.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 甚至是我在写这篇博客的时候我都提前写个简单的大纲,避免思路的中断 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072612202269.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)这样的习惯对于我而言还是蛮好的,它让我执行重要事情的时候可以更有条理,不会有那种大敌当前却手忙脚乱的感觉。 ## 四、项目结构 ### 1.数据库结构 库名:myblog blog表结构: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726115856995.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)comment表结构: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726115926363.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) type表结构: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120035790.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)tag表结构: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120109473.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) user表结构: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120155299.png) ### 2.项目结构 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120343467.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120454753.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726120515368.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072612055884.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 标准的SpringBoot结构! ## 五、项目思路 在这个模块,我来讲讲我做项目过程中几个关键问题的解决思路 ### 1.用户登录 我这里采用的是一种比较常规的手法,那就是拦截器+session的组合。 首先写个拦截器,对所有访问后台的请求进行拦截,如果该请求的session中没有user对象,则拦截并将其重定向到登录页面(这里要注意登录页面不能被自己给拦截了)。如果存在该user对象,则放行通过 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072615142020.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)登录的时候验证管理员账户密码,如果正确就在session中加入该对象。当然还有一种情况就是用户什么也不输入直接提交,如果不对这种情况加以处理,那么数据库就会报错。我采取的方法是前端进行非空验证。 当然后台也可以注销,即销毁session中的user对象。 用流程图演示就是下面这样 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726153440230.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 2.restful风格多变处理 什么是restful风格? **REST的核心原则是将你的API拆分为逻辑上的资源。这些资源通过http被操作(GET ,POST,PUT,DELETE)。** 如https://blog.csdn.net/newjueqi/article/details/44037011这个接口。 其实csdn接口就是采用这种风格。不信?你看看你当前的地址栏就知道了。 **restful在命名上有个特点就是把所有东西当做资源,这就要求接口命名上以名词为主,然后通过发送请求方式的不同来区分增删改查的操作。** **这样好处就是我一看接口就知道我要干什么,把后端定义成资源的获取,后端分工明确,职责清晰。** **但是这样也存在一些问题,如果全按这种方式,那么在前后端分离不那么明显的情况下,接口不能完全应对前端错综复杂的需求变化。这就很考验接口的设计。** 所以这种情况下就要求我们不能完全采用这种风格,该加参数还得加,而且还得应对一个接口适应多种变化。 ### 3.评论功能 评论功能还是有点复杂的,解决思路也很多。 而且你在建表的时候就得好好思考思路了。思考如何存储评论内容,如何存储评论与评论之间的关系。这样你后面处理起来才不会手忙脚乱。 这里我介绍一下我的思路。 首先,我把评论comment赋予以下几个属性 id,name,email,blog,isAdmin,content,time,parent。 前面几个属性好理解,无非就是存储评论的用户昵称,邮箱,评论内容之类。最后一个parent表示什么呢?其实这个parent使用用来存储评论与评论之间的关系的,它是int类型,主要存储父评论的id。如果没有父评论,那么则用-1存储以示区别。这样我们就可以分清以及评论和二级评论了。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726155830894.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)不过这还是我偷懒的情况,因为在二级评论里你会发现没有回复按钮。 实际上是被我删了,用@XXX代替,不然加了这按钮,这逻辑会复杂很多,存储起来也很麻烦。反正主要的效果都能达到,不如删去些细枝末节的东西来简化逻辑(好吧,我承认是我偷懒了QAQ)。 ### 4.区分博主和普通游客的评论 有人可能会问:为什么要区分博主和普通游客的评论? 那你有没有想过一种很有意思的情况,就是游客伪装成博主的用户名和头像来“过愚人节”,这很有意思,但是机智的我为了防止这种情况的发生,在comment类中加了isAdmin属性以区分是否是管理员的评论,前端也根据此来区别显示评论。 而判断的依据就是session中有没有user对象。 ### 5.分页显示 **分页显示实际上有三种思路, 一是后端把所有查询结果都发到前端,然后由前端进行分页显示处理; 二是后端查询后由后端出来分页,把其分好再发到前端 三是我需要时再查,每次点击上一页下一页时发送一个请求,请求包含分页的信息,由后端返回该分页的结果** 我这里采用的是第三种方法,因为这种方法是通过后端处理,而我又擅长后端,而且这种方法展示的数据具有实时性,前端接收的数据量小,反应快,用户体验好。 但是麻烦的地方随之而来,随着分页的信息都由后端来处理,还要肩负渲染的工作,导致后端的接口(controller)极其多。**因为需求变化多。特别是同一个页面有多种返回数据的需求,而每种返回的需求都需要分页显示,这样的话接口就呈指数式快速增加。这显然会把系统搞复杂,这就要求我接口的设计必须应对多种场景。** 其实我在写的时候也很犹豫,当时我写了一半,发现比较麻烦,想尝试第一种方法,但是由于我前端能力实在不行,主要是我不知道怎么实现点击后重新加载数据。然后考虑再三,最终还是选择第三种方法,虽然麻烦是麻烦了点,但是折腾一下后发现也不是什么问题。 ### 6.利用thymeleaf模板中的if来达到选中效果 大家应该知道选中时会出现选中状态,这对导航来说还好,因为毕竟页面切换了,选中状态也都是写静态效果。 但是如果不切换页面呢? 这对前端老手根本不是什么问题,但对于我这个前端菜鸟来说要解决就有点烦了。 这时候我想到了个取巧的方法,利用thymeleaf模板引擎中的if和switch,case来间接达到选中的效果。 举个例子, ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726162119388.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)在分类专栏上有这么一个需求,点击相应分页然后返回相应分类下的博客。然后切换分类的选中效果。 我的做法就是后端传数据的时候就传入一个全局的数据,比如这里就是typeId,渲染分类栏的时候,通过if比较typeId是否一致如果一致就采用选中状态,如果不是就采用非选中状态 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726162450373.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 这样就能巧妙的间接实现选中效果切换的目的。 但对于前端大佬来说可能会不屑一顾,不过对于我这种不善前端的人来说,那确实对我还是蛮方便的。 前端虽然自己看得懂,也会写一部分,但如果要我做那种交互效果,虽然我会,但既然有取巧的办法干嘛不用呢? ## 六、遇到的问题 这里写一些我写代码过程中比较坑的问题。 ### 1.Semantic UI文件的导入 视频中时采用链接的方式导入,但是我怕部署到服务器上的时候响应会变慢,所以我就采用本地的方式来导入文件,但最主要的原因是官网上找不到cdn链接了,也许是官网不推荐使用了。 不过也遇到了些问题, 首先遇到的是图标显示异常,最后找了下百度,找到了缘由 原因:图标资源未导入。 最简单的办法加入这句 ```java `` ``` 或者把icon.min.css文件下载到本地,再引入你的html。 但是这有个问题,就是你如果单个文件引入的话,由于其内部src路径是按照压缩包里面写的路径写的,这样就会造成路径问题。 解决方法就是把引用的路径改成现在的路径。这很麻烦,所以我才用另外一种,将这个文件夹复制粘贴至项目根目录,这样,引用的时候只要引用这三句就行了。 ```javascript ``` #### blogs.html ```java 后台管理
标题 分类 更新时间 状态 操作
1 【一年总结】记我的大一生活 一年总结 2020-7-04 15:12 草稿 编辑
新增
``` ## 八.部分测试结果及效果展示 这部分其实我不想写的,因为前言里提到了,全部展示出来又太费空间,这里就展示一部分前言里没提到过的效果图 ### 登录页 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726173954273.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 登录失败效果 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726174033895.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 博客管理页 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726174211168.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 评论管理 #### 列表页 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726174311880.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) #### 详情页 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726174404308.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 归档页 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200726174544957.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ## 九、博客部署 这个部分我从租服务器开始讲,直至部署完成! ### 1、租服务器 这里我选择阿里云的服务器来进行演示 首先把你的账号注册完后打开活动页面,找到云翼计划(因为我是学生,有学生优惠),选择你需要的服务器,我这里选择的是ecs云服务器。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807151040954.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 购买支付后打开实例详情 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807151655763.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ### 2、连接服务器 点击更多设置你的密码,然后复制公网ip,打开远程桌面连接 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807151815714.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70)输入你的用户名(windows用户名默认是administrator,linux默认是root)和密码即可远程连接至服务器。 ### 3、配置服务器环境 开始安装mysql数据库,以下是下载地址 https://dev.mysql.com/downloads/file/?id=497106 具体操作看这篇博文 https://blog.csdn.net/NOWSHUT/article/details/107722623 安装Navicat,创建myblog数据库,在此数据库中运行sql文件 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807152410985.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 把你的jdk复制粘贴至服务器,然后配上环境变量 ### 4、把项目打成jar包发布至服务器 在pom.xml中把打包方式设置为jar(`jar` ),使用package命令,然后你的target目录下就会出现一个jar文件 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807152549638.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 将其复制粘贴至服务器上,选择你想要的存储的文件夹下,这里我直接选择c盘(不过建议大家还是创建个文件夹比较好) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807152745642.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 在上面地址栏中输入cmd打开命令行, 输入:java -jar blog.jar ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807152946507.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 启动成功! ### 5、设置服务器安全组 其实就是设置外网能访问的端口, ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020080715311658.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807153121357.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 不知道怎么打开这个界面的可以看这里https://developer.aliyun.com/article/702814 ### 6、访问项目 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200807153336115.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MTAxODY5,size_16,color_FFFFFF,t_70) 博客部署成功了! ## 十、总结和收获 这个人博客系统总计耗时半个月,前端页面花了3天,后端设计编写花了12天。总计好多行代码QAQ 这次项目让我收获良多,原先我SpringBoot和SSM虽然学了,但是远没有到掌握的程度,真正做起项目来的时候还是要去看别人的博客。真正自己经历过设计,编写之后,我的工程能力有了很大的提升,对于架构方面也有了新的理解。 其实做过项目和没做过项目完全是两个层次的。 就算你理论学的再好,不实践,不去做项目,你的知识永远是在纸上谈兵,很多问题是你在设计编写的时候才能发现的,有些理解是你只有亲身经历才能懂得。 所以做项目真的很重要,这是成长最快的一种方式! 这也算是我正式写app后端之前的一种锻炼吧! 也希望未来的我能不忘初心,砥砺前行! 谨以此记,共勉! 该项目源码已上传至码云,[项目地址](https://gitee.com/dreamchasers/myblog),需要的可以自行下载,对Java学习感兴趣的也可以加入q群1028457867,我们一起交流学习! 最后,欢迎访问[我的博客](http://dreamchaser.net.cn)! 如果对此项目有什么疑惑或者建议,欢迎大家在评论区评论指正。
### 项目更新日志 2020.8.7 修复路径错误引发的bug,优化了配置属性,新增运行环境配置,添加了博客介绍 2020.8.14 修复添加标签分类时博客数量为空的bug 2020.8.21 优化展示效果,完善浏览数功能 2020.8.22 修复更新博客后浏览量归零的bug,修复无法删除博客的bug