← 返回上一页

第2章: 项目一:上线级聊天接口(HTTP + 可直接调用)

从 0 到 1 搭建第一个 Spring AI 聊天接口

📖 本章目标

本章是 Spring AI 实战项目的第一步:我们将基于第 1 章搭建好的 Spring AI 项目, 实现一个真正可用的 HTTP 聊天接口,可以通过 curl 或 Postman 直接与 AI 对话。

你将完成:

  • ✅ 定义请求和响应 DTO(ChatRequest / ChatResponse
  • ✅ 编写 ChatController,提供 /api/chat 聊天接口
  • ✅ 接入 ChatModel,让接口真正调用大模型
  • ✅ 使用 curl 测试接口,请求和响应都是 JSON
  • ✅ 了解接口的错误处理和简单日志

📦 前端示例文件下载 & 项目结构图

为了方便你在本地做前后端联调,本课程提供了一套简单的前端页面示例(基于原项目的 static 目录)。 你可以直接下载到本机,修改后用任何静态服务器或 IDE 打开调试。

📥 前端示例文件下载

  • index.html — 聊天页面 HTML 模板
  • app.js — 与后端聊天接口交互的前端逻辑
  • style.css — 聊天页面样式文件
  • demo.html — 课程演示页面(多章节统一入口)
  • demo-style.css — 演示页面样式文件
  • demo-script.js — 演示页面交互脚本(按章节调用不同 API)

📂 项目前后端结构示意图

当前章节完成后,你的项目结构(后端工程 + 前端静态页)大致如下:

text
spring-ai-tutorial-root/             # 本课程示例根目录
└── windsurf-project/                 # Spring AI 后端示例工程
    ├── pom.xml
    └── src/
        ├── main/
        │   ├── java/com/example/chatbot/
        │   │   ├── AiChatbotApplication.java
        │   │   ├── controller/ChatController.java
        │   │   └── dto/
        │   │       ├── ChatRequest.java
        │   │       └── ChatResponse.java
        │   └── resources/
        │       ├── application.yml
        │       └── static/
        │           ├── index.html
        │           ├── app.js
        │           ├── style.css
        │           ├── demo.html
        │           ├── demo-style.css
        │           └── demo-script.js
        └── test/
            └── java/com/example/chatbot/knowledge/
                └── Test01_SpringAIBasics.java

你可以把后端项目单独用 IDE 打开运行,然后通过 http://localhost:8080/index.html 访问前端页面。 如果你的后端接口不是示例中的路径,请在 app.js 中把 API 地址改成你的实际接口(例如 /api/chat)。

🎯 前置准备

在开始之前,请确认你已经完成:

🧱 Step 1:定义请求和响应 DTO

我们先定义两个最基础的数据结构:ChatRequest(请求)和 ChatResponse(响应)。

1.1 聊天请求类 ChatRequest

路径:src/main/java/com/example/chatbot/dto/ChatRequest.java

java
package com.example.chatbot.dto;

/**
 * 聊天请求 DTO
 */
public record ChatRequest(
        /** 用户输入的消息 */
        String message
) {
    /** 简单的参数校验 */
    public void validate() {
        if (message == null || message.trim().isEmpty()) {
            throw new IllegalArgumentException("消息不能为空");
        }
    }
}

1.2 聊天响应类 ChatResponse

路径:src/main/java/com/example/chatbot/dto/ChatResponse.java

python
package com.example.chatbot.dto;

import java.time.LocalDateTime;

/**
 * 聊天响应 DTO
 */
public record ChatResponse(
        String message,          // AI 回复内容
        LocalDateTime timestamp, // 响应时间
        boolean success,         // 是否成功
        String error             // 错误信息(如果有)
) {
    // 工厂方法:成功
    public static ChatResponse success(String message) {
        return new ChatResponse(message, LocalDateTime.now(), true, null);
    }

    // 工厂方法:失败
    public static ChatResponse error(String errorMessage) {
        return new ChatResponse(null, LocalDateTime.now(), false, errorMessage);
    }
}

💡 为什么使用 record?

  • 自动生成构造方法、getter、equals/hashCodetoString
  • 默认不可变,更安全,也更适合表示“数据结构”。
  • 代码非常简洁,适合作为 DTO 使用。

🧩 Step 2:创建 ChatController

接下来,我们创建一个 REST 控制器,对外暴露 /api/chat 接口。

2.1 控制器代码

路径:src/main/java/com/example/chatbot/controller/ChatController.java

java
package com.example.chatbot.controller;

import com.example.chatbot.dto.ChatRequest;
import com.example.chatbot.dto.ChatResponse;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.*;

/**
 * 聊天控制器:提供基础聊天 API
 */
@RestController
@RequestMapping("/api/chat")
public class ChatController {

    private final ChatModel chatModel;

    // 构造方法注入 ChatModel
    public ChatController(ChatModel chatModel) {
        this.chatModel = chatModel;
    }

    /**
     * 基础聊天接口
     * POST /api/chat
     */
    @PostMapping
    public ChatResponse chat(@RequestBody ChatRequest request) {
        try {
            // 1️⃣ 参数校验
            request.validate();

            // 2️⃣ 调用大模型
            String aiResponse = chatModel.call(request.message());

            // 3️⃣ 返回成功响应
            return ChatResponse.success(aiResponse);

        } catch (IllegalArgumentException e) {
            // 参数错误
            return ChatResponse.error("参数错误: " + e.getMessage());

        } catch (Exception e) {
            // 其他错误
            return ChatResponse.error("服务器错误: " + e.getMessage());
        }
    }

    /**
     * 健康检查接口:GET /api/chat/health
     */
    @GetMapping("/health")
    public String health() {
        return "Chat API is running! 🚀";
    }
}

📌 代码要点

  • @RestController:返回值自动序列化为 JSON。
  • @RequestMapping("/api/chat"):统一前缀,便于管理接口。
  • ChatModel 由 Spring AI 和 Spring Boot 自动注入。
  • 使用 ChatResponse.success / ChatResponse.error 统一响应格式。

🧪 Step 3:启动项目并用 curl 测试

现在启动应用,并用 curl 进行最基础的接口测试。

3.1 启动应用

text
mvn spring-boot:run

看到控制台输出 Started AiChatbotApplication 和欢迎 ASCII 即表示启动成功。

3.2 测试健康检查接口

text
curl http://localhost:8080/api/chat/health

预期输出:

text
Chat API is running! 🚀

3.3 测试基础聊天接口

text
curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "你好,请介绍一下你自己"}'

