支付宝支付——沙箱环境
0x1. 前言
蚂蚁沙箱环境 (Beta) 是协助开发者进行接口功能开发及主要功能联调的辅助环境,通过配置参数、搭建页面及下载沙箱版支付宝可以测试PC端扫码支付功能以及达到快速熟悉搭建流程的目的。
注意:
- 由于沙箱为模拟环境,在沙箱完成接口开发及主要功能调试后,请务必在蚂蚁正式环境进行完整的功能验收测试。所有返回码及业务逻辑以正式环境为准。
- 为保证沙箱稳定,沙箱环境测试数据会进行定期数据清理。Beta 测试阶段每周日中午12点至每周一中午12点为维护时间(也就是无法使用沙箱环境)。在此时间内沙箱环境部分功能可能会不可用。
- 请勿在沙箱进行压力测试,以免触发相应的限流措施,导致无法正常使用沙箱环境。
- 沙箱支持的各个开放产品,沙箱使用的特别说明请参考各产品的快速接入文档或技术接入文档章节。
0x2. 简介
登录支付宝开放平台——到达沙箱环境页面(首次登录需要入驻为自研开发者)
登录成功后可得如下界面:
沙箱与线上不同,请注意更改代码配置。
- APPID:发起请求的应用ID。
- 支付宝网关:向支付宝发起请求的网关。
- RSA2密钥:即加密公钥,需要手动设置,必须配置,否则无法调用接口。
注意:
- 密钥和应用(APPID)一一对应,即开发者需要为名下的每个应用分别设置密钥,且不同应用的密钥不能混用(意思就是一个应用只能对应一个密钥)。
- 支付宝开放平台支持开发者使用 普通公钥、公钥证书 两种签名方式;以下步骤采用普通公钥方式说明,如需采用公钥证书签名方式,请查阅官方帮助手册。
0x3. 配置RSA2密钥
支付宝为技术开发人员提供了一键生成密钥工具(Windows版下载—MacOS版下载),可根据该软件生成一对RSA密钥、公钥证书申请CSR文件(在线申请应用公钥证书需要)。
普通公钥方式
- 下载相应环境工具并安装后即可使用,如下图所示:
- 开发者根据开发语言选择密钥格式和密钥长度,新建应用请务必使用 RSA2 密钥长度 即 2048 位(目前已使用 RSA 密钥长度即 1024 位密钥长度的应用仍然可以正常调用接口)。点击 生成密钥 后,工具会自动生成商户应用公钥(public key)和应用私钥(private key),如下图所示:
- 开发者点击工具界面下方的 打开文件位置,即可找到生成的公私钥文件,如下图所示:
- 生成密钥后,点击页面上的RSA2密钥 — 设置 — 公钥 。
- 复制生成的公钥,点击 保存设置,即可完成公钥的设置,如下图所示。
注意:
生成的私钥需妥善保管,避免遗失,不要泄露。应用私钥需填写到代码中供签名时使用。应用公钥需提供给支付宝账号管理者上传到支付宝开放平台。
0x4. 测试账户
沙箱环境提供了沙箱版支付宝与测试账户,其中包含商户号和买家号,但是该账户只能在支付宝提供的测试APK上才能使用。沙箱环境下方有提供二维码可以下载沙箱版支付宝(也可以点击此处下载)。
下载完成后,可根据左侧栏中沙箱账号获取相应的账号密码等信息进行登录,如下图所示。
0x5. 项目配置(Java语言)
可自行下载官方DEMO进行查阅:https://opendocs.alipay.com/open/54/cyz7do
- 导入Maven依赖:
1 2 3 4 5 6
| <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.9.100.ALL</version> </dependency>
|
- 在项目中新建AlipayConfig类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import java.io.FileWriter; import java.io.IOException;
public class AlipayConfig {
public static String APP_ID = "201610xxxxxx";
public static String MERCHANT_PRIVATE_KEY = "官方密钥工具中生成的私钥";
public static String ALIPAY_PUBLIC_KEY = "沙箱环境中的支付宝公钥";
public static String notify_url = "异步通知回调地址";
public static String return_url = "支付完成后返回地址";
public static String SIGN_TYPE = "RSA2";
public static String CHARSET = "utf-8";
public static String FORMAT = "json";
public static String GATEWAY_URL = "https://openapi.alipaydev.com/gateway.do";
public static String LOG_PATH = "C:\\";
public static void logResult(String sWord) { FileWriter writer = null; try { writer = new FileWriter(LOG_PATH + "alipay_log_" + System.currentTimeMillis() + ".txt"); writer.write(sWord); } catch (Exception e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
|
- RSA_PRIVATE_KEY:私钥,这个参数就是通过 支付宝开放平台开放助手 生成的应用公钥、应用私钥 中的应用私钥。
- notify_url:异步通知,当你支付成功时,支付宝回调你本地启动项目的接口,必须是外网可以访问的,否则支付宝请求不到,但是又得是你本地的方法「不讨论线上测试」,所以这就需要用到内网映射(内网穿透),推荐使用免费版的 natapp(自行百度)。
- ALIPAY_PUBLIC_KEY:支付宝公钥,注意这个参数不是你上边生成的应用公钥,而是的支付宝公钥。
- 新建AlipayVO视图对象类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class AlipayVO {
private String outTradeNo;
private String totalAmount;
private String subject; }
|
- 新建AlipayServer支付接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public interface AlipayService {
void pay(HttpServletResponse response, HttpServletRequest request, AlipayVO alipayVO) throws IOException, AlipayApiException;
}
|
- 新建AlipayServiceImpl支付接口实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@Service public class AlipayServiceImpl implements AlipayService {
DefaultAlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.GATEWAY_URL, AlipayConfig.APP_ID, AlipayConfig.MERCHANT_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
@Override public void pay(HttpServletResponse response, HttpServletRequest request, AlipayVO alipayVO) throws IOException, AlipayApiException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setReturnUrl(AlipayConfig.return_url); alipayRequest.setNotifyUrl(AlipayConfig.notify_url); alipayRequest.setBizContent("{\"out_trade_no\":\"" + alipayVO.getOutTradeNo() + "\"," + "\"total_amount\":\"" + alipayVO.getTotalAmount() + "\"," + "\"subject\":\"" + alipayVO.getSubject() + "\"," + "\"body\":\"商品名称\"," + "\"timeout_express\":\"90m\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); String body = alipayClient.pageExecute(alipayRequest).getBody(); response.setContentType("text/html;charset=" + AlipayConfig.CHARSET); response.getWriter().write(body); response.getWriter().flush(); response.getWriter().close(); } }
|
- 新建AlipayController支付宝支付控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@RestController @Slf4j public class AlipayController {
private AlipayService alipayService;
public AlipayController(AlipayService alipayService) { this.alipayService = alipayService; }
@GetMapping("payment/{TotalAmount}") private void alipayPay(HttpServletResponse response, HttpServletRequest request, @PathVariable("TotalAmount") String totalAmount) { AlipayVO vo = new AlipayVO() .setOutTradeNo(UUID.randomUUID().toString().replace("-", "")) .setTotalAmount(totalAmount) .setSubject("捐赠计划"); log.info("发起支付传参:" + vo.toString()); try { alipayService.pay(response, request, vo); } catch (IOException | AlipayApiException e) { log.error(e.getMessage()); } } }
|
- HTML页面调用donate方法:
1 2 3
| function donate(amount){ window.location.href = "/payment/" + amount }
|
上述项目后端采用SpringBoot框架,可根据自身项目需求进行扩展业务。
0x6. 页面视图
当提交支付请求后跳转至此页面(此时用沙箱支付宝扫码支付即可):
沙箱支付宝扫描结果:
手机端支付成功后结果:
PC端支付成功后结果:
0x7. 注意事项
若出现支付环境异常,请检查是否在一个浏览器中登录了多个支付宝账号,或者是否将应用公钥配置给多个应用。
0x8. 结论
至此,即已完成支付宝沙箱环境快速搭建,实现过程并不复杂,线上搭建流程大致也是如此,写下此文以便后续回顾。
Author:
zchengb
License:
Copyright (c) 2019-2024 zchengb