700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 基于Java+SpringBoot+Vue前后端分离博客系统设计与实现

基于Java+SpringBoot+Vue前后端分离博客系统设计与实现

时间:2021-08-06 08:59:14

相关推荐

基于Java+SpringBoot+Vue前后端分离博客系统设计与实现

博主介绍:✌全网粉丝3W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌

博主作品:《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦

开源项目:点击这里克隆或者下载

🍅文末关注公众号获取联系🍅精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟

✨【微服务】Nacos为什么丢弃短连接(http)而选择拥抱长连接(gRPC)

目录

一、前言

1.导言

1.1编写目的

1.2项目范围

1.3参考资料

2.项目介绍

2.1项目背景

2.2项目目标

二、系统设计

1、系统运行环境

2、系统架构设计

三、功能需求简介

1、系统角色分析

1.1、游客

1.2、会员

1.3管理员

2、用例分析与设计

2.1、管理员

2.2、博主

2.3、游客​编辑

四、功能截图

1、管理员

1.1、文章管理

1.2、消息管理

1.3、用户管理

1.4、权限管理

1.5、系统管理

1.6、相册管理

1.7、说说管理

2、博主

2.1、首页

2.2、点击测试文章进来

五、实现代码

1、文章控制器

2、服务接口

3、实现类

六、获取源码

一、前言

1.导言

1.1编写目的

该文档描述了个人博客网站的功能和性能的要求,将作为对该项目在概要设计阶段的设计输入。

本文档的预期读者包括:

1.设计开发人员

2.项日管理人员

3.测试人员

4.用户

1.2项目范围

该文档的月的是解决整个项月系统中“做仁么”的问题。对于开发技术在这里并没有涉及,而+要是通过建立模型的方式来描述用户的需求为,客户、用户,开发方等不同参与方提供一个交流的平台。

1.3参考资料

[1]《软件工程导论第6版》 张海潘等清华大学出版社

[2]《软件项目管理案例教程第3版》韩万江等,机械工业出版社

2.项目介绍

2.1项目背景

博客是使用特定的软件,在网络上出版、发表和张贴个人文章的人,或者是一种通常由个人管理、不定期张贴新的文章的网站。博客上的文章通常以网页形式出现,并根据张贴时间,以倒序排列。博客是继MSN、BBS、ICQ之后出现的第4种网络交流方式,现已受到大家的欢迎,是网络时代的个人“读者文摘”,是以超级链接为入口的网络日记,它代表着新的生活、工作和学习方式。许多博客专注在特定的课题上提供评论或新闻,其他则被作为个人性的日记。一个典型的博客结合了文字、图像、其他博客或网站的链接及其它与主题相关的媒体,能够让读者以互动的方式留下意见,是许多博客的重要要素。大部分的博客内容以文字为主,但仍有一些博客专注在艺术、摄影、视频、音乐、播客等各种主题

2.2项目目标

开发一个具有开放体系结构的、易扩充的、易维护的、具有良好人机交互界面的个人博客网站,为网络用户提供进行在线交流的网络平台。

通过个人博客网站可以结交更多的朋友,表达更多的想法,它随时可以发布文章。

二、系统设计

1、系统运行环境

开发系统:Windows10左右

架构模式:MVC/前后端分离

JDK版本:Java JDK1.8

开发工具:IDEA

数据库版本:mysql5.7

数据库可视化工具:SQL yog或Navicat for MySQL

服务器:SpringBoot自带 apache tomcat

主要技术:Java、SpringBoot2、MyBatis-plus、SpringSecurity、MySQL、RabbitMQ、ES、Html、Vue、Elementui等,建造者模式、策略模式等

2、系统架构设计

三、功能需求简介

1、系统角色分析

角色是指与系统产生交互的外部用户或者外部系统。本系统的使用角色主要有游客、会员、管理员三种。以下是详细介绍

1.1、游客

游客是第一次进入网站,但未进行注册,进行部分功能试用,在具体的功能实现上,可以分为以下几个部分:

