从零开始搭建基于Spring Boot的MCP(Model Context Protocol)系统完整教程
从零开始搭建基于Spring Boot的MCP(Model Context Protocol)系统完整教程
项目介绍
本教程将详细介绍如何从零开始搭建一个基于Spring Boot的MCP(Model Context Protocol)系统,该系统能够让AI模型(如通义千问)直接调用MyBatis数据库查询方法,实现自然语言查询数据库的功能。
要求dao层必须在com.dao这个路径下面,如果不是请自行更改代码,(详见包扫描工具)
系统架构
1 | 前端(Vue) -> Controller -> Service -> AI模型 -> 工具类 -> MyBatis -> 数据库 |
核心功能
- 自然语言查询:用户可以用自然语言描述查询需求
- AI理解与转换:AI模型将自然语言转换为具体的数据库查询
- 动态方法调用:系统动态调用MyBatis Mapper方法执行查询
- 流式响应:通过SSE(Server-Sent Events)实现流式响应
- 智能重试:当单条查询返回多条记录时,自动重试列表查询
1. 环境准备
1.1 技术栈
- 后端:Spring Boot 2.2.2 + MyBatis Plus + 通义千问AI SDK
- 前端:Vue.js + Element UI
- 数据库:MySQL
- Java版本:JDK 1.8
1.2 创建Spring Boot项目
使用Spring Initializr创建项目,或直接使用本教程提供的pom.xml
配置。
2. Maven依赖配置
以下是实现MCP系统所需的关键Maven依赖:
1 | <!-- Spring Boot Web支持 --> |
关键依赖说明
- dashscope-sdk-java:通义千问AI SDK,用于与AI模型交互,是MCP系统的核心组件
- mybatis-spring-boot-starter:提供MyBatis集成,用于数据库操作
- mybatis-plus:MyBatis增强工具,简化CRUD操作
- spring-boot-starter-web:提供Web MVC支持,处理HTTP请求
- mysql-connector-java:MySQL数据库驱动
- lombok:通过注解简化Java代码,减少样板代码
3. 后端实现
3.1 配置文件
在application.yml
中添加以下配置:
1 | server: |
3.2 Controller层实现
创建DeepSeekController.java
:
1 | package com.controller; |
3.3 Service接口定义
创建DeepSeekService.java
接口:
1 | package com.service; |
3.4 Service实现类
创建DeepSeekServiceImpl.java
实现类,这是整个MCP系统的核心。下面我们逐步讲解其中的关键方法:
3.4.1 类结构与初始化
1 |
|
这个类实现了两个接口:DeepSeekService
提供业务方法,ApplicationContextAware
用于获取Spring上下文。关键属性包括:
aiKey
:AI模型的API密钥sqlSessionFactory
:MyBatis会话工厂,用于数据库操作availableMethodsCache
:缓存所有可用的MyBatis方法executor
:线程池,用于异步处理请求
3.4.2 Mapper方法发现
1 |
|
这个方法在应用启动时被调用,用于发现所有可用的MyBatis Mapper方法。它会:
- 首先尝试从Spring上下文中查找带
@Mapper
注解的Bean - 如果没有找到,则查找实现了
BaseMapper
接口的类 - 遍历所有找到的Mapper,提取其中的方法信息
- 为方法添加智能标记,如”✅推荐-返回列表”、”⚠️单条记录”等
- 如果Spring上下文中没有找到任何Mapper,则回退到文件系统扫描模式
3.4.3 SSE处理核心方法
1 |
|
这是处理用户请求的核心方法,它:
- 创建一个
SseEmitter
对象,设置10分钟的超时时间 - 设置连接完成、错误和超时的回调处理
- 使用线程池异步处理请求,避免阻塞主线程
- 构建消息列表,包括系统提示和用户问题
- 调用
processConversation
方法处理对话
3.4.4 对话处理与工具调用
1 | private void processConversation(List<Message> messages, SseEmitter emitter) throws Exception { |
这个方法是MCP系统的核心,它实现了与AI模型的对话和工具调用:
- 调用AI模型,获取回复
- 检查AI的回复中是否包含工具调用
- 如果有工具调用,执行相应的工具(这里是MyBatis查询)
- 将工具执行结果添加到消息列表中
- 递归调用自身,继续与AI对话,直到AI不再调用工具
- 如果没有工具调用,将AI的最终回答发送给前端
3.4.5 系统提示构建
1 | private Message buildSystemMessage() { |
这个方法构建了系统提示,指导AI如何使用MyBatis工具:
- 定义AI的角色和能力
- 提供重要提示,指导AI选择合适的查询方法
- 列出所有可用的MyBatis方法,并添加智能标记
- 要求AI根据用户问题选择最合适的查询方法
3.4.6 SSE响应发送
1 | private void sendSseResponse(SseEmitter emitter, String data) { |
这个方法负责向客户端发送SSE响应:
- 生成唯一的事件ID
- 将换行符替换为
<br>
标签,确保SSE传输安全且前端能正确渲染 - 构建SSE事件并发送给客户端
- 处理发送失败的情况,完成连接
通过这些关键方法的组合,DeepSeekServiceImpl
实现了完整的MCP系统功能,包括AI对话、工具调用、数据库查询和流式响应。
3.4.7 完整代码
1 | package com.service.impl; |
3.5 工具类实现
3.5.1 MyBatis工具类
MyBatisToolCall
是MCP系统的核心工具类,负责动态执行MyBatis Mapper方法。下面我们分步讲解其关键方法:
3.5.1.1 类结构与核心方法
1 | public class MyBatisToolCall { |
这个类提供了静态方法execute
,接收SqlSessionFactory
和JSON格式的参数,返回JSON格式的查询结果。
3.5.1.2 参数解析与验证
1 | public static String execute(SqlSessionFactory sqlSessionFactory, String arguments) { |
execute
方法首先解析AI模型提供的JSON参数,支持两种格式:
methodName
格式:直接指定完整的方法名mapper/method
格式:分别指定Mapper名和方法名
3.5.1.3 动态查找Mapper和方法
1 | // 解析Mapper名和方法名 |
这段代码实现了动态查找Mapper类和方法的功能:
- 从方法名字符串中解析出Mapper名和方法名
- 在MyBatis配置中查找匹配的Mapper类
- 在Mapper类中查找匹配的方法,优先选择参数最少的方法
3.5.1.4 方法调用与结果处理
1 | // 准备方法参数 |
最后,准备好方法参数后,通过反射调用目标方法,并将结果序列化为JSON格式返回。
3.5.1.5 智能重试机制
1 | private static String retryWithListMethod(SqlSessionFactory sqlSessionFactory, |
当单条查询方法返回多条记录时,系统会自动重试对应的列表查询方法:
- 智能转换方法名(如
selectView
->selectListView
) - 添加查询限制,避免返回过多数据
- 执行列表查询方法并返回结果
3.5.1.6 方法参数准备
1 | private static Object[] prepareMethodArguments(Method method, JsonNode argsNode) { |
prepareMethodArguments
方法负责准备方法调用所需的参数:
- 跳过分页参数(我们不使用分页)
- 为每个参数创建
EntityWrapper
对象 - 将JSON中的查询条件添加到
EntityWrapper
中
3.5.1.7 完整代码
1 |
|
3.5.2 包扫描工具类
PackageScanner
是一个辅助工具类,用于在Spring上下文中找不到Mapper时,通过文件系统扫描来发现Mapper方法。
3.5.2.1 核心扫描方法
1 | public class PackageScanner { |
这个方法的主要功能是:
- 查找指定包中的所有接口类
- 提取每个接口中的方法
- 返回完整的方法名列表
3.5.2.2 文件系统扫描实现
1 | private static List<Class<?>> findMapperInterfaces(String basePackage) |
findMapperInterfaces
方法实现了文件系统扫描功能:
- 将包名转换为文件系统路径
- 获取类加载器中的所有资源
- 遍历文件系统中的.class文件
- 将文件名转换为类名并加载类
这个工具类作为备用机制,当Spring上下文中找不到Mapper时,可以通过文件系统扫描来发现Mapper方法,确保系统的健壮性。
3.5.2.3 完整代码
1 | package com.utils; |
4. 前端实现
4.1 前端组件说明
前端使用Vue.js实现,主要组件为Model.vue
,负责与后端SSE接口交互并展示AI回复。
4.2 完整前端代码
1 | <template> |
5. 系统工作流程
5.1 整体流程
- 用户输入:用户在前端输入自然语言查询
- SSE连接:前端建立与后端的SSE连接
- AI处理:后端将用户问题发送给AI模型
- 工具调用:AI模型决定调用MyBatis工具查询数据库
- 动态执行:
MyBatisToolCall
动态执行Mapper方法 - 结果返回:查询结果返回给AI模型
- 格式化输出:AI模型将结果格式化为自然语言回答
- 流式响应:通过SSE将回答流式返回给前端
- 逐字显示:前端逐字显示AI回答
5.2 关键技术点
5.2.1 SSE流式响应
使用Spring Boot的SseEmitter
实现服务器向客户端的实时数据推送:
1 | private void sendSseResponse(SseEmitter emitter, String data) { |
5.2.2 动态方法调用
通过反射动态调用MyBatis Mapper方法:
1 | // Get the mapper instance and invoke the method |
5.2.3 智能重试机制
当单条查询返回多条记录时,自动重试列表查询:
1 | private static String retryWithListMethod(SqlSessionFactory sqlSessionFactory, String originalMethodNameWithMapper, JsonNode originalArgsNode) throws Exception { |
6. 部署与测试
6.1 部署步骤
- 配置数据库:修改
application.yml
中的数据库连接信息 - 配置AI密钥:在
application.yml
中设置ai-key
6.2 测试用例
简单查询:
1
查询会员账号为"会员1"的会员信息
列表查询:
1
查询所有男性会员的信息
模糊查询:
1
查询姓名包含"张"的会员
7. 总结与展望
7.1 系统优势
- 自然语言交互:用户无需编写SQL,用自然语言即可查询数据库
- 智能方法选择:AI能够根据查询需求选择最合适的Mapper方法
- 自动错误处理:系统具有智能重试机制,提高查询成功率
- 实时响应:通过SSE实现流式响应,提升用户体验
7.2 扩展方向
- 多数据源支持:扩展支持多种数据库类型
- 权限控制:添加用户权限验证,确保数据安全
- 查询优化:添加查询缓存和性能优化
- 更多AI模型:支持多种AI模型,如GPT、Claude等
7.3 注意事项
- 安全性:确保AI密钥和数据库连接信息的安全
- 性能监控:监控系统性能,及时处理异常情况
- 日志管理:合理配置日志级别,便于问题排查
本教程详细介绍了从零开始搭建MCP系统的全过程,包括完整的代码实现和部署说明。通过这个系统,用户可以用自然语言轻松查询数据库,大大降低了数据查询的门槛。