refactor(search):重构搜索服务模块结构

- 将 han-note-search 模块拆分为 han-note-search-api 和 han-note-search-biz
- 调整包路径,统一添加 biz 子包以区分业务实现
- 更新相关类的导入路径以适配新的包结构
- 修改 Maven 模块配置,设置父模块打包方式为 pom- 添加新的 API 模块用于 RPC 接口定义
- 更新依赖配置,确保模块间正确引用
- 调整 IDEA 编译器配置以识别新模块
- 更新 HTTP 客户端测试数据和请求示例
- 添加 Feign 客户端支持以实现服务间通信
- 实现笔记文档重建功能并提供对外接口
- 增加数据对齐服务中远程调用搜索服务的能力
- 更新全局异常处理器和枚举类的包路径
- 调整应用启动类的 Mapper 扫描路径
- 更新 Elasticsearch 配置类和索引相关类路径
- 修改控制器和服务接口以支持新架构
- 更新测试类路径以匹配新的项目结构
This commit is contained in:
2025-11-03 16:00:22 +08:00
parent 218f4c6974
commit 2b2cd2be70
52 changed files with 512 additions and 181 deletions

3
.idea/compiler.xml generated
View File

@@ -27,7 +27,7 @@
<module name="han-note-data-align" />
<module name="han-note-kv-api" />
<module name="han-note-note-biz" />
<module name="han-note-search" />
<module name="han-note-search-api" />
<module name="han-note-user-relation-api" />
<module name="han-note-user-api" />
<module name="han-note-user-biz" />
@@ -35,6 +35,7 @@
<module name="hanserwei-common" />
<module name="han-note-distributed-id-generator-biz" />
<module name="han-note-auth" />
<module name="han-note-search-biz" />
<module name="han-note-user-relation-biz" />
<module name="hanserwei-spring-boot-starter-biz-context" />
</profile>

4
.idea/encodings.xml generated
View File

@@ -37,6 +37,10 @@
<file url="file://$PROJECT_DIR$/han-note-oss/han-note-oss-biz/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-oss/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-oss/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/han-note-search-api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/han-note-search-api/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/han-note-search-biz/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/han-note-search-biz/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-search/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/han-note-user-relation/han-note-user-relation-api/src/main/java" charset="UTF-8" />

View File

