胖头猫游戏提供热门游戏下载和手游攻略!

SpringBoot 集成支付宝当面付 指南

发布时间:2024-10-23浏览:23

一:简介

当面付条码支付(商家使用扫码设备扫描买家支付宝的付款码):条码支付是支付宝给到线下传统行业的一种收款方式。商户使用扫码枪等条码识别设备扫描用户支付宝钱包上的条码/二维码,完成收款。一般在超市、便利店、店铺等使用。扫码支付(买家使用支付宝扫一扫扫描卖家的二维码):指用户打开支付宝钱包中的“扫一扫”功能,扫描商户针对每个订单实时生成的订单二维码,并在手机端确认支付。一般在类似于无人售货机上使用,像地铁中的无人售货饮料机、医院中的自助挂号收费机等声波支付

在接入之前首先要熟悉一下当面付产品的业务文档:

当面付文档

沙箱当面付接入引导

快速接入

当面付SDK&Demo 拿到demo我们熟悉一下demo,就可以依葫芦画瓢了,集成到自己工程中来。

通过下载Demo可以看到有两个工程,一个是TradePayDemo,一个是TradePaySDK,集成SDK必须要使用alipay-sdk-java20161213173952.jar,而TradePaySDK是对alipay-sdk-java.jar的进一步封装,在TradePayDemo中可以看到已经对TradePaySDK打成了jar包依赖进来了,当然也可以将整个TradePaySDK的src目录拖入到自己工程中, 当然也可以不使用alipay-trade-sdk.jar直接使用alipay-sdk-java.jar来开发。

条码付参考trade_pay.jsp

扫码付参考trade_precreate.jsp

退款参考trade_refund.jsp

交易查询参考trade_query.jsp

条码支付流程图:

扫码支付流程图:

二:集成步骤

0. 创建应用、配置密钥

集成前需要先创建应用、配置密钥、回调地址等,具体操作请查看Spring Boot入门教程(三十五):支付宝集成-准备工作

1. 将Demo中的alipay-sdk-java和alipay-trade-sdk两个jar安装到本地maven仓库中

注意:将jar打到本地maven仓库时命令行最好是一行,不好有回车换行, 这里使用2017版本的,不是2016版本的,Demo中的还是2016的版本。

mvn install:install-file -DgroupId=com.alipay -DartifactId=alipay-sdk-java -Dversion= 20170725114550 -Dpackaging=jar -Dfile=alipay-sdk-java-20170725114550.jarmvn install:install-file -DgroupId=com.alipay -DartifactId=alipay-trade-sdk -Dversion=20161215 -Dpackaging=jar -Dfile=alipay-trade-sdk-20161215.jar

2. 引入依赖

<!-- alipay begin --><dependency> <groupId>com.alipay</groupId> <artifactId>alipay-sdk-java</artifactId> <version>20170725114550</version></dependency><dependency> <groupId>com.alipay</groupId> <artifactId>alipay-trade-sdk</artifactId> <version>20161215</version></dependency><dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId></dependency><dependency> <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> <version>1.10</version></dependency><dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.2.1</version></dependency><!-- alipay end --><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId></dependency>

3. 配置application.yml

注意:配置appPrivateKey和alipayPublicKey时值不要换行,returnUrl在当面付中不是必须的 注意:这里的returnUrl和notifyUrl在测试的时候需要外网能访问,可以通过natapp来实现

