跳转到主内容
极星编程网:以代码为星,赴技术山海!

从0到1搭建Java企业级支付系统:整合微信/支付宝支付,搞定核心业务逻辑

引言:为什么支付系统是Java开发者的“硬技能”?

做Java开发多年,发现“支付系统开发”是区分“普通CRUD程序员”和“企业级开发工程师”的关键—— 新手一听到“支付对接”就怕:微信支付v3的签名验签、支付宝的异步回调、支付订单的幂等性、跨系统的分布式事务、资金对账……每一个点都容易踩坑,要么对接失败,要么出现“重复支付”“订单状态不一致”的致命问题。

这套教程完全对标企业真实支付场景,从 0到1搭建一套可落地的支付系统 :整合微信支付v3、支付宝支付两大主流渠道,覆盖“下单→生成支付链接→用户支付→支付回调→订单更新→退款→对账”全核心流程,每一行代码都讲清楚“为什么这么写”“怎么避坑”,哪怕你只懂SpringBoot基础,也能跟着做出一套符合企业标准的支付系统。

项目定位 :通用型企业级支付系统,支持微信H5支付、支付宝电脑网站支付,涵盖「订单管理、支付对接、回调处理、退款管理、简单对账」五大核心模块,完全符合支付行业开发规范。

一、 先搞懂:企业级支付系统的核心逻辑(避坑基石) 做支付系统前,必须先理清“钱怎么流转”,这是所有代码的核心: 1.1 支付核心流程(企业真实场景) 是否用户下单生成支付订单(本地)调用微信/支付宝统一下单接口生成支付链接/二维码用户扫码/点击支付支付成功?

支付平台异步回调我方接口验签通过后更新本地订单状态异步对账(可选)订单超时关闭 1.2 核心痛点&技术落地方向(新手必看) 核心痛点企业级解决方案技术落地方向 签名/验签失败严格按支付平台规范实现签名,统一工具类微信v3使用SHA256-RSA,支付宝使用RSA2回调重复通知幂等性处理(订单号+回调流水号唯一标识)Redis分布式锁+数据库唯一索引订单状态不一致分布式事务+状态机控制本地消息表+RabbitMQ异步确认支付超时定时任务关闭超时未支付订单MyBatis-Plus+定时线程池(或XXL-Job)资金对账差异每日拉取支付平台账单,对比本地订单微信/支付宝账单接口+Excel/数据库对账 1.3 技术栈选型(企业级稳定优先,新手友好) 技术领域选型方案选型理由(实战+新手友好) 核心框架SpringBoot 2.7.122.x稳定版,文档最全,避坑成本最低ORM框架MyBatis-Plus 3.5.3.1简化CRUD,分页、条件查询开箱即用数据库MySQL 8.0主流关系型数据库,事务支持完善缓存/分布式锁Redis 6.2缓存支付订单、实现幂等性、分布式锁消息队列RabbitMQ 3.9.x异步处理回调、对账,解耦核心流程微信支付微信支付v3 SDK官方最新版,安全性更高(推荐企业使用)支付宝支付支付宝开放平台SDK 4.38企业主流版本,文档详细,新手易对接加密/签名BCrypt、RSA2密码加密+支付签名,符合支付安全规范构建工具Maven 3.8.xIDEA集成度高,一键导入依赖辅助工具Lombok、HuTool简化代码+通用工具(日期、加密、HTTP) 二、 0到1环境搭建(新手一次成功,避坑版) 2.1 支付平台开发者账号准备(关键!

必须先做) (1)微信支付开发者账号(新手用测试号) 注册地址:https://pay.weixin.qq.com/ 新手推荐:申请“微信支付测试号”(https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login),无需企业资质,直接获取appid、商户号、API密钥; 记录关键信息:

appid

、

mch_id

(商户号)、

api_v3_key

(v3密钥)、商户私钥/公钥(用于签名)。

