Spring AI 应用开发实践课程教导站 · Spring AI 2.0 课程首页 速查
课程首页 / 第 0 章

CH 00环境准备

工欲善其事,必先利其器。本章不写一行 AI 代码,但决定你后面十一章是「一路顺畅」还是「天天踩坑」。跟着本章把 JDK、IDEA、Maven、API 密钥四件事全部就位,并逐项验收。

教学目标
开发环境全部就位并验收
教学重点
Maven 配置与密钥管理
教学难点
环境变量与代理问题
建议学时
1 学时(课前完成+课上检查)

教学设计说明(教师参考):本章建议以「课前自学 + 课上抽查」方式实施——环境安装视频化或文档化发给学生课前完成,课上用 s9 的验收清单逐项检查(10 分钟内完成)。重点盯两件事:① mvn -v 的输出(JDK 与 Maven 版本是否匹配);② 密钥是否按要求放进环境变量而不是源码。本章验收不通过的学生,不允许进入第 1 章实操。

0.1版本基准:本课程所有代码基于这套环境

先记住这张表。全课程的每一行代码、每一条命令,都以它为基准。版本不一致是学生环境问题里占比最高的一类——遇到报错先回来对照这张表,再动手排查。

组件版本说明
Spring AI2.0.1由 spring-ai-bom 统一管版本;2.0 与 1.x 的 API 有大量不兼容差异,网上教程混着看时会踩坑
Spring Boot4.1.x课程示例用 4.1.1;Boot 3.x 与本课程不兼容,不可混用
Java(JDK)17Spring AI 2.0 的硬性底线是 17;装 21 也可以,但别装 8/11
Maven≥ 3.6.3(推荐 3.9.x)Boot 4 的插件要求 3.6.3 以上;老版本 3.6.1 会直接构建失败
IDEIntelliJ IDEA社区版(Community)完全够用,无需旗舰版
应用端口8080全部示例统一 8080,与课程工程配置一致
模型服务DeepSeek(默认)OpenAI 兼容协议;换其他厂商见第 6 章「多模型」
最常见的版本坑:网上大量教程基于 Spring AI 1.x(甚至更老的 0.8.x),代码复制过来编译不过或运行报「找不到类」。判断教程是否适用:看它的 spring-ai-bom 版本号——2.x 开头才是本课程兼容的写法。这不是教程写错了,是 API 换代了。

0.2软件清单与检查命令

要装什么去哪下载装完怎么验证(命令行执行)
JDK 17 Oracle 官网 / Adoptium(temurin) java -version 输出包含 17
IntelliJ IDEA 社区版 jetbrains.com 能正常启动并打开一个项目
Maven 3.9.x maven.apache.org(IDEA 内置版也可用) mvn -v 输出 Maven 与 Java 版本
API 测试工具 curl(系统自带)/ Apifox(推荐图形界面) curl --version;或 Apifox 能打开
命令行用哪个?Windows 用 PowerShell 或 CMD 都可以;macOS / Linux 用终端(Terminal)。下文所有命令统一写成可直接复制的形式,Windows 用户如果看到 /path/to 这种写法,把它换成你自己的实际路径即可。

★ 先看这里:三种终端的命令差异(照抄命令前必读)

后面每一章都会给可以直接复制的命令。但同一句命令在三种终端里不一定都能跑——这是学生"照抄了却报错"的第一大来源。花 3 分钟看完这张表,能省掉后面几十次无效排查。

