本文最后更新于 2026年4月19日 下午
前台和后台一些关于获取文章列表接口对文章所属分类检测的优化
起因
在测试后台删除和修改(状态修改为禁用)分类时前后台对获取文章列表会出现关于 分类 的空指针异常
经过检测发现是在前后台中的获取文章列表接口在获取列表时没对分类的状态进行检测
应该做的检测是
获取文章列表时要获取状态正常的分类(正常且未删除)下的文章
为了减少对数据库的查询
应该在查文章表时使用子查询
代码实现
使用子查询
1 2 3 lambdaQueryWrapper.inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" );
这样查出来的sql语句是这样的
1 2 3 4 5 6 7 SELECT * FROM article WHERE category_id IN ( SELECT id FROM category WHERE status = '0' AND del_flag = '0' ) AND status = 0 ORDER BY is_top DESC , create_time DESC
再加到相应的方法中
前台 articleList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 @Override public ResponseResult articleList (Integer pageNum, Integer pageSize) { LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper <>(); lambdaQueryWrapper.inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" ); lambdaQueryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); lambdaQueryWrapper.orderByDesc(Article::getIsTop); lambdaQueryWrapper.orderByDesc(Article::getCreateTime); Page<Article> page = new Page <>(pageNum, pageSize); page(page, lambdaQueryWrapper); List<Article> articles = page.getRecords(); articles.forEach(article -> { article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()); Integer viewCount = redisCache.getCacheMapValue(SystemConstants.ARTICLE_VIEW_COUNT, article.getId().toString()); article.setViewCount(viewCount.longValue()); }); List<ArticleListVo> articleListVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class); fillArticleListTags(articleListVos); PageVo pageVo = new PageVo (articleListVos, page.getTotal()); return ResponseResult.okResult(pageVo); }
前台 articleListByTagId
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Override public ResponseResult articleListByTagId (Long tagId, Integer pageNum, Integer pageSize) { LambdaQueryWrapper<ArticleTag> articleTagWrapper = new LambdaQueryWrapper <>(); articleTagWrapper.eq(ArticleTag::getTagId, tagId); List<ArticleTag> articleTagList = articleTagMapper.selectList(articleTagWrapper); List<Long> articleIds = articleTagList.stream() .map(ArticleTag::getArticleId) .collect(Collectors.toList()); LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper <>(); if (!articleIds.isEmpty()) { lambdaQueryWrapper.in(Article::getId, articleIds); } else { lambdaQueryWrapper.eq(Article::getId, -1L ); } lambdaQueryWrapper.inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" ); lambdaQueryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); lambdaQueryWrapper.orderByDesc(Article::getIsTop); Page<Article> page = new Page <>(pageNum, pageSize); page(page, lambdaQueryWrapper); List<Article> articles = page.getRecords(); articles.forEach(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()) ); List<ArticleListVo> articleListVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class); PageVo pageVo = new PageVo (articleListVos, page.getTotal()); return ResponseResult.okResult(pageVo); }
前台 getArchiveList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public ResponseResult getArchiveList (Integer pageNum, Integer pageSize) { LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper <>(); queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL) .eq(Article::getDelFlag, SystemConstants.NOT_DELETED) .orderByDesc(Article::getCreateTime) .inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" ); Page<Article> page = new Page <>(pageNum, pageSize); articleMapper.selectPage(page, queryWrapper); SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" ); List<ArchiveArticleVo> articleVos = page.getRecords().stream() .map(article -> new ArchiveArticleVo ( article.getId(), article.getTitle(), sdf.format(article.getCreateTime()) )) .collect(Collectors.toList()); PageVo pageVo = new PageVo (articleVos, page.getTotal()); return ResponseResult.okResult(pageVo); }
前台 getTagList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 @Override public ResponseResult getTagList () { LambdaQueryWrapper<Article> articleWrapper = new LambdaQueryWrapper <>(); articleWrapper.inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" ) .eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); List<Article> articleList = articleService.list(articleWrapper); Set<Long> articleIds = articleList.stream() .map(Article::getId) .collect(Collectors.toSet()); LambdaQueryWrapper<ArticleTag> articleTagWrapper = new LambdaQueryWrapper <>(); if (!articleIds.isEmpty()) { articleTagWrapper.in(ArticleTag::getArticleId, articleIds); } else { articleTagWrapper.eq(ArticleTag::getArticleId, -1L ); } List<ArticleTag> articleTagList = articleTagMapper.selectList(articleTagWrapper); Set<Long> tagIds = articleTagList.stream() .map(ArticleTag::getTagId) .collect(Collectors.toSet()); Map<Long, Long> tagArticleCountMap = articleTagList.stream() .collect(Collectors.groupingBy(ArticleTag::getTagId, Collectors.counting())); LambdaQueryWrapper<Tag> tagWrapper = new LambdaQueryWrapper <>(); if (!tagIds.isEmpty()) { tagWrapper.in(Tag::getId, tagIds); } else { tagWrapper.eq(Tag::getId, -1L ); } tagWrapper.eq(Tag::getDelFlag, SystemConstants.NOT_DELETED) .eq(Tag::getStatus, SystemConstants.STATUS_NORMAL); List<Tag> tagList = list(tagWrapper); List<TagVo> tagVoList = tagList.stream() .map(tag -> { TagVo tagVo = BeanCopyUtils.copyBean(tag, TagVo.class); tagVo.setArticleCount(tagArticleCountMap.getOrDefault(tag.getId(), 0L ).intValue()); return tagVo; }) .collect(Collectors.toList()); return ResponseResult.okResult(tagVoList); }
后台 tagList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @Override public ResponseResult tagList (Integer pageNum, Integer pageSize, TagListDto tagListDto) { LambdaQueryWrapper<Tag> tagQueryWrapper = new LambdaQueryWrapper <>(); if (StringUtils.hasText(tagListDto.getKeywords())) { tagQueryWrapper.like(Tag::getName, tagListDto.getKeywords()); } tagQueryWrapper.eq(Tag::getDelFlag, SystemConstants.NOT_DELETED); tagQueryWrapper.orderByDesc(Tag::getCreateTime); Page<Tag> page = new Page <>(pageNum, pageSize); tagService.page(page, tagQueryWrapper); LambdaQueryWrapper<Article> articleQueryWrapper = new LambdaQueryWrapper <>(); articleQueryWrapper.eq(Article::getDelFlag, SystemConstants.NOT_DELETED) .eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL) .select(Article::getId) .inSql(Article::getCategoryId, "SELECT id FROM category WHERE status = '0' AND del_flag = '0'" ); List<Article> validArticles = articleService.list(articleQueryWrapper); Set<Long> validArticleIds = validArticles.stream() .map(Article::getId) .collect(Collectors.toSet()); List<ArticleTag> articleTagList = articleTagMapper.selectList(null ); Map<Long, Long> tagArticleCountMap = articleTagList.stream() .filter(articleTag -> validArticleIds.contains(articleTag.getArticleId())) .collect(Collectors.groupingBy(ArticleTag::getTagId, Collectors.counting())); List<AdminTagListVo> tagListVos = page.getRecords().stream() .map(tag -> { AdminTagListVo tagListVo = BeanCopyUtils.copyBean(tag, AdminTagListVo.class); tagListVo.setArticleCount(tagArticleCountMap.getOrDefault(tag.getId(), 0L ).intValue()); return tagListVo; }) .collect(Collectors.toList()); PageVo pageVo = new PageVo (tagListVos, page.getTotal()); return ResponseResult.okResult(pageVo); }
后台 postsList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @Override public ResponseResult postsList (Integer pageNum, Integer pageSize, PostsListDto postsListDto) { LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper <>(); if (Objects.nonNull(postsListDto.getCategoryId()) && postsListDto.getCategoryId() > 0 ) { queryWrapper.eq(Article::getCategoryId, postsListDto.getCategoryId()); } if (StringUtils.hasText(postsListDto.getStatus())) { queryWrapper.eq(Article::getStatus, postsListDto.getStatus()); } if (StringUtils.hasText(postsListDto.getKeywords())) { queryWrapper.and(wrapper -> wrapper .like(Article::getTitle, postsListDto.getKeywords()) .or() .like(Article::getSummary, postsListDto.getKeywords()) ); } queryWrapper.orderByDesc(Article::getIsTop); queryWrapper.orderByDesc(Article::getCreateTime); Page<Article> page = new Page <>(pageNum, pageSize); articleService.page(page, queryWrapper); List<Article> articles = page.getRecords(); articles.forEach(article -> { article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()); Integer viewCount = redisCache.getCacheMapValue(SystemConstants.ARTICLE_VIEW_COUNT, article.getId().toString()); article.setViewCount(viewCount.longValue()); }); List<AdminPostsListVo> postsListVos = BeanCopyUtils.copyBeanList(page.getRecords(), AdminPostsListVo.class); postsListVos.forEach(postsListVo -> { List<TagVo> tags = getTagsByArticleId(postsListVo.getId()); postsListVo.setTags(tags); }); PageVo pageVo = new PageVo (postsListVos, page.getTotal()); return ResponseResult.okResult(pageVo); }
PS:该系列只做为作者学习开发项目做的笔记用
不一定符合读者来学习,仅供参考
预告
后续会记录博客的开发过程
每次学习会做一份笔记来进行发表
“一花一世界,一叶一菩提”
版权所有 © 2026 云梦泽 欢迎访问我的个人网站:https://hgt12.github.io/