😊 @ 作者: 一恍过去 💖 @ 主页: /zhuocailing3390 🎊 @ 社区: Java技术栈交流 🎉 @ 主题: 支付宝直付通实现合单支付完整Demo ⏱️ @ 创作时间: 09月05日
目录
1、POM2、YAML3、支付配置类4、支付枚举类5、支付API封装6、合并支付预创建接口7、合并支付接口1、POM
<!--支付宝SDK --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.31.48.ALL</version></dependency><!-- 支付宝SDK依赖的日志--><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>
2、YAML
alipay:# appidappId: # 商户PID,卖家支付宝账号IDsellerId: # 私钥 pkcs8格式的,rsc中的私钥:/platform/appDaily.htm?tab=infoprivateKey: # 支付宝公钥:/platform/appDaily.htm?tab=infopublicKey: # 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问notifyUrl: /alipay/notify# 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问returnUrl: /alipay/return# 请求网关地址# 正式为:"/gateway.do"serverUrl: /gateway.do
3、支付配置类
package com.lhz.config;import com.alipay.api.AlipayClient;import com.alipay.api.AlipayConstants;import com.alipay.api.DefaultAlipayClient;import lombok.Data;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.ponent;/*** @Description:**/@Component@Data@ConfigurationProperties(prefix = "alipay")public class AlipayConfig {/*** 商户appid*/private String appId;/*** 商户PID,卖家支付宝账号ID*/private String sellerId;/*** 私钥 pkcs8格式的,rsc中的私钥*/private String privateKey;/*** 支付宝公钥*/private String publicKey;/*** 请求网关地址*/private String serverUrl;/*** 页面跳转同步通知(可以直接返回前端页面、或者通过后端进行跳转)*/private String returnUrl;/*** 服务器异步通知*/private String notifyUrl;/*** 获得初始化的AlipayClient** @return*/@Beanpublic AlipayClient alipayClient() {// 获得初始化的AlipayClientreturn new DefaultAlipayClient(serverUrl, appId, privateKey,AlipayConstants.FORMAT_JSON, AlipayConstants.CHARSET_UTF8,publicKey, AlipayConstants.SIGN_TYPE_RSA2);}}
4、支付枚举类
package com.lhz.enums;import lombok.AllArgsConstructor;import lombok.Data;import lombok.Getter;/*** @Description:**/@Getter@AllArgsConstructorpublic enum PayTypeEnum {/*** H5*/H5("h5","QUICK_WAP_WAY"),/*** App*/APP("app","QUICK_MSECURITY_PAY");String type;String code;public static String getCode(String type) {for (PayTypeEnum payType : PayTypeEnum.values()) {if (payType.getType().equals(type)) {return payType.getCode();}}return null;}}
5、支付API封装
import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.request.*;import com.alipay.api.response.*;/*** @Description:**/public class AliPayApi {public static String combineAppPay(AlipayClient alipayClient, String bizContent) throws AlipayApiException {// 相应请求API的requestAlipayTradeAppMergePayRequest alipayRequest = new AlipayTradeAppMergePayRequest();alipayRequest.setBizContent(bizContent);AlipayTradeAppMergePayResponse payResponse = alipayClient.pageExecute(alipayRequest);return readData(payResponse.isSuccess(), payResponse.getBody());}public static String combineH5Pay(AlipayClient alipayClient, String bizContent) throws AlipayApiException {// 相应请求API的requestAlipayTradeWapMergePayRequest alipayRequest = new AlipayTradeWapMergePayRequest();alipayRequest.setBizContent(bizContent);AlipayTradeWapMergePayResponse payResponse = alipayClient.pageExecute(alipayRequest);return readData(payResponse.isSuccess(), payResponse.getBody());}private static String readData(boolean isSuccess, String body) {if (isSuccess) {return body;} else {throw new RuntimeException(body);}}}
6、合并支付预创建接口
@Api(tags = "合单支付接口")@RestController@RequestMapping("/combine")@Slf4jpublic class CombinePayController {@Resourceprivate AlipayClient alipayClient;@Resourceprivate AlipayConfig alipayConfig;/*** 合单支付预创建接口* 用户在电商平台购买不同商家的商品,电商平台合并多笔交易,先请求支付宝做预创建,支付宝返回预下单pre_order_no,* 后续商户使用该pre_order_no进行无线支付。** @return*/@ApiOperation(value = "合单支付预创建接口", notes = "合单支付预创建接口")@ApiOperationSupport(order = 1)@GetMapping("/tradeMerge")@ResponseBodypublic String tradeMerge() throws Exception {AlipayTradeMergePrecreateRequest request = new AlipayTradeMergePrecreateRequest();JSONObject bizContent = new JSONObject();// 子订单详情JSONArray orderDetails = new JSONArray();// 设置子单列表数据,此处模拟添加多个订单for (int a = 1; a <= 2; a++) {double amount = 0.01;JSONObject orderDetail = new JSONObject();orderDetail.put("app_id", alipayConfig.getAppId());long outTradeNo = System.currentTimeMillis();log.info("支付订单,订单号:" + outTradeNo);orderDetail.put("out_trade_no", outTradeNo + "");orderDetail.put("subject", "测试商品" + a);orderDetail.put("total_amount", amount);orderDetail.put("product_code", "QUICK_MSECURITY_PAY");// 商品明细信息,按需传入JSONArray goodsDetail = new JSONArray();// 可以多个商品信息JSONObject goods = new JSONObject();goods.put("goods_id", "goodsNo1");goods.put("goods_name", "子商品1");// 商品数量goods.put("quantity", 1);goods.put("price", 0.01);goods.put("body", "商品描述信息");goodsDetail.add(goods);orderDetail.put("goods_detail", goodsDetail);// 二级商户信息,按需传入JSONObject subMerchant = new JSONObject();// 支付宝二级商户编号subMerchant.put("merchant_id", "2088000603999128");orderDetail.put("sub_merchant", subMerchant);// 结算信息,按需传入JSONObject settleInfo = new JSONObject();JSONArray settleDetailInfos = new JSONArray();JSONObject settleDetail = new JSONObject();/*** 结算收款方的账户类型。** cardAliasNo:结算收款方的银行卡编号;* userId:表示是支付宝账号对应的支付宝唯一用户号;* loginName:表示是支付宝登录号;* defaultSettle:表示结算到商户进件时设置的默认结算账号,结算主体为门店时不支持传defaultSettle;*/settleDetail.put("trans_in_type", "defaultSettle");/*** 结算收款方。当结算收款方类型是cardAliasNo时,本参数为用户在支付宝绑定的卡编号;* 结算收款方类型是userId时,本参数为用户的支付宝账号对应的支付宝唯一用户号,以2088开头的纯16位数字;* 当结算收款方类型是loginName时,本参数为用户的支付宝登录号;* 当结算收款方类型是defaultSettle时,本参数不能传值,保持为空。*/// settleDetail.put("trans_in", "xxx");settleDetail.put("amount", amount);settleDetailInfos.add(settleDetail);settleInfo.put("settle_detail_infos", settleDetailInfos);orderDetail.put("settle_info", settleInfo);orderDetails.add(orderDetail);}bizContent.put("order_details", orderDetails);request.setBizContent(bizContent.toString());AlipayTradeMergePrecreateResponse response = alipayClient.execute(request);// 根据response中的结果继续业务逻辑处理if (response.isSuccess()) {String preOrderNo = response.getPreOrderNo();log.info("预支付订单号:" + preOrderNo);return preOrderNo;} else {log.error("调用支付宝失败");log.error(response.getSubCode());log.error(response.getSubMsg());return response.getSubMsg();}}}
7、合并支付接口
@Api(tags = "合单支付接口")@RestController@RequestMapping("/combine")@Slf4jpublic class CombinePayController {@Resourceprivate AlipayClient alipayClient;@Resourceprivate AlipayConfig alipayConfig;/*** @param type 支付类型:app、h5* @param preOrderNo 预支付订单号* @return*/@ApiOperation(value = "合并支付接口", notes = "合并支付接口")@ApiOperationSupport(order = 1)@GetMapping("/pay/{type}")@ResponseBodypublic Map<String, String> pay(@PathVariable("type") String type, String preOrderNo) {String payCode = PayTypeEnum.getCode(type);String body = null;log.info("预支付订单号:" + preOrderNo);JSONObject bizContent = new JSONObject();bizContent.put("pre_order_no", preOrderNo);if (payCode.equals(PayTypeEnum.H5.getCode())) {body = requestPay(PayTypeEnum.H5.getCode(), bizContent.toString());}if (payCode.equals(PayTypeEnum.APP.getCode())) {body = requestPay(PayTypeEnum.APP.getCode(), bizContent.toString());}log.info("支付表单:{}", body);Map<String, String> map = new HashMap<>();map.put("body", body);return map;}private String requestPay(String payType, String bizContent) {try {String body = null;if (PayTypeEnum.H5.getCode().equals(payType)) {body = bineH5Pay(alipayClient, bizContent);}if (PayTypeEnum.APP.getCode().equals(payType)) {body = bineAppPay(alipayClient, bizContent);}return body;} catch (Exception e) {log.error(e.getMessage());throw new RuntimeException("创建支付交易失败");}}}