校园文件发布系统|基于Springboot实现校园文章发布系统

时间:2022-12-23 07:52:05

作者主页:编程千纸鹤

作者简介:Java、前端、Pythone开发多年,做过高程,项目经理,架构师

主要内容:Java项目开发、毕业设计开发、面试技术整理、最新技术分享

收藏点赞不迷路  关注作者有好处

文末获得源码

项目编号:BS-PT-077

前言:

对于当前的个人博客系统,比较封闭并且有自己的局限性,一旦流量大了以后就会受到不明来历的恶意流量攻击。无论你买什么服务器都没有用。对于个人来说,基本都是重启服务器是最佳的解决办法。所以,安全问题对于独立博客来说是一个很大的挑战。并且作为一个个人博客,网站中只有拥有者才能进行文章的发布等操作,这使得其他用户不能发布自己的文章。

校园文章发布系统吸收了个人博客部分特点。允许所有用户发布文章,摒弃掉博客网站只能拥有者发文章这一弊端,用户还能建立属于自己个人的分类与标签,使得用户个性化设置达到最大,并且每个用户既是文章发布者,也是文章的阅读者,能对别人发布的文章进行查看评论等操作,并且本系统主要面向对象为在校大学生,所以在网站安全方面,后期可以将项目运行在局域网内,使得只有使用校园网才能对我们的系统进行访问。

一,项目简介

本系统设计了两种用户角色:普通用户和系统管理员。普通用户可以新建属于个人的分类与标签,可以发布个人的公开或者私有文章,并且还能游览系统内的其他公开文章,对文章进行点赞、评论等操作。系统管理员主要是对用户产生的数据进行统计与维护;能对系统中的用户进行统计和操作,对用户的信息进行查看、删除等;能对用户发布的文章进行审核,对于一些非法的文章不予通过,并提醒用户所发的文章违规,还能对文章进行删除和维护等操作;能对用户的评论信息进行管理,查看用户们所发布的评论,还可以将违规评论直接删除;能对用户创建的分类信息进行查看、修改、删除等操作;能对用户创建的标签信息进行查看、修改、删除等。该系统的功能模块图如图3-1所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图3-1系统功能模块图

普通用户可以使用网站的基础功能,如查看平台首页、进入用户个人中心、进入用户管理、对个人的文章管理、搜索系统的所有文章等,用户功能用例图如图3-2所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图3-2 用户功能用例图

管理员通过系统自带的帐号登录,管理员账号除了可以使用普通用户的所有功能外,还可以进入后台管理页面,对用户和文章进行管理,对文章进行评论管理,对文章进行分类和标签管理。管理员功能用例图如图3-3所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图3-3 管理员用例图

本系统有文章搜索模块、文章管理模块、平台首页模块、用户管理模块、个人中心模块、管理员模块6个功能模块,其主要功能分析如下:

1.文章搜索模块功能

表3-1 文章搜索模块功能描述

功能名称

功能描述

按文章标题搜索

输入文章的部分标题,查看对应的文章

按分类搜索

通过文章的大分类得到一个类型的文章

按标签搜索

通过文章所包含的标签,得到对应的文章

按文章信息搜索

通过关键字搜索包含该关键字的文章

2.文章管理模块

表3-2 文章管理模块功能描述

功能名称

功能描述

文章回收站

用户可以将文章删除放入回收站

用户发布文章

用户可以发布自己的个人文章

用户修改文章

用户可以修改自己发布的文章的内容

3.平台首页模块

表3-3 平台首页模块功能描述

功能名称

功能描述

用户注册

用户通过QQ邮箱注册系统的账号

用户登录

用户通过个人账号登录系统

游览平台文章

对系统中的文章进行查阅游览

查看文章详细信息

查看某一篇文章的详细内容

用户评论文章

在文章详细内容界面可对文章发布个人的评论

文章点赞

在文章详细内容界面可对文章点赞

4.用户管理模块

表3-4 用户管理模块功能描述

功能名称

功能描述

查看归档信息

用户可按照文章发布时间查看发布的所有文章

管理分类信息

用户对个人文章的分类做增删改查

管理标签信息

用户对个人的文章标签做增删改查

个人通知

当别人对用户的文章进行评论或者别人回复用户的文章后,都会在个人通知中显示

