Skip to content

七、动手练习

只看不写是学不会的。以下练习都是从简单到复杂排列的。 每个练习都标注了你能学到什么,以及前端类比。


练习 1:新增一个简单的 GET 接口

目标

在用户服务中添加一个 /user/hello 接口,返回 { "message": "Hello, Frontend!" }

步骤

  1. 打开 UserController.java
  2. 添加一个新方法:
java
@GetMapping("/hello")
public RtData<Map<String, String>> hello(@RequestHeader("uid") Long uid) {
    Map<String, String> result = new HashMap<>();
    result.put("message", "Hello, Frontend! Your uid is " + uid);
    return RtData.ok(result);
}
  1. 如果希望不登录也能访问,去网关的白名单配置中添加路径
  2. 重启服务,用 Postman 或 curl 测试:
    bash
    curl -H "uid: 12345" http://localhost:8080/v1/user/hello

前端类比

typescript
// 这就像你在 Next.js 里写:
// app/api/user/hello/route.ts
export async function GET(req: Request) {
  const uid = req.headers.get('uid')
  return Response.json({ message: `Hello! Your uid is ${uid}` })
}

你会学到

  • Controller 的基本写法
  • RtData 统一响应格式
  • 请求头提取

练习 2:跟踪一个请求的完整链路

目标

在代码中添加日志,观察一个请求经过的所有节点

步骤

  1. 在网关的 AuthFilter.javafilter 方法开头添加:

    java
    log.info(">>> [Gateway] 收到请求: {} {}", request.getMethod(), path);
  2. 在用户 Controller 的 login 方法开头添加:

    java
    log.info(">>> [UserController] 收到登录请求");
  3. 在 Service 的 login 方法中添加:

    java
    log.info(">>> [LoginService] 开始处理登录逻辑");
  4. 启动所有服务,发送一个登录请求

  5. 在控制台日志中观察三条日志的打印顺序和时间戳

预期日志输出

text
2024-01-01 10:00:00.001 >>> [Gateway] 收到请求: POST /api/user/login
2024-01-01 10:00:00.050 >>> [UserController] 收到登录请求
2024-01-01 10:00:00.051 >>> [LoginService] 开始处理登录逻辑

你会学到

  • 微服务请求链路的执行顺序
  • Java 日志框架的使用(log.info
  • 数据在不同层之间的传递方式

练习 3:修改一个已有接口的返回值

目标

给配额查询接口增加一个新字段

步骤

  1. 找到接口入口(QuotaController.java
  2. 看它调用了哪个 Service
  3. 找到返回的 VO 类
  4. 在 VO 中添加一个新字段:
    java
    private String welcomeMessage = "欢迎使用!";
  5. 运行测试或用 Postman 验证响应中多了这个字段

你会学到

  • Controller → Service → VO 的数据流向
  • 修改后端接口返回值的标准流程
  • 前端视角:字段是怎么从后端源码一直传到你的 response.data 里的

练习 4:理解 Feign 调用

目标

搞清楚画布服务是怎么调用 AI 服务的

步骤

  1. 打开 AiFeignClient.java,阅读接口定义
  2. 全局搜索 aiFeignClient 找到所有使用的地方
  3. 在调用处添加日志:
    java
    log.info(">>> 即将调用 AI 服务,请求参数: {}", request);
  4. 打开 AiFeignFallback.java,理解降级逻辑
  5. 尝试模拟 AI 服务不可用(不启动 AI 服务),观察 fallback 是否生效

尝试画出这个调用链

text
画布服务 Controller
  → 画布服务 Service
    → AiFeignClient.generateImage(request)
      → [HTTP] POST http://ai-service/internal/generate
        → AI 服务 Controller
          → AI 服务 Service
            → 调用外部 AI API

你会学到

  • 服务间通信的声明式写法
  • Fallback 降级保护机制
  • 网络失败时的兜底策略

练习 5:阅读 MQ 消息流转

目标

画出图片生成任务的完整异步流程图

步骤

  1. 全局搜索 RocketMQUtils,找到所有消息发送处
  2. 打开 AI 服务的消费者,阅读消息消费逻辑
  3. 打开画布服务的结果消费者,阅读结果处理逻辑
  4. 用纸笔或 draw.io 画出完整流程:
text
┌──────────┐    发送     ┌──────────┐    消费     ┌──────────┐
│ 画布服务  │ ─────────▶ │ RocketMQ │ ─────────▶ │  AI 服务  │
│          │            │  Topic A  │            │          │
└──────────┘            └──────────┘            └──────────┘
     ▲                                               │
     │     消费    ┌──────────┐    发送               │
     └───────────  │ RocketMQ │ ◀──────────────────────┘
                   │  Topic B  │
                   └──────────┘

回答这些问题

  • 谁发的消息?发到哪个 Topic?
  • 消息的内容(payload)是什么?
  • 谁消费了消息?
  • 消费后做了什么?
  • 如果消费失败会怎样?(有没有重试机制?)

你会学到

  • 消息队列在实际业务中的使用方式
  • Topic、Tag、Consumer Group 的概念
  • 异步任务的完整生命周期