1.1.1.搜索和浏览他人的博客

游客不须登录系统就可以实现查看日志照片以及博客主的资料信息。

1.1.2.用户注册

游客将个人的信息存储到博客网站的数据库中,以成为本博客的正式用户。

1.2、会员

通过计算机网络将前台与后台的数据库相连,系统用户将从前台得到的信息进行处理,实现文章管理,信息管理,个人相册管理,评论,留言等子系统。

1.2.1.博客管理

注册用户员对网站中自己的文章进行删除,更新等操作。

1.2.2.信息管理

发布,更改个人资料信息。

1.2.3.个人相册管理

对博客相册中的图片进行上传,更新,删除操作。

1.2.4.好友管理

添加或删除好友。

1.2.5.评论

对于他人给自己的不恰当评论予以删除。

1.2.6.留言

对他人给自己的留言进行回复或删除。

1.3管理员

1.3.1.用户管理

对已注册的用户进行管理。

1.3.2.评论、留言管理

对已注册的用户发表的评论和留言进行管理。

1.3.3.相册管理

对已注册用户上传的照片进行审核,严禁上传不和谐的照片。

1.3.4.博客管理

对用户已发表的博文进行管理,规范其内容,屏蔽掉一些不健康或反动的言论。

2、用例分析与设计

分析现有情况及问题,将个人博客系统划分为三个功能用例:游客用例、用户用例、管理员用例。

在个人博客系统中,管理员要让每个博客申请个人博客账号,并让博客设置个人密码,账户内存储每个博客的个人信息。有账号的博客用员可以通过管理员浏览好友动态、写博文、分享博文等。每个博客浏览的范围、期限不同,可通过互联网或登录个人博客网站查询个人信息和其他情况。

登录个人博客主页时,先输入博客的账号和密码,系统验证该帐号的有效性,无效则提示其原因,有效则显示博客的主页信息,供管理员人工核对。然后可以进行浏览动态,添加应用等一些功能。

1系统总体用例

2.1、管理员

2.2、博主

2.3、游客

四、功能截图

1、管理员

登录界面:

首页:

1.1、文章管理

1)发布文章

2)文章列表

3)分类管理

4)标签管理

1.2、消息管理

1)评论管理

2)留言管理

1.3、用户管理

1)用户列表

2)在线用户

1.4、权限管理

1)角色管理

2)接口管理

3)菜单管理

1.5、系统管理

1)友链管理

1.6、相册管理

1)相册列表

1.7、说说管理

1)发布说说

2)说说列表

2、博主

博主也有很多功能界面,这里就不一一举出了。

2.1、首页

可以播放音乐,试听结合

2.2、点击测试文章进来

五、实现代码

1、文章控制器