5.个人中心模块

表3-5 个人中心模块功能描述

功能名称

功能描述

查看个人信息

用户可查看个人的详细信息

修改个人信息

对自己的信息进行修改

修改密码

修改个人的账号密码

6.管理员模块

表3-6 管理员模块功能描述

功能名称

功能描述

登录注册

管理员可注册和登录后台系统

用户管理

可查看、删除用户的信息

文章管理

审核用户发布的文章,可对文章进行增删查

评论管理

查看用户的评论,对非法的评论进行删除

分类管理

对用户新建的分类进行管理

标签管理

对用户新建的标签进行管理

二,环境介绍

语言环境:Java:  jdk1.8

数据库:Mysql: mysql5.7

应用服务器:Tomcat:  tomcat8.5.31

开发工具:IDEA或eclipse

三,系统展示

5.1  平台首页模块

5.1.1  注册与登录

前端的登录界面由login.vue实现,注册页面由register.vue实现。用户注册时,用户需要先填写邮箱,接着发送验证码,通过/user/getSendCode接口将邮箱号传入后端,后端接收到请求后,首先判断当前邮箱是否已经在系统中,若存在系统则返回信息提示用户直接登录,否则调用UserService类中的getSendCode方法,先生成一个六位的随机验证码,将验证码存入Redis中,再通过qq邮箱接口,发送对应邮件到用户的邮箱中,返回成功信息,提示用户验证码发送成功,用户输入正确的邮箱和合法的密码后,点击注册按钮,此时调用/user/regist接口,将用户的信息和验证码一起传给后端,后端首先从Redis中获取当前用户的正确验证码,与传来的验证码进行匹配,如果匹配成功则将用户的信息写入数据库,返回成功信息给用户,提示用户注册成功,若验证码不正确,则直接返回验证码输入有误的信息给前端,前端提示用户验证码输入错误。界面实现效果如图5-1所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-1 用户注册界面

用户注册完成后,则可以进行账号登录,输入邮箱和密码之后点击登录,前端通过/user/loginPwd接口向后端发送请求,后端从数据库中查询是否存在这个用户,并且查询该用户的密码,与当前用户输入的是否一致,若密码也一致则返回用户的信息给前端,前端通过传回的数据是否为用户个人信息为判断的标准,如果返回了个人信息,则提示用户登录成功,将页面跳转到系统的主页,并且将用户的个人信息存储到游览器的sessionStorage中,以便用户只是刷新游览器时,保证用户的登录状态,若返回flase则提示用户账号或者密码输出错误。界面实现效果如图5-2所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-2 用户登录界面

5.1.2  游览平台文章

在用户登录后,前端通过this.$router.push('/homeIndex')进行路由跳转,进入主页,在主页界面进行挂载之前,前端通过/article/initGetArticleList接口,向后端发送请求,对主页的文章列表数据进行初始化,后端将查询到的数据返回给前端,前端接收到数据后对文章列表进行渲染。界面实现效果图如图5-3所示。接着前端还会通过/home/getTjCarouselArticle接口,向后端请求首页轮播图的数据,因为轮播图数据是通过文章的点赞量来确定,并且通过定时器每天凌晨五点对数据进行更新,因此会将数据放入Redis缓存,以此减轻数据库的压力,所以每次请求时都会从Redis缓存中获取数据,将结果返回给前端,前端对数据进行渲染。界面实现效果如图5-4所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-3 文章列表界面

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-4 首页轮播图界面

5.1.3  查看文章详细信息

当用户点击某一篇文章时,前端进行路由跳转,并且会将该篇文章的id作为路由参数一起放入请求的路由中,在页面组件挂载前,会先准备文章详细信息界面所需要的数据,通过/home/getArticleById接口获取当前文章的详细信息,前端接收后端返回的数据后,对文章的详细内容进行渲染,加载文章的详细信息和目录信息,如图5-5所示;通过/home/getFiveArticleByUserid接口获取当前文章的作者的最新发布的五篇文章的跳转链接,后端实现为通过用户的id加以文章发布的日期做降序排列,最终取前五条数据得到需要的数据,前端接收后端的数据后,对数据进行渲染,界面实现效果图如图5-6所示;通过/comment/getArticleCommentCount接口分页获取当前文章的评论信息,后端接收请求后,通过文章id查询属于该文章的评论的信息,将得到的数据返回给前端,前端将得到的数据进行渲染,界面实现效果图如图5-7所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-5 文章详细信息界面

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-6 用户其他文章推荐界面

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-7 文章评论信息界面