@@ -96,6 +96,11 @@
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-search-api</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -3,9 +3,11 @@ package com.hanserwei.hannote.data.align;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@MapperScan("com.hanserwei.hannote.data.align.domain.mapper")
@EnableFeignClients(basePackages = "com.hanserwei.hannote")
public class HannoteDataAlignApplication {
public static void main(String[] args) {
SpringApplication.run(HannoteDataAlignApplication.class, args);

View File

@@ -6,6 +6,7 @@ import com.hanserwei.hannote.data.align.constant.TableConstants;
import com.hanserwei.hannote.data.align.domain.mapper.DeleteRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.SelectRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.UpdateRecordMapper;
import com.hanserwei.hannote.data.align.rpc.SearchRpcService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Resource;
@@ -29,6 +30,8 @@ public class FansCountShardingXxlJob {
private DeleteRecordMapper deleteRecordMapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private SearchRpcService searchRpcService;
/**
* 分片广播任务
@@ -80,6 +83,8 @@ public class FansCountShardingXxlJob {
redisTemplate.opsForHash().put(redisKey, RedisKeyConstants.FIELD_FANS_TOTAL, fansTotal);
}
}
// 远程 RPC, 调用搜索服务,重新构建索引
searchRpcService.rebuildUserDocument(userId);
});
// 删除t_data_align_fans_count_temp_日期_分片序号中的记录

View File

@@ -6,6 +6,7 @@ import com.hanserwei.hannote.data.align.constant.TableConstants;
import com.hanserwei.hannote.data.align.domain.mapper.DeleteRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.SelectRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.UpdateRecordMapper;
import com.hanserwei.hannote.data.align.rpc.SearchRpcService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Resource;
@@ -33,6 +34,9 @@ public class NoteCollectCountShardingXxlJob {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private SearchRpcService searchRpcService;
@XxlJob("noteCollectCountShardingJobHandler")
public void noteCollectCountShardingJobHandler() throws Exception {
// 获取分片参数
@@ -81,6 +85,8 @@ public class NoteCollectCountShardingXxlJob {
redisTemplate.opsForHash().put(redisKey, RedisKeyConstants.FIELD_COLLECT_TOTAL, likeTotal);
}
}
// 远程 RPC, 调用搜索服务,重新构建文档
searchRpcService.rebuildNoteDocument(noteId);
});
// 4. 批量物理删除这一批次记录

View File

@@ -6,6 +6,7 @@ import com.hanserwei.hannote.data.align.constant.TableConstants;
import com.hanserwei.hannote.data.align.domain.mapper.DeleteRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.SelectRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.UpdateRecordMapper;
import com.hanserwei.hannote.data.align.rpc.SearchRpcService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Resource;
@@ -33,6 +34,9 @@ public class NoteLikeCountShardingXxlJob {
@Resource
private DeleteRecordMapper deleteRecordMapper;
@Resource
private SearchRpcService searchRpcService;
@XxlJob("noteLikeCountShardingJobHandler")
public void noteLikeCountShardingJobHandler() throws Exception {
// 获取分片参数
@@ -83,6 +87,9 @@ public class NoteLikeCountShardingXxlJob {
redisTemplate.opsForHash().put(redisKey, RedisKeyConstants.FIELD_LIKE_TOTAL, likeTotal);
}
}
// 远程 RPC, 调用搜索服务,重新构建文档
searchRpcService.rebuildNoteDocument(noteId);
});
// 4. 批量物理删除这一批次记录
deleteRecordMapper.batchDeleteDataAlignNoteLikeCountTempTable(tableNameSuffix, noteIds);

View File

@@ -6,6 +6,7 @@ import com.hanserwei.hannote.data.align.constant.TableConstants;
import com.hanserwei.hannote.data.align.domain.mapper.DeleteRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.SelectRecordMapper;
import com.hanserwei.hannote.data.align.domain.mapper.UpdateRecordMapper;
import com.hanserwei.hannote.data.align.rpc.SearchRpcService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import jakarta.annotation.Resource;
@@ -29,6 +30,8 @@ public class NotePublishCountShardingXxlJob {
private DeleteRecordMapper deleteRecordMapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private SearchRpcService searchRpcService;
@XxlJob("notePublishCountShardingJobHandler")
public void notePublishCountShardingJobHandler() throws Exception {
@@ -72,6 +75,8 @@ public class NotePublishCountShardingXxlJob {
redisTemplate.opsForHash().put(redisKey, RedisKeyConstants.FIELD_NOTE_TOTAL, notePublishTotal);
}
}
// 远程 RPC, 调用搜索服务,重新构建索引
searchRpcService.rebuildUserDocument(userId);
});
// 删除 t_data_align_note_publish_count_temp_日期_分片序号

View File

@@ -0,0 +1,41 @@
package com.hanserwei.hannote.data.align.rpc;
import com.hanserwei.hannote.search.api.SearchFeignApi;
import com.hanserwei.hannote.search.dto.RebuildNoteDocumentReqDTO;
import com.hanserwei.hannote.search.dto.RebuildUserDocumentReqDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class SearchRpcService {
@Resource
private SearchFeignApi searchFeignApi;
/**
* 调用重建笔记文档接口
*
* @param noteId 笔记ID
*/
public void rebuildNoteDocument(Long noteId) {
RebuildNoteDocumentReqDTO rebuildNoteDocumentReqDTO = RebuildNoteDocumentReqDTO.builder()
.id(noteId)
.build();
searchFeignApi.rebuildNoteDocument(rebuildNoteDocumentReqDTO);
}
/**
* 调用重建用户文档接口
*
* @param userId 用户ID
*/
public void rebuildUserDocument(Long userId) {
RebuildUserDocumentReqDTO rebuildUserDocumentReqDTO = RebuildUserDocumentReqDTO.builder()
.id(userId)
.build();
searchFeignApi.rebuildUserDocument(rebuildUserDocumentReqDTO);
}
}

View File

@@ -0,0 +1,38 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-search</artifactId>
<version>${revision}</version>
</parent>
<!-- 打包方式 -->
<packaging>jar</packaging>
<artifactId>han-note-search-api</artifactId>
<name>${project.artifactId}</name>
<description>RPC层, 供其他服务调用</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-common</artifactId>
</dependency>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,35 @@
package com.hanserwei.hannote.search.api;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.constant.ApiConstants;
import com.hanserwei.hannote.search.dto.RebuildNoteDocumentReqDTO;
import com.hanserwei.hannote.search.dto.RebuildUserDocumentReqDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.SERVICE_NAME)
public interface SearchFeignApi {
String PREFIX = "/search";
/**
* 重建笔记文档
*
* @param rebuildNoteDocumentReqDTO 重建笔记文档请求参数对象,包含重建所需的相关信息
* @return 返回重建操作的结果响应对象
*/
@PostMapping(value = PREFIX + "/note/document/rebuild")
Response<?> rebuildNoteDocument(@RequestBody RebuildNoteDocumentReqDTO rebuildNoteDocumentReqDTO);
/**
* 重建用户文档
*
* @param rebuildUserDocumentReqDTO 重建用户文档请求参数对象,包含重建所需的相关信息
* @return 返回重建操作的结果响应对象
*/
@PostMapping(value = PREFIX + "/user/document/rebuild")
Response<?> rebuildUserDocument(@RequestBody RebuildUserDocumentReqDTO rebuildUserDocumentReqDTO);
}

View File

@@ -0,0 +1,9 @@
package com.hanserwei.hannote.search.constant;
public interface ApiConstants {
/**
* 服务名称
*/
String SERVICE_NAME = "han-note-search";
}

View File

@@ -0,0 +1,18 @@
package com.hanserwei.hannote.search.dto;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RebuildNoteDocumentReqDTO {
@NotNull(message = "笔记 ID 不能为空")
private Long id;
}

View File

@@ -0,0 +1,18 @@
package com.hanserwei.hannote.search.dto;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RebuildUserDocumentReqDTO {
@NotNull(message = "用户 ID 不能为空")
private Long id;
}

View File

@@ -0,0 +1,108 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 指定父项目 -->
<parent>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-search</artifactId>
<version>${revision}</version>
</parent>
<!-- 指定打包方式 -->
<packaging>jar</packaging>
<artifactId>han-note-search-biz</artifactId>
<name>${project.artifactId}</name>
<description>搜索服务</description>
<dependencies>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 业务接口日志组件 -->
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-spring-boot-starter-biz-operationlog</artifactId>
</dependency>
<!-- Jackson 组件 -->
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-spring-boot-starter-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 服务注册发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Elasticsearch 分布式搜索引擎 -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</dependency>
<!-- Canal -->
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.protocol</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- Druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-search-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search;
package com.hanserwei.hannote.search.biz;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
@@ -7,7 +7,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@MapperScan("com.hanserwei.hannote.search.domain.mapper")
@MapperScan("com.hanserwei.hannote.search.biz.domain.mapper")
public class HannoteSearchApplication {
public static void main(String[] args) {
SpringApplication.run(HannoteSearchApplication.class, args);

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.canal;
package com.hanserwei.hannote.search.biz.canal;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.canal;
package com.hanserwei.hannote.search.biz.canal;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.canal;
package com.hanserwei.hannote.search.biz.canal;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkRequest;
@@ -9,11 +9,11 @@ import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.common.collect.Maps;
import com.hanserwei.framework.common.enums.StatusEnum;
import com.hanserwei.hannote.search.domain.mapper.SelectMapper;
import com.hanserwei.hannote.search.enums.NoteStatusEnum;
import com.hanserwei.hannote.search.enums.NoteVisibleEnum;
import com.hanserwei.hannote.search.index.NoteIndex;
import com.hanserwei.hannote.search.index.UserIndex;
import com.hanserwei.hannote.search.biz.domain.mapper.SelectMapper;
import com.hanserwei.hannote.search.biz.enums.NoteStatusEnum;
import com.hanserwei.hannote.search.biz.enums.NoteVisibleEnum;
import com.hanserwei.hannote.search.biz.index.NoteIndex;
import com.hanserwei.hannote.search.biz.index.UserIndex;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.config;
package com.hanserwei.hannote.search.biz.config;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;

View File

@@ -1,7 +1,7 @@
package com.hanserwei.hannote.search.controller;
package com.hanserwei.hannote.search.biz.controller;
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
import com.hanserwei.hannote.search.service.ExtDictService;
import com.hanserwei.hannote.search.biz.service.ExtDictService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;

View File

@@ -1,10 +1,12 @@
package com.hanserwei.hannote.search.controller;
package com.hanserwei.hannote.search.biz.controller;
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.hannote.search.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.model.vo.SearchNoteRspVO;
import com.hanserwei.hannote.search.service.NoteService;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteRspVO;
import com.hanserwei.hannote.search.biz.service.NoteService;
import com.hanserwei.hannote.search.dto.RebuildNoteDocumentReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
@@ -27,4 +29,10 @@ public class NoteController {
return noteService.searchNote(searchNoteReqVO);
}
// ===================================== 对其他服务提供的接口 =====================================
@PostMapping("/note/document/rebuild")
@ApiOperationLog(description = "用户文档重建")
public Response<Long> rebuildDocument(@Validated @RequestBody RebuildNoteDocumentReqDTO rebuildNoteDocumentReqDTO) {
return noteService.rebuildDocument(rebuildNoteDocumentReqDTO);
}
}

View File

@@ -1,10 +1,12 @@
package com.hanserwei.hannote.search.controller;
package com.hanserwei.hannote.search.biz.controller;
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.hannote.search.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.service.UserService;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.biz.service.UserService;
import com.hanserwei.hannote.search.dto.RebuildUserDocumentReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
@@ -27,4 +29,11 @@ public class UserController {
return userService.searchUser(searchUserReqVO);
}
// ===================================== 对其他服务提供的接口 =====================================
@PostMapping("/user/document/rebuild")
@ApiOperationLog(description = "用户文档重建")
public Response<Long> rebuildDocument(@Validated @RequestBody RebuildUserDocumentReqDTO rebuildUserDocumentReqDTO) {
return userService.rebuildDocument(rebuildUserDocumentReqDTO);
}
}

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.domain.mapper;
package com.hanserwei.hannote.search.biz.domain.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.enums;
package com.hanserwei.hannote.search.biz.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.enums;
package com.hanserwei.hannote.search.biz.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.enums;
package com.hanserwei.hannote.search.biz.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.enums;
package com.hanserwei.hannote.search.biz.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.enums;
package com.hanserwei.hannote.search.biz.enums;
import com.hanserwei.framework.common.exception.BaseExceptionInterface;
import lombok.AllArgsConstructor;

View File

@@ -1,8 +1,8 @@
package com.hanserwei.hannote.search.exception;
package com.hanserwei.hannote.search.biz.exception;
import com.hanserwei.framework.common.exception.ApiException;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.enums.ResponseCodeEnum;
import com.hanserwei.hannote.search.biz.enums.ResponseCodeEnum;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.index;
package com.hanserwei.hannote.search.biz.index;
public class NoteIndex {

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.index;
package com.hanserwei.hannote.search.biz.index;
public class UserIndex {

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.model.vo;
package com.hanserwei.hannote.search.biz.model.vo;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.model.vo;
package com.hanserwei.hannote.search.biz.model.vo;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.model.vo;
package com.hanserwei.hannote.search.biz.model.vo;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.model.vo;
package com.hanserwei.hannote.search.biz.model.vo;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

View File

@@ -1,4 +1,4 @@
package com.hanserwei.hannote.search.service;
package com.hanserwei.hannote.search.biz.service;
import org.springframework.http.ResponseEntity;

View File

@@ -0,0 +1,26 @@
package com.hanserwei.hannote.search.biz.service;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteRspVO;
import com.hanserwei.hannote.search.dto.RebuildNoteDocumentReqDTO;
public interface NoteService {
/**
* 搜索笔记
*
* @param searchNoteReqVO 搜索笔记请求
* @return 搜索笔记响应
*/
PageResponse<SearchNoteRspVO> searchNote(SearchNoteReqVO searchNoteReqVO);
/**
* 重建笔记文档
*
* @param rebuildNoteDocumentReqDTO 重建笔记文档请求
* @return 响应
*/
Response<Long> rebuildDocument(RebuildNoteDocumentReqDTO rebuildNoteDocumentReqDTO);
}

View File

@@ -0,0 +1,26 @@
package com.hanserwei.hannote.search.biz.service;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.dto.RebuildUserDocumentReqDTO;
public interface UserService {
/**
* 搜索用户
*
* @param searchUserReqVO 搜索用户请求
* @return 搜索用户响应
*/
PageResponse<SearchUserRspVO> searchUser(SearchUserReqVO searchUserReqVO);
/**
* 重建用户文档
*
* @param rebuildUserDocumentReqDTO 重建用户文档请求
* @return 响应
*/
Response<Long> rebuildDocument(RebuildUserDocumentReqDTO rebuildUserDocumentReqDTO);
}

View File

@@ -1,6 +1,6 @@
package com.hanserwei.hannote.search.service.impl;
package com.hanserwei.hannote.search.biz.service.impl;
import com.hanserwei.hannote.search.service.ExtDictService;
import com.hanserwei.hannote.search.biz.service.ExtDictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;

View File

@@ -1,10 +1,11 @@
package com.hanserwei.hannote.search.service.impl;
package com.hanserwei.hannote.search.biz.service.impl;
import cn.hutool.core.collection.CollUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Highlight;
@@ -13,14 +14,17 @@ import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.util.NamedValue;
import com.hanserwei.framework.common.constant.DateConstants;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.framework.common.utils.DateUtils;
import com.hanserwei.framework.common.utils.NumberUtils;
import com.hanserwei.hannote.search.enums.NotePublishTimeRangeEnum;
import com.hanserwei.hannote.search.enums.NoteSortTypeEnum;
import com.hanserwei.hannote.search.index.NoteIndex;
import com.hanserwei.hannote.search.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.model.vo.SearchNoteRspVO;
import com.hanserwei.hannote.search.service.NoteService;
import com.hanserwei.hannote.search.biz.domain.mapper.SelectMapper;
import com.hanserwei.hannote.search.biz.enums.NotePublishTimeRangeEnum;
import com.hanserwei.hannote.search.biz.enums.NoteSortTypeEnum;
import com.hanserwei.hannote.search.biz.index.NoteIndex;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchNoteRspVO;
import com.hanserwei.hannote.search.biz.service.NoteService;
import com.hanserwei.hannote.search.dto.RebuildNoteDocumentReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -39,6 +43,8 @@ public class NoteServiceImpl implements NoteService {
@Resource
private ElasticsearchClient client;
@Resource
private SelectMapper selectMapper;
@Override
public PageResponse<SearchNoteRspVO> searchNote(SearchNoteReqVO searchNoteReqVO) {
@@ -295,4 +301,30 @@ public class NoteServiceImpl implements NoteService {
return PageResponse.success(searchNoteRspVOS, pageNo, total);
}
@Override
public Response<Long> rebuildDocument(RebuildNoteDocumentReqDTO rebuildNoteDocumentReqDTO) {
Long noteId = rebuildNoteDocumentReqDTO.getId();
// 从数据库查询 Elasticsearch 索引数据
List<Map<String, Object>> result = selectMapper.selectEsNoteIndexData(noteId, null);
// 遍历查询结果将每条记录同步到 Elasticsearch
for (Map<String, Object> recordMap : result) {
IndexRequest<Object> request = IndexRequest.of(r -> r
// 创建索引请求对象指定索引名称
.index(NoteIndex.NAME)
// 设置文档的 ID使用记录中的主键 id 字段值
.id((String.valueOf(recordMap.get(NoteIndex.FIELD_NOTE_ID))))
// 设置文档的内容使用查询结果的记录数据
.document(recordMap));
try {
// 将数据写入 Elasticsearch 索引
client.index(request);
} catch (IOException e) {
log.error("==> 同步笔记数据异常: {}", e.getMessage());
}
}
return Response.success();
}
}

View File

@@ -1,10 +1,11 @@
package com.hanserwei.hannote.search.service.impl;
package com.hanserwei.hannote.search.biz.service.impl;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType;
import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Highlight;
@@ -12,11 +13,14 @@ import co.elastic.clients.elasticsearch.core.search.HighlightField;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.util.NamedValue;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.framework.common.utils.NumberUtils;
import com.hanserwei.hannote.search.index.UserIndex;
import com.hanserwei.hannote.search.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.service.UserService;
import com.hanserwei.hannote.search.biz.domain.mapper.SelectMapper;
import com.hanserwei.hannote.search.biz.index.UserIndex;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.biz.service.UserService;
import com.hanserwei.hannote.search.dto.RebuildUserDocumentReqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -32,6 +36,8 @@ public class UserServiceImpl implements UserService {
@Resource
private ElasticsearchClient client;
@Resource
private SelectMapper selectMapper;
@Override
public PageResponse<SearchUserRspVO> searchUser(SearchUserReqVO searchUserReqVO) {
@@ -114,4 +120,30 @@ public class UserServiceImpl implements UserService {
}
return PageResponse.success(searchUserRspVOS, pageNo, total);
}
@Override
public Response<Long> rebuildDocument(RebuildUserDocumentReqDTO rebuildUserDocumentReqDTO) {
Long userId = rebuildUserDocumentReqDTO.getId();
// 从数据库查询 Elasticsearch 索引数据
List<Map<String, Object>> result = selectMapper.selectEsUserIndexData(userId);
// 遍历查询结果将每条记录同步到 Elasticsearch
for (Map<String, Object> recordMap : result) {
IndexRequest<Object> request = IndexRequest.of(indexRequest -> indexRequest
// 创建索引请求对象指定索引名称
.index(UserIndex.NAME)
// 设置文档的 ID使用记录中的主键 id 字段值
.id((String.valueOf(recordMap.get(UserIndex.FIELD_USER_ID))))
// 设置文档的内容使用查询结果的记录数据
.document(recordMap));
// 将数据写入 Elasticsearch 索引
try {
client.index(request);
} catch (IOException e) {
log.error("==> 同步用户数据到 Elasticsearch 索引中失败: " + e.getMessage());
}
}
return Response.success();
}
}

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hanserwei.hannote.search.domain.mapper.SelectMapper">
<mapper namespace="com.hanserwei.hannote.search.biz.domain.mapper.SelectMapper">
<select id="selectEsNoteIndexData" resultType="map" parameterType="map">
select n.id,
n.title,
n.topic_name as topic,
n.type,
n.img_uris,
SUBSTRING_INDEX(n.img_uris, ',', 1) AS cover,
DATE_FORMAT(n.create_time, '%Y-%m-%d %H:%i:%s') AS create_time,
DATE_FORMAT(n.update_time, '%Y-%m-%d %H:%i:%s') AS update_time,
u.nickname,
u.avatar,
u.nickname AS creator_nickname,
u.avatar AS creator_avatar,
IFNULL(nc.like_total, 0) as like_total,
IFNULL(nc.collect_total, 0) as collect_total,
IFNULL(nc.comment_total, 0) as comment_total

View File

@@ -3,7 +3,7 @@ package com.hanserwei.hannote.search;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.hanserwei.hannote.search.model.vo.SearchUserRspVO;
import com.hanserwei.hannote.search.biz.model.vo.SearchUserRspVO;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -8,96 +8,17 @@
<version>${revision}</version>
</parent>
<!-- 指定打包方式 -->
<packaging>jar</packaging>
<!-- 多模块项目需要配置打包方式为 pom -->
<packaging>pom</packaging>
<modules>
<module>han-note-search-biz</module>
<module>han-note-search-api</module>
</modules>
<artifactId>han-note-search</artifactId>
<!-- 项目名称 -->
<name>${project.artifactId}</name>
<!-- 项目描述 -->
<description>搜索服务</description>
<dependencies>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 业务接口日志组件 -->
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-spring-boot-starter-biz-operationlog</artifactId>
</dependency>
<!-- Jackson 组件 -->
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>hanserwei-spring-boot-starter-jackson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 服务注册发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Elasticsearch 分布式搜索引擎 -->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</dependency>
<!-- Canal -->
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.protocol</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- Druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,16 +0,0 @@
package com.hanserwei.hannote.search.service;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.hannote.search.model.vo.SearchNoteReqVO;
import com.hanserwei.hannote.search.model.vo.SearchNoteRspVO;
public interface NoteService {
/**
* 搜索笔记
*
* @param searchNoteReqVO 搜索笔记请求
* @return 搜索笔记响应
*/
PageResponse<SearchNoteRspVO> searchNote(SearchNoteReqVO searchNoteReqVO);
}

View File

@@ -1,16 +0,0 @@
package com.hanserwei.hannote.search.service;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.hannote.search.model.vo.SearchUserReqVO;
import com.hanserwei.hannote.search.model.vo.SearchUserRspVO;
public interface UserService {
/**
* 搜索用户
*
* @param searchUserReqVO 搜索用户请求
* @return 搜索用户响应
*/
PageResponse<SearchUserRspVO> searchUser(SearchUserReqVO searchUserReqVO);
}

View File

@@ -75,13 +75,15 @@ Authorization: Bearer {{token}}
{
"type": 0,
"imgUris": [
"https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg"
"http://116.62.199.48:9000/weblog/c58c6db953d24922803a65ca4f79a0a9.png",
"http://116.62.199.48:9000/weblog/04c7312e0b4b41be996004517c247e2b.jpg"
],
"title": "bug修复2",
"content": "bugbugbug",
"topicId": 1
"title": "最美的风景不是诗和远方,而就在身边",
"content": "最美的风景不是诗和远方,而就在身边",
"topicId": 2
}
### 发布视频笔记
POST http://localhost:8000/note/note/publish
Content-Type: application/json

View File

@@ -331,6 +331,11 @@
<artifactId>canal.protocol</artifactId>
<version>${canal.version}</version>
</dependency>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-search-api</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</dependencyManagement>