feat(search): 初始化搜索服务模块- 添加搜索服务基础配置文件 application.yml 和 bootstrap.yml

- 配置 Nacos 服务发现与配置中心集成
- 引入 Elasticsearch 客户端依赖并配置连接参数
- 创建全局异常处理器 GlobalExceptionHandler
- 定义响应码枚举 ResponseCodeEnum
- 添加用户搜索请求/响应 VO 类
- 定义用户索引常量 UserIndex
- 创建 UserService 接口及实现类
This commit is contained in:
2025-10-29 22:37:08 +08:00
parent c216ca4c63
commit 3437c2bff4
16 changed files with 474 additions and 1 deletions

View File

@@ -0,0 +1,11 @@
package com.hanserwei.hannote.search;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HannoteSearchApplication {
public static void main(String[] args) {
SpringApplication.run(HannoteSearchApplication.class, args);
}
}

View File

@@ -0,0 +1,31 @@
package com.hanserwei.hannote.search.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticsearchConfig {
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
@Value("${elasticsearch.scheme:http}")
private String scheme;
@Value("${elasticsearch.username:}")
private String username;
@Value("${elasticsearch.password:}")
private String password;
@Value("${elasticsearch.api-key:}")
private String apiKey;
@Value("${elasticsearch.use-api-key:false}")
private boolean useApiKey;
}

View File

@@ -0,0 +1,23 @@
package com.hanserwei.hannote.search.enums;
import com.hanserwei.framework.common.exception.BaseExceptionInterface;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ResponseCodeEnum implements BaseExceptionInterface {
// ----------- 通用异常状态码 -----------
SYSTEM_ERROR("SEARCH-10000", "出错啦,后台小哥正在努力修复中..."),
PARAM_NOT_VALID("SEARCH-10001", "参数错误"),
// ----------- 业务异常状态码 -----------
;
// 异常码
private final String errorCode;
// 错误信息
private final String errorMsg;
}

View File

@@ -0,0 +1,103 @@
package com.hanserwei.hannote.search.exception;
import com.hanserwei.framework.common.exception.ApiException;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.search.enums.ResponseCodeEnum;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Optional;
@SuppressWarnings("LoggingSimilarMessage")
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 捕获自定义业务异常
*
* @return Response.fail(e)
*/
@ExceptionHandler({ApiException.class})
@ResponseBody
public Response<Object> handleApiException(HttpServletRequest request, ApiException e) {
log.warn("{} request fail, errorCode: {}, errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getErrorMsg());
return Response.fail(e);
}
/**
* 捕获参数校验异常
*
* @return Response.fail(errorCode, errorMessage)
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
@ResponseBody
public Response<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
// 参数错误异常码
String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
// 获取 BindingResult
BindingResult bindingResult = e.getBindingResult();
StringBuilder sb = new StringBuilder();
// 获取校验不通过的字段,并组合错误信息,格式为: email 邮箱格式不正确, 当前值: '123124qq.com';
Optional.of(bindingResult.getFieldErrors()).ifPresent(errors -> {
errors.forEach(error ->
sb.append(error.getField())
.append(" ")
.append(error.getDefaultMessage())
.append(", 当前值: '")
.append(error.getRejectedValue())
.append("'; ")
);
});
// 错误信息
String errorMessage = sb.toString();
log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
return Response.fail(errorCode, errorMessage);
}
/**
* 捕获 guava 参数校验异常
*
* @return Response.fail(ResponseCodeEnum.PARAM_NOT_VALID)
*/
@ExceptionHandler({IllegalArgumentException.class})
@ResponseBody
public Response<Object> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
// 参数错误异常码
String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
// 错误信息
String errorMessage = e.getMessage();
log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
return Response.fail(errorCode, errorMessage);
}
/**
* 其他类型异常
*
* @param request 请求
* @param e 异常
* @return Response.fail(ResponseCodeEnum.SYSTEM_ERROR)
*/
@ExceptionHandler({Exception.class})
@ResponseBody
public Response<Object> handleOtherException(HttpServletRequest request, Exception e) {
log.error("{} request error, ", request.getRequestURI(), e);
return Response.fail(ResponseCodeEnum.SYSTEM_ERROR);
}
}

View File

@@ -0,0 +1,40 @@
package com.hanserwei.hannote.search.index;
public class UserIndex {
/**
* 索引名称
*/
public static final String NAME = "user";
/**
* 用户ID
*/
public static final String FIELD_USER_ID = "id";
/**
* 昵称
*/
public static final String FIELD_USER_NICKNAME = "nickname";
/**
* 头像
*/
public static final String FIELD_USER_AVATAR = "avatar";
/**
* 小憨书ID
*/
public static final String FIELD_USER_HAN_NOTE_ID = "han_note_id";
/**
* 发布笔记总数
*/
public static final String FIELD_USER_NOTE_TOTAL = "note_total";
/**
* 粉丝总数
*/
public static final String FIELD_USER_FANS_TOTAL = "fans_total";
}

View File

@@ -0,0 +1,22 @@
package com.hanserwei.hannote.search.model.vo;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SearchUserReqVO {
@NotBlank(message = "搜索关键词不能为空")
private String keyword;
@Min(value = 1, message = "页码不能小于 1")
private Integer pageNo = 1; // 默认值为第一页
}

View File

@@ -0,0 +1,44 @@
package com.hanserwei.hannote.search.model.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SearchUserRspVO {
/**
* 用户ID
*/
private Long userId;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
/**
* 小憨书ID
*/
private String hanNoteId;
/**
* 笔记发布总数
*/
private Integer noteTotal;
/**
* 粉丝总数
*/
private Integer fansTotal;
}

View File

@@ -0,0 +1,16 @@
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

@@ -0,0 +1,14 @@
package com.hanserwei.hannote.search.service.impl;
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;
public class UserServiceImpl implements UserService {
@Override
public PageResponse<SearchUserRspVO> searchUser(SearchUserReqVO searchUserReqVO) {
return null;
}
}