5.1.4  用户评论

用户评论功能分为两类,一类是用户对文章进行评论,另一类是用户对其他用户的评论进行回复。当用户对文章进行评论时,点击提交按钮,如图5-8所示,前端会先判断当前用户是否登录,若未登录,则提示用户登录,并通过this.$router.push('/login')语句跳转到登录界面,再判断当前用户评论的内容是否为空,若为空则提示用户评论不能为空,不为空则通过/comment/addComment发送请求到后端,后端在数据库中新增一条数据后,返回成功信息给前端,前端提示用户评论成功。如果是用户回复其他用户的评论,则先点击目标评论后面的回复按钮,此时会出现回复框,如图5-9所示,用户输入需要回复的内容后,点击提交按钮,前端也是通过/comment/addComment接口发送请求到后端,后端插入一条数据后,返回成功信息给前端,前端提示用户回复成功。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-8 用户评论文章界面

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-9 用户回复评论界面

5.2  文章管理模块

5.2.1  文章回收站

用户可以在个人中心查看自己所发布的文章的列表,在这里用户可以点击删除按钮,将文章放入回收站,如图5-10所示,点击删除按钮后,界面会提示用户是否确认删除,用户点击确认,前端会通过/article/delArticleList接口向后端发送删除选中文件的请求,后端接收到请求后,将对应文章移入回收站中,返回成功信息给前端,前端提示用户删除成功。接着用户可以在回收站中找到被删除的文章,如图5-11所示,用户可以恢复被删除的文章,也可以彻底删除文章,若点击恢复按钮,前端会通过/article/delArticleList接口,发送对应的参数到后端,后端通过其中的参数去进行判断,是将文章移入回收站还是恢复该文章,恢复成功后,返回成功信息给前端,前端提示用户恢复文章成功;若用户点击的是删除按钮,则通过/article/delArticleList接口,给后端发送对应的参数,后端解析参数后会将选定的文章数据进行彻底删除,最后返回给前端成功信息,前端进行渲染,提示用户删除成功。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-10 用户操作个人文章界面

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-11 用户查看文章回收站界面

5.2.2  用户发布文章

用户点击发布文章按钮后,进入文章编写界面,在这里用户可以编写文章内容,还可以在文章中插入图片,插入图片时通过/file/uploadImg接口直接将图片保存到服务器中,再将该图片的访问路径返回给前端,前端会通过markdown保存图片的请求路径,并显示图片的预览,如图5-12所示,当用户编写好文章内容后,则可以进入文章发布界面,如图5-13所示,在这里用户需要将文章的必要信息完善,在选择分类时,前端已经通过/classify/getMyClassify接口,获取了该用户现有的所有分类,接着监视分类输入框,展示用户可能想要选择的分类,也可以直接在这里创建一个新的分类,如图5-14所示,在选择标签时,系统不仅仅会显示用户个人的标签,还会推荐本平台文章数前五的五个标签供用户选择,平台前五标签通过/labels/getTJLabels接口向后端发送请求,将标签信息封装在数组中,返回给前端,前端就能进行展示,用户在这里可以选择多个标签,也会根据用户在搜索框中输入的关键字,通过/labels/getMyLabels接口进行模糊查询,显示用户可能想要选择的标签,如图5-15所示,最终用户点击发表按钮,前端通过/article/addArticle接口将文章信息发送给后端,后端接收数据后,将文章信息插入数据库,将分类表和标签表中文章数量加一,再文章分类表、文章标签表中添加文章和分类、标签之间的关联数据,返回成功信息给前端,前端接收后提示用户文章发布成功,并通过this.$router.push({path:'/userCenter/articleList'})跳转到用户中心的文章列表。

校园文件发布系统|基于Springboot实现校园文章发布系统

图5-12 用户文章内容上传图片界面

四,核心代码展示

package com.qst.controller;

