文章目录
- 一、项目演示
- 二、项目介绍
- 三、项目运行截图
- 四、主要代码
一、项目演示
项目演示地址: 视频地址
二、项目介绍
项目描述:这是一个基于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);
}