# 沙箱配置pay: alipay: gatewayUrl: https://openapi.alipaydev.com/gateway.do appid: 2016091400508498 appPrivateKey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtXKWs+trRSuCxEUvlsEeSAuLWs3B/Dh74R8223BnfzoA29aGeoycAqfKlBMcbzU2G1KayESvZKGpwBLeejSbecRYjgZsQDyEaDimQQJtGFvZVV6u4XNnvIJ72eQzEaEIQfuiorjBTLm6DQuds4R0GxftqON6QFoIZkWB9ZrZKd02cuy16dW+UqtLVGGAHcCIAkB63zUiKSNfweMddneZ7MVs3lvu3xhMnD+5us/+n2Vp4qhfmpYLcdqIW6InU4GypeoOpyUTrfUGpgdR0l924vHy/GQJZEKFaRcK3cYK+ECyKpSIoqaJJFLHbkqsliuPpMUG+rM3jiqeIAH4psAznAgMBAAECggEBAJ5jyEbbxrJzrAh7GhHX1fwUQPYSadTbrPYAfHX2cHlnrQMJtsk+nTLhEv0r+VJwZ8WpYkfMong8kcqYtL7ajcmsHqMAFhE9EWxBxj2ymWsXLabZe93sj30IG9Rq0nxcGQgDO0RqKWLGSFgK93Al2KRInKT3InkY53K+vR61ihVLmGf7+GwPtIZteBy+tuAyvcj2RlkYvjiFi3ySyZ1wA3sJIlgrGiixd6fj20XFGNE3CnAwu0BJgXXbP/S9J4C0RRa3ZXj8fX7oONhVxz2xKxn7AT4e8OWjt7J41H2LRct8Fgl9pqgz2FJYv/WfbkG8x9fGiKYYvPXoxjjrk/tkewkCgYEA8f9Lcu5JPrE9rpw9zlwhm5cOO81xLxdwL5R5/1bRP48BZGIYuqlCbVvjJVqtO8eTnLhUwH7fG8B7cmoeO9bGr9GQrtfyCqz6FtVymTBieJlfgZDVhtzyv2qKOBMIFE8jsbSBK/NHHMvykJ+XdQ1riwCeQDdXICRuYTTFwGk2OsUCgYEAt2SoN95tVmVrvKG6ATLNEtge/ozeVywA4GjltrSw/G9vqp+DkkT2pY19uROuzMazoTzKWpPho2q/qzNlv/ANbOFM2GEmKamQ7CO88JgRxMsPTvc/HxCLU/ClMJU8LcOf9LfP2KYZpPwuheKJoF4vDGj8NsbFmccJyYSdpkNEk7sCgYBJlL2FMaz1sgC2Ue19DIhvfaunRV1P20mSPgwmNmijccETm7w3LXX0OIdFeV/JGHLqqSWj7i+6iXk/ncKZoUGCfi8G6sQ+uL/GJ5qTt6GJV+ExTS+PtSjeSO/EAw1m13Vb+C16hpstx1l23f+4aJ81gbecgPct38XsKpaiXZtOnQKBgQCMsN7QRYYxwoq9YoDUzIlAzKYyeBVWYL6najHYUZR5hG/xQIBqZRem9/4cTvpJxKInrwA6LrrqaEl0aHDFp75U6h7O3PCvA5PXZK9dD/yJsZIj7U/yX/nTQokn1UUegrYiwiTkusBvrrtuINWePsLvTVc4GpObHnPmsiNTWsWwYwKBgENaeTNOCHV2km/ysXQSEIhKbtlAMQPsgWHCt/bzHlF9m18izb1LrJyjzcSsd+Zy78R+pv4G50Q27c3e/DFPz/wYxN/yHWRbyLBA8ipJbCtMtPEdS9krpmN6cChIdLGbz4CVUqOPSRzNb9lhhgPCcCNRq6DG3HBceb1Se9VnO3zk alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApFQKccMq+wPoWh93DcX3XYrnT7FJ3gntJA/jEwgk6Jd3iEVS2CyUCCgFVcQn8xjXT81YbZHYvoC50IBuu+A+Ey+J8VIgsBm5g9uwbOLRf66GrZjuKOlalHm5gHXjcL2gZRMBJEStOxstcO2YQriqhQzdL3EKp+HQc9u14IOVFpZdR8qq1l7CzKHn1vQo/1fUPfUrTLQqSuQTU9Ospv/QHFqOJA7DPetUQ+jnaZ082f3clr4ITw4EE8A6IWqTXcETTx5j/udCGP84g2Y4j+8i9DqYGyD5ePVgt4G0ICBX1bi1qNlylfxRg8Y3c1DFrRGyr0NpKQxSVXkYaVNvrCoudQIDAQAB returnUrl: http://fuzsmc.natappfree.cc/alipay/return notifyUrl: http://fuzsmc.natappfree.cc/alipay/notify