@Api(tags = "文章模块")@RestControllerpublic class ArticleController {@Autowiredprivate ArticleService articleService;@Autowiredprivate UploadStrategyContext uploadStrategyContext;@Autowiredprivate ArticleImportStrategyContext articleImportStrategyContext;/*** 查看文章归档** @return {@link Result<ArchiveDTO>} 文章归档列表*/@ApiOperation(value = "查看文章归档")@GetMapping("/articles/archives")public Result<PageResult<ArchiveDTO>> listArchives() {return Result.ok(articleService.listArchives());}/*** 查看首页文章** @return {@link Result<ArticleHomeDTO>} 首页文章列表*/@ApiOperation(value = "查看首页文章")@GetMapping("/articles")public Result<List<ArticleHomeDTO>> listArticles() {return Result.ok(articleService.listArticles());}/*** 查看后台文章** @param conditionVO 条件* @return {@link Result<ArticleBackDTO>} 后台文章列表*/@ApiOperation(value = "查看后台文章")@GetMapping("/admin/articles")public Result<PageResult<ArticleBackDTO>> listArticleBacks(ConditionVO conditionVO) {return Result.ok(articleService.listArticleBacks(conditionVO));}/*** 添加或修改文章** @param articleVO 文章信息* @return {@link Result<>}*/@OptLog(optType = SAVE_OR_UPDATE)@ApiOperation(value = "添加或修改文章")@PostMapping("/admin/articles")public Result<?> saveOrUpdateArticle(@Valid @RequestBody ArticleVO articleVO) {articleService.saveOrUpdateArticle(articleVO);return Result.ok();}/*** 修改文章置顶状态** @param articleTopVO 文章置顶信息* @return {@link Result<>}*/@OptLog(optType = UPDATE)@ApiOperation(value = "修改文章置顶")@PutMapping("/admin/articles/top")public Result<?> updateArticleTop(@Valid @RequestBody ArticleTopVO articleTopVO) {articleService.updateArticleTop(articleTopVO);return Result.ok();}/*** 恢复或删除文章** @param deleteVO 逻辑删除信息* @return {@link Result<>}*/@OptLog(optType = UPDATE)@ApiOperation(value = "恢复或删除文章")@PutMapping("/admin/articles")public Result<?> updateArticleDelete(@Valid @RequestBody DeleteVO deleteVO) {articleService.updateArticleDelete(deleteVO);return Result.ok();}/*** 上传文章图片** @param file 文件* @return {@link Result<String>} 文章图片地址*/@ApiOperation(value = "上传文章图片")@ApiImplicitParam(name = "file", value = "文章图片", required = true, dataType = "MultipartFile")@PostMapping("/admin/articles/images")public Result<String> saveArticleImages(MultipartFile file) {return Result.ok(uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.ARTICLE.getPath()));}/*** 删除文章** @param articleIdList 文章id列表* @return {@link Result<>}*/@OptLog(optType = REMOVE)@ApiOperation(value = "物理删除文章")@DeleteMapping("/admin/articles")public Result<?> deleteArticles(@RequestBody List<Integer> articleIdList) {articleService.deleteArticles(articleIdList);return Result.ok();}/*** 根据id查看后台文章** @param articleId 文章id* @return {@link Result<ArticleVO>} 后台文章*/@ApiOperation(value = "根据id查看后台文章")@ApiImplicitParam(name = "articleId", value = "文章id", required = true, dataType = "Integer")@GetMapping("/admin/articles/{articleId}")public Result<ArticleVO> getArticleBackById(@PathVariable("articleId") Integer articleId) {return Result.ok(articleService.getArticleBackById(articleId));}/*** 根据id查看文章** @param articleId 文章id* @return {@link Result<ArticleDTO>} 文章信息*/@ApiOperation(value = "根据id查看文章")@ApiImplicitParam(name = "articleId", value = "文章id", required = true, dataType = "Integer")@GetMapping("/articles/{articleId}")public Result<ArticleDTO> getArticleById(@PathVariable("articleId") Integer articleId) {return Result.ok(articleService.getArticleById(articleId));}/*** 根据条件查询文章** @param condition 条件* @return {@link Result<ArticlePreviewListDTO>} 文章列表*/@ApiOperation(value = "根据条件查询文章")@GetMapping("/articles/condition")public Result<ArticlePreviewListDTO> listArticlesByCondition(ConditionVO condition) {return Result.ok(articleService.listArticlesByCondition(condition));}/*** 搜索文章** @param condition 条件* @return {@link Result<ArticleSearchDTO>} 文章列表*/@ApiOperation(value = "搜索文章")@GetMapping("/articles/search")public Result<List<ArticleSearchDTO>> listArticlesBySearch(ConditionVO condition) {return Result.ok(articleService.listArticlesBySearch(condition));}/*** 点赞文章** @param articleId 文章id* @return {@link Result<>}*/@ApiOperation(value = "点赞文章")@ApiImplicitParam(name = "articleId", value = "文章id", required = true, dataType = "Integer")@PostMapping("/articles/{articleId}/like")public Result<?> saveArticleLike(@PathVariable("articleId") Integer articleId) {articleService.saveArticleLike(articleId);return Result.ok();}/*** 导出文章** @param articleIdList 文章id列表* @return {@link List<String>} 文件url列表*/@ApiOperation(value = "导出文章")@ApiImplicitParam(name = "articleIdList", value = "文章id", required = true, dataType = "List<Integer>")@PostMapping("/admin/articles/export")public Result<List<String>> exportArticles(@RequestBody List<Integer> articleIdList) {return Result.ok(articleService.exportArticles(articleIdList));}/*** 导入文章** @param file 文件* @param type 文章类型* @return {@link Result<>}*/@ApiOperation(value = "导入文章")@PostMapping("/admin/articles/import")public Result<?> importArticles(MultipartFile file, @RequestParam(required = false) String type) {articleImportStrategyContext.importArticles(file, type);return Result.ok();}}

