【支付宝支付】支付宝手机网站支付流程
程序员文章站
2024-03-22 22:52:52
...
官方文档
支付宝手机网站支付没有微信支付那么琐碎(这里真的是想吐槽一下wxpay,配置太多了,文档阅读性也不友好!!),支付宝官方文档已经写得挺详细了,所以本文不对参数做详细的解释
开放能力文档:
https://opendocs.alipay.com/open/203/107084
手机网站支付api
https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay
开发准备工作
- 创建应用
开发者使用支付宝账号登录开放平台(需实名认证的支付宝账号),根据实际需求创建应用(如“支付应用”)。
备注:创建应用时的应用状态为“开发中”,无法在线上正式调用接口。
- 填写应用基础信息
- 添加应用功能
- 配置应用环境
- 应用申请上线,等待审核
代码实现
引入依赖
<!-- 支付宝支,基础jdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.5.ALL</version>
</dependency>
参数配置
application.yml
# 支付宝相关
ALIPAY:
# 应用ID
APP_ID:
# 应用私钥
APP_PRIVATE_KEY:
#应用公钥
APP_PUBLIC_KEY:
# 支付宝公钥
ALIPAY_PUBLIC_KEY:
# 统一签名算法
SIGN_TYPE: RSA2
# 统一字符
CHARSET: utf-8
# 返回数据格式
FORMAT: json
# 支付基础API
SERVER_URL: https://openapi.alipay.com/gateway.do
#支付宝支付回调地址
ALIPAY_NOTIFY_URL:
# 支付宝H5收银台会自动跳转回商户return_url指定的页面。
RETURN_URL:
# 支付宝Api版本
API_VERSION: 1.0
# 产品码
PROD_CODE:
# 终端信息
TERMINAL_INFO:
# 终端信息类型
TERMINAL_TYPE:
YmlParament
//支付宝相关
@Value("${ALIPAY.APP_ID}")
private String appId;
@Value("${ALIPAY.APP_PRIVATE_KEY}")
private String appPrivatekey;
@Value("${ALIPAY.APP_PUBLIC_KEY}")
private String appPublickey;
@Value("${ALIPAY.ALIPAY_PUBLIC_KEY}")
private String alipayPublickey;
@Value("${ALIPAY.SIGN_TYPE}")
private String signType;
@Value("${ALIPAY.CHARSET}")
private String charset;
@Value("${ALIPAY.FORMAT}")
private String format;
@Value("${ALIPAY.SERVER_URL}")
private String serverUrl;
@Value("${ALIPAY.ALIPAY_NOTIFY_URL}")
private String alipayNotifyUrl;
@Value("${ALIPAY.RETURN_URL}")
private String returnUrl;
@Value("${ALIPAY.API_VERSION}")
private String apiVersion;
@Value("${ALIPAY.PROD_CODE}")
private String prodCode;
@Value("${ALIPAY.TERMINAL_INFO}")
private String terminalInfo;
@Value("${ALIPAY.TERMINAL_TYPE}")
private String terminalType;
初始化支付宝支付配置
AlipayConfig
@Autowired
private YmlParament ymlParament;
/**
* 设置支付宝客户端
* @return
*/
@Bean
public AlipayClient setAlipayClient() {
return new DefaultAlipayClient(
ymlParament.getServerUrl(),
ymlParament.getAppId(),
ymlParament.getAppPrivatekey(),
ymlParament.getFormat(),
ymlParament.getCharset(),
//这里不要搞错,这里是应用公钥而不是支付宝公钥
ymlParament.getAppPublickey(),
ymlParament.getSignType()
);
}
/**
* 设置网页支付请求基础参数
* @return
*/
@Bean
public AlipayTradeWapPayRequest setAlipayTradeWapPayRequest() {
AlipayTradeWapPayRequest atwpr = new AlipayTradeWapPayRequest();
atwpr.setApiVersion(ymlParament.getApiVersion());
atwpr.setProdCode(ymlParament.getProdCode());// 产品码
atwpr.setTerminalInfo(ymlParament.getTerminalInfo());// 终端信息
atwpr.setTerminalType(ymlParament.getTerminalType());// 终端信息类型
return atwpr;
}
手机网站支付
ZfbPay
/**
* 手机网站支付
*
* @param ac 支付宝客户端,传入 @Autowired AlipayClient
* @param rquest 基础参数,传入 @Autowired AlipayTradeWapPayRequest
* @param returnUrl 付款成功后跳转的页面
* @param notifyUrl 付款成功后通知的页面或方法
* @param mode 实际参数,参考:https://opendocs.alipay.com/open/203/107090
*/
public static AlipayTradeWapPayResponse wapPay(AlipayClient ac, AlipayTradeWapPayRequest rquest, String returnUrl,
String notifyUrl, AlipayTradeWapPayModel mode) throws AlipayApiException {
rquest.setBizModel(mode);
rquest.setReturnUrl(returnUrl);
rquest.setNotifyUrl(notifyUrl);
return ac.pageExecute(rquest);
}
/**
* 手机网站支付,处理业务参数
*/
public static AlipayTradeWapPayResponse wapPay(AlipayClient ac, AlipayTradeWapPayRequest rquest, String returnUrl,
String notifyUrl, String orderNo,String subject,String orderAmount) throws AlipayApiException {
AlipayTradeWapPayModel mode = new AlipayTradeWapPayModel();
mode.setOutTradeNo(orderNo);
mode.setSubject(subject);
mode.setTotalAmount(orderAmount);
return wapPay(ac, rquest, returnUrl, notifyUrl, mode);
}
/**
* 支付宝支付回调验证签名
* 验证签名;参考:https://opendocs.alipay.com/open/203/105286
* @param params 参数
* @param alipayPublickey 传入支付宝公钥
* @return true 正确 false 失败
* @throws AlipayApiException
*/
public static boolean rsaCheckV1(Map<String, String> params, String alipayPublickey) throws AlipayApiException {
return AlipaySignature.rsaCheckV1(params, alipayPublickey, "utf-8", "RSA2");
}
服务层(业务逻辑略)
@Autowired
private AlipayClient alipayClient;
@Autowired
private AlipayTradeWapPayRequest alipayTradeWapPayRequest;
@Transactional
@Override
public String insertAlipayH5PayInfo(String sendOrderNo,String subject, String orderAmount){
try {
AlipayTradeWapPayResponse alipayTradeWapPayResponse = ZfbPay.wapPay(alipayClient, alipayTradeWapPayRequest, ymlParament.getReturnUrl(),
ymlParament.getAlipayNotifyUrl(), sendOrderNo, subject, orderAmount);
/* 获取页面成功 */
if (!alipayTradeWapPayResponse.isSuccess()) {
throw new RuntimeException(alipayTradeWapPayResponse.getMsg());
}
return alipayTradeWapPayResponse.getBody();
} catch (Exception e) {
e.printStackTrace();
}
}
controller(略)
到这里支付宝支付就成功了,是不是相当微信支付简单多了_,接下来支付宝支付成功就会回调页面和服务端啦
支付宝回调通知
官方文档:https://opendocs.alipay.com/open/203/105286
@ApiOperation("支付宝回调")
@PostMapping("callback")
public String callback(HttpServletRequest request) throws Exception {
Object object = new Object();
Map<String, String> params = convertRequestParamsToMap(request);
log.info("支付宝回调:已回调,参数为====" + params);
try {
checkCallbackAlipay(params);
/*处理一些业务*/
} catch (Exception e) {
e.printStackTrace();
}
return ZfbUtils.RETURN_SUCCESS;
}
}
/**
* 校验签名
*验签文档:https://opendocs.alipay.com/open/203/105286
*/
private void checkCallbackAlipay(Map<String, String> params) throws Exception {
if (!"TRADE_SUCCESS".equals(params.get("trade_status"))) {
throw new Exception("支付宝支付失败!");
}
//校验签名
if (!ZfbPay.rsaCheckV1(params, ymlParament.getAlipayPublickey())) {
throw new Exception("支付宝回调签名认证失败");
}
//校验一些业务逻辑
//订单是否支付重复
//判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)
//.....
// 校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
// 验证app_id是否为该商户本身。
if (!params.get("app_id").equals(ymlParament.getAppId())) {
throw new Exception("APPID不对!");
}
}
/**
* 获取支付宝回调参数
*/
private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
Map<String, String> retMap = new HashMap<String, String>();
Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
for (Map.Entry<String, String[]> entry : entrySet) {
String name = entry.getKey();
String[] values = entry.getValue();
int valLen = values.length;
if (valLen == 1) {
retMap.put(name, values[0]);
} else if (valLen > 1) {
StringBuilder sb = new StringBuilder();
for (String val : values) {
sb.append(",").append(val);
}
retMap.put(name, sb.toString().substring(1));
} else {
retMap.put(name, "");
}
}
return retMap;
}
交易查询
若不想在支付回调时候去做签名校验,那我们可以主动去查询这笔订单是否支付成功
/*查询订单是否支付成功*/
AlipayTradeQueryResponse response = orderQuery(ac, params.get("out_trade_no"));
if (!"TRADE_SUCCESS".equals(response.getTradeStatus())){
throw new Exception("<==支付宝支付失败==>订单号为【"+ params.get("out_trade_no")+ "】的订单");
}
/**
* 交易查询接口,处理业务参数 https://opendocs.alipay.com/apis/api_1/alipay.trade.query#%E5%93%8D%E5%BA%94%E5%8F%82%E6%95%B0
* @param outTradeNo 订单号
* @return
* @throws AlipayApiException
*/
public static AlipayTradeQueryResponse orderQuery(AlipayClient ac , String outTradeNo) throws Exception {
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(outTradeNo);
AlipayTradeQueryResponse response = tradeQuery(ac,model);
if(!response.isSuccess()){
throw new Exception("调用支付宝查询接口失败");
}
return response;
}
/*交易查询接口*/
public static AlipayTradeQueryResponse tradeQuery(AlipayClient ac,AlipayTradeQueryModel model) throws AlipayApiException{
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizModel(model);
return ac.execute(request);
}
推荐阅读
-
【支付宝支付】支付宝手机网站支付流程
-
支付开发(七)----支付宝开发之手机网站支付(H5支付)
-
记阿里电话面试的一个遗留问题:淘宝订单如何保证与支付宝订单的同步“? 博客分类: 原创 阿里面试异步系统同步kafka
-
记阿里电话面试的一个遗留问题:淘宝订单如何保证与支付宝订单的同步“? 博客分类: 原创 阿里面试异步系统同步kafka
-
支付宝&&银联官网 博客分类: pay pay
-
支付宝&&银联官网 博客分类: pay pay
-
多多客发布 3.0.0-alpha.3开源版,支持微信、百度、支付宝小程序 博客分类: 小程序 小程序微信小程序支付宝小程序百度小程序
-
多多客发布 3.0.0-alpha.3开源版,支持微信、百度、支付宝小程序 博客分类: 小程序 小程序微信小程序支付宝小程序百度小程序
-
【全开源】可视化DIY微信/百度/支付宝小程序saas平台源码 小程序微信小程序支付宝小程序百度小程序
-
百度小程序代码提交五部曲 小程序微信小程序百度小程序支付宝小程序