预期返回的 JSON 类似:

text
{
  "message": "你好!我是通义千问,由阿里云开发的 AI 助手...",
  "timestamp": "2024-01-01T12:34:56",
  "success": true,
  "error": null
}

3.4 测试空消息(错误处理)

text
curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": ""}'

预期输出:

text
{
  "message": null,
  "timestamp": "2024-01-01T12:34:56",
  "success": false,
  "error": "参数错误: 消息不能为空"
}

📂 Step 4:项目结构总览

完成本章后,你的项目结构大致如下:

text
src/
├── main/
│   ├── java/com/example/chatbot/
│   │   ├── AiChatbotApplication.java      # 主类
│   │   ├── controller/
│   │   │   └── ChatController.java        # 聊天控制器
│   │   └── dto/
│   │       ├── ChatRequest.java           # 请求 DTO
│   │       └── ChatResponse.java          # 响应 DTO
│   └── resources/
│       ├── application.yml
│       └── static/
│           ├── index.html
│           ├── app.js
│           └── style.css
└── test/
    └── java/com/example/chatbot/
        └── knowledge/
            └── Test01_SpringAIBasics.java # 第1章中的测试类

📝 本章小结

🎓 你已经完成:

  • 实现了一个可直接调用的 基础聊天 REST API
  • 学会了如何设计请求/响应 DTO,并进行简单的参数校验。
  • 掌握了 ChatModel.call(String) 的最基础用法。
  • 通过 curl 完成了健康检查和多种问题的接口测试。
  • 为后续对话记忆、多角色 System Prompt 等进阶功能打下了基础。
← 上一章:Spring AI入门 下一章:向量存储与Embedding →