4. AliPayProperties

import lombok.Data;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.springframework.boot.context.properties.ConfigurationProperties;import javax.annotation.PostConstruct;/** * @author mengday zhang */@Data@Slf4j@ConfigurationProperties(prefix = "pay.alipay")public class AlipayProperties { /** 支付宝gatewayUrl */ private String gatewayUrl; /** 商户应用id */ private String appid; /** RSA私钥,用于对商户请求报文加签 */ private String appPrivateKey; /** 支付宝RSA公钥,用于验签支付宝应答 */ private String alipayPublicKey; /** 签名类型 */ private String signType = "RSA2"; /** 格式 */ private String formate = "json"; /** 编码 */ private String charset = "UTF-8"; /** 同步地址 */ private String returnUrl; /** 异步地址 */ private String notifyUrl; /** 最大查询次数 */ private static int maxQueryRetry = 5; /** 查询间隔(毫秒) */ private static long queryDuration = 5000; /** 最大撤销次数 */ private static int maxCancelRetry = 3; /** 撤销间隔(毫秒) */ private static long cancelDuration = 3000; private AlipayProperties() {} /** * PostContruct是spring框架的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。 */ @PostConstruct public void init() { log.info(description()); } public String description() { StringBuilder sb = new StringBuilder("\nConfigs{"); sb.append("支付宝网关: ").append(gatewayUrl).append("\n"); sb.append(", appid: ").append(appid).append("\n"); sb.append(", 商户RSA私钥: ").append(getKeyDescription(appPrivateKey)).append("\n"); sb.append(", 支付宝RSA公钥: ").append(getKeyDescription(alipayPublicKey)).append("\n"); sb.append(", 签名类型: ").append(signType).append("\n"); sb.append(", 查询重试次数: ").append(maxQueryRetry).append("\n"); sb.append(", 查询间隔(毫秒): ").append(queryDuration).append("\n"); sb.append(", 撤销尝试次数: ").append(maxCancelRetry).append("\n"); sb.append(", 撤销重试间隔(毫秒): ").append(cancelDuration).append("\n"); sb.append("}"); return sb.toString(); } private String getKeyDescription(String key) { int showLength = 6; if (StringUtils.isNotEmpty(key) && key.length() > showLength) { return new StringBuilder(key.substring(0, showLength)).append("******") .append(key.substring(key.length() - showLength)).toString(); } return null; }}

5. AliPayConfiguration

@Configuration@EnableConfigurationProperties(AlipayProperties.class)public class AlipayConfiguration { private AlipayProperties properties; public AlipayConfiguration(AlipayProperties properties) { this.properties = properties; } @Bean public AlipayTradeService alipayTradeService() { return new AlipayTradeServiceImpl.ClientBuilder() .setGatewayUrl(properties.getGatewayUrl()) .setAppid(properties.getAppid()) .setPrivateKey(properties.getAppPrivateKey()) .setAlipayPublicKey(properties.getAlipayPublicKey()) .setSignType(properties.getSignType()) .build(); }}

6. PayUtil

public class PayUtil { /** * 根据url生成二位图片对象 * * @param codeUrl * @return * @throws WriterException */ public static BufferedImage getQRCodeImge(String codeUrl) throws WriterException { Map<EncodeHintType, Object> hints = new Hashtable(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); hints.put(EncodeHintType.CHARACTER_SET, "UTF8"); int width = 256; BitMatrix bitMatrix = (new MultiFormatWriter()).encode(codeUrl, BarcodeFormat.QR_CODE, width, width, hints); BufferedImage image = new BufferedImage(width, width, 1); for(int x = 0; x < width; ++x) { for(int y = 0; y < width; ++y) { image.setRGB(x, y, bitMatrix.get(x, y) ? -16777216 : -1); } } return image; }}

7. AlipayF2FController