(2)支付宝开发者账号(新手用沙箱环境) 注册地址:https://open.alipay.com/ 进入“开发者中心→沙箱环境”,获取:

app_id

、支付宝公钥、应用私钥(自己生成); 沙箱账号:可获取测试用的买家账号/密码,用于支付测试。

2.2 本地环境搭建(新手复制粘贴就行) (1)SpringBoot项目初始化(IDEA可视化操作) 打开IDEA→New→Project→Spring Initializr→Next; 填写信息: Group:

com.xxx

(新手填

com.pay

); Artifact:

payment-system

; Java:11; Spring Boot:2.7.12; 勾选核心依赖: Web→Spring Web; SQL→MySQL Driver、MyBatis Framework; NoSQL→Spring Data Redis; Messaging→Spring AMQP(RabbitMQ); Developer Tools→Lombok、Spring Boot DevTools; Finish,等待依赖加载完成。

(2)补充支付SDK依赖(pom.xml)

com.github.wechatpay-apiv3 wechatpay-java 0.2.10 com.alipay.sdk alipay-sdk-java 4.38.0.ALL cn.hutool hutool-all 5.8.20 com.alibaba fastjson 2.0.32

点击IDEA的Maven刷新按钮,等待依赖下载完成。

(3)核心配置(application.yml)

server:

port: 8080 servlet: context-path: /pay

spring: # 数据库配置(新手改密码) datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/payment_system?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 # Redis配置 redis: host: localhost port: 6379 password: 123456 database: 0 # RabbitMQ配置 rabbitmq: host: localhost port: 5672 username: guest password: guest

# MyBatis-Plus配置 mybatis-plus: mapper-locations: classpath:mapper/**/*.xml type-aliases-package: com.pay.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

# 支付平台配置(新手替换为自己的测试号信息) pay: # 微信支付v3配置 wechat: appid: wx1234567890abcdef # 测试号appid mch_id: 1900009999 # 测试号商户号 api_v3_key: abcdef1234567890abcdef1234567890 # v3密钥 private_key_path: classpath:cert/wechat_private_key.pem # 商户私钥路径 notify_url: http://你的外网域名/pay/wechat/notify # 回调地址(必须外网可访问) # 支付宝配置 alipay: app_id: 2021000000000000 # 沙箱appid private_key: 你的应用私钥 # 自己生成的应用私钥 public_key: 支付宝公钥 # 沙箱环境的支付宝公钥 gateway_url: https://openapi.alipaydev.com/gateway.do # 沙箱网关 notify_url: http://你的外网域名/pay/alipay/notify # 回调地址

(4)创建数据库(新手复制建表语句) 在MySQL中创建

payment_system

数据库,执行以下建表语句(核心表):

-- 支付订单表(核心)

CREATE TABLE pay_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '订单ID', order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '本地订单号', out_trade_no VARCHAR(50) COMMENT '支付平台订单号', pay_type TINYINT NOT NULL COMMENT '支付类型:1-微信 2-支付宝', total_amount DECIMAL(10,2) NOT NULL COMMENT '支付金额(元)', subject VARCHAR(100) NOT NULL COMMENT '订单标题', status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待支付 1-支付成功 2-已取消 3-退款中 4-已退款', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', pay_time DATETIME COMMENT '支付时间', notify_time DATETIME COMMENT '回调时间', notify_id VARCHAR(100) COMMENT '回调ID(幂等性)' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付订单表';

-- 退款订单表 CREATE TABLE refund_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '退款ID', order_no VARCHAR(50) NOT NULL COMMENT '关联本地订单号', refund_no VARCHAR(50) NOT NULL UNIQUE COMMENT '退款单号', refund_amount DECIMAL(10,2) NOT NULL COMMENT '退款金额', refund_status TINYINT DEFAULT 0 COMMENT '退款状态:0-退款中 1-退款成功 2-退款失败', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', FOREIGN KEY (order_no) REFERENCES pay_order(order_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='退款订单表';

