支付对接:微信/支付宝支付、回调解析、订单核销
支付对接微信/支付宝支付、回调解析、订单核销钱货两讫天经地义——但在无人售货柜里钱这一步可比你想的复杂多了。一、支付在无人售货柜中的完整流程先说清楚整个支付链路搞不懂全貌写出来的代码一定是漏的。无人售货柜的支付流程和普通电商不同它不是先下单再付款而是先拿货再付款。完整链路如下关门 → 视觉识别商品 → 生成订单 → 用户支付 → 支付平台回调 → 核销订单 → 交易完成 ↓ (失败)→ 超时关单/退款核心区别在于订单是在用户拿完商品关门后才生成的用户扫码开门时不需要支付关门瞬间由视觉识别系统判断拿了什么生成订单后调起支付。二、微信支付对接2.1 JSAPI支付小程序场景无人售货柜多配套微信小程序所以微信支付主要走JSAPI支付。流程是后端调用微信「统一下单」接口拿到预支付会话标识prepay_id后端用prepay_id生成前端调起支付所需参数前端调用wx.requestPayment拉起支付界面用户输入密码/指纹完成支付微信服务器异步通知后端回调接口2.2 统一下单核心代码ServiceSlf4jpublicclassWechatPayService{AutowiredprivateWxPayConfigwxPayConfig;/** * 统一下单生成小程序调起支付参数 */publicWxPayJsapiResultunifiedOrder(Orderorder){try{// 1. 构建统一下单请求WxPayUnifiedOrderRequestrequestnewWxPayUnifiedOrderRequest();request.setAppid(wxPayConfig.getAppId());request.setMchId(wxPayConfig.getMchId());request.setNonceStr(WxPayKit.generateNonceStr());request.setBody(无人售货柜-order.getOrderNo());request.setOutTradeNo(order.getOrderNo());// 金额单位分request.setTotalFee(order.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue());request.setSpbillCreateIp(IpUtil.getClientIp());request.setNotifyUrl(wxPayConfig.getNotifyUrl());request.setTradeType(JSAPI);// 用户openid小程序登录后获取request.setOpenid(order.getOpenid());// 2. 签名request.setSign(WxPayKit.createSign(BeanUtil.beanToTreeMap(request),wxPayConfig.getApiKey()));// 3. 调用微信统一下单接口StringxmlWxPayKit.toXml(request);StringresultHttpUtil.post(wxPayConfig.getUnifiedOrderUrl(),xml);MapString,StringresultMapWxPayKit.xmlToMap(result);// 4. 校验返回结果StringreturnCoderesultMap.get(return_code);StringresultCoderesultMap.get(result_code);if(!SUCCESS.equals(returnCode)||!SUCCESS.equals(resultCode)){log.error(微信统一下单失败: {},resultMap);thrownewBusinessException(微信支付下单失败);}// 5. 生成前端调起支付参数StringprepayIdresultMap.get(prepay_id);WxPayJsapiResultjsapiResultnewWxPayJsapiResult();jsapiResult.setAppId(wxPayConfig.getAppId());jsapiResult.setTimeStamp(String.valueOf(System.currentTimeMillis()/1000));jsapiResult.setNonceStr(WxPayKit.generateNonceStr());jsapiResult.setPackage(prepay_idprepayId);jsapiResult.setSignType(RSA);// 支付签名jsapiResult.setPaySign(WxPayKit.createPaySign(jsapiResult.getAppId(),jsapiResult.getTimeStamp(),jsapiResult.getNonceStr(),jsapiResult.getPackage(),wxPayConfig.getApiKey()));returnjsapiResult;}catch(Exceptione){log.error(微信统一下单异常, orderNo{},order.getOrderNo(),e);thrownewBusinessException(支付服务异常);}}}新手提醒微信支付金额单位是分不是元。BigDecimal转换时一定要乘以100这个坑踩过的人都知道。三、支付宝对接3.1 当面付扫码场景支付宝这边我们用「当面付」F2FPay适用于用户扫码直接支付的流程。支付宝的SDK封装得比较友好用alipay-sdk-java即可。ServiceSlf4jpublicclassAlipayService{AutowiredprivateAlipayConfigalipayConfig;/** * 当面付预创建交易生成二维码 */publicAlipayTradePrecreateResultprecreate(Orderorder){try{AlipayClientclientnewDefaultAlipayClient(alipayConfig.getGateway(),alipayConfig.getAppId(),alipayConfig.getPrivateKey(),json,UTF-8,alipayConfig.getAlipayPublicKey(),RSA2);AlipayTradePrecreateRequestrequestnewAlipayTradePrecreateRequest();request.setNotifyUrl(alipayConfig.getNotifyUrl());MapString,ObjectbizContentnewHashMap();bizContent.put(out_trade_no,order.getOrderNo());bizContent.put(total_amount,order.getPayAmount().toString());bizContent.put(subject,无人售货柜-order.getOrderNo());request.setBizContent(JSON.toJSONString(bizContent));AlipayTradePrecreateResponseresponseclient.execute(request);if(!response.isSuccess()){log.error(支付宝预下单失败: {},response.getSubMsg());thrownewBusinessException(支付宝支付下单失败);}AlipayTradePrecreateResultresultnewAlipayTradePrecreateResult();result.setQrCode(response.getQrCode());result.setTradeNo(response.getTradeNo());returnresult;}catch(AlipayApiExceptione){log.error(支付宝预下单异常,e);thrownewBusinessException(支付服务异常);}}}四、支付回调处理核心中的核心4.1 回调处理流程支付回调是整个支付链路最关键的一环处理不好就是资损。流程如下支付平台异步通知 → 验签 → 金额校验 → 幂等判断 → 更新订单状态 → 扣减库存 → 记录流水 → 返回SUCCESS4.2 回调处理Service完整实现ServiceSlf4jpublicclassPayCallbackService{AutowiredprivateOrderServiceorderService;AutowiredprivatePaymentServicepaymentService;AutowiredprivateInventoryServiceinventoryService;AutowiredprivateRedissonClientredissonClient;/** * 微信支付回调处理 */publicStringhandleWechatCallback(StringxmlData){try{MapString,StringparamsWxPayKit.xmlToMap(xmlData);// 1. 验签 —— 防止伪造回调if(!WxPayKit.verifySign(params,wxPayConfig.getApiKey())){log.error(微信回调验签失败);returnxmlreturn_codeFAIL/return_code/xml;}// 2. 解析回调数据StringorderNoparams.get(out_trade_no);StringtransactionIdparams.get(transaction_id);StringtotalFeeparams.get(total_fee);StringresultCodeparams.get(result_code);if(!SUCCESS.equals(resultCode)){log.error(微信回调支付失败, orderNo{},orderNo);returnxmlreturn_codeSUCCESS/return_code/xml;}// 3. 金额校验 —— 防止金额被篡改OrderorderorderService.getByOrderNo(orderNo);if(ordernull){log.error(订单不存在, orderNo{},orderNo);returnxmlreturn_codeSUCCESS/return_code/xml;}intexpectedFeeorder.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue();if(expectedFee!Integer.parseInt(totalFee)){log.error(金额不一致, 期望{}分, 实际{}分,expectedFee,totalFee);// 记录异常人工介入paymentService.recordAmountMismatch(orderNo,expectedFee,totalFee);returnxmlreturn_codeSUCCESS/return_code/xml;}// 4. 幂等处理 —— 分布式锁防重复处理RLocklockredissonClient.getLock(pay:callback:orderNo);if(!lock.tryLock(0,30,TimeUnit.SECONDS)){log.warn(回调重复到达, 已有处理中, orderNo{},orderNo);returnxmlreturn_codeSUCCESS/return_code/xml;}try{// 再次检查订单状态双重幂等if(order.getStatus()!OrderStatus.UNPAID){log.info(订单已处理, 跳过, orderNo{}, status{},orderNo,order.getStatus());returnxmlreturn_codeSUCCESS/return_code/xml;}// 5. 更新订单状态orderService.paySuccess(orderNo,transactionId);// 6. 确认扣减库存预占 → 确认inventoryService.confirmDeduct(order);// 7. 记录支付流水PaymentpaymentnewPayment();payment.setOrderNo(orderNo);payment.setTransactionId(transactionId);payment.setPayType(PayType.WECHAT);payment.setAmount(order.getPayAmount());payment.setStatus(PaymentStatus.SUCCESS);payment.setCallbackTime(LocalDateTime.now());paymentService.save(payment);log.info(微信支付回调处理成功, orderNo{},orderNo);returnxmlreturn_codeSUCCESS/return_code/xml;}finally{lock.unlock();}}catch(Exceptione){log.error(微信回调处理异常,e);returnxmlreturn_codeFAIL/return_code/xml;}}}4.3 幂等性设计详解支付平台会重试回调微信最多通知15次所以幂等性是生命线。实现方式层级方案说明第一层分布式锁Redisson锁同一订单号防止并发处理第二层状态判断订单非UNPAID状态直接返回SUCCESS第三层流水号去重transaction_id唯一索引防止重复入账三层防护缺一不可。五、支付状态查询兜底回调可能因网络问题丢失所以必须有主动查询兜底机制/** * 定时扫描未确认支付的订单主动查询支付状态 */Scheduled(cron0 */5 * * * ?)publicvoidcheckUnpaidOrders(){// 查询创建超过5分钟但仍未支付的订单ListOrderordersorderService.findUnpaidOrders(5);for(Orderorder:orders){try{// 主动查询微信/支付宝支付状态PayStatusResultresultpayQueryService.queryPayStatus(order);if(result.isPaid()){// 主动补偿走和回调一样的逻辑payCallbackService.processPaySuccess(order,result.getTransactionId());}elseif(result.isExpired()){// 支付已过期关闭订单orderService.closeOrder(order.getOrderNo(),支付超时关闭);inventoryService.releasePreempt(order);}}catch(Exceptione){log.error(查询支付状态异常, orderNo{},order.getOrderNo(),e);}}}六、退款流程退款不是简单的把钱还回去涉及多步状态流转发起退款 → 第三方处理 → 退款回调 → 更新订单(已退款) → 恢复库存 → 通知用户/** * 发起微信退款 */publicvoidrefund(Orderorder,Stringreason){// 1. 创建退款记录RefundRecordrefundnewRefundRecord();refund.setOrderNo(order.getOrderNo());refund.setRefundNo(IdUtil.generateRefundNo());refund.setAmount(order.getPayAmount());refund.setReason(reason);refund.setStatus(RefundStatus.PROCESSING);refundRecordService.save(refund);// 2. 调用微信退款接口WxPayRefundRequestrequestnewWxPayRefundRequest();request.setOutTradeNo(order.getOrderNo());request.setOutRefundNo(refund.getRefundNo());request.setTotalFee(order.getPayAmount().multiply(BigDecimal.valueOf(100)).intValue());request.setRefundFee(refund.getAmount().multiply(BigDecimal.valueOf(100)).intValue());request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());WxPayRefundResponseresponsewxPayService.refund(request);if(!response.isSuccess()){thrownewBusinessException(退款发起失败: response.getErrMsg());}// 退款结果由异步回调通知}七、支付流水表设计CREATETABLEpayment(idBIGINTPRIMARYKEYAUTO_INCREMENT,order_noVARCHAR(64)NOTNULLCOMMENT订单号,transaction_idVARCHAR(64)COMMENT第三方流水号,refund_noVARCHAR(64)COMMENT退款单号,pay_typeTINYINTNOTNULLCOMMENT支付方式:1微信2支付宝,amountDECIMAL(10,2)NOTNULLCOMMENT支付金额,statusTINYINTNOTNULLCOMMENT状态:0待支付1成功2失败3已退款,callback_timeDATETIMECOMMENT回调时间,create_timeDATETIMEDEFAULTCURRENT_TIMESTAMP,INDEXidx_order_no(order_no),INDEXidx_transaction_id(transaction_id),UNIQUEINDEXuk_transaction_id(transaction_id))COMMENT支付流水表;transaction_id加唯一索引既是查询索引又是去重保障一箭双雕。八、安全设计要点安全风险防护方案伪造回调回调验签微信MD5/HMAC-SHA256支付宝RSA2金额篡改回调金额与订单金额比对校验重放攻击校验回调时间戳超时拒绝重复入账分布式锁 状态判断 流水号唯一索引退款超退退款金额校验不超过原支付金额九、常见问题排查回调网络超时微信要求5秒内返回响应回调处理逻辑中不要做耗时操作。库存扣减走异步MQ回调只做核心状态更新。金额不一致最危险的情况。回调金额与订单金额不符时不要自动处理记录异常流水转人工审核。重复回调幂等设计兜底重复回调直接返回SUCCESS即可微信收到SUCCESS就不再重试。但如果你返回FAIL微信会疯狂重试15次系统压力陡增。支付了但订单没更新这就是支付状态查询兜底机制存在的意义——定时任务主动查不依赖回调。支付对接看着简单坑全在细节里。验签、幂等、金额校验、兜底查询每一环都是血的教训换来的。把这几块设计扎实了后面不管是加新的支付渠道还是处理退款都是照猫画虎的事。

相关新闻

订单核心模块:下单流程、状态机、防重下单设计

订单核心模块:下单流程、状态机、防重下单设计

订单核心模块:下单流程、状态机、防重下单设计如果说购物车是"开门快乐拿",那订单就是"关门老实付"。订单模块承载着从结算到支付的完整链路,也是整个系统中并发压力最大、数据一致性要求最高的模块。一、订单在无人售货…

2026/8/3 3:20:35阅读更多 →
存储芯片成半导体增长引擎,开发者如何应对内存与存储性能挑战?

存储芯片成半导体增长引擎,开发者如何应对内存与存储性能挑战?

大家好,我是专注于科技产业趋势分析的博主。最近,一份来自权威研究机构Omdia的半导体市场预测报告引发了业界广泛关注。报告指出,到2026年,全球半导体行业营收将迎来高达94.1%的惊人增长,而其中存储芯片(IC…

2026/8/3 3:20:35阅读更多 →
企业 Agent 死在试点:88% 背后的四大死因与 5 信号自查框架(技术视角)

企业 Agent 死在试点:88% 背后的四大死因与 5 信号自查框架(技术视角)

一、核心判断:试点 ≠ 产品 2026 年企业圈最热的关键词是 Agentic AI,但数据给了冷水: KPMG 2026-06-30 调研:88% 企业已启动 Agentic AI 试点,仅 24% 真正见回报;MIT:约 95% 已上线 GenAI 试点…

2026/8/3 3:18:35阅读更多 →
量化交易的市场博弈与散户防御策略

量化交易的市场博弈与散户防御策略

1. 量化交易的市场博弈本质金融市场就像个巨大的赌场,而量化交易机构就是那些拿着超级计算机的"职业赌徒"。他们通过算法在毫秒级别捕捉市场机会,普通投资者常常还没反应过来就被"割了韭菜"。这种现象在A股市场尤为明显——据统计&a…

2026/8/3 4:27:13阅读更多 →
可转债量化投资策略:双低值筛选与市场温度模型

可转债量化投资策略:双低值筛选与市场温度模型

1. 可转债投资策略概述可转债作为一种兼具债券安全性和股票收益潜力的金融工具,近年来受到越来越多投资者的关注。与传统债券不同,可转债赋予持有者在特定条件下将债券转换为发行公司股票的权利,这种独特的"债性股性"双重特征&…

2026/8/3 4:27:13阅读更多 →
OPC UA技术专家如何通过知识管理实现品牌化增长

OPC UA技术专家如何通过知识管理实现品牌化增长

1. 为什么OPC超级个体需要品牌化增长?在工业自动化领域,OPC(OLE for Process Control)技术从业者正面临一个关键转折点。过去十年间,我见证了无数技术专家从单纯的"问题解决者"成长为行业意见领袖的过程。OP…

2026/8/3 4:27:13阅读更多 →
达美乐忠诚度计划:外卖增长的数字引擎

达美乐忠诚度计划:外卖增长的数字引擎

1. 达美乐忠诚度计划如何成为外卖增长引擎上周五晚上8点,我在北京朝阳区的一家达美乐门店看到这样一幕:五个外卖骑手同时在等餐,柜台前挤满了扫码兑换积分的顾客。店长告诉我,自从升级了忠诚度计划,外卖订单同比增加了…

2026/8/3 4:27:13阅读更多 →
基于蒙特卡洛树搜索的2048游戏AI策略分析与Python实现

基于蒙特卡洛树搜索的2048游戏AI策略分析与Python实现

1. 项目概述:当经典益智游戏遇上AI2048,这个由意大利开发者Gabriele Cirulli在2014年创造的滑动方块合并游戏,相信很多人都玩过,也卡在某个分数上过。它的规则简单到极致:在一个4x4的网格中,通过上下左右滑…

2026/8/3 4:27:13阅读更多 →
SpringBoot定时任务详解:@Scheduled与@Schedules对比与实践

SpringBoot定时任务详解:@Scheduled与@Schedules对比与实践

1. SpringBoot定时任务基础解析在SpringBoot应用中实现定时任务功能时,Scheduled和Schedules这两个注解经常让开发者产生混淆。作为Spring框架定时任务模块的核心注解,它们虽然名称相似,但在使用场景和功能特性上存在本质区别。定时任务在现代…

2026/8/3 4:25:02阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/3 0:29:53阅读更多 →
限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

限时公开!某头部SaaS公司内部AI模板工厂架构文档(含5类行业模板源码+性能压测报告)

更多请点击: https://intelliparadigm.com 第一章:AI模板批量生成的核心价值与落地全景 AI模板批量生成正从实验性工具演进为现代软件工程的关键基础设施。它通过语义理解、上下文感知与结构化约束,将重复性高、模式明确的代码/文档/配置生成…

2026/8/3 0:33:53阅读更多 →
如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南

如何快速找回消失的网页:Web Archives浏览器扩展终极指南 【免费下载链接】web-archives Browser extension for viewing archived and cached versions of web pages, available for Chrome, Edge and Safari 项目地址: https://gitcode.com/gh_mirrors/we/web-a…

2026/8/3 0:20:37阅读更多 →
3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。…

2026/8/3 0:00:32阅读更多 →
[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

PC服务器具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构一、前言:具身智能需要“混合算力闭环系统”传统人工智能依赖云端静态数据集训练,不具备物理交互能力,无法适应真实世界的不确定性。具身智能(Embodied…

2026/8/3 0:00:32阅读更多 →
[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

前言构建机器人、具身智能这类分布式实时系统,通信底座直接决定整套系统的实时性、容错性、组网能力。分布式领域长期存在 4 类经典通信架构:点对点模式、Broker 中间代理模式、广播模式、以数据为中心(DDS)模式。很多开发者疑惑&…

2026/8/3 0:00:32阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/3 2:32:59阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/3 2:33:01阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/3 2:33:04阅读更多 →