差异点Git Bash
本文示例默认
CMD(命令提示符)PowerShell
JSON 里的双引号 直接照抄:-d '{"question":"hi"}' 外层用双引号、内部转义:-d "{\"question\":\"hi\"}" 会被悄悄吃掉:内嵌双引号被剥离,服务端收到 {question:hi} → 报 400。见下方「三条出路」
curl 这个名字 真实的 curl 真实的 curl curl 是 Invoke-WebRequest 的别名,参数写法完全不同 → 必须写 curl.exe
Maven 的 -D 参数 mvn dependency:tree -Dincludes=org.springframework.ai 同上,可直接用 -D 传参会被拆坏 → 改用 --define "includes=org.springframework.ai"
读环境变量 echo $DEEPSEEK_API_KEY echo %DEEPSEEK_API_KEY% echo $env:DEEPSEEK_API_KEY
命令换行续行符 反斜杠 \ 脱字符 ^ 反引号 `
脚本文件后缀 .sh .bat .ps1(执行需 -ExecutionPolicy Bypass)
PowerShell 下 curl 发 JSON 报 400,怎么都调不通——三条出路(任选一条,推荐第 ① 条):
  1. 换 Apifox(图形化接口工具):URL、Header、Body 分开填,不用跟引号搏斗。初学者最省心,课程后续联调也建议用它。
  2. 改用 PowerShell 原生命令 Invoke-RestMethod(它不认识 -d,但能正确解析 JSON):
    Invoke-RestMethod -Uri http://localhost:8080/api/v1/chat/ask `
      -Method Post -ContentType "application/json" `
      -Body '{"question":"用一句话解释 Spring AI"}'
  3. 换成 Git Bash 或 CMD 再跑 curl:Git Bash 可直接照抄本文示例;CMD 按上表把内层双引号写成 \"。
另有一个 Windows 细节:原生 curl 里 -o /dev/null(丢弃输出)在 Windows 上会写入失败并报错,看起来像"请求失败",其实请求是成功的。想只看状态码,用 curl -i -s ...,或者在 Git Bash 里用 -o /dev/null。

把重复命令固化成一键脚本(强烈建议)

环境准备好之后,你会反复执行三类命令:清端口 → 启动应用 → 打接口验证。每次手敲既慢又容易错,建议在工程根目录存成三个脚本(本课程配套 lab 已自带,可直接用):

工程根目录/ ├── start-app.ps1 # 启动应用(自动注入密钥 + 启动数据库依赖) ├── stop-app.ps1 # 清理占用 8080 的进程(解决「端口被占用」) └── test-chat.ps1 # 打一个接口做冒烟验证

① stop-app.ps1:解决「Port 8080 was already in use」(写成文件执行,避免长命令在终端里被引号拆坏):

# stop-app.ps1 —— 找到并结束占用 8080 的进程
$pids = (netstat -ano | Select-String ":8080\s+.*LISTENING") -replace '.*\s+(\d+)$', '$1' | Sort-Object -Unique
if (-not $pids) { Write-Host "8080 未被占用"; exit }
foreach ($p in $pids) {
    Write-Host "结束进程 PID=$p"
    Stop-Process -Id $p -Force -ErrorAction SilentlyContinue
}
Write-Host "完成"

② start-app.ps1:把密钥注入本次会话再启动(避免"设了环境变量但进程读不到"):

# start-app.ps1 —— 从用户级环境变量取密钥,注入当前会话后启动
$env:DEEPSEEK_API_KEY = [Environment]::GetEnvironmentVariable("DEEPSEEK_API_KEY", "User")
if (-not $env:DEEPSEEK_API_KEY) { Write-Host "找不到 DEEPSEEK_API_KEY,请先按 0.6 节设置"; exit 1 }
Set-Location "D:\path\to\lab"        # ★ 换成你自己的 pom.xml 所在目录
.\mvnw.cmd spring-boot:run

③ test-chat.ps1:一发请求验证服务真的活了(用 Invoke-RestMethod 绕开 curl 的引号问题):

# test-chat.ps1 —— 冒烟测试:服务能收到请求并返回模型回答
try {
    $r = Invoke-RestMethod -Uri http://localhost:8080/api/v1/chat/ask `
         -Method Post -ContentType "application/json" `
         -Body '{"question":"只回答两个字:收到"}'
    Write-Host "成功:" -ForegroundColor Green; $r
} catch {
    Write-Host "失败:$_" -ForegroundColor Red
    Write-Host "排查:① 应用起来了吗(8080 是否监听)② 密钥非空吗 ③ 端口是否被别的程序占用" -ForegroundColor Yellow
}

运行方式(在脚本所在目录打开 PowerShell):

powershell -ExecutionPolicy Bypass -File .\stop-app.ps1
powershell -ExecutionPolicy Bypass -File .\start-app.ps1
powershell -ExecutionPolicy Bypass -File .\test-chat.ps1
坑:自己写的 .ps1 脚本里有中文,一跑就报语法错误或中文变问号。 根因:Windows PowerShell 5.1 默认按 ANSI(GBK) 解析没有 BOM 的文件;而编辑器通常存成 UTF-8 无 BOM,于是中文注释和中文字符串被按 GBK 解码,直接破坏语法。 两种解法:① 脚本里只用 ASCII(注释和数据都写英文)——最省事,课程脚本都这么做;② 用 UTF-8 with BOM 保存(VS Code 右下角编码处选 "UTF-8 with BOM")。中文测试数据不要直接写进命令行或脚本,放进单独的 UTF-8 JSON 文件,用 -Body (Get-Content -Raw -Encoding UTF8 body.json) 读进来——这条在后续章节会被反复用到。

0.3安装 JDK 17 并验证

  1. 下载并安装 JDK 17(推荐 Temurin 17,免费、无登录;Oracle 版本也可以)。安装时记下安装路径,例如 Windows 的 C:\Program Files\Java\jdk-17。

  2. 配置环境变量 JAVA_HOME 指向安装根目录,并把 %JAVA_HOME%\bin(macOS/Linux 为 $JAVA_HOME/bin)加入 Path。IDEA 通常能自动识别,但命令行构建(第 11 章打包部署)依赖它。

  3. 关掉所有已打开的终端窗口,重新开一个(环境变量改完不重开终端不生效——这是新手第一大坑),执行:

    java -version

    看到类似下面的输出即为成功:

    openjdk version "17.0.x" 2025-xx-xx
    OpenJDK Runtime Environment Temurin-17.0.x ...
    OpenJDK 64-Bit Server VM Temurin-17.0.x ...
排查:java 不是内部或外部命令。按顺序检查:① 环境变量改完后终端有没有重开?② Path 里加的是 bin 目录还是安装根目录(必须是 bin)?③ 机器上是否装了多个 JDK、Path 里被别的版本抢先?用 where java(Windows)查看实际生效的是哪一个。

0.4安装 IDEA

  1. 下载 IDEA Community(社区版),安装时勾选「创建桌面快捷方式」和「添加到 PATH」(可选)。
  2. 首次启动选择你喜欢的主题即可,不需要安装任何 AI 相关插件。本课程不使用 Lombok(所有 getter/setter 用 Java record 或手写,目的是让学生看全每一行代码),所以也不装 Lombok 插件。
  3. 中文界面插件可选装(Plugins → 搜索 Chinese),不影响任何功能。

0.5配置 Maven(国内镜像,必做)

Maven 默认从国外中央仓库下载依赖,国内直连速度慢甚至超时。这一步不做,第 1 章第一次构建就会卡死在下载依赖上。

  1. 找到 Maven 的配置文件 settings.xml:

    • 独立安装的 Maven:在安装目录 conf/settings.xml;
    • 建议复制一份到 ~/.m2/settings.xml(用户级配置,升级 Maven 不丢失)。
  2. 在 <settings> 标签内加入以下两段(完整文件可直接照抄):

    <?xml version="1.0" encoding="UTF-8"?>
    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
    
      <!-- ① 本地仓库路径:依赖 jar 包的存放位置。
           默认在 C 盘用户目录,建议改到 D 盘等其他数据盘 -->
      <localRepository>D:/maven-repo</localRepository>
    
      <mirrors>
        <!-- ② 阿里云公共仓库:国内下载依赖快且稳 -->
        <mirror>
          <id>aliyunmaven</id>
          <mirrorOf>central</mirrorOf>
          <name>阿里云公共仓库</name>
          <url>https://maven.aliyun.com/repository/public</url>
        </mirror>
      </mirrors>
    
    </settings>
  3. 验证(重开终端):

    mvn -v

    输出里确认两行:Maven 版本 ≥ 3.6.3,Java version 是 17。Maven 运行用的 JDK 和 JAVA_HOME 指向的一致,如果这里显示的不是 17,回去检查 JAVA_HOME。

  4. IDEA 侧确认:File → Settings → Build Tools → Maven,把 Maven home path 指向你的 Maven 目录,User settings file 勾选 Override 并指向刚改的 settings.xml。

为什么强烈建议自配 Maven 而不是用 IDEA 内置的?内置版隐藏了配置细节,出问题时学生不知道去哪改镜像;自配一次,以后所有项目(包括第 11 章的综合项目、毕业设计)通用。
真实案例:机器上装了多个 Maven,「明明配了新版,用的却是旧版」。 Windows 解析命令时系统 PATH(Machine)优先于用户 PATH(User)。如果系统 PATH 里残留了旧版 Maven(如 3.6.1),即使你把 3.9.x 加进了用户 PATH,终端里的 mvn 仍然解析到旧版——构建时报 xxx-plugin requires Maven version 3.6.3(插件要求新版,实际跑的却是旧版)。 排查三步: ① mvn -v 看版本是否符合预期; ② where mvn(Windows)看命令实际解析到哪个路径; ③ 解决任选其一:用项目自带 Wrapper .\mvnw.cmd(最推荐,锁定构建版本)、写完整路径调用、或从系统 PATH 删掉旧条目后新开终端。 另外注意:IDEA 的 Maven home 设置只影响 IDEA 内部构建,管不到外部终端;改完环境变量必须重开终端/重启 IDEA,运行中的进程不会刷新。

0.6申请 DeepSeek API Key

课程默认使用 DeepSeek(便宜、OpenAI 协议兼容、注册即用)。流程五步:

  1. 打开 deepseek.com,右上角进入「API 开放平台」,用手机号注册登录(是开放平台,不是聊天 App)。
  2. 左侧「充值」:先充 1~10 元即可。deepseek-chat 计价极低,做完全部课程实验花不了几块钱。
  3. 左侧「API keys」→「创建 API key」,名称随意(如 springai-course)。
  4. 创建后立刻复制保存——弹窗关掉后就再也看不到完整 key 了,只能重新创建。key 形如 sk-63956d56xxxxxxxxxxa3e4c2fc。
  5. 把 key 设置为环境变量(见下),不要写在任何源码文件里。

Windows(PowerShell,设置后重开终端生效):

setx DEEPSEEK_API_KEY "sk-你的完整key"

macOS / Linux(写入 ~/.zshrc 或 ~/.bashrc 后 source 生效):

export DEEPSEEK_API_KEY="sk-你的完整key"
为什么设置完密钥,应用还是报 401?——运行中的进程不会刷新环境变量。 每个进程只在启动那一刻继承一次环境变量,之后永远不会自动更新。如果 IDEA 是在 setx 之前启动的,它以及它带起来的应用进程里根本没有这个变量——典型症状:应用启动正常、接口也能访问,一调模型就 401。 解决(二选一): ① 完全退出并重启 IDEA(最简单); ② 在 IDEA 的 Run Configuration → Environment variables 里手动添加。 验证:项目里临时打印 System.getenv("DEEPSEEK_API_KEY"),输出为空就说明进程没继承到,重开即好。
密钥安全三条纪律(课程要求,违反按实验不合格处理): ① 密钥只放环境变量或 application.yml 的 ${DEEPSEEK_API_KEY:} 占位符里,绝不硬编码; ② 代码仓库上传前必须确认密钥不在任何文件里(key 一旦进 Git 历史,即使删除也还在); ③ 密钥泄露(比如不小心发到群里)立即去平台删除重建。 真实事故参考:无数公司的云账单爆炸,都是从「一个 key 提交到了 GitHub」开始的。

0.7创建课程工程(两种方式任选)

方式 A(推荐):使用课程配套工程 springai-lab

课程提供配套可运行工程 springai-lab,与教程代码逐字一致、每行都有中文注释,已随本课程包放在本教程目录的 lab/ 文件夹。使用:

  1. IDEA → Open → 选中 lab 目录(认准有 pom.xml 的那层)打开;
  2. 等待右下角 Maven 同步完成(首次会下载依赖,配好镜像约 1~3 分钟);
  3. 检查 src/main/resources/application.yml 中密钥占位符与你的环境变量名一致。
lab/ # 课程配套工程,随章节递增包结构 ├── pom.xml # Maven 依赖清单(含大量注释) └── src/main/ ├── java/com/example/springai/ │ ├── SpringaiLabApplication.java # 启动类 │ ├── common/ # 全局配置(跨章节共用) │ └── ch01/ ch02/ ... # 每章一个包 └── resources/application.yml # 模型/超时/日志配置

方式 B:从零创建(体验完整流程)

  1. 打开 start.spring.io,按下表选择:
选项选择
ProjectMaven
LanguageJava
Spring Boot4.1.x(不要选 3.x,更不要选 SNAPSHOT)
Group / Artifactcom.example / springai-lab
Package namecom.example.springai
Packaging / JavaJar / 17
DependenciesSpring Web + Spring AI Model Chat OpenAI(在 AI 区域)
  1. Generate 下载 zip,解压后用 IDEA 打开;
  2. 手动在 pom.xml 补上 spring-ai-bom 的 dependencyManagement 段(第 1 章会逐行讲解为什么必须有它)。

0.8全环境验收:三条命令

以下三条全部通过,环境才算就绪。课上教师逐人检查第 ①② 条的输出。

# ① JDK 版本(期望 17.x)
java -version

# ② Maven 版本 + 用的 JDK(期望 Maven ≥ 3.6.3,Java 17)
mvn -v

# ③ 环境变量里的密钥已就位(期望打印出 sk- 开头的 key,而不是空)
#    PowerShell:
echo $env:DEEPSEEK_API_KEY
#    macOS / Linux:
echo $DEEPSEEK_API_KEY

0.9常见问题排错表

现象原因解决
java -version 显示的不是 17装了多个 JDK,Path 顺序问题把 %JAVA_HOME%\bin 上移到 Path 最前;重开终端
mvn -v 报错或 Java 版本不对Maven 用了别的 JDK检查 JAVA_HOME 指向 17 的安装根目录
IDEA 里依赖一直转圈/下载失败没配国内镜像,或 IDEA 没用你的 settings.xml按 0.5 节检查 IDEA 的 Maven 配置;右下角 Maven 面板点刷新
Boot 4 插件要求 Maven 版本类报错Maven 太老(如 3.6.1)升级到 3.9.x
程序启动报 401密钥没读到(环境变量没重开终端)或 key 无效0.8 节命令 ③ 确认;确认充值到账、key 复制完整
端口 8080 被占用(Port already in use)上一个应用没停,或别的程序占了找到占用进程结束;或临时改 application.yml 的 server.port
setx 后 echo 还是空终端没重开关掉所有终端重开;IDEA 也要重启才能读到新环境变量(见 0.6 节「进程继承」说明)
mvn -v 版本不对 / 构建报插件要求更高 Maven 版本机器装了多个 Maven,系统 PATH 优先于用户 PATH,旧版抢先见 0.5 节末尾「真实案例」:用 where mvn 定位,改用 mvnw.cmd 或删旧条目后重开终端
在工程上层目录执行 mvn spring-boot:run 报 No plugin found for prefix 'spring-boot'当前目录没有 pom.xml(工程在子目录里)先 cd 到 pom.xml 所在目录再执行;或用 mvn -f 子目录/pom.xml spring-boot:run
PowerShell 里 curl 发 JSON 报 400,日志显示请求体 {question:hi}PS 5.1 传参不转义内嵌双引号;且 curl 被解析成 Invoke-WebRequest 别名换 Apifox;或用 Invoke-RestMethod;或写 curl.exe 并在 Git Bash / CMD 中执行(见 0.2 节对照表)
PowerShell 报 -Dincludes=... 参数不识别PS 会把 -D 拆坏改用 --define "includes=org.springframework.ai"
自己写的 .ps1 含中文就报语法错误PS 5.1 按 GBK 解析 UTF-8 无 BOM 文件脚本内只用 ASCII;或另存为 UTF-8 with BOM。中文数据放 JSON 文件读取

0.10课堂练习与课后作业

课堂练习(课上完成):

  • 互相交换检查 0.8 节三条命令的输出并截图;
  • 故意把 JAVA_HOME 改错,观察 mvn -v 报什么,再改回来——知道错误长什么样,比记住正确答案更重要。

课后作业:

  • 完成方式 B 的工程创建(即使你用方式 A),目的:熟悉 Initializr 每个选项的含义,写 200 字说明「Spring Web 和 Spring AI Model Chat OpenAI 两个依赖分别给项目带来了什么」;
  • 阅读配套工程 lab/pom.xml 的注释,圈出三处你看不懂的地方,下次课提问。

0.11本章验收标准