三、 核心代码实现(0到1,手把手敲) 先梳理项目结构(新手严格按这个建包):

com.pay

├── entity // 实体类(订单、退款) ├── mapper // Mapper层(MyBatis-Plus) ├── service // 服务层(核心业务) │ └── impl // 服务实现类 ├── controller // 控制器(下单、回调、退款) ├── config // 配置类(微信/支付宝、Redis、RabbitMQ) ├── util // 工具类(签名、订单号生成) └── PaymentApplication.java // 启动类

3.1 通用工具类(支付核心:订单号生成+签名) (1)订单号生成工具(PayOrderNoUtil.java)

package com.pay.util;

import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.RandomUtil;

/** * 支付订单号生成工具(企业级规范:日期+随机数+支付类型) */ public class PayOrderNoUtil { /** * 生成本地订单号 * @param payType 1-微信 2-支付宝 * @return 订单号(如:PAY202601061620301234561) */ public static String generateOrderNo(Integer payType) { // 日期:yyyyMMddHHmmss String dateStr = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"); // 6位随机数 String randomStr = RandomUtil.randomNumbers(6); // 拼接:PAY+日期+随机数+支付类型 return "PAY" + dateStr + randomStr + payType; }

/** * 生成退款单号 * @return 退款单号(如:REFUND20260106162030123456) */ public static String generateRefundNo() { String dateStr = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"); String randomStr = RandomUtil.randomNumbers(6); return "REFUND" + dateStr + randomStr; } }

(2)微信支付v3签名工具(新手不用懂原理,直接用)

package com.pay.util;

import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.Signer; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component;

import java.io.IOException; import java.security.PrivateKey;

/** * 微信支付v3签名工具 */ @Component public class WeChatPaySignUtil { @Value("${pay.wechat.mch_id}") private String mchId; @Value("${pay.wechat.private_key_path}") private Resource privateKeyResource;

// 获取商户私钥 public PrivateKey getPrivateKey() throws IOException { return PemUtil.loadPrivateKey(privateKeyResource.getInputStream()); }

// 获取签名器 public Signer getSigner() throws IOException { return new PrivateKeySigner(mchId, getPrivateKey()); } }

3.2 支付配置类(对接微信/支付宝) (1)微信支付配置(WeChatPayConfig.java)

package com.pay.config;

import com.pay.util.WeChatPaySignUtil; import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

import java.io.IOException; import java.security.PrivateKey;

/** * 微信支付v3配置(新手直接用,不用改) */ @Configuration public class WeChatPayConfig { @Value("${pay.wechat.appid}") private String appid; @Value("${pay.wechat.mch_id}") private String mchId; @Value("${pay.wechat.api_v3_key}") private String apiV3Key;

@Bean public AutoUpdateCertificatesVerifier verifier(WeChatPaySignUtil signUtil) throws IOException { PrivateKey privateKey = signUtil.getPrivateKey(); return new AutoUpdateCertificatesVerifier( new com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeyCredential(mchId, privateKey), apiV3Key.getBytes()); }

@Bean public org.apache.http.client.HttpClient weChatPayClient(AutoUpdateCertificatesVerifier verifier, WeChatPaySignUtil signUtil) throws IOException { WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() .withMerchant(mchId, appid, signUtil.getPrivateKey()) .withValidator(new WechatPay2Validator(verifier)); return builder.build(); } }

(2)支付宝支付配置(AlipayConfig.java)

package com.pay.config;

import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

/** * 支付宝配置(新手替换参数即可) */ @Configuration public class AlipayConfig { @Value("${pay.alipay.app_id}") private String appId; @Value("${pay.alipay.private_key}") private String privateKey; @Value("${pay.alipay.public_key}") private String publicKey; @Value("${pay.alipay.gateway_url}") private String gatewayUrl;

@Bean public AlipayClient alipayClient() { // 创建支付宝客户端(核心) return new DefaultAlipayClient( gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2" // 加密方式:RSA2(企业标准) ); } }

3.3 核心业务:创建支付订单+生成支付链接 (1)支付订单实体类(PayOrder.java)

package com.pay.entity;

import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;

import java.math.BigDecimal; import java.util.Date;

@Data @TableName("pay_order") public class PayOrder { @TableId(type = IdType.AUTO) private Long id; private String orderNo; // 本地订单号 private String outTradeNo; // 支付平台订单号 private Integer payType; // 1-微信 2-支付宝 private BigDecimal totalAmount;// 支付金额 private String subject; // 订单标题 private Integer status; // 0-待支付 1-支付成功 private Date createTime; private Date payTime; private Date notifyTime; private String notifyId; // 回调ID(幂等性) }

(2)支付订单Service接口(PayOrderService.java)

package com.pay.service;

import com.baomidou.mybatisplus.extension.service.IService; import com.pay.entity.PayOrder;

/** * 支付订单服务接口 */ public interface PayOrderService extends IService { /** * 创建支付订单并生成支付链接 * @param payType 1-微信 2-支付宝 * @param totalAmount 支付金额 * @param subject 订单标题 * @return 支付链接 */ String createPayOrder(Integer payType, BigDecimal totalAmount, String subject); }

(3)支付订单Service实现类(核心!

)

package com.pay.service.impl;

import com.alipay.api.AlipayClient; import com.alipay.api.request.AlipayTradePagePayRequest; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.pay.entity.PayOrder; import com.pay.mapper.PayOrderMapper; import com.pay.service.PayOrderService; import com.pay.util.PayOrderNoUtil; import com.wechat.pay.contrib.apache.httpclient.util.JsonUtil; import com.wechat.pay.java.core.RSAAutoCertificateConfig; import com.wechat.pay.java.service.payments.h5.H5Service; import com.wechat.pay.java.service.payments.h5.model.CreateOrderRequest; import com.wechat.pay.java.service.payments.h5.model.H5CreateOrderResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service;

import javax.annotation.Resource; import java.math.BigDecimal;

/** * 支付订单服务实现(整合微信+支付宝) */ @Service public class PayOrderServiceImpl extends ServiceImpl implements PayOrderService { @Value("${pay.wechat.appid}") private String weChatAppId; @Value("${pay.wechat.mch_id}") private String weChatMchId; @Value("${pay.wechat.api_v3_key}") private String weChatApiV3Key; @Value("${pay.wechat.notify_url}") private String weChatNotifyUrl; @Value("${pay.alipay.notify_url}") private String alipayNotifyUrl;

@Resource private AlipayClient alipayClient;

// 微信H5支付服务 private H5Service getWeChatH5Service() { RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder() .merchantId(weChatMchId) .privateKeyFromPath("classpath:cert/wechat_private_key.pem") .merchantSerialNumber("你的商户证书序列号") .apiV3Key(weChatApiV3Key) .build(); return new H5Service.Builder().config(config).build(); }

@Override public String createPayOrder(Integer payType, BigDecimal totalAmount, String subject) { // 1. 生成本地订单号 String orderNo = PayOrderNoUtil.generateOrderNo(payType); // 2. 保存本地订单(待支付状态) PayOrder payOrder = new PayOrder(); payOrder.setOrderNo(orderNo); payOrder.setPayType(payType); payOrder.setTotalAmount(totalAmount); payOrder.setSubject(subject); payOrder.setStatus(0); // 待支付 this.save(payOrder);

// 3. 根据支付类型生成支付链接 if (payType == 1) { // 微信H5支付 return createWeChatH5Order(orderNo, totalAmount, subject); } else if (payType == 2) { // 支付宝电脑网站支付 return createAlipayPageOrder(orderNo, totalAmount, subject); } else { throw new RuntimeException("不支持的支付类型"); } }

// 生成微信H5支付链接 private String createWeChatH5Order(String orderNo, BigDecimal totalAmount, String subject) { CreateOrderRequest request = new CreateOrderRequest(); request.setAppid(weChatAppId); request.setMchid(weChatMchId); request.setDescription(subject); request.setOutTradeNo(orderNo); // 金额:分(微信支付单位是分,需转换) request.setAmount(new CreateOrderRequest.Amount().setTotal(totalAmount.multiply(new BigDecimal(100)).intValue())); request.setNotifyUrl(weChatNotifyUrl); // 场景信息(H5支付必填) CreateOrderRequest.SceneInfo sceneInfo = new CreateOrderRequest.SceneInfo(); sceneInfo.setPayerClientIp("127.0.0.1"); // 客户端IP sceneInfo.setH5Info(new CreateOrderRequest.H5Info().setType("WAP")); request.setSceneInfo(sceneInfo);

// 调用微信统一下单接口 H5Service h5Service = getWeChatH5Service(); H5CreateOrderResponse response = h5Service.createOrder(request); // 返回支付链接 return response.getH5Url(); }

// 生成支付宝电脑网站支付链接 private String createAlipayPageOrder(String orderNo, BigDecimal totalAmount, String subject) { try { AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); // 同步回调(可选) request.setReturnUrl("http://你的域名/pay/alipay/return"); // 异步回调 request.setNotifyUrl(alipayNotifyUrl); // 业务参数 String bizContent = "{" + "\"out_trade_no\":\"" + orderNo + "\"," + "\"total_amount\":\"" + totalAmount + "\"," + "\"subject\":\"" + subject + "\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"" + "}"; request.setBizContent(bizContent); // 生成支付链接(支付宝会返回HTML表单,直接跳转) return alipayClient.pageExecute(request).getBody(); } catch (Exception e) { throw new RuntimeException("支付宝下单失败:" + e.getMessage()); } } }

3.4 控制器层(下单接口+回调接口) (1)支付订单控制器(PayOrderController.java)

package com.pay.controller;

import com.pay.service.PayOrderService; import com.pay.util.Result; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource; import java.math.BigDecimal;

/** * 支付订单控制器(新手直接访问即可生成支付链接) */ @RestController public class PayOrderController { @Resource private PayOrderService payOrderService;

/** * 创建支付订单 * @param payType 1-微信 2-支付宝 * @param amount 支付金额(元) * @param subject 订单标题 * @return 支付链接 */ @GetMapping("/create") public Result createPayOrder( @RequestParam Integer payType, @RequestParam BigDecimal amount, @RequestParam String subject) { String payUrl = payOrderService.createPayOrder(payType, amount, subject); return Result.success(payUrl); } }

(2)微信支付回调控制器(核心!

幂等性处理)

package com.pay.controller;

import cn.hutool.core.util.StrUtil; import com.pay.entity.PayOrder; import com.pay.service.PayOrderService; import com.wechat.pay.contrib.apache.httpclient.util.AesUtil; import com.wechat.pay.contrib.apache.httpclient.util.JsonUtil; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.TimeUnit;

/** * 微信支付回调控制器(企业级幂等性处理) */ @RestController public class WeChatPayNotifyController { @Value("${pay.wechat.api_v3_key}") private String apiV3Key; @Resource private PayOrderService payOrderService; @Resource private RedisTemplate redisTemplate;

// 回调成功返回(微信要求必须返回这个JSON) private static final String SUCCESS_RESPONSE = "{\"code\":\"SUCCESS\",\"message\":\"成功\"}"; private static final String FAIL_RESPONSE = "{\"code\":\"FAIL\",\"message\":\"失败\"}";

@PostMapping("/wechat/notify") public String weChatNotify( @RequestHeader("Wechatpay-Serial") String serial, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestBody String body) { try { // 1. 解密回调数据(微信v3回调数据是加密的) AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8)); Map notifyMap = JsonUtil.decodeJson(body, Map.class); String ciphertext = (String) notifyMap.get("resource"); Map resourceMap = JsonUtil.decodeJson(ciphertext, Map.class); String plainText = aesUtil.decryptToString( (String) resourceMap.get("associated_data"), (String) resourceMap.get("nonce"), (String) resourceMap.get("ciphertext")); Map resultMap = JsonUtil.decodeJson(plainText, Map.class);

// 2. 提取关键参数 String outTradeNo = (String) resultMap.get("out_trade_no"); // 本地订单号 String transactionId = (String) resultMap.get("transaction_id"); // 微信订单号 String notifyId = serial + "_" + nonce; // 回调唯一标识(幂等性)

// 3. 幂等性处理:Redis分布式锁+唯一标识 String lockKey = "pay:notify:wechat:" + outTradeNo; Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, notifyId, 5, TimeUnit.MINUTES); if (!lock) { return SUCCESS_RESPONSE; // 重复回调,直接返回成功 }

// 4. 更新订单状态 PayOrder payOrder = payOrderService.getOne(com.baomidou.mybatisplus.core.conditions.query.QueryWrapper.lambda() .eq(PayOrder::getOrderNo, outTradeNo)); if (payOrder == null) { return FAIL_RESPONSE; } if (payOrder.getStatus() == 1) { return SUCCESS_RESPONSE; // 已支付,无需处理 } // 更新为支付成功 payOrder.setStatus(1); payOrder.setOutTradeNo(transactionId); payOrder.setPayTime(new java.util.Date()); payOrder.setNotifyTime(new java.util.Date()); payOrder.setNotifyId(notifyId); payOrderService.updateById(payOrder);

return SUCCESS_RESPONSE; } catch (Exception e) { e.printStackTrace(); return FAIL_RESPONSE; } } }

四、 实战踩坑复盘(企业级避坑指南) 坑1:微信支付v3签名失败 原因:商户私钥格式错误、商户证书序列号填错、api_v3_key长度不足32位; 解决:私钥用PEM格式,api_v3_key必须是32位字符串,证书序列号在微信支付商户平台查看。

坑2:支付宝回调验签失败 原因:应用私钥/支付宝公钥不匹配、回调参数被修改、编码不是UTF-8; 解决:重新生成RSA2密钥对,确保回调接口返回的参数未被篡改,统一用UTF-8编码。

坑3:回调重复通知导致订单重复更新 原因:支付平台会多次发送回调(网络问题); 解决:用“订单号+回调唯一标识”做幂等性,Redis锁+数据库唯一索引双重保障。

坑4:微信支付金额单位错误 原因:微信支付金额单位是“分”,直接传了“元”(比如1元传1,实际要传100); 解决:下单时将金额×100转换为分,回调时÷100转换回元。

五、 部署上线(企业级注意事项) 域名备案 :支付回调地址必须是备案的外网域名,不能用IP; HTTPS配置 :微信/支付宝回调要求接口是HTTPS,需配置SSL证书; 日志记录 :所有支付流程必须记录详细日志(下单、支付、回调、退款),便于对账和排查问题; 资金对账 :每日定时拉取微信/支付宝账单,对比本地订单,确保资金一致; 异常监控 :对接告警工具(钉钉/邮件),支付失败、回调失败时及时通知。

总结 关键点回顾 核心收获 :从0到1搭建了企业级支付系统,整合微信v3、支付宝两大支付渠道,掌握支付系统的核心流程(下单→支付→回调→更新订单); 实战重点 :学会了签名验签、幂等性处理、回调解密等支付开发核心技术,代码可直接落地到企业项目; 避坑要点 :解决了签名失败、重复回调、金额单位错误等支付开发高频问题。

这套支付系统的核心是“企业级落地”——没有花里胡哨的技术,聚焦支付的核心业务逻辑,每一步都符合行业规范,新手跟着做,既能掌握支付开发的核心技能,又能做出一套可上线的支付系统,这也是企业Java开发的核心竞争力之一。

相关文章