import com.qst.pojo.ResultInfo;
import com.qst.pojo.schoolarticle.Article;
import com.qst.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/article")
public class ArticleController {
    @Autowired
    ArticleService articleService;
    //添加普通文章
    @RequestMapping("/addArticle")
    public ResultInfo addArticle(Article article){
        System.out.println(article);
        try {
            return articleService.addArticle(article);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,请稍后再试");
        }

    }
    //添加文章草稿
    @RequestMapping("/addArticleDraft")
    public ResultInfo addArticleDraft(Article article){
        try {
            return articleService.addArticleDraft(article);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,请稍后再试");
        }    }
    //展示文章列表、分页、多条件查询
    @RequestMapping("/showArticleList")
    public ResultInfo showArticleList( Article article,Integer current, Integer size){

        try {
            return articleService.showArticleList(article,current,size);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,查询失败,请稍后再试");
        }
    }//展示首页文章列表
    @RequestMapping("/initGetArticleList")
    public ResultInfo initGetArticleList( Article article,Integer current, Integer size){

        try {
            return articleService.initGetArticleList(article,current,size);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,查询失败,请稍后再试");
        }
    }
    //将文章放入回收站或者将回收站的文章恢复或将文章彻底删除
    @RequestMapping("/delArticleList")
    public ResultInfo delArticleList(Article article,Integer[] idList){
        try {
            return articleService.delArticleList(article,idList);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统暂时出现异常,请稍后再试");
        }
    }
    //搜索功能
    @RequestMapping("/search")
    public ResultInfo search(String keywords){
        try {
            return articleService.search(keywords);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统暂时出现异常,请稍后再试");
        }
    }
}
package com.qst.controller;

import com.qst.pojo.ResultInfo;
import com.qst.pojo.schoolarticle.Comments;
import com.qst.pojo.schoolarticle.Likes;
import com.qst.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/comment")
public class CommentController {
    @Autowired
    CommentService commentService;
    //获取文章所拥有的评论数量
    @RequestMapping("/getArticleCommentCount")
    public ResultInfo getArticleCommentCount(Integer articleid){
        try {
            return commentService.getArticleCommentCount(articleid);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,获取文章评论数失败");
        }
    }
    //添加一条评论
    @RequestMapping("/addComment")
    public ResultInfo addComment(Comments comments){
        System.out.println(comments);
        try {
            return commentService.addComment(comments);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,插入评论失败");
        }
    }
    //查询当前页的评论
    @RequestMapping("/showComment")
    public ResultInfo showComment(Comments comments,Integer current){
        try {
            return commentService.showComment(comments,current);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,查询评论失败");
        }
    }
    //查询评论的回复评论
    @RequestMapping("/showCommentReply")
    public ResultInfo showCommentReply(Comments comments,Integer current,Integer size){
        try {
            return commentService.showCommentReply(comments,current,size);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,查询评论的回复失败");
        }
    }
    //查询当前用户的评论
    @RequestMapping("/getCommentListByUserid")
    public ResultInfo getCommentListByUserid(Comments comments,Integer current,Integer size,String keywords){
        try {
            return commentService.getCommentListByUserid(comments,current,size,keywords);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,查询评论列表失败");
        }
    }
    //查询当前用户发布的评论
    @RequestMapping("/getUserComment")
    public ResultInfo getUserComment(Comments comments,Integer current,Integer size,String keywords){
        try {
            return commentService.getUserComment(comments,current,size,keywords);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,查询评论列表失败");
        }
    }
    //查询当前用户对该片文章的信息点赞了多少
    @RequestMapping("/getLikesByUseridArticleid")
    public ResultInfo getLikesByUseridArticleid(Likes likes){
        try {
            return commentService.getLikesByUseridArticleid(likes);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,查询用户点赞信息失败");
        }
    }
    //用户对评论点赞或取消点赞
    @RequestMapping("/setCommentLikes")
    public ResultInfo setCommentLikes(Likes likes,Integer status){
        try {
            return commentService.setCommentLikes(likes,status);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,用户点赞操作失败");
        }
    }
    //用户通过评论
    @RequestMapping("/setCommentStatus")
    public ResultInfo setCommentStatus(Integer[] idList){
        try {
            return commentService.setCommentStatus(idList);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,通过评论失败");
        }
    }
    //用户删除评论
    @RequestMapping("/delComment")
    public ResultInfo delComment(Integer[] idList){
        try {
            return commentService.delComment(idList);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,删除评论失败");
        }
    }
    //更改用户收到的回复的状态
    @RequestMapping("/setReceivedRelpyStatus")
    public ResultInfo setReceivedRelpyStatus(Comments comments){
        try {
            return commentService.setReceivedRelpyStatus(comments);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,修改回复状态失败");
        }
    }
}

