From 7942a46592227088ba46f8e6c2585be08faffc4c Mon Sep 17 00:00:00 2001 From: Hanserwei <2628273921@qq.com> Date: Sun, 12 Oct 2025 15:02:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(relation):=20=E5=AE=9E=E7=8E=B0=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=85=B3=E6=B3=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增关注用户接口,支持通过用户ID关注其他用户 - 添加参数校验,确保被关注用户ID不为空 - 实现关注用户时的业务逻辑,包括: -不能关注自己 - 校验被关注用户是否存 - 集成Feign客户端,调用用户服务查询用户信息 - 定义关注相关的异常码和错误信息 - 更新网关配置,路由/relation/**请求到用户关系服务- 添加HTTP客户端测试用例,用于验证关注功能 - 引入用户API依赖,支持远程调用用户服务 --- .../src/main/resources/application.yml | 6 +++ .../han-note-user-relation-biz/pom.xml | 6 +++ .../HannoteUserRelationBizApplication.java | 2 + .../biz/controller/RelationController.java | 29 +++++++++++ .../relation/biz/enums/ResponseCodeEnum.java | 2 + .../biz/model/vo/FollowUserReqVO.java | 17 +++++++ .../user/relation/biz/rpc/UserRpcService.java | 37 ++++++++++++++ .../relation/biz/service/RelationService.java | 15 ++++++ .../biz/service/impl/RelationServiceImpl.java | 48 +++++++++++++++++++ http-client/gateApi.http | 18 +++++++ http-client/http-client.private.env.json | 3 +- 11 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/controller/RelationController.java create mode 100644 han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/model/vo/FollowUserReqVO.java create mode 100644 han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/rpc/UserRpcService.java create mode 100644 han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/RelationService.java create mode 100644 han-note-user-relation/han-note-user-relation-biz/src/main/java/com/hanserwei/hannote/user/relation/biz/service/impl/RelationServiceImpl.java 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