SpringBoot+React博客论坛系统 附带详细运行指导视频

news2024/11/25 19:33:21

文章目录

  • 一、项目演示
  • 二、项目介绍
  • 三、项目运行截图
  • 四、主要代码

一、项目演示

项目演示地址: 视频地址

二、项目介绍

项目描述:这是一个基于SpringBoot+React框架开发的博客论坛系统。首先,这是一个前后端分离的项目,文章编辑器支持Markdown语法,项目代码简洁规范,注释说明详细,易于理解和学习。其次,这项目功能丰富,具有一个博客论坛系统该有的所有功能。

项目功能:此项目分为两个角色:普通用户管理员普通用户有登录注册、浏览博客和问答信息、发表评论、问答发起者也能采纳评论、写文章、提问题、管理个人信息、关注他人等等功能。管理员除了拥有普通用户的所有功能,还有管理所有用户信息、管理所有文章信息、管理所有文章分类信息、管理所有文章标签信息、管理所有评论信息等等功能。

应用技术:SpringBoot + React + MySQL + MyBatis + Redis + Antd

运行环境:IntelliJ IDEA2019.3.5 + MySQL5.7(项目压缩包中自带) + Redis5.0.5(项目压缩包中自带) + JDK1.8 + Maven3.6.3(项目压缩包中自带)+ Node14.16.1(项目压缩包中自带)

三、项目运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、主要代码

1.前台编辑器页面代码:

 <div className={editorStyle.editor}>
     <div className={editorStyle.title}>
          <div className={editorStyle.back} onClick={() => backHome()}>
              返回首页
          </div>
          <div style={{width: '80%', paddingTop: '0.5rem'}}>
              <Input defaultValue={article.title} value={article.title} onChange={ e => setArticle({...article, title: e.target.value}) } ref={inputTitle} className={editorStyle.input} placeholder="请在这里输入文章标题"/>
          </div>
      </div>
      <div className={editorStyle.content}>
          <EditorContent onSave={() => saveArticle(6, 1)} ref={editor} preview={true} subfield={true}
             addImg={($file) => addImg($file)}
             value={article.contentMarkdown} onChange={handleChange}/>
      </div>
      <div className={editorStyle.footer}>
          <div className={editorStyle.left}>
              <div style={{width: '50%'}}>
                  <Select defaultValue={article.categoryId} value={article.categoryId} onChange={ e => setArticle({...article, categoryId: e}) }  style={{width: '100%'}} placeholder="请选择文章分类">
                      {
                          categoryList && categoryList.map((item, index) => {
                              return (
                                  <Select.Option key={index} value={item.id}>{item.name}</Select.Option>
                              )
                          })
                      }
                  </Select>
              </div>
              <div style={{width: '50%', marginLeft: '1rem'}} >
                  <ConfigProvider locale={zhCN}>
                      <Select mode="multiple" defaultValue={article.tagList} value={article.tagList} onChange={ e => {
                          if(e.length > 3) {
                              message.warning("最多选择3个标签哦!")
                          } else {
                              setArticle({...article, tagList: e});
                          }
                      } } style={{width: '100%'}} placeholder="请选择文章标签">
                          {
                              tagList && tagList.map((item, index) => {
                                  return (
                                      <Select.Option key={index} value={item.id}>{item.name}</Select.Option>
                                  )
                              })
                          }
                      </Select>
                  </ConfigProvider>
              </div>

          </div>
          <div className={editorStyle.center}>
              <TextArea rows={1} defaultValue={article.summary} value={article.summary} onChange={ e => setArticle({...article, summary: e.target.value}) } placeholder="请输入文章摘要" />
          </div>
          <div className={editorStyle.right}>
              <div className={editorStyle.save} onClick={() => saveArticle(6, 1)}>
                  保存草稿箱
              </div>
              <div className={editorStyle.submit} onClick={() => saveArticle(1, 2)}>
                  发布
              </div>
          </div>
      </div>

  </div>