package com.qst.controller;

import com.qst.pojo.ResultInfo;
import com.qst.pojo.schoolarticle.Article;
import com.qst.service.HomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/home")
public class HomeController {
    @Autowired
    HomeService homeService;
    //查询前台首页用户的文章数、分类数、标签数
    @RequestMapping("/getUserArticleLabelClassifyCount")
    public ResultInfo getUserArticleLabelClassifyCount(Integer userid){
        try {
            return homeService.getUserArticleLabelClassifyCount(userid);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,获取用户文章数量失败");
        }
    }
    //查询首页轮播图的推荐文章列表
    @RequestMapping("/getTjCarouselArticle")
    public ResultInfo getTjCarouselArticle(){
        try {
            return homeService.getTjCarouselArticle();
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,获取推荐文章列表失败");
        }
    }
    //通过文章id,获取文章的详细信息
    @RequestMapping("/getArticleById")
    public ResultInfo getArticleById(Integer articleid){
        if (articleid==null)
            return new ResultInfo(false,"请选择正确的文章");
        try {
            return homeService.getArticleById(articleid);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常,获取文章详细信息失败");
        }
    }
    //通过用户id获取该用户的5篇最新文章
    @RequestMapping("/getFiveArticleByUserid")
    public ResultInfo getFiveArticleByUserid(Integer userid,Integer articleid){
        if(userid==null)
            return new ResultInfo(false,"用户名为空,所以无法查询用户的最新文章");
        try {
            return homeService.getFiveArticleByUserid(articleid,userid);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,请稍后再试");
        }
    }
    //判断用户是否为当前文章点赞
    @RequestMapping("/isLikeArticle")
    public ResultInfo isLikeArticle(Article article){
        System.out.println(article);
        try {
            return homeService.isLikeArticle(article);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,请稍后再试");
        }
    }
    //给当前文章点赞的状态进行修改
    @RequestMapping("/setArticleLike")
    public ResultInfo setArticleLike(Article article,Integer flag,Integer articleuserid){
        try {
            return homeService.setArticleLike(article,flag,articleuserid);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultInfo(false,"系统异常啦,请稍后再试");
        }
    }
}

五,项目总结

本系统采用前后端分离设计,前端与后端相互独立,前端使用Vue+ Element-UI开发,后端基于SSM框架开发。前端项目名称byVue,如图4-1所示。后端项目名称final-project,如图4-2所示。

校园文件发布系统|基于Springboot实现校园文章发布系统

图4-1 前端项目结构图

前端目录说明如下:

node_modules: 它用于存储项目的各种依赖项,例如Axios。没有moudles文件,项目就不能运行;

public:用于存储静态文件;

public/index.html: 它是一个模板文件,用于生成项目的条目文件。webpack打包的JS和CSS也会自动注入到页面中。当我们的浏览器访问项目时,它将默认打开生成的index.html;

src:我们存放各种vue文件的地方;

src/assets:用于存放各种静态文件,如图片等;

src/compnents:用于存放我们的公共组件,如 header、footer等;

src/views:用于存放我们写好的各种页面,如login、main等;

src/APP.VUE: 主vue模块 引入其他模块,app.vue是项目的主组件,所有页面都是在app.vue下切换的;

src/main.js: 入口文件的主要功能是初始化Vue实例。同时,可以在这个文件中引用一些组件库,或者全局挂起一些变量;

src/router.js: 路由文件可以理解为我们访问的每个页面的地址路径。同时,路由保护可以直接写入其中;

src/store.js:主要用于项目里边的一些状态的保存,state中保存状态,mutations中写用于修改state中的状态;

package.json: 模块基本信息项目开发所需要模块,版本,项目名称;

package-lock.json: 在NPM安装过程中会生成一个文件,记录当前状态下实际安装的每个NPM包的具体源代码和版本号;

vue.config.js: 保存vue配置的文件,可以用于设置代理,打包配置等。