2、服务接口

public interface ArticleService extends IService<Article> {/*** 查询文章归档** @return 文章归档*/PageResult<ArchiveDTO> listArchives();/*** 查询后台文章** @param condition 条件* @return 文章列表*/PageResult<ArticleBackDTO> listArticleBacks(ConditionVO condition);/*** 查询首页文章** @return 文章列表*/List<ArticleHomeDTO> listArticles();/*** 根据条件查询文章列表** @param condition 条件* @return 文章列表*/ArticlePreviewListDTO listArticlesByCondition(ConditionVO condition);/*** 搜索文章** @param condition 条件* @return 文章列表*/List<ArticleSearchDTO> listArticlesBySearch(ConditionVO condition);/*** 根据id查看后台文章** @param articleId 文章id* @return 文章列表*/ArticleVO getArticleBackById(Integer articleId);/*** 根据id查看文章** @param articleId 文章id* @return {@link ArticleDTO} 文章信息*/ArticleDTO getArticleById(Integer articleId);/*** 点赞文章** @param articleId 文章id*/void saveArticleLike(Integer articleId);/*** 添加或修改文章** @param articleVO 文章信息*/void saveOrUpdateArticle(ArticleVO articleVO);/*** 修改文章置顶** @param articleTopVO 文章置顶信息*/void updateArticleTop(ArticleTopVO articleTopVO);/*** 删除或恢复文章** @param deleteVO 逻辑删除对象*/void updateArticleDelete(DeleteVO deleteVO);/*** 物理删除文章** @param articleIdList 文章id集合*/void deleteArticles(List<Integer> articleIdList);/*** 导出文章** @param articleIdList 文章id列表* @return {@link List}<{@link String}> 文件地址*/List<String> exportArticles(List<Integer> articleIdList);}

3、实现类

