diff --git a/han-note-gateway/src/main/resources/application.yml b/han-note-gateway/src/main/resources/application.yml
index f8913b7..7ff4e57 100644
--- a/han-note-gateway/src/main/resources/application.yml
+++ b/han-note-gateway/src/main/resources/application.yml
@@ -22,6 +22,12 @@ spring:
- Path=/note/**
filters:
- StripPrefix=1
+ - id: user-relation
+ uri: lb://han-note-user-relation
+ predicates:
+ - Path=/relation/**
+ filters:
+ - StripPrefix=1
data:
redis:
database: 5 # Redis 数据库索引(默认为 0)
diff --git a/han-note-user-relation/han-note-user-relation-biz/pom.xml b/han-note-user-relation/han-note-user-relation-biz/pom.xml
index 9631123..79e25a7 100644
--- a/han-note-user-relation/han-note-user-relation-biz/pom.xml
+++ b/han-note-user-relation/han-note-user-relation-biz/pom.xml
@@ -91,6 +91,12 @@
spring-boot-starter-data-redis
+
+ com.hanserwei
+ han-note-user-api
+
+
+
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/HannoteUserRelationBizApplication.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/HannoteUserRelationBizApplication.java
index d3b6f91..eb900ad 100644
--- a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/HannoteUserRelationBizApplication.java
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/HannoteUserRelationBizApplication.java
@@ -3,9 +3,11 @@ package com.hanserwei.hannote.user.relation.biz;
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.user.relation.biz.domain.mapper")
+@EnableFeignClients(basePackages = "com.hanserwei.hannote")
public class HannoteUserRelationBizApplication {
public static void main(String[] args) {
SpringApplication.run(HannoteUserRelationBizApplication.class, args);
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/controller/RelationController.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/controller/RelationController.java
new file mode 100644
index 0000000..4fc0062
--- /dev/null
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/controller/RelationController.java
@@ -0,0 +1,29 @@
+package com.hanserwei.hannote.user.relation.biz.controller;
+
+import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
+import com.hanserwei.hannote.user.relation.biz.service.RelationService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/relation")
+@Slf4j
+public class RelationController {
+
+ @Resource
+ private RelationService relationService;
+
+ @PostMapping("/follow")
+ @ApiOperationLog(description = "关注用户")
+ public Response> follow(@Validated @RequestBody FollowUserReqVO followUserReqVO) {
+ return relationService.follow(followUserReqVO);
+ }
+
+}
\ No newline at end of file
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/enums/ResponseCodeEnum.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/enums/ResponseCodeEnum.java
index b66ad1b..9887019 100644
--- a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/enums/ResponseCodeEnum.java
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/enums/ResponseCodeEnum.java
@@ -13,6 +13,8 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
PARAM_NOT_VALID("RELATION-10001", "参数错误"),
// ----------- 业务异常状态码 -----------
+ CANT_FOLLOW_YOUR_SELF("RELATION-20001", "无法关注自己"),
+ FOLLOW_USER_NOT_EXISTED("RELATION-20002", "关注的用户不存在"),
;
// 异常码
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/model/vo/FollowUserReqVO.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/model/vo/FollowUserReqVO.java
new file mode 100644
index 0000000..f176154
--- /dev/null
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/model/vo/FollowUserReqVO.java
@@ -0,0 +1,17 @@
+package com.hanserwei.hannote.user.relation.biz.model.vo;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class FollowUserReqVO {
+
+ @NotNull(message = "被关注用户 ID 不能为空")
+ private Long followUserId;
+}
\ No newline at end of file
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/rpc/UserRpcService.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/rpc/UserRpcService.java
new file mode 100644
index 0000000..d56f4cd
--- /dev/null
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/rpc/UserRpcService.java
@@ -0,0 +1,37 @@
+package com.hanserwei.hannote.user.relation.biz.rpc;
+
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.user.api.UserFeignApi;
+import com.hanserwei.hannote.user.dto.req.FindUserByIdReqDTO;
+import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+@Component
+public class UserRpcService {
+
+ @Resource
+ private UserFeignApi userFeignApi;
+
+ /**
+ * 根据用户 ID 查询
+ *
+ * @param userId 用户 ID
+ * @return 用户信息
+ */
+ public FindUserByIdRspDTO findById(Long userId) {
+ FindUserByIdReqDTO findUserByIdReqDTO = new FindUserByIdReqDTO();
+ findUserByIdReqDTO.setId(userId);
+
+ Response response = userFeignApi.findById(findUserByIdReqDTO);
+
+ if (!response.isSuccess() || Objects.isNull(response.getData())) {
+ return null;
+ }
+
+ return response.getData();
+ }
+
+}
\ No newline at end of file
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/RelationService.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/RelationService.java
new file mode 100644
index 0000000..435e37d
--- /dev/null
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/RelationService.java
@@ -0,0 +1,15 @@
+package com.hanserwei.hannote.user.relation.biz.service;
+
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
+
+public interface RelationService {
+
+ /**
+ * 关注用户
+ *
+ * @param followUserReqVO 关注用户请求
+ * @return 响应
+ */
+ Response> follow(FollowUserReqVO followUserReqVO);
+}
diff --git a/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/impl/RelationServiceImpl.java b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/impl/RelationServiceImpl.java
new file mode 100644
index 0000000..e901f12
--- /dev/null
+++ b/han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/impl/RelationServiceImpl.java
@@ -0,0 +1,48 @@
+package com.hanserwei.hannote.user.relation.biz.service.impl;
+
+import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
+import com.hanserwei.framework.common.exception.ApiException;
+import com.hanserwei.framework.common.response.Response;
+import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
+import com.hanserwei.hannote.user.relation.biz.enums.ResponseCodeEnum;
+import com.hanserwei.hannote.user.relation.biz.model.vo.FollowUserReqVO;
+import com.hanserwei.hannote.user.relation.biz.rpc.UserRpcService;
+import com.hanserwei.hannote.user.relation.biz.service.RelationService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+@Service
+@Slf4j
+public class RelationServiceImpl implements RelationService {
+
+ @Resource
+ private UserRpcService userRpcService;
+
+ @Override
+ public Response> follow(FollowUserReqVO followUserReqVO) {
+ // 获取被关注用户 ID
+ Long followUserId = followUserReqVO.getFollowUserId();
+
+ // 获取当前登录用户 ID
+ Long userId = LoginUserContextHolder.getUserId();
+ if (Objects.equals(userId, followUserId)) {
+ throw new ApiException(ResponseCodeEnum.CANT_FOLLOW_YOUR_SELF);
+ }
+ // 校验关注的用户是否存在
+ FindUserByIdRspDTO findUserByIdRspDTO = userRpcService.findById(followUserId);
+ if (Objects.isNull(findUserByIdRspDTO)){
+ throw new ApiException(ResponseCodeEnum.FOLLOW_USER_NOT_EXISTED);
+ }
+
+ // TODO: 校验关注数是否已经达到上限
+
+ // TODO: 写入 Redis ZSET 关注列表
+
+ // TODO: 发送 MQ
+
+ return Response.success();
+ }
+}
diff --git a/http-client/gateApi.http b/http-client/gateApi.http
index aeb348d..fa2ce0b 100644
--- a/http-client/gateApi.http
+++ b/http-client/gateApi.http
@@ -118,4 +118,22 @@ Authorization: Bearer {{token}}
"title": "笔记修改测试",
"content": "我把图文笔记的内容修改了",
"topicId": 1
+}
+
+### 关注自己
+POST http://localhost:8000/relation/relation/follow
+Content-Type: application/json
+Authorization: Bearer {{token}}
+
+{
+ "followUserId": {{userId}}
+}
+
+### 关注不存在的用户
+POST http://localhost:8000/relation/relation/follow
+Content-Type: application/json
+Authorization: Bearer {{token}}
+
+{
+ "followUserId": -1
}
\ No newline at end of file
diff --git a/http-client/http-client.private.env.json b/http-client/http-client.private.env.json
index 975296f..1a94659 100644
--- a/http-client/http-client.private.env.json
+++ b/http-client/http-client.private.env.json
@@ -1,6 +1,7 @@
{
"dev": {
"token": "4bXpiBbjXEDFE4ZpqjCOHu1rP81qepl2ROOygrxRGb61K536ckLuyAwfyQHSMcyRdUzf8CxntLEMfbU2ynbYx9nJKlx4vpWZrHqv2mI4iMhnShQ4mPBi7OPPgZi22O2f",
- "noteId": "1977249693272375330"
+ "noteId": "1977249693272375330",
+ "userId": "100"
}
}
\ No newline at end of file