前端 (Next.js): 作为应用入口和BFF (Backend for Frontend) 层。它直接负责渲染UI、提供极致的流式聊天体验(通过其后端API直连AI模型),并作为客户端与后端微服务之间的唯一代理,简化前端逻辑,增强安全性。
后端 (Spring Cloud Microservices): 作为系统的核心业务能力中心。它处理所有与数据持久化、复杂业务规则、用户身份与权限管理相关的核心逻辑,确保系统的安全、稳定和高可用。
上午 (9:00 - 12:00)
9:00 - 10:00 | 模块一:开营与成果导向
内容详情:
(15分) 破冰与期望对齐:
讲师自我介绍,活跃气氛。
让每位学员简单介绍自己的技术背景(例如:后端Java经验、前端了解程度)和本次培训最想解决的问题。讲师快速记录,以便后续课程有所侧重。
(15分) 上期优秀项目展示与点评:
展示1-2个上期学员完成度高的项目代码。
教学重点: 指出项目的亮点,例如“这位同学实现了流畅的流式输出”、“他的微服务拆分很清晰”,以此来设定本期学员的目标,激发其学习动力。
(30分) 最终项目演示与架构蓝图揭示:
操作演示: 讲师现场打开最终成品的URL。演示完整的用户流程:注册 -> 登录 -> 进入问答界面 -> 提出一个问题(例如“解释一下什么是云原生”)-> 展示AI流畅的回答。
重点: 切换到白板工具,展示最终的系统架构图。逐一介绍每个组件:“这是用户的浏览器,它访问的是我们的Next.js前端。Next.js作为BFF,会处理一些轻量级逻辑,然后通过API网关(Gateway)请求后端。网关后面是我们的Nacos注册中心,它管理着所有的微服务,比如用户服务和问答服务。大家看,这就是我们这三天要亲手搭建的蓝图,每完成一个模块,就是点亮了这张图的一部分。”
10:00 - 12:00 | 模块二:AI问答系统的微服务架构设计
内容详情:
(60分)AI发展趋势讲解,
主流产品 -
IDE:vscode/cursor/cline/windsurf/
大模型:gemini/openai gpt系列/claude/deepseek
生图:gpt-4o,gemini
agent,agi等概念
(20分) 理论先行:从本项目出发:
白板绘制: 先画一个大方框,代表“单体AI问答系统”,里面包含“用户管理模块”、“问答逻辑模块”、“AI调用模块”。
引导式提问:
“如果我们想升级密码加密算法,需要动哪个模块?(用户管理)。发布时需要把整个系统停掉重启吗?(是)。这就是迭代风险。”
“现在AI调用是用Java的HTTP客户端,未来想换成更高效的Python gRPC库,方便吗?(不方便,整个项目技术栈被锁定了)。这就是技术栈锁定。”
“双十一搞活动,注册用户暴增,但提问的人不多,我们需要扩容。单体架构下,我们只能把整个应用复制几份,但其实只有用户模块需要资源,AI模块的资源被浪费了。这就是资源浪费。”
拆分演示: 在白板上,将单体方框擦掉,画出三个独立的服务小方框,并用API Gateway将它们连接起来,自然地引出微服务的形态。
(20分) 企业级组件选型与讲解:
Nacos (服务注册与发现): “现在服务分开了,用户服务想调用问答服务,它怎么知道地址?硬编码IP吗?如果问答服务部署了3台机器,地址是什么?这就是‘服务发现’要解决的问题。Nacos就像一本动态更新的电话本,每个服务启动时把自己的号码(IP:Port)登记上去,要找谁就去查一下。”
Nacos (统一配置中心): “我们的用户服务和问答服务都要连同一个数据库,数据库密码写在哪里?是不是每个服务的配置文件里都有一份?如果密码要改,是不是得改两个地方再重新发布?太麻烦了。Nacos的配置中心就是所有配置的唯一托管处。服务启动时来这里拿配置,而且我们后续会看到,在这里改了配置,服务能动态感知到,无需重启。”
Spring Cloud Gateway: “现在我们有多个服务,每个都有自己的端口。前端应用难道要记所有服务的地址吗?不安全也不方便。网关就是我们系统的唯一大门和前台。所有请求先进来,由它负责安检(鉴权)、登记(日志),然后根据请求的路径(比如/api/user)把它带到正确的房间(用户服务)。”
(20分) 绘制最终架构图:
打开在线白板工具,与学员互动,一步步从零开始,将刚刚讨论的所有组件(浏览器, Next.js, Gateway, Nacos, User-Service, QA-Service, 数据库)画出来,并用箭头标明请求流和注册流,加深理解。
下午 (13:30 - 16:30)
13:30 - 15:00 | 模块三:微服务环境搭建与服务注册 (Hands-on Lab)
内容详情:
(20分) 环境确认: 快速过一遍学员的java -version, mvn -v, docker --version,确保环境统一。
(70分) 项目初始化与Nacos集成:
操作演示 (讲师带领编码):
创建父项目: IDEA -> New Project -> Maven,创建一个名为ai-qa-system的父项目,pom.xml中packaging设为pom,并引入Spring Boot和Spring Cloud Alibaba的dependencyManagement。
创建子模块: 在父项目上右键 -> New Module,创建api-gateway, user-service, qa-service三个Spring Boot模块。
编写docker-compose.yml: 在项目根目录创建此文件。
version: '3.8'
services:
nacos:
image: nacos/nacos-server:latest
container_name: nacos-standalone
environment:
- PREFER_HOST_MODE=hostname
- MODE=standalone # 单机模式
ports:
- "8848:8848"
指令: 带领学员执行docker-compose up -d,并访问http://localhost:8848/nacos确认Nacos启动成功。
添加Nacos依赖: 在所有子模块的pom.xml中加入spring-cloud-starter-alibaba-nacos-discovery。
配置application.yml: 在每个子模块的application.yml中添加:
spring:
application:
name: user-service # 每个服务名字不同
cloud:
nacos:
discovery:
server-addr: localhost:8848
验证环节: 启动user-service和qa-service。
重点: 带领学员刷新Nacos控制台的“服务列表”页面,让他们亲眼看到自己启动的两个服务以及它们的实例信息。这是第一个“正反馈”。
15:00 - 16:30 | 模块四:构建用户微服务 (Hands-on Lab)
内容详情:
(20分) 数据库user表设计: 快速设计user表(id, username, password, create_time),提供SQL脚本给学员执行。
(60分) 实现用户CRUD与API:
操作演示 (讲师带领编码):
在user-service中添加spring-boot-starter-data-jpa, mysql-connector-java依赖。
创建User实体类,并用@Entity, @Table注解。
创建UserRepository接口,继承JpaRepository。
创建UserService,实现注册(密码要用BCryptPasswordEncoder加密)和登录逻辑。
创建UserController,提供@PostMapping("/register")和@PostMapping("/login")接口。
(10分) 关键点强调:
回顾注解: 在UserServiceApplication主类上,讲解@EnableDiscoveryClient注解的作用是“开启服务发现功能,让我去Nacos注册”。
再次验证: 确保user-service重启后,依然能在Nacos控制台看到它。
答疑与总结 (16:30 - 17:00)
总结: “今天,我们从零设计了整个系统的微服务架构,并成功地搭建了开发环境,启动了Nacos服务中心,还完成了第一个核心服务——用户服务的开发,并让它成功地注册到了Nacos。我们已经为后续的服务协同打下了坚实的基础。”
上午 (9:00 - 12:00)
9:00 - 10:30 | 模块一:智能网关与动态路由 (Hands-on Lab)
内容详情:
(60分) 基于服务发现的路由配置:
操作演示 (讲师带领编码):
在api-gateway的pom.xml中添加spring-cloud-starter-gateway和Nacos服务发现依赖。
在api-gateway的application.yml中配置:
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 开启从Nacos自动发现路由
lower-case-service-id: true # 将服务名转为小写路径
routes:
- id: user_route # 路由ID,自定义
uri: lb://user-service # lb代表load balancer
predicates:
- Path=/api/user/**
filters:
- StripPrefix=2 # 去掉/api/user,转发给后端的路径是/**
- id: qa_route
uri: lb://qa-service
predicates:
- Path=/api/qa/**
filters:
- StripPrefix=2
重点: 详细解释uri: lb://user-service。lb是关键,它告诉网关:“不要去固定的IP地址,去Nacos问一下名叫user-service的服务在哪里,然后把请求发过去。如果它有多个实例,你得负责做负载均衡。”
(30分) 全局过滤器实战:
操作演示 (讲师带领编码): 创建一个LoggingFilter类实现GlobalFilter接口。
codeJava
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("Request received: {} {}", exchange.getRequest().getMethod(), exchange.getRequest().getURI());
// 可以在这里写JWT校验逻辑
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 过滤器顺序,-1表示较高优先级
}
}
重点: 启动网关,用Postman访问一个不存在的地址,观察控制台是否打印日志。讲解过滤器链(FilterChain)的概念,以及getOrder()的作用。
10:30 - 12:00 | 模块二:配置中心与AI集成 (Hands-on Lab)
内容详情:
(30分) 动态配置管理:
操作演示 (讲师带领编码):
在qa-service中引入spring-cloud-starter-alibaba-nacos-config依赖。
在qa-service的resources目录下创建bootstrap.yml(它的加载优先级高于application.yml):
spring:
application:
name: qa-service
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yml # 指定配置文件格式
Nacos控制台操作: 登录Nacos -> 配置管理 -> 配置列表 -> 点击“+”创建配置。
Data ID: qa-service.yml
Group: DEFAULT_GROUP
配置内容: gemini: { api: { key: 'YOUR_INITIAL_KEY' } }
在qa-service代码中,创建一个类来接收配置,并用@Value或@ConfigurationProperties注入。关键是加上@RefreshScope注解。
动态刷新演示: 启动qa-service,调用一个接口返回这个key。然后,去Nacos页面把key改成'NEW_KEY_123'并发布。不重启服务,再次调用接口,展示返回的值已经变成了新的key。这是Nacos配置中心最核心的魅力。
(60分) 问答服务核心实现:
操作演示 (讲师带领编码):
在qa-service中引入spring-boot-starter-webflux以使用WebClient。
创建GeminiClient,注入WebClient.Builder和从Nacos获取的API Key。编写一个ask(String question)方法,使用WebClient异步调用Gemini API。
创建QARestController,提供POST /ask接口,调用GeminiClient。
下午 (13:30 - 16:30)
13:30 - 14:30 | 模块三:声明式服务间调用 (OpenFeign) (Hands-on Lab)
内容详情:
(15分) 场景引入: "现在问答服务需要用户信息,我们总不能再连一次用户库吧?这违背了微服务单一职责原则。正确做法是,问答服务应该像一个普通用户一样,去'请求'用户服务来获取数据。"
(45分) OpenFeign实战:
操作演示 (讲师带领编码):
在qa-service的pom.xml中引入spring-cloud-starter-openfeign。
在qa-service的Application主类上添加@EnableFeignClients注解。
创建一个client包,在里面新建一个UserClient接口:
// UserDTO是需要自己定义的数据传输对象,字段和User类似
@FeignClient("user-service") // 这里的名字必须和用户服务在Nacos注册的名字一致
public interface UserClient {
@GetMapping("/users/{userId}") // 路径和方法要和UserController中的一致
UserDTO getUserById(@PathVariable("userId") Long userId);
}
在QAService中直接@Autowired注入UserClient,然后像调用本地方法一样调用userClient.getUserById(1L)。
教学重点: 强调@FeignClient("user-service")的魔力。Feign结合了Ribbon(负载均衡)和Nacos,自动将这个接口的调用转换成对user-service某个健康实例的HTTP请求。
14:30 - 16:30 | 模块四:全链路集成测试 (Hands-on Lab)
内容详情:
(20分) 讲解测试策略: "现在所有后端组件都已就位,我们要进行'黑盒测试'。我们的测试工具Postman只和唯一的大门——API Gateway对话,来模拟真实的前端请求。" 启动所有服务:docker-compose up -d启动Nacos,然后依次启动user-service, qa-service, api-gateway。
(100分) Postman端到端联调:
Step 1: 注册和登录:
创建一个Postman请求,POST http://localhost:8080/api/user/register,在Body中传入用户名和密码。确认返回成功。
再创建一个请求,POST http://localhost:8080/api/user/login,获取Token(如果实现了的话)。
Step 2: 提问:
创建一个请求,POST http://localhost:8080/api/qa/ask,在Body中传入问题。
核心调试: 观察qa-service的日志,看它是否成功通过Feign调用了user-service并获取到了用户信息。
带领排错: 故意制造错误,例如停掉user-service,然后调用提问接口,观察网关或qa-service的报错(通常是503 Service Unavailable),带领学员查看Nacos控制台,发现user-service实例已经不在了,从而学会定位“服务调用失败”这类问题。
答疑与总结 (16:30 - 17:00)
总结: “今天我们打通了任督二脉!服务之间不再是孤岛,网关统一了入口,Nacos统一了配置,Feign实现了优雅的服务调用。我们的后端系统已经是一个能协同工作的有机整体了。”
上午 (9:00 - 12:00)
9:00 - 10:30 | 模块一:Next.js全栈开发入门 (Hands-on Lab)
内容详情:
(20分) 现代前端理念: "我们不只学React,我们学的是用Next.js来做React开发。把React看作是乐高积木,那Next.js就是官方出品的、带说明书和底板的'千年隼'套装。它帮你处理好了路由、打包、优化等所有烦心事。"
(70分) 项目创建与核心概念:
操作演示 (讲师带领编码):
在项目根目录外,执行npx create-next-app@latest frontend,选择TypeScript, TailwindCSS等。
讲解app目录结构:layout.tsx是全局布局,page.tsx是主页。
创建登录页:新建目录app/login/page.tsx,这就自动创建了/login路由。
在实践中学React: 在LoginPage组件中,演示如何用const [username, setUsername] = useState('');来管理输入框状态,这就是useState Hook。在ChatInterface组件中,演示如何在组件加载后自动聚焦输入框,useEffect(() => { inputRef.current?.focus(); }, []);,这就是useEffect Hook。
10:30 - 12:00 | 模块二:构建BFF层,实现极致AI体验 (Hands-on Lab)
内容详情:
(45分) AI流式对话实现:
操作演示 (讲师带领编码):
在frontend项目中,安装Vercel AI SDK: npm install ai。
创建API路由: app/api/chat/route.ts。
编写后端逻辑,直接从process.env读取Gemini API Key。
// app/api/chat/route.ts
import { GoogleGenerativeAI } from '@google/generative-ai';
import { GoogleAIStream, StreamingTextResponse } from 'ai';
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || '');
export async function POST(req: Request) {
const { messages } = await req.json();
const result = await genAI.getGenerativeModel({ model: 'gemini-pro' })
.generateContentStream(messages); // Simplified
const stream = GoogleAIStream(result);
return new StreamingTextResponse(stream);
}
在ChatInterface组件中,使用useChat hook:
// ChatInterface.tsx
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
// ... JSX to render messages and form
}
教学重点: 强调这种架构的优势。AI的流式响应直接从Next.js后端推送到前端,延迟极低,体验极好。Spring Cloud后端完全不用关心流式处理的复杂性。
(45分) 代理后端微服务:
操作演示 (讲师带领编码):
创建代理路由: app/api/auth/[...slug]/route.ts。
编写代理逻辑,将请求原样转发到Spring Cloud Gateway。
// app/api/auth/[...slug]/route.ts
export async function POST(req: Request, { params }: { params: { slug: string[] } }) {
const backendUrl = `http://localhost:8080/api/user/${params.slug.join('/')}`;
const response = await fetch(backendUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(await req.json()),
});
// ... handle response and cookies
return response;
}
修改LoginPage的fetch请求地址为/api/auth/login。
教学重点: 讲解BFF的好处:前端的端口是3000,后端的端口是8080,这样直接请求会有跨域问题。通过BFF代理,前端始终是访问同源的/api路径,完美规避跨域。同时,后端的地址对浏览器是不可见的,更安全。
下午 (13:30 - 16:30)
13:30 - 15:00 | 模块三:容器化与CI/CD自动化 (Hands-on Lab)
内容详情:
(30分) Dockerfile编写:
教学重点: 讲解多阶段构建 (multi-stage build) 的好处——最终镜像只包含运行所需的文件,体积大大减小。
提供优化后的Dockerfile模板给user-service (基于maven构建,最后拷贝jar到openjdk镜像) 和 frontend (基于node构建,最后拷贝.next目录到node-slim镜像)。
(30分) Docker Compose编排:
操作演示: 更新docker-compose.yml,加入user-service, qa-service, api-gateway, frontend 四个服务,并配置好build上下文和端口映射。使用depends_on确保Nacos最先启动。
关键指令: docker-compose up --build -d。执行后,学员应该能通过访问前端端口,使用完整的、容器化的应用。
(30分) 智能化CI/CD流水线:
操作演示: 在项目根目录创建.github/workflows/ci.yml。
on:
push:
branches: [ main ]
jobs:
build-user-service:
if: "contains(join(github.event.commits.*.message), '#userservice') or contains(join(github.event.files.*.filename), 'user-service/')"
runs-on: ubuntu-latest
steps:
# ... steps to build and push user-service docker image
教学重点: 讲解if条件或paths关键字的用法,演示如何通过commit信息或文件路径变更,来触发特定的job,实现“精准部署”。
15:00 - 16:30 | 模块四:Serverless初探与未来架构展望 (Live Demo)
内容详情:
(20分) Serverless理念: "想象一下,容器是租了一个带厨房的房间(服务器资源),不管做不做饭(跑不跑代码),房租都要付。Serverless是去了一家公共厨房,只有在你切菜、炒菜的时候(代码执行时)才按秒付费,不用了就走人,不产生任何费用。"
(60分) AWS Lambda动手实验:
操作演示:
登录AWS控制台,进入Lambda服务。
创建一个新的Java函数,选择模板。
现场编写一个简单的handleRequest方法,接收一个字符串,返回它的大写形式。
点击部署。
配置一个API Gateway触发器,选择HTTP API类型,AWS会自动生成一个公网URL。
关键时刻: 切换到Postman,用这个URL发送一个请求,立即看到返回结果。
展示Lambda的监控页面,看到调用次数、执行时间等指标,强调其“按需付费”的特性。
(10分) 架构升华: "我们项目里,如果要做一个每天凌晨才执行一次的'用户问题热点分析'任务,是为此专门跑一个微服务24小时待命划算,还是用Lambda函数,只在执行的那几分钟付费划算?" 引导学员思考Serverless的适用场景。
课程总结与未来学习路径展望 (16:30 - 17:00)
总结: “三天时间,我们从一张白纸开始,设计、开发、联调并部署了一个包含前端BFF、API网关、服务治理、多个后端微服务的完整AI应用。大家掌握了从单体到微服务,从本地开发到云原生部署的全流程核心技能。”
布置大作业: 再次明确学员成果展示的要求。
提供进阶方向: “今天的Nacos保证了服务高可用,但如果数据库挂了呢?(数据库高可用、分库分表)。服务调用失败怎么办?(熔断、降级-Sentinel)。一个请求经过这么多服务,出错了怎么定位?(分布式链路追踪-SkyWalking)。这些就是大家后续深造的方向。”
Comments (0)