Spring AI Agent实战:订单系统+支付宝MCP,对接支付渠道像说话一样简单
摘要: 本文介绍了如何利用SpringAI结合MCP协议简化支付宝支付对接。传统支付接口开发涉及复杂的签名校验和回调处理,而SpringAI通过智能Agent和MCP协议(类似“AI世界的USB接口”)将支付功能转化为自然语言交互,显著降低开发门槛。实战演示了电商订单系统场景,通过order-agent解析用户意图,调用mcp-server-alipay完成支付,并同步更新本地订单状态。
引言:为什么选择Spring AI及MCP协议对接支付宝
大家好,我是小冬瓜。在数字化时代,支付渠道对接是每个订单系统的核心痛点。传统开发中,调用支付宝API需要繁琐的签名、参数校验和错误处理,耗时耗力。想象一下,如果对接支付渠道像和AI助手对话一样简单,会怎样?Spring AI结合MCP(Model Context Protocol)让这一切成为现实!传统支付对接的复杂性(如手动处理支付宝API的签名、回调验证等)与企业对快速上线的需求矛盾。通过Spring AI Agent和支付宝MCP,开发者可以像调用自然语言接口一样完成支付功能,降低开发门槛,提升效率。 本文将带你实战Spring AI与支付宝MCP,学习如何用Spring AI构建智能Agent,通过MCP协议无缝对接支付宝,打造智能订单系统,让支付对接如丝般顺滑。
技术背景:Spring AI、MCP和Agent的核心概念
Spring AI:Spring AI是Spring官方推出的AI开发框架,支持大模型集成(如DeepSeek、Claude)和MCP协议,提供统一的API接口,简化AI与外部工具的交互。
MCP协议:MCP(Model Context Protocol)是由Anthropic提出的标准化协议,类似“AI世界的USB接口”,让大模型通过统一接口调用外部服务(如支付宝支付API)。它解决了数据孤岛和重复开发问题。
Spring AI Agent的作用:Agent是大模型的“智能代理”,通过MCP协议,Spring AI Agent可以自动调用支付宝服务,完成支付、查询、退款等操作,无需手动编码复杂逻辑。
实战场景:基于Spring AI的订单系统对接支付宝
业务场景:设计一个电商订单系统,用户下单通过支付宝支付后,系统自动验证支付状态并更新订单。
演示效果:
agent-order演示
系统模块:
order-agent: Spring AI Agent,负责解析用户意图,调用MCP Client发起支付请求。
mcp-server-order:自定义MCP Server,负责本地订单业务逻辑
mcp-server-alipay:支付宝MCP服务,支付渠道
实现步骤:手把手带你对接支付宝MCP
准备工作: 申请支付宝开放平台参数
-
登录支付宝开放平台创建网页/移动应用,完成相关配置并上线。开通手机网站支付或者电脑网站支付产品
-
调用MCP服务还需要在支付宝开放平台申请MCP场景受限密钥。
-
我是个人开发者,没有商户资质,申请使用的沙箱环境参数。
-
将获取的参数在Modalscope中配置为MCP sse服务。(在springai中使用stdio方式调用支付宝mcp服务会有些问题,对参数限制也比较死,这里踩了好多坑,最后配置为sse服务才调通)
依赖配置,在pom.xml中引入Spring AI、MCP相关依赖。
mcp-server-order/pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
order-agent/pom.xml
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
mcp-server-order具体代码
application.yml
spring:
ai:
mcp:
server:
name: mcp-server-order
version: 0.0.1
datasource:
url: jdbc:mysql://127.0.0.1:3306/demodb?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: xgourd
password: xgourd123
#sse方式需要启动web
server:
port: 8081
# stdio方式需要加一下配置项禁用web
# main:
# banner-mode: off
# web-application-type: none
#logging:
# pattern:
# console: ''
MCP Server工具类
/**
* @author 任海东
* @since 2025年7月10日
*/
@Service
@Slf4j
@AllArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
@AllArgsConstructor
@Getter
enum State {
/**
* 等待支付中
*/
WAITING("0"),
/**
* 已取消
*/
CANCEL("1"),
/**
* 已支付
*/
PAYED("2"),
/**
* 已退款
*/
REFUND("3"),
/**
* 已超时
*/
TIMEOUT("4");
private final String code;
}
/**
* 模拟某软件商品三种套餐及价格
*/
private static final Map<String, BigDecimal> PKGS = Map.of("1", BigDecimal.valueOf(9.9), "2",
BigDecimal.valueOf(29.9), "3", BigDecimal.valueOf(99.9));
@Tool(description = "根据客户购买的套餐,本地生成一笔待支付订单")
public Order createOrder(@ToolParam(description = "客户手机号") final String phoneNo,
@ToolParam(description = "购买套餐的数字编号") final String pkgNo) {
return orderRepository.save(new Order().setOrderNo(System.currentTimeMillis() + "").setProductNo(pkgNo)
.setOrderAmount(PKGS.get(pkgNo)).setCustomerId(phoneNo).setCreateTime(new Date())
.setOrderStatus(State.WAITING.getCode()));
}
@Tool(description = "完成本地订单,更新本地订单状态为已支付, 并记录支付宝交易号")
public void complete(@ToolParam(description = "本地订单号,即商户订单号") final String orderNo,
@ToolParam(description = "支付宝订单号") final String alipayTradeNo) {
final Order order = orderRepository.findByOrderNo(orderNo).orElseThrow();
orderRepository.save(
order.setOrderStatus(State.PAYED.getCode()).setAlipayTradeNo(alipayTradeNo).setUpdateTime(new Date()));
}
@Tool(description = "取消本地订单,更新本地订单状态为已取消")
public void cancel(final String orderNo) {
final Order order = orderRepository.findByOrderNo(orderNo).orElseThrow();
orderRepository.save(order.setOrderStatus(State.CANCEL.getCode()).setUpdateTime(new Date()));
}
@Tool(description = "发生退款,更新本地订单状态为已退款")
public void refund(final String orderNo) {
final Order order = orderRepository.findByOrderNo(orderNo).orElseThrow();
orderRepository.save(order.setOrderStatus(State.REFUND.getCode()).setUpdateTime(new Date()));
}
}
工具注册
@Bean
public ToolCallbackProvider dataTool(final OrderService orderService) {
return MethodToolCallbackProvider.builder().toolObjects(orderService).build();
}
Agent具体代码
application.yml
spring:
application:
name: order-agent
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
chat:
options:
model: deepseek-v3
mcp:
client:
# stdio:
# servers-configuration: classpath:mcp-servers.json
sse:
connections:
ali:
url: https://mcp.api-inference.modelscope.net
sse-endpoint: /cb8d2f1aad9341/sse
order:
url: http://localhost:8081
toolcallback:
enabled: false
logging:
level:
'[io.modelcontextprotocol.client]': debug
'[io.modelcontextprotocol.spec]': debug
入口代码
/**
* @author 任海东
* @since 2025年7月10日
*/
@SpringBootApplication
@RestController
@Slf4j
public class AgentApplication {
private final ChatClient chatClient;
/**
* @param args
*/
public static void main(final String[] args) {
SpringApplication.run(AgentApplication.class, args);
}
/**
* 初始化chatClient
*
* @param mcpClients
* @param builder
*/
public AgentApplication(final List<McpSyncClient> mcpClients, final ChatClient.Builder builder) {
this.chatClient = builder.defaultToolCallbacks(new SyncMcpToolCallbackProvider(mcpClients)).build();
}
/**
* 客户下单
*
* @param phone 客户手机号
* @param pkgNo 选择的套餐
* @param response
*/
@PostMapping("/buy")
public void buy(@RequestParam final String phone, @RequestParam final String plan,
final HttpServletResponse response) {
final String prompt = """
请根据用户输入信息: 手机号: %s, 套餐号: %s
1. 生成一笔本地订单;
2. 将订单号、订单金额、订单主题<套餐n:选择的套餐对应的名称>[1-基础套餐、2-专业套餐、3-尊享套餐]作为参数生成支付宝订单,将支付链接<https://xxx>返回;
3. 输出格式:key为url的可解析的json字符串,eg: {"url":"https://xxx"}
4. 请注意url的提取末尾不含括号,输出json字符串末尾不含"]";
""".formatted(phone, plan);
final String resp = chatClient.prompt(prompt).call().content().replace("```json", "").replace("```", "");
log.info("生成订单响应: {}", resp);
final String url = JSON.parseObject(resp).getString("url");
log.info("支付链接: {}", url);
try {
response.sendRedirect(url);
} catch (final IOException e) {
log.error("重定向失败", e);
try {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "重定向失败");
} catch (final IOException ioException) {
log.error("发送错误响应失败", ioException);
}
}
}
/**
*
* @param params
* @return
*/
@GetMapping("/callback")
public String callback(@RequestParam final Map<String, String> params) {
log.info("订单回调: {}", params);
// 这里最好还有验签逻辑,回调更新
final String prompt = """
根据回调参数: %s,完成本地订单
1. 将本地订单状态更新为已支付,并记录支付宝交易号;
2. 请注意本地订单号是out_trade_no, 支付宝交易号是trade_no
""".formatted(JSON.toJSONString(params));
return chatClient.prompt(prompt).call().content();
}
}
结论:开始你的Spring AI支付之旅
总结:通过Spring AI Agent和支付宝MCP,支付对接从繁琐的API调用变为自然语言般的简单交互,极大降低了开发难度。
行动号召:立即尝试Spring AI,用MCP对接支付宝,打造属于你的智能订单系统!
资源推荐:
Spring AI官方文档:Spring AI
MCP协议介绍:MCP 简介 - MCP 中文文档
支付宝开放平台:支付宝开放平台
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)