支付宝订单支付动态二维码如何生成
支付小周
结论
不能从支付 URL 中直接”提取”支付宝动态二维码。二维码只是 URL 或支付凭证的图形编码,URL 本身通常不包含二维码图片。
如果要为每笔线上订单生成可供支付宝扫码支付的动态二维码,应调用支付宝当面付的预创建接口 alipay.trade.precreate。接口调用成功后会返回 qr_code。商户将这个字符串编码成二维码图片并展示,用户扫码后即可进入该订单的支付宝支付流程,不需要先跳转到商户网页。
推荐实现流程
- 商户系统创建订单,并生成唯一的
out_trade_no。 - 调用
alipay.trade.precreate创建支付宝预支付订单。 - 读取接口响应中的
qr_code。 - 使用二维码组件将
qr_code编码成二维码图片。 - 由前端定时查询订单状态,或者等待支付宝发送异步通知。
- 确认交易状态为
TRADE_SUCCESS后,再更新业务订单。
qr_code 是二维码中需要编码的原始内容,不一定是普通网页 URL。请按原值生成二维码,不要修改、解析或拼接其中的参数。
Java 调用示例
下面的示例使用支付宝 Java SDK。不同版本 SDK 的客户端构造方式可能不同,请以当前接入版本的官方文档为准。
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
public class AlipayQrCodeService {
private static final String GATEWAY_URL =
"https://openapi.alipay.com/gateway.do";
public static String createQrCode(
String appId,
String merchantPrivateKey,
String alipayPublicKey,
String outTradeNo,
String subject,
String totalAmount) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
GATEWAY_URL,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradePrecreateRequest request =
new AlipayTradePrecreateRequest();
AlipayTradePrecreateModel model =
new AlipayTradePrecreateModel();
model.setOutTradeNo(outTradeNo);
model.setSubject(subject);
model.setTotalAmount(totalAmount);
model.setTimeoutExpress("15m");
request.setBizModel(model);
// 支付宝异步通知地址,必须是公网可访问的 HTTPS 地址
request.setNotifyUrl(
"https://example.com/api/alipay/notify"
);
AlipayTradePrecreateResponse response =
alipayClient.execute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建支付宝二维码失败,code="
+ response.getCode()
+ ", subCode="
+ response.getSubCode()
+ ", message="
+ response.getSubMsg()
);
}
return response.getQrCode();
}
}
支付宝返回的 qr_code 可以通过 ZXing 等二维码库生成图片:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
public class QrCodeWriter {
public static void write(
String content,
OutputStream outputStream) throws Exception {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix matrix = new MultiFormatWriter().encode(
content,
BarcodeFormat.QR_CODE,
320,
320,
hints
);
MatrixToImageWriter.writeToStream(
matrix,
"PNG",
outputStream
);
}
}
content 必须直接使用支付宝返回的 qr_code,不要对它进行 URL 解码、截取或参数重组。
查询支付结果
成功生成二维码不等于支付成功。可以调用 alipay.trade.query 查询交易状态:
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
public static String queryTrade(
AlipayClient alipayClient,
String outTradeNo) throws AlipayApiException {
AlipayTradeQueryRequest request =
new AlipayTradeQueryRequest();
AlipayTradeQueryModel model =
new AlipayTradeQueryModel();
model.setOutTradeNo(outTradeNo);
request.setBizModel(model);
AlipayTradeQueryResponse response =
alipayClient.execute(request);
if (!response.isSuccess()) {
return "QUERY_FAILED";
}
return response.getTradeStatus();
}
常见的交易状态有:
WAIT_BUYER_PAY:订单已创建,等待付款。TRADE_SUCCESS:付款成功。TRADE_CLOSED:交易关闭。TRADE_FINISHED:交易结束,不可退款。
业务系统不能根据”用户已扫码”或前端跳转结果认定付款成功。最终结果应以支付宝异步通知或服务端主动查询的结果为准。
与现有 URL 支付方式的区别
如果当前调用的是手机网站支付接口,例如 alipay.trade.wap.pay,返回内容主要用于唤起支付宝或打开收银台页面。把对应的 URL 再生成二维码,虽然可能可以扫码访问,但本质上是”扫码打开网页”,并非标准的当面付扫码模式。
应根据支付场景选择对应产品:
- PC 网站跳转支付:通常使用
alipay.trade.page.pay。 - 手机浏览器内支付:通常使用
alipay.trade.wap.pay。 - 展示订单二维码供支付宝扫码:通常使用
alipay.trade.precreate。
这些接口对应不同的支付宝产品能力和签约权限。应用能否直接调用 alipay.trade.precreate,取决于是否已开通并签约相应产品,以及是否具备所需权限。
注意事项
- 每个
out_trade_no都应保持唯一,不能在不同业务订单之间重复使用。 - 金额必须由服务端确定,不能直接信任前端传入的金额。
- 私钥只能保存在服务端,不能放入网页、App 或小程序前端。
- 收到异步通知后必须验签,同时核对
app_id、out_trade_no、金额、商户身份和交易状态。 - 支付宝可能重复发送异步通知,因此订单更新逻辑必须保证幂等。
- 二维码应设置合理的有效期。二维码过期后,应关闭旧订单或重新创建支付订单,不能只替换二维码图片。
- 不建议长期保存二维码图片。保存
qr_code和订单状态即可,需要展示时再即时生成。 - 沙箱环境和生产环境使用不同的网关、应用标识及密钥,不能混用。
- 支付接口名称、可用参数和签约条件可能发生调整。上线前请以支付宝开放平台当前文档及应用后台显示的权限为准。
备注:内容仅供参考。
