From 1b0d102ef95c108c742658dee2e98c8a974dec0a Mon Sep 17 00:00:00 2001 From: wangzhiwei Date: Fri, 6 Mar 2026 18:58:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(content):=20=E5=A2=9E=E5=BC=BA=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=8D=E5=8C=B9=E9=85=8D=E5=92=8C=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=E5=85=B3=E8=81=94=E6=8E=A8=E8=8D=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 CmsContentDto 中新增 tagIdList 和 keyword 字段用于批量查询和全文搜索 - 修改数据库查询映射文件支持基于关键词的标题、描述、标签多字段模糊匹配 - 实现标签 ID 列表批量查询功能,支持多标签条件筛选 - 添加基于关键词搜索的智能关联推荐机制,根据首个结果的标签自动推荐相关内容 - 优化分页查询逻辑,在关键词搜索结果较少时自动补充相关技能内容 - 增强搜索结果排序算法,综合考虑排序权重和创建时间因素 --- .../skills/entity/dto/CmsContentDto.java | 10 +++ .../service/impl/CmsContentServiceImpl.java | 81 ++++++++++++++++++- .../resources/mapper/CmsContentMapper.xml | 47 +++++++++-- 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java b/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java index 3593f38..8bef0d4 100644 --- a/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java +++ b/src/main/java/com/kexue/skills/entity/dto/CmsContentDto.java @@ -45,5 +45,15 @@ public class CmsContentDto extends BaseQueryDto { private Long parentCategoryId; private Long tagId; + + /** + * 标签 ID 列表,用于批量查询 + */ + private List tagIdList; + + /** + * 搜索关键字,同时搜索 title、description、tags + */ + private String keyword; } diff --git a/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java b/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java index 286d957..1052430 100644 --- a/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java +++ b/src/main/java/com/kexue/skills/service/impl/CmsContentServiceImpl.java @@ -16,8 +16,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Date; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; import cn.dev33.satoken.stp.StpUtil; @@ -57,11 +57,84 @@ public class CmsContentServiceImpl implements CmsContentService { if (queryDto.getPageSize() == null || queryDto.getPageSize() < 1) { queryDto.setPageSize(BaseQueryDto.DEFAULT_PAGE_SIZE); } - - // 使用PageHelper进行分页 + + // 使用 PageHelper 进行分页 PageHelper.startPage(queryDto.getPageNum(), queryDto.getPageSize()); List list = this.cmsContentMapper.getPageList(queryDto); PageInfo pageInfo = new PageInfo<>(list); + + // 如果使用了 keyword 搜索且返回结果小于等于 3 条,则根据第一个 skill 的标签查询相关 skill + if (queryDto.getKeyword() != null && !queryDto.getKeyword().trim().isEmpty() + && list.size() <= 3 && !list.isEmpty()) { + // 获取第一个 skill 的标签 + CmsContent firstSkill = list.get(0); + String tagsStr = firstSkill.getTags(); + if (tagsStr != null && !tagsStr.trim().isEmpty()) { + // 解析标签(逗号分隔) + String[] tags = tagsStr.split(","); + if (tags.length > 0) { + // 构建标签 ID 列表 + Set tagIdSet = new HashSet<>(); + for (String tag : tags) { + if (tag != null && !tag.trim().isEmpty()) { + try { + Long tagId = Long.parseLong(tag.trim()); + tagIdSet.add(tagId); + } catch (NumberFormatException e) { + // 忽略格式不正确的标签 + } + } + } + + // 如果有有效的标签 ID,查询相关内容 + if (!tagIdSet.isEmpty()) { + // 排除已返回的 contentId + Set existingIds = list.stream() + .map(CmsContent::getContentId) + .collect(Collectors.toSet()); + + // 构建查询条件,使用 tagIdList 一次性查询 + CmsContentDto tagQueryDto = new CmsContentDto(); + tagQueryDto.setDeleteFlag(0); + tagQueryDto.setPublishStatus(2); // 已发布 + tagQueryDto.setTagIdList(new ArrayList<>(tagIdSet)); + tagQueryDto.setPageNum(1); + tagQueryDto.setPageSize(1000); + + // 查询包含这些标签的所有 skill + List taggedContents = this.cmsContentMapper.getPageList(tagQueryDto); + + // 过滤掉已返回的内容 + List relatedContents = taggedContents.stream() + .filter(content -> !existingIds.contains(content.getContentId())) + .collect(Collectors.toList()); + + // 如果有相关 skill,添加到结果中 + if (!relatedContents.isEmpty()) { + // 按 sort 和 create_time 排序 + relatedContents.sort((a, b) -> { + int sortCompare = Integer.compare( + a.getSort() != null ? a.getSort() : 0, + b.getSort() != null ? b.getSort() : 0); + if (sortCompare != 0) { + return sortCompare; + } + if (a.getCreateTime() == null || b.getCreateTime() == null) { + return 0; + } + return b.getCreateTime().compareTo(a.getCreateTime()); + }); + + list.addAll(relatedContents); + // 重新构建 PageInfo + pageInfo = new PageInfo<>(list); + pageInfo.setTotal(list.size()); + } + } + } + } + } + return pageInfo; } diff --git a/src/main/resources/mapper/CmsContentMapper.xml b/src/main/resources/mapper/CmsContentMapper.xml index 37edfc4..cf6285d 100644 --- a/src/main/resources/mapper/CmsContentMapper.xml +++ b/src/main/resources/mapper/CmsContentMapper.xml @@ -56,8 +56,8 @@ select - content_id, title, subtitle, content_type, summary, description, requirement, introduce, content, cover_image, author_id, author_name, - reviewer_id, reviewer_name, audit_status, audit_comment, publish_status, publish_time, + content_id, title, subtitle, content_type, summary, description, requirement, introduce, content, cover_image, author_id, author_name, + reviewer_id, reviewer_name, audit_status, audit_comment, publish_status, publish_time, view_count, like_count, comment_count, sort, is_paid, price, required_points, support_points_pay, is_official, share_count, file_url, icon, background, origin, tags, create_time, update_time, create_by, update_by, delete_flag from cms_content @@ -115,7 +122,12 @@ and content_id = #{queryDto.contentId} - and (title like concat('%', #{queryDto.title}, '%') or summary like concat('%', #{queryDto.title}, '%')) + and (title like concat('%', #{queryDto.title}, '%') or description like concat('%', #{queryDto.title}, '%')) + + + and (title like concat('%', #{queryDto.keyword}, '%') + or description like concat('%', #{queryDto.keyword}, '%') + or tags like concat('%', #{queryDto.keyword}, '%')) and content_type = #{queryDto.contentType} @@ -144,6 +156,13 @@ and find_in_set(#{queryDto.tagId}, tags) + + and ( + + find_in_set(#{tagId}, tags) + + ) + order by ${queryDto.sortBy} ${queryDto.sortDesc ? 'desc' : 'asc'} @@ -198,8 +217,8 @@