package com.example.paydemo.controller;import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import com.alipay.api.internal.util.AlipaySignature;import com.alipay.api.request.AlipayTradePagePayRequest;import com.alipay.api.response.AlipayTradePrecreateResponse;import com.alipay.api.response.AlipayTradeQueryResponse;import com.alipay.demo.trade.model.GoodsDetail;import com.alipay.demo.trade.model.builder.AlipayTradePayRequestBuilder;import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;import com.alipay.demo.trade.model.result.AlipayF2FPayResult;import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;import com.alipay.demo.trade.service.AlipayTradeService;import com.alipay.demo.trade.utils.ZxingUtils;import com.example.paydemo.configuration.AlipayProperties;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.MediaType;import org.springframework.util.ResourceUtils;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.util.*;/** * 支付宝-当面付 控制器. * <p> * https://openclub.alipay.com/read.php?tid=1720&fid=40 * * https://docs.open.alipay.com/203/105910 * * @author Mengday Zhang * @version 1.0 * @since 2018/6/4 */@Slf4j@RestController@RequestMapping("/alipay")public class AlipayF2FController { @Autowired private AlipayTradeService alipayTradeService; @Autowired private AlipayProperties aliPayProperties; /** * 当面付-条码付 * * 商家使用扫码工具(扫码枪等)扫描用户支付宝的付款码 * * @param authCode */ @PostMapping("/f2fpay/barCodePay") public String barCodePay(String authCode){ // 实际使用时需要根据商品id查询商品的基本信息并计算价格(可能还有什么优惠),这里只是写死值来测试 // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, String outTradeNo = UUID.randomUUID().toString(); // (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费” String subject = "测试订单"; // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元" String body = "购买商品2件共20.05元"; // (必填) 订单总金额,单位为元,不能超过1亿元 // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 String totalAmount = "0.01"; // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 String undiscountableAmount = ""; // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 String storeId = "test_store_id"; // 商户操作员编号,添加此参数可以为商户操作员做销售统计 String operatorId = "test_operator_id"; // 商品明细列表,需填写购买商品详细信息, List<GoodsDetail> goodsDetailList = new ArrayList<>(); GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "全麦小面包", 1, 1); goodsDetailList.add(goods1); GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "黑人牙刷", 1, 2); goodsDetailList.add(goods2); // 支付超时,线下扫码交易定义为5分钟 String timeoutExpress = "5m"; AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder() .setOutTradeNo(outTradeNo) .setSubject(subject) .setBody(body) .setTotalAmount(totalAmount) .setAuthCode(authCode) .setTotalAmount(totalAmount) .setStoreId(storeId) .setOperatorId(operatorId) .setGoodsDetailList(goodsDetailList) .setTimeoutExpress(timeoutExpress); // 当面付,面对面付,face to face pay -> face 2 face pay -> f2f pay // 同步返回支付结果 AlipayF2FPayResult f2FPayResult = alipayTradeService.tradePay(builder); // 注意:一定要处理支付的结果,因为不是每次支付都一定会成功,可能会失败 switch (f2FPayResult.getTradeStatus()) { case SUCCESS: log.info("支付宝支付成功: )"); break; case FAILED: log.error("支付宝支付失败!!!"); break; case UNKNOWN: log.error("系统异常,订单状态未知!!!"); break; default: log.error("不支持的交易状态,交易返回异常!!!"); break; } /** * { * "alipay_trade_pay_response": { * "code": "10000", * "msg": "Success", * "buyer_logon_id": "ekf***@sandbox.com", * "buyer_pay_amount": "0.01", * "buyer_user_id": "2088102176027680", * "buyer_user_type": "PRIVATE", * "fund_bill_list": [ * { * "amount": "0.01", * "fund_channel": "ALIPAYACCOUNT" * } * ], * "gmt_payment": "2018-06-10 14:54:16", * "invoice_amount": "0.01", * "out_trade_no": "91fbd3fa-8558-443a-82c2-bd8e941d7e71", * "point_amount": "0.00", * "receipt_amount": "0.01", * "total_amount": "0.01", * "trade_no": "2018061021001004680200326495" * }, * "sign": "BNgMmA2t8fwFZNSa39kyEKgL6hV45DVOKOsdyyzTzsQnX8HEkKOzVevQEDyK083dNYewip1KK/K92BTDY2KMAsrOEqcCNxsk9NLAvK9ZQVxQzFbAFKqs5EBAEzncSWnChJcb7VMhDakUxHZFmclHg38dLJiHE2bEcF8ar9R1zj0p4V0Jr+BXO10kLtaSTc9NeaCwJZ89sPHKitNnUWRroU7t0xPHc1hWpstObwixKmAWnsFyb9eyGwPQnqNBsUVNSNWCJ7Pg3rb03Tx6J3zNsqH5f0YhWilMi09npPe33URFc6zG1HJSfhEm4Gq1zwQrPoA/anW8BbdmEUUmNo1dEw==" * } */ String result = f2FPayResult.getResponse().getBody(); return result; } /** * 当面付-扫码付 * * 扫码支付,指用户打开支付宝钱包中的“扫一扫”功能,扫描商户针对每个订单实时生成的订单二维码,并在手机端确认支付。 * * 发起预下单请求,同步返回订单二维码 * * 适用场景:商家获取二维码展示在屏幕上,然后用户去扫描屏幕上的二维码 * @return * @throws AlipayApiException */ @PostMapping("/precreate") public void precreate(HttpServletRequest request, HttpServletResponse response) throws Exception { // 实际使用时需要根据商品id查询商品的基本信息并计算价格(可能还有什么优惠),这里只是写死值来测试 // (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线, String outTradeNo = UUID.randomUUID().toString(); // (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费” String subject = "测试订单"; // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元" String body = "购买商品2件共20.05元"; // (必填) 订单总金额,单位为元,不能超过1亿元 // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 String totalAmount = "0.01"; // (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】 String undiscountableAmount = ""; // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号) // 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID String sellerId = ""; // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持 String storeId = "test_store_id"; // 商户操作员编号,添加此参数可以为商户操作员做销售统计 String operatorId = "test_operator_id"; // 商品明细列表,需填写购买商品详细信息, List<GoodsDetail> goodsDetailList = new ArrayList<>(); GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "全麦小面包", 1, 1); goodsDetailList.add(goods1); GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "黑人牙刷", 1, 2); goodsDetailList.add(goods2); // 支付超时,线下扫码交易定义为5分钟 String timeoutExpress = "5m"; AlipayTradePrecreateRequestBuilder builder =new AlipayTradePrecreateRequestBuilder() .setSubject(subject) .setTotalAmount(totalAmount) .setOutTradeNo(outTradeNo) .setUndiscountableAmount(undiscountableAmount) .setSellerId(sellerId) .setBody(body) .setOperatorId(operatorId) .setStoreId(storeId) .setTimeoutExpress(timeoutExpress) //支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置 .setNotifyUrl(aliPayProperties.getNotifyUrl()) .setGoodsDetailList(goodsDetailList); AlipayF2FPrecreateResult result = alipayTradeService.tradePrecreate(builder); String qrCodeUrl = null; switch (result.getTradeStatus()) { case SUCCESS: log.info("支付宝预下单成功: )"); AlipayTradePrecreateResponse res = result.getResponse(); BufferedImage image = PayUtil.getQRCodeImge(res.getQrCode()); response.setContentType("image/jpeg"); response.setHeader("Pragma","no-cache"); response.setHeader("Cache-Control","no-cache"); response.setIntHeader("Expires",-1); ImageIO.write(image, "JPEG", response.getOutputStream()); break; case FAILED: log.error("支付宝预下单失败!!!"); break; case UNKNOWN: log.error("系统异常,预下单状态未知!!!"); break; default: log.error("不支持的交易状态,交易返回异常!!!"); break; } } /** * 订单查询(最主要用于查询订单的支付状态) * @param orderNo 商户订单号 * @return */ @GetMapping("/query") public String query(String orderNo){ AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder() .setOutTradeNo(orderNo); AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder); switch (result.getTradeStatus()) { case SUCCESS: log.info("查询返回该订单支付成功: )"); AlipayTradeQueryResponse resp = result.getResponse(); log.info(resp.getTradeStatus());// log.info(resp.getFundBillList()); break; case FAILED: log.error("查询返回该订单支付失败!!!"); break; case UNKNOWN: log.error("系统异常,订单支付状态未知!!!"); break; default: log.error("不支持的交易状态,交易返回异常!!!"); break; } return result.getResponse().getBody(); } /** * 退款 * @param orderNo 商户订单号 * @return */ @PostMapping("/refund") public String refund(String orderNo){ AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder() .setOutTradeNo(orderNo) .setRefundAmount("0.01") .setRefundReason("当面付退款测试") .setOutRequestNo(String.valueOf(System.nanoTime())) .setStoreId("A1"); AlipayF2FRefundResult result = alipayTradeService.tradeRefund(builder); switch (result.getTradeStatus()) { case SUCCESS: log.info("支付宝退款成功: )"); break; case FAILED: log.error("支付宝退款失败!!!"); break; case UNKNOWN: log.error("系统异常,订单退款状态未知!!!"); break; default: log.error("不支持的交易状态,交易返回异常!!!"); break; } return result.getResponse().getBody(); } /** * 扫码付异步结果通知 * https://docs.open.alipay.com/194/103296 * @param request */ @RequestMapping("/notify") public String notify(HttpServletRequest request) throws AlipayApiException { // 一定要验签,防止黑客篡改参数 Map<String, String[]> parameterMap = request.getParameterMap(); parameterMap.forEach((key, value) -> System.out.println(key+"="+value[0])); // https://docs.open.alipay.com/54/106370 // 获取支付宝POST过来反馈信息 Map<String,String> params = new HashMap<>(); Map requestParams = request.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } params.put(name, valueStr); } boolean flag = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAlipayPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType()); if (flag) { /** * TODO 需要严格按照如下描述校验通知数据的正确性 * * 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, * 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), * 同时需要校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email), * * 上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。 * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。 * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。 */ return "success"; } return null; }}

总结

用户评论

余温散尽ぺ

这游戏名有点意思啊,感觉是那种手把手教学类型的。

    有12位网友表示赞同!

稳妥

学编程就是要这种一步一步来的,感谢开发者提供了这样的干货。

    有8位网友表示赞同!

〆mè村姑

支付宝集成教程,对于小白来说真是太实用了。

    有13位网友表示赞同!

有你,很幸福

正好在找这方面的资料,这个标题太合适了。

    有15位网友表示赞同!

弃我者亡

一步一步教,我这种新手也能轻松上手。

    有14位网友表示赞同!

抚涟i

游戏行业里还能看到这样的教学资源,太有爱了。

    有19位网友表示赞同!

关于道别

以前总感觉支付宝集成复杂,现在有了这个教程,心里有底了。

    有12位网友表示赞同!

糖果控

这标题一看就是用心良苦,对新手友好。

    有11位网友表示赞同!

?娘子汉

希望教程里不仅有代码,还能有详细的操作步骤。

    有11位网友表示赞同!

陌颜

学编程就是要从实际应用入手,这个教程正合适。

    有19位网友表示赞同!

惯例

集成支付宝的当面付,对于电商平台来说很重要啊。

    有6位网友表示赞同!

月下独酌

我朋友也一直在找这方面的资料,推荐给他。

    有8位网友表示赞同!

命该如此

这种教学游戏让我觉得学习编程不再枯燥。

    有8位网友表示赞同!

孤城暮雨

看了标题,我已经迫不及待想要学习了。

    有11位网友表示赞同!

┲﹊怅惘。

希望教程里有详细的示例代码,这样更容易理解。

    有20位网友表示赞同!

绝版女子

我之前尝试过自己集成,但总是出问题,现在有了这个教程,希望会顺利一些。

    有8位网友表示赞同!

最怕挣扎

教程如果能配视频讲解就更好了,视觉学习效果更佳。

    有17位网友表示赞同!

陌潇潇

学习编程,这样的干货真的很重要。

    有9位网友表示赞同!

热点资讯