@Service@Slf4jpublic class ArticleServiceImpl extends ServiceImpl<ArticleDao, Article> implements ArticleService {@Autowiredprivate ArticleDao articleDao;@Autowiredprivate CategoryDao categoryDao;@Autowiredprivate TagDao tagDao;@Autowiredprivate TagService tagService;@Autowiredprivate ArticleTagDao articleTagDao;@Autowiredprivate SearchStrategyContext searchStrategyContext;@Autowiredprivate HttpSession session;@Autowiredprivate RedisService redisService;@Autowiredprivate ArticleTagService articleTagService;@Autowiredprivate BlogInfoService blogInfoService;@Autowiredprivate UploadStrategyContext uploadStrategyContext;@Overridepublic PageResult<ArchiveDTO> listArchives() {Page<Article> page = new Page<>(PageUtils.getCurrent(), PageUtils.getSize());// 获取分页数据Page<Article> articlePage = articleDao.selectPage(page, new LambdaQueryWrapper<Article>().select(Article::getId, Article::getArticleTitle, Article::getCreateTime).orderByDesc(Article::getCreateTime).eq(Article::getIsDelete, FALSE).eq(Article::getStatus, PUBLIC.getStatus()));List<ArchiveDTO> archiveDTOList = BeanCopyUtils.copyList(articlePage.getRecords(), ArchiveDTO.class);return new PageResult<>(archiveDTOList, (int) articlePage.getTotal());}@Overridepublic PageResult<ArticleBackDTO> listArticleBacks(ConditionVO condition) {// 查询文章总量Integer count = articleDao.countArticleBacks(condition);if (count == 0) {return new PageResult<>();}// 查询后台文章List<ArticleBackDTO> articleBackDTOList = articleDao.listArticleBacks(PageUtils.getLimitCurrent(), PageUtils.getSize(), condition);// 查询文章点赞量和浏览量Map<Object, Double> viewsCountMap = redisService.zAllScore(ARTICLE_VIEWS_COUNT);Map<String, Object> likeCountMap = redisService.hGetAll(ARTICLE_LIKE_COUNT);// 封装点赞量和浏览量articleBackDTOList.forEach(item -> {Double viewsCount = viewsCountMap.get(item.getId());if (Objects.nonNull(viewsCount)) {item.setViewsCount(viewsCount.intValue());}item.setLikeCount((Integer) likeCountMap.get(item.getId().toString()));});return new PageResult<>(articleBackDTOList, count);}@Overridepublic List<ArticleHomeDTO> listArticles() {return articleDao.listArticles(PageUtils.getLimitCurrent(), PageUtils.getSize());}@Overridepublic ArticlePreviewListDTO listArticlesByCondition(ConditionVO condition) {// 查询文章List<ArticlePreviewDTO> articlePreviewDTOList = articleDao.listArticlesByCondition(PageUtils.getLimitCurrent(), PageUtils.getSize(), condition);// 搜索条件对应名(标签或分类名)String name;if (Objects.nonNull(condition.getCategoryId())) {name = categoryDao.selectOne(new LambdaQueryWrapper<Category>().select(Category::getCategoryName).eq(Category::getId, condition.getCategoryId())).getCategoryName();} else {name = tagService.getOne(new LambdaQueryWrapper<Tag>().select(Tag::getTagName).eq(Tag::getId, condition.getTagId())).getTagName();}return ArticlePreviewListDTO.builder().articlePreviewDTOList(articlePreviewDTOList).name(name).build();}@Overridepublic ArticleDTO getArticleById(Integer articleId) {// 查询推荐文章CompletableFuture<List<ArticleRecommendDTO>> recommendArticleList = CompletableFuture.supplyAsync(() -> articleDao.listRecommendArticles(articleId));// 查询最新文章CompletableFuture<List<ArticleRecommendDTO>> newestArticleList = CompletableFuture.supplyAsync(() -> {List<Article> articleList = articleDao.selectList(new LambdaQueryWrapper<Article>().select(Article::getId, Article::getArticleTitle, Article::getArticleCover, Article::getCreateTime).eq(Article::getIsDelete, FALSE).eq(Article::getStatus, PUBLIC.getStatus()).orderByDesc(Article::getId).last("limit 5"));return BeanCopyUtils.copyList(articleList, ArticleRecommendDTO.class);});// 查询id对应文章ArticleDTO article = articleDao.getArticleById(articleId);if (Objects.isNull(article)) {throw new BizException("文章不存在");}// 更新文章浏览量updateArticleViewsCount(articleId);// 查询上一篇下一篇文章Article lastArticle = articleDao.selectOne(new LambdaQueryWrapper<Article>().select(Article::getId, Article::getArticleTitle, Article::getArticleCover).eq(Article::getIsDelete, FALSE).eq(Article::getStatus, PUBLIC.getStatus()).lt(Article::getId, articleId).orderByDesc(Article::getId).last("limit 1"));Article nextArticle = articleDao.selectOne(new LambdaQueryWrapper<Article>().select(Article::getId, Article::getArticleTitle, Article::getArticleCover).eq(Article::getIsDelete, FALSE).eq(Article::getStatus, PUBLIC.getStatus()).gt(Article::getId, articleId).orderByAsc(Article::getId).last("limit 1"));article.setLastArticle(BeanCopyUtils.copyObject(lastArticle, ArticlePaginationDTO.class));article.setNextArticle(BeanCopyUtils.copyObject(nextArticle, ArticlePaginationDTO.class));// 封装点赞量和浏览量Double score = redisService.zScore(ARTICLE_VIEWS_COUNT, articleId);if (Objects.nonNull(score)) {article.setViewsCount(score.intValue());}article.setLikeCount((Integer) redisService.hGet(ARTICLE_LIKE_COUNT, articleId.toString()));// 封装文章信息try {article.setRecommendArticleList(recommendArticleList.get());article.setNewestArticleList(newestArticleList.get());} catch (Exception e) {log.error(StrUtil.format("堆栈信息:{}", ExceptionUtil.stacktraceToString(e)));}return article;}@Overridepublic void saveArticleLike(Integer articleId) {// 判断是否点赞String articleLikeKey = ARTICLE_USER_LIKE + UserUtils.getLoginUser().getUserInfoId();if (redisService.sIsMember(articleLikeKey, articleId)) {// 点过赞则删除文章idredisService.sRemove(articleLikeKey, articleId);// 文章点赞量-1redisService.hDecr(ARTICLE_LIKE_COUNT, articleId.toString(), 1L);} else {// 未点赞则增加文章idredisService.sAdd(articleLikeKey, articleId);// 文章点赞量+1redisService.hIncr(ARTICLE_LIKE_COUNT, articleId.toString(), 1L);}}@Transactional(rollbackFor = Exception.class)@Overridepublic void saveOrUpdateArticle(ArticleVO articleVO) {// 查询博客配置信息CompletableFuture<WebsiteConfigVO> webConfig = CompletableFuture.supplyAsync(() -> blogInfoService.getWebsiteConfig());// 保存文章分类Category category = saveArticleCategory(articleVO);// 保存或修改文章Article article = BeanCopyUtils.copyObject(articleVO, Article.class);if (Objects.nonNull(category)) {article.setCategoryId(category.getId());}// 设定默认文章封面if (StrUtil.isBlank(article.getArticleCover())){try {article.setArticleCover(webConfig.get().getArticleCover());} catch (Exception e) {throw new BizException("设定默认文章封面失败");}}article.setUserId(UserUtils.getLoginUser().getUserInfoId());this.saveOrUpdate(article);// 保存文章标签saveArticleTag(articleVO, article.getId());}/*** 保存文章分类** @param articleVO 文章信息* @return {@link Category} 文章分类*/private Category saveArticleCategory(ArticleVO articleVO) {// 判断分类是否存在Category category = categoryDao.selectOne(new LambdaQueryWrapper<Category>().eq(Category::getCategoryName, articleVO.getCategoryName()));if (Objects.isNull(category) && !articleVO.getStatus().equals(DRAFT.getStatus())) {category = Category.builder().categoryName(articleVO.getCategoryName()).build();categoryDao.insert(category);}return category;}@Overridepublic void updateArticleTop(ArticleTopVO articleTopVO) {// 修改文章置顶状态Article article = Article.builder().id(articleTopVO.getId()).isTop(articleTopVO.getIsTop()).build();articleDao.updateById(article);}@Overridepublic void updateArticleDelete(DeleteVO deleteVO) {// 修改文章逻辑删除状态List<Article> articleList = deleteVO.getIdList().stream().map(id -> Article.builder().id(id).isTop(FALSE).isDelete(deleteVO.getIsDelete()).build()).collect(Collectors.toList());this.updateBatchById(articleList);}@Transactional(rollbackFor = Exception.class)@Overridepublic void deleteArticles(List<Integer> articleIdList) {// 删除文章标签关联articleTagDao.delete(new LambdaQueryWrapper<ArticleTag>().in(ArticleTag::getArticleId, articleIdList));// 删除文章articleDao.deleteBatchIds(articleIdList);}@Overridepublic List<String> exportArticles(List<Integer> articleIdList) {// 查询文章信息List<Article> articleList = articleDao.selectList(new LambdaQueryWrapper<Article>().select(Article::getArticleTitle, Article::getArticleContent).in(Article::getId, articleIdList));// 写入文件并上传List<String> urlList = new ArrayList<>();for (Article article : articleList) {try (ByteArrayInputStream inputStream = new ByteArrayInputStream(article.getArticleContent().getBytes())) {String url = uploadStrategyContext.executeUploadStrategy(article.getArticleTitle() + FileExtEnum.MD.getExtName(), inputStream, FilePathEnum.MD.getPath());urlList.add(url);} catch (Exception e) {log.error(StrUtil.format("导入文章失败,堆栈:{}", ExceptionUtil.stacktraceToString(e)));throw new BizException("导出文章失败");}}return urlList;}@Overridepublic List<ArticleSearchDTO> listArticlesBySearch(ConditionVO condition) {return searchStrategyContext.executeSearchStrategy(condition.getKeywords());}@Overridepublic ArticleVO getArticleBackById(Integer articleId) {// 查询文章信息Article article = articleDao.selectById(articleId);// 查询文章分类Category category = categoryDao.selectById(article.getCategoryId());String categoryName = null;if (Objects.nonNull(category)) {categoryName = category.getCategoryName();}// 查询文章标签List<String> tagNameList = tagDao.listTagNameByArticleId(articleId);// 封装数据ArticleVO articleVO = BeanCopyUtils.copyObject(article, ArticleVO.class);articleVO.setCategoryName(categoryName);articleVO.setTagNameList(tagNameList);return articleVO;}/*** 更新文章浏览量** @param articleId 文章id*/public void updateArticleViewsCount(Integer articleId) {// 判断是否第一次访问,增加浏览量Set<Integer> articleSet = CommonUtils.castSet(Optional.ofNullable(session.getAttribute(ARTICLE_SET)).orElseGet(HashSet::new), Integer.class);if (!articleSet.contains(articleId)) {articleSet.add(articleId);session.setAttribute(ARTICLE_SET, articleSet);// 浏览量+1redisService.zIncr(ARTICLE_VIEWS_COUNT, articleId, 1D);}}/*** 保存文章标签** @param articleVO 文章信息*/private void saveArticleTag(ArticleVO articleVO, Integer articleId) {// 编辑文章则删除文章所有标签if (Objects.nonNull(articleVO.getId())) {articleTagDao.delete(new LambdaQueryWrapper<ArticleTag>().eq(ArticleTag::getArticleId, articleVO.getId()));}// 添加文章标签List<String> tagNameList = articleVO.getTagNameList();if (CollectionUtils.isNotEmpty(tagNameList)) {// 查询已存在的标签List<Tag> existTagList = tagService.list(new LambdaQueryWrapper<Tag>().in(Tag::getTagName, tagNameList));List<String> existTagNameList = existTagList.stream().map(Tag::getTagName).collect(Collectors.toList());List<Integer> existTagIdList = existTagList.stream().map(Tag::getId).collect(Collectors.toList());// 对比新增不存在的标签tagNameList.removeAll(existTagNameList);if (CollectionUtils.isNotEmpty(tagNameList)) {List<Tag> tagList = tagNameList.stream().map(item -> Tag.builder().tagName(item).build()).collect(Collectors.toList());tagService.saveBatch(tagList);List<Integer> tagIdList = tagList.stream().map(Tag::getId).collect(Collectors.toList());existTagIdList.addAll(tagIdList);}// 提取标签id绑定文章List<ArticleTag> articleTagList = existTagIdList.stream().map(item -> ArticleTag.builder().articleId(articleId).tagId(item).build()).collect(Collectors.toList());articleTagService.saveBatch(articleTagList);}}}

六、获取源码

大家点赞、收藏、关注、评论啦、关注下方公众号获取联系方式👇🏻👇🏻

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。