2.后端查询文章列表代码:

    /**
     * 分页获取文章数据
     * @param pageDTO
     * @return
     */
    @Override
    public ResponseDTO<PageDTO<ArticleDTO>> getArticleList(PageDTO<ArticleDTO> pageDTO) {
        ArticleExample articleExample = new ArticleExample();
        // 不知道当前页多少,默认为第一页
        if(pageDTO.getPage() == null){
            pageDTO.setPage(1);
        }
        // 不知道每页多少条记录,默认为每页5条记录
        if(pageDTO.getSize() == null){
            pageDTO.setSize(5);
        }
        ArticleExample.Criteria c1 = articleExample.createCriteria();
        if(pageDTO.getParam() != null) {
            ArticleDTO articleDTO = pageDTO.getParam();
            if(!CommonUtil.isEmpty(articleDTO.getCategoryId()) && !"0".equals(articleDTO.getCategoryId())) {
                c1.andCategoryIdEqualTo(articleDTO.getCategoryId());
            }
            if(!CommonUtil.isEmpty(articleDTO.getTitle())) {
                c1.andTitleLike("%" + articleDTO.getTitle() + "%");
            }
            if(articleDTO.getType() != null && articleDTO.getType() != 0) {
                c1.andTypeEqualTo(articleDTO.getType());
            }
            if(articleDTO.getState() != null && articleDTO.getState() != 0) {
                c1.andStateEqualTo(articleDTO.getState());
            }
            if(articleDTO.getState() == null) {
                List<Integer> stateList = new ArrayList<>();
                stateList.add(ArticleStateEnum.WAIT.getCode());
                stateList.add(ArticleStateEnum.DRAFT.getCode());
                stateList.add(ArticleStateEnum.FAIL.getCode());
                c1.andStateNotIn(stateList);
            }
            if(!CommonUtil.isEmpty(articleDTO.getUserId())
                    && !ArticleQueryTypeEnum.LIKE.getCode().equals(articleDTO.getQueryType())
                    && !ArticleQueryTypeEnum.COLLECT.getCode().equals(articleDTO.getQueryType())) {
                c1.andUserIdEqualTo(articleDTO.getUserId());
            }
            if(ArticleQueryTypeEnum.BLOG.getCode().equals(articleDTO.getQueryType())) {
                c1.andTypeEqualTo(ArticleTypeEnum.BLOG.getCode());
            }
            if(ArticleQueryTypeEnum.FORUM.getCode().equals(articleDTO.getQueryType())) {
                c1.andTypeEqualTo(ArticleTypeEnum.FORUM.getCode());
            }
            if(ArticleQueryTypeEnum.LIKE.getCode().equals(articleDTO.getQueryType())) {
                LikeExample likeExample = new LikeExample();
                likeExample.createCriteria().andUserIdEqualTo(articleDTO.getUserId());
                List<Like> likeList = likeMapper.selectByExample(likeExample);
                List<String> articleIdList = likeList.stream().map(Like::getArticleId).collect(Collectors.toList());
                if(articleIdList.size() == 0) {
                    articleIdList.add("-1");
                }
                c1.andIdIn(articleIdList);
            }
            if(ArticleQueryTypeEnum.COLLECT.getCode().equals(articleDTO.getQueryType())) {
                CollectExample collectExample = new CollectExample();
                collectExample.createCriteria().andUserIdEqualTo(articleDTO.getUserId());
                List<Collect> collectList = collectMapper.selectByExample(collectExample);
                List<String> articleIdList = collectList.stream().map(Collect::getArticleId).collect(Collectors.toList());
                if(articleIdList.size() == 0) {
                    articleIdList.add("-1");
                }
                c1.andIdIn(articleIdList);
            }
        }
        articleExample.setOrderByClause("top desc, essence desc, official desc, create_time desc");
        PageHelper.startPage(pageDTO.getPage(), pageDTO.getSize());
        // 分页查出文章数据
        List<Article> articleList = articleMapper.selectByExample(articleExample);
        PageInfo<Article> pageInfo = new PageInfo<>(articleList);
        // 获取数据的总数
        pageDTO.setTotal(pageInfo.getTotal());
        // 讲domain类型数据  转成 DTO类型数据
        List<ArticleDTO> articleDTOList = CopyUtil.copyList(articleList, ArticleDTO.class);
        for(ArticleDTO articleDTO : articleDTOList) {
            // 获取文章所属用户信息
            User user = userMapper.selectByPrimaryKey(articleDTO.getUserId());
            articleDTO.setUserDTO(CopyUtil.copy(user, UserDTO.class));
            // 获取文章所属标签信息
            TagItemExample tagItemExample = new TagItemExample();
            tagItemExample.createCriteria().andArticleIdEqualTo(articleDTO.getId());
            List<TagItem> tagItemList = tagItemMapper.selectByExample(tagItemExample);
            List<String> tagIdList = tagItemList.stream().map(TagItem::getTagId).collect(Collectors.toList());
            List<Tag> tagList;
            if(tagIdList.size() == 0) {
                tagList = new ArrayList<>();
            } else {
                TagExample tagExample = new TagExample();
                tagExample.createCriteria().andIdIn(tagIdList);
                tagList = tagMapper.selectByExample(tagExample);
            }
            articleDTO.setTagDTOList(CopyUtil.copyList(tagList, TagDTO.class));
            // 获取文章所属分类信息
            Category category = categoryMapper.selectByPrimaryKey(articleDTO.getCategoryId());
            if(category == null) {
                articleDTO.setCategoryDTO(CopyUtil.copy(new Category(), CategoryDTO.class));
            } else {
                articleDTO.setCategoryDTO(CopyUtil.copy(category, CategoryDTO.class));
            }
        }
        pageDTO.setList(articleDTOList);
        return ResponseDTO.success(pageDTO);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373508.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大学物理期末大题专题训练总结-磁学大题

&#xff08;事先声明指的是简单的那个磁学大题&#xff0c;另外一类涉及储存的磁能、磁感应强度分布下次说&#xff09;求个磁通量&#xff0c;求个感应电动势&#xff0c;求个安培力大小......这个感觉是不是像你梦回高中&#xff1f;当然&#xff0c;这一块大题跟高中磁学部…

hadoop-Combiner合并、OutputFormat

一、Combiner合并 Combiner是MR程序中Mapper和Reducer之外的一种组件。 2&#xff09;Combiner组件的父类就是Reducer 3&#xff09;Combiner和Reducer的区别在与运行的位置&#xff1b;Combiner是在每一个MapTask所在的节点运行&#xff1b;Reducer是接收全局所有Mapper的输出…

c++11 标准模板(STL)(std::unordered_set)(九)

定义于头文件 <unordered_set>template< class Key, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator<Key> > class unordered_set;(1)(C11 起)namespace pmr { templat…

Linux学习(8.5)文件内容查阅

目录 文件内容查阅&#xff1a; 直接检视文件内容 cat (concatenate) tac (反向列示) nl (添加行号列印) 可翻页检视 more (一页一页翻动) less (一页一页翻动) 数据撷取 tail (取出后面几行) 非纯文字档&#xff1a; od 修改文件时间或建置新档&#xff1a; touc…

数据结构(六)二叉树

一、树形结构概念树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a;1、有一个…

昇腾AI新技能,还能预防猪生病?

国药集团动物保健股份有限公司&#xff08;简称“国药动保”&#xff09;是专业从事动物保健产品研发、生产和销售的国家高新技术企业&#xff0c;是国内少数几家具备新产品原创能力的动物保健企业。其中&#xff0c;猪圆环病毒灭活疫苗等市场份额位居行业前列。 “猪圆环病毒…

【Linux学习笔记】8.Linux yum 命令和apt 命令

前言 本章介绍Linux的yum命令和apt命令。 Linux yum 命令 yum&#xff08; Yellow dog Updater, Modified&#xff09;是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。 基于 RPM 包管理&#xff0c;能够从指定的服务器自动下载 RPM 包并且安装&#xf…

一种全新的图像滤波理论的实验(三)

一、前言 2023年02月22日&#xff0c;我发布了滤波后&#xff0c;为针对异常的白色和黑色像素进行处理的实验&#xff0c;本次发布基于上下文处理的方案的实验&#xff0c;目的是通过基于加权概率模型滤波后&#xff0c;在逆滤波时直接修复大量的白色和黑色的异常像素&#xf…

html css输入框获得焦点、失去焦点效果

input输入框获得焦点、失去焦点效果 废话shao shuo ! 直接看效果图&#xff0c;好吧&#xff01; 效果图&#xff1a; code: <!DOCTYPE html> <html> <head><title></title><meta charset"utf-8" /><style type"text…

电子统计台账:海量数据中导入特定行,极力减少键盘编辑工作量

1 前言从事企业统计工作的小伙伴&#xff0c;本来已经够忙的了&#xff0c;现在又要加上什么电子台账这种鬼任务&#xff0c;而且居然还要每月来一次&#xff0c;简直不能忍。如果非要捏着鼻子忍了&#xff0c;那么有什么办法&#xff0c;减轻工作量&#xff1f;2 问题的提出有…

应用场景五: 西门子PLC通过Modbus协议连接DCS系统

应用描述&#xff1a; 西门子PLC&#xff08;S7200/300/400/200SMART&#xff09;通过桥接器可以支持ModbusRTU串口和ModbusTCP以太网&#xff08;有线和无线WIFI同时支持&#xff09;两种通讯方式连接DCS系统&#xff0c;不需要编程PLC通讯程序&#xff0c;直接在模块中进行地…

【数据库】第九章 关系查询处理与优化

第九章 关系查询处理与优化 索引 索引文件是一种辅助存储结构&#xff0c;其存在与否不改变存储表的物理存储结 构&#xff1b;然而其存在&#xff0c;可以明显提高存储表的访问速度。 索引文件组织方式有两种&#xff1a;(相对照的&#xff0c;主文件组织有堆文件、排序文件、…

Python3-字符串

Python3 字符串 字符串是 Python 中最常用的数据类型。我们可以使用引号( ’ 或 " )来创建字符串。 创建字符串很简单&#xff0c;只要为变量分配一个值即可。 Python 访问字符串中的值 Python 不支持单字符类型&#xff0c;单字符在 Python 中也是作为一个字符串使用…

行测-判断推理-图形推理-位置规律-旋转、翻转

短指针每次逆时针旋转60&#xff08;排除法选C走人&#xff09;长指针每次顺时针旋转120选C左上菱形每次顺时针旋转90&#xff08;排除C D&#xff09;右上每次旋转180&#xff08;选B走人&#xff09;左下每次保持不变右下每次逆时针旋转90选B左上和右上为左右翻转&#xff0c…

结合JasperReports输出报表

结合JasperReports输出报表 前面我们已经使用Jaspersoft Studio设计了两个模板文件&#xff1a;demo1.jrxml和demo2.jrxml。其中demo1.jrxml的动态列表数据是基于JDBC数据源方式进行数据填充&#xff0c;demo2.jrxml的动态列表数据是基于JavaBean数据源方式进行数据填充。本小节…

ATTCK实战系列-红队评估(一)

from ATT&CK实战系列-红队评估(一) 环境搭建 下载地址:http://vulnstack.qiyuanxuetang.net/vuln/detail/2/ 将三个虚拟机启动起来 除了windows 7那个主机&#xff0c;其他都只设置成仅主机模式 windows 7添加两个网卡&#xff0c;一个是仅主机&#xff0c;一个是NAT …

解决SpringBoot中@RequestBody不能和Multipart同时传递的问题

问题描述 今天在做文件上传的时候&#xff0c;遇到了这么一个错误日志&#xff1a; Resolved[org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘multipart/form-data;boundary--------------------------771899451541318130280588;charsetUTF-8’…

[牛客Hot101]链表篇

文章目录1.翻转链表2.链表内指定区间翻转3. 链表中的节点每k个一组翻转4. 合并两个排序的链表5. 合并k个排序的链表6. 判断链表是否有环7. 链表中倒数第k个节点8. 删除链表中的倒数第k和节点9. 两个链表的第一个公共节点10.链表的入环节点11. 链表相加&#xff08;二&#xff0…

mac 如何设置 oh my zsh 终端terminal 和添加主题powerlevel10k

Oh My Zsh 是什么 Oh My Zsh 是一款社区驱动的命令行工具&#xff0c;正如它的主页上说的&#xff0c;Oh My Zsh 是一种生活方式。它基于 zsh 命令行&#xff0c;提供了主题配置&#xff0c;插件机制&#xff0c;已经内置的便捷操作。给我们一种全新的方式使用命令行。 **Oh …

Buuctf reverse [FlareOn4]IgniteMe 题解

一. 查壳 无壳32位程序 二. ida打开 GetStdHandle函数根据微软官方文档可以得知是获取标准输入/输出/错误的句柄 参数里的 0xFFFFFFF6转换一下是4294967286, 对应(DWORD) -10 所以这里的WriteFile函数实际上是实现了printf的功能 sub_4010F0()函数 其功能是通过ReadFile函数读取…