官方使用说明文档
SDK & Demo(Eclipse+JDK 1.6 及以上+Tomcat 6.0 及以上)
开发工具包SDK下载
【推荐参考】电脑网站支付接入助手
通用版SDK

  1. <dependency>
  2. <groupId>com.alipay.sdk</groupId>
  3. <artifactId>alipay-sdk-java</artifactId>
  4. <version>4.31.7.ALL</version>
  5. </dependency>

新建springboot项目,引入相关依赖

  1. <!-- 解决Spring Boot Configuration Annotation Processor not configured报错 -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-configuration-processor</artifactId>
  5. </dependency>
  6. <!-- 通用连接池-->
  7. <dependency>
  8. <groupId>org.apache.commons</groupId>
  9. <artifactId>commons-pool2</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-web</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. <scope>runtime</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.projectlombok</groupId>
  22. <artifactId>lombok</artifactId>
  23. <optional>true</optional>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. <!--druid 连接池依赖-->
  31. <dependency>
  32. <groupId>com.alibaba</groupId>
  33. <artifactId>druid-spring-boot-starter</artifactId>
  34. <version>1.2.9</version>
  35. </dependency>
  36. <!--mybatis-plus依赖-->
  37. <dependency>
  38. <groupId>com.baomidou</groupId>
  39. <artifactId>mybatis-plus-boot-starter</artifactId>
  40. <version>3.5.1</version>
  41. </dependency>
  42. <!--操作JSON字符串-->
  43. <dependency>
  44. <groupId>com.alibaba</groupId>
  45. <artifactId>fastjson</artifactId>
  46. <version>1.2.80</version>
  47. </dependency>
  48. <!--语言包,处理字符串,日期等工具包-->
  49. <dependency>
  50. <groupId>org.apache.commons</groupId>
  51. <artifactId>commons-lang3</artifactId>
  52. </dependency>
  53. <!--项目启动热部署-->
  54. <dependency>
  55. <groupId>org.springframework.boot</groupId>
  56. <artifactId>spring-boot-devtools</artifactId>
  57. </dependency>
  58. <!-- 支付宝开发工具包-通用版 -->
  59. <dependency>
  60. <groupId>com.alipay.sdk</groupId>
  61. <artifactId>alipay-sdk-java</artifactId>
  62. <version>4.31.7.ALL</version>
  63. </dependency>

制作controller,根据官方提供的代码,进行改造一下,

先做支付的API接口

  1. package com.tj.alipay.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.alipay.api.AlipayApiException;
  5. import com.alipay.api.AlipayClient;
  6. import com.alipay.api.DefaultAlipayClient;
  7. import com.alipay.api.domain.AlipayTradePagePayModel;
  8. import com.alipay.api.domain.AlipayTradeQueryModel;
  9. import com.alipay.api.request.AlipayTradePagePayRequest;
  10. import com.alipay.api.request.AlipayTradeQueryRequest;
  11. import com.alipay.api.response.AlipayTradeQueryResponse;
  12. import com.tj.alipay.domain.PayData;
  13. import com.tj.alipay.service.BaseZhifubaoParamService;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.web.bind.annotation.*;
  17. import java.util.HashMap;
  18. @Slf4j
  19. @RestController
  20. @RequestMapping("/zhifubao")
  21. public class ZhiFuBaoCtrl {
  22. @Autowired(required = false)
  23. private BaseZhifubaoParamService baseZhifubaoParamService;
  24. @PostMapping
  25. String getPayForm(@RequestBody PayData payData) {
  26. /** 支付宝网关 **/
  27. String URL = "https://openapi.alipaydev.com/gateway.do"; //沙箱地址
  28. /** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
  29. String APP_ID = baseZhifubaoParamService.getAppId();
  30. /** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
  31. String APP_PRIVATE_KEY = baseZhifubaoParamService.getAppPrivateKey();
  32. /** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
  33. String ALIPAY_PUBLIC_KEY = baseZhifubaoParamService.getAlipayPublicKey();
  34. /** 初始化 **/
  35. AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
  36. /** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.page.pay(电脑网站支付) **/
  37. AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
  38. /** 设置业务参数 **/
  39. AlipayTradePagePayModel model = new AlipayTradePagePayModel();
  40. /** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
  41. model.setOutTradeNo(payData.getOutTradeNo());
  42. /** 销售产品码,固定值:FAST_INSTANT_TRADE_PAY **/
  43. model.setProductCode("FAST_INSTANT_TRADE_PAY");
  44. /**
  45. * PC扫码支付的方式。
  46. * 支持前置模式和跳转模式。
  47. * 前置模式是将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面。具体支持的枚举值有以下几种:
  48. * 0:订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px;
  49. * 1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于600px;
  50. * 3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于75px;
  51. * 4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。
  52. *
  53. * 跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。支持传入的枚举值有:
  54. * 2:订单码-跳转模式
  55. */
  56. model.setQrPayMode("0");
  57. /**订单标题 **/
  58. model.setSubject(payData.getSubject());
  59. /** 订单金额,精确到小数点后两位 **/
  60. model.setTotalAmount(payData.getTotalAmount());
  61. /** 订单描述 **/
  62. model.setBody(payData.getBody());
  63. /** 业务扩展参数 **/
  64. //ExtendParams extendParams = new ExtendParams();
  65. /** 花呗分期参数传值前提:必须有该接口花呗收款准入条件,且需签约花呗分期 **/
  66. /** 指定可选期数,只支持3/6/12期,还款期数越长手续费越高 **/
  67. // extendParams.setHbFqNum("3");
  68. /** 指定花呗分期手续费承担方式,手续费可以由用户全承担(该值为0),也可以商户全承担(该值为100),但不可以共同承担,即不可取0和100外的其他值。 **/
  69. //extendParams.setHbFqSellerPercent("0");
  70. //model.setExtendParams(extendParams);
  71. /** 将业务参数传至request中 **/
  72. alipayRequest.setBizModel(model);
  73. /** 注:支付结果以异步通知为准,不能以同步返回为准,因为如果实际支付成功,但因为外力因素,如断网、断电等导致页面没有跳转,则无法接收到同步通知;**/
  74. /** 同步通知地址,以http或者https开头,支付完成后跳转的地址,用于用户视觉感知支付已成功,传值外网可以访问的地址,如果同步未跳转可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602474937 **/
  75. alipayRequest.setReturnUrl("");
  76. /** 异步通知地址,以http或者https开头,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
  77. alipayRequest.setNotifyUrl("");
  78. /** 第三方调用(服务商模式),传值app_auth_token后,会收款至授权app_auth_token对应商家账号,如何获传值app_auth_token请参考文档:https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
  79. //request.putOtherTextParam("app_auth_token", "传入获取到的app_auth_token值");
  80. String form = null;
  81. try {
  82. /** 调用SDK生成表单form表单 **/
  83. form = alipayClient.pageExecute(alipayRequest).getBody();
  84. /** 调用SDK生成支付链接,可在浏览器打开链接进入支付页面 **/
  85. //form = alipayClient.pageExecute(alipayRequest,"GET").getBody();
  86. } catch (AlipayApiException e) {
  87. e.printStackTrace();
  88. }
  89. /** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/97 **/
  90. System.out.println(form);
  91. /** 直接将完整的表单html输出到页面 **/
  92. return form;
  93. }
  94. @GetMapping
  95. String queryResult(String outTradeNo) {
  96. /** 支付宝网关 **/
  97. String URL = "https://openapi.alipaydev.com/gateway.do";
  98. /** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
  99. String APP_ID = baseZhifubaoParamService.getAppId();
  100. /** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
  101. String APP_PRIVATE_KEY = baseZhifubaoParamService.getAppPrivateKey();
  102. /** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
  103. String ALIPAY_PUBLIC_KEY = baseZhifubaoParamService.getAlipayPublicKey();
  104. /** 初始化 **/
  105. AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
  106. /** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.query(统一收单线下交易查询) **/
  107. AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
  108. /** 设置业务参数 **/
  109. AlipayTradeQueryModel model = new AlipayTradeQueryModel();
  110. /** 注:交易号(TradeNo)与订单号(OutTradeNo)二选一传入即可,如果2个同时传入,则以交易号为准 **/
  111. /** 支付接口传入的商户订单号。如:2020061601290011200000140004 **/
  112. model.setOutTradeNo(outTradeNo);
  113. /** 异步通知/查询接口返回的支付宝交易号,如:2020061622001473951448314322 **/
  114. //model.setTradeNo("2020061622001473951448314322");
  115. /** 将业务参数传至request中 **/
  116. request.setBizModel(model);
  117. /** 第三方调用(服务商模式),必须传值与支付接口相同的app_auth_token **/
  118. //request.putOtherTextParam("app_auth_token", "传入获取到的app_auth_token值");
  119. AlipayTradeQueryResponse response = null;
  120. try {
  121. /** 通过alipayClient调用API,获得对应的response类 **/
  122. response = alipayClient.execute(request);
  123. log.info("返回结果:{}", response.getBody());
  124. //参数处理
  125. String tradeQueryResponse = JSON.parseObject(response.getBody()).getString("alipay_trade_query_response");
  126. HashMap<String, String> map = new HashMap<>();
  127. JSONObject jsonObject = JSON.parseObject(tradeQueryResponse);
  128. map.put("out_trade_no", jsonObject.getString("out_trade_no"));
  129. map.put("total_amount", jsonObject.getString("total_amount"));
  130. map.put("trade_no", jsonObject.getString("trade_no"));
  131. map.put("trade_status", jsonObject.getString("trade_status"));
  132. map.put("send_pay_date", jsonObject.getString("send_pay_date"));
  133. return JSON.toJSONString(map);
  134. } catch (AlipayApiException e) {
  135. e.printStackTrace();
  136. }
  137. /** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/101 **/
  138. return null;
  139. }
  140. }

1、其中需要传入的参数,我们可以使用实体类进行定义,方便读取和调用

  1. package com.tj.alipay.domain;
  2. import lombok.Data;
  3. import java.io.Serializable;
  4. /**
  5. * 支付信息
  6. */
  7. @Data
  8. public class PayData implements Serializable {
  9. /**
  10. * 商户订单号。
  11. * 由商家自定义,64个字符以内,仅支持字母、数字、下划线且需保证在商户端不重复。
  12. */
  13. private String outTradeNo;
  14. /**
  15. * 订单总金额,单位为元,精确到小数点后两位,取值范围为 [0.01,100000000]。金额不能为0。
  16. */
  17. private String totalAmount;
  18. /**
  19. * 订单标题。
  20. * 注意:不可使用特殊字符,如 /,=,& 等。
  21. */
  22. private String subject;
  23. /**
  24. * 订单描述
  25. **/
  26. private String body;
  27. private static final long serialVersionUID = 1L;
  28. }

2、接口请求成功后,支付宝返回的是一个html格式的字符串,里面类似下面的代码

  1. <form name="punchout_form" method="post" action="https://openapi.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.page.pay&sign=XZ%2BLINIxDqMW%2FxMgjIoXUrSk0uWuJGnxuRyYcqkxFCqubYULdBM1godWmH1S9Qgf2Eoz8TOdJXF1i%2FykDRbiNuEeOYZT8%2BJirKiBTSPfh%2Bl1pwxwDkx%2F5e5cwvzeVwyhKd6Yq3HsM3Eh7CZLfLq8ormpmCE4HEQgZvY1Bij%2FDS0AwecjzEwAtwyjh6mIP5ax48IlUwPIkWxdYpfoJ7aytfzK0cCX8H%2BYr%2B5YztGhozRUTaHwP74D5D6TXd%2BTS%2BIH%2Fm74XfcYuMRwkTZVhUyL31DyeRfur3TiOygs0U2ycsgw6dU8L4P1XRbidbQJkUXTmE9docbleDAB0drY2RbUBA%3D%3D&version=1.0&app_id=2021000120612546&sign_type=RSA2&timestamp=2022-06-11+20%3A14%3A25&alipay_sdk=alipay-sdk-java-dynamicVersionNo&format=json">
  2. <input type="hidden" name="biz_content" value="{&quot;body&quot;:&quot;海外批次付款:1004322060701&quot;,&quot;out_trade_no&quot;:&quot;GWTEST2022061100002&quot;,&quot;product_code&quot;:&quot;FAST_INSTANT_TRADE_PAY&quot;,&quot;qr_pay_mode&quot;:&quot;0&quot;,&quot;subject&quot;:&quot;海外批次付款:1004322060701&quot;,&quot;total_amount&quot;:&quot;476.2&quot;}">
  3. <input type="submit" value="立即支付" style="display:none" >
  4. </form>
  5. <script>document.forms[0].submit();</script>

1、这个里面有关键参数“qr_pay_mode”,我们设置为0,我用ifranme窗口来现在返回的支付页面

这里可以参考:vue支付宝pc支付的扫码支付和跳转支付两种支付方式
PC扫码支付的方式。
支持前置模式和跳转模式。
前置模式是将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面。具体支持的枚举值有以下几种:
0:订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px;
1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于600px;
3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于75px;
4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。

跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。支持传入的枚举值有:
2:订单码-跳转模式

  1. <iframe v-show="iframeShow" :srcdoc="alipayHtml" frameborder="no" border="0" marginwidth="0"
  2. marginheight="0" scrolling="no" width="600" height="300" style="overflow:hidden;">
  3. </iframe>

这样就做出这样一个界面,我个人不太喜欢“跳转模式”,体验不是很好,还是“前置模式”好点,这个qr_pay_mode如果不设置,就默认是“跳转模式”哦
image.png

再做一个支付结果查询的接口,根据这个接口,可以做支付完成后的一些逻辑

官方给出了3种方法来处理支付完成后的逻辑。分别是

  1. 同步接口(不推荐)
  2. 异步通知接口(这个接口必须是外网可放访问的接口,在本地调试的时候不太方便,但是尽量还是使用这个接口来处理支付成功后的逻辑)
  3. 查询接口(如果异步回调接口有问题,可以使用这个接口再次确认支付的状态)

    查询接口JAVA代码

    1. @GetMapping
    2. String queryResult(String outTradeNo) {
    3. /** 支付宝网关 **/
    4. String URL = "https://openapi.alipaydev.com/gateway.do";
    5. /** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
    6. String APP_ID = baseZhifubaoParamService.getAppId();
    7. /** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
    8. String APP_PRIVATE_KEY = baseZhifubaoParamService.getAppPrivateKey();
    9. /** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
    10. String ALIPAY_PUBLIC_KEY = baseZhifubaoParamService.getAlipayPublicKey();
    11. /** 初始化 **/
    12. AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
    13. /** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.query(统一收单线下交易查询) **/
    14. AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
    15. /** 设置业务参数 **/
    16. AlipayTradeQueryModel model = new AlipayTradeQueryModel();
    17. /** 注:交易号(TradeNo)与订单号(OutTradeNo)二选一传入即可,如果2个同时传入,则以交易号为准 **/
    18. /** 支付接口传入的商户订单号。如:2020061601290011200000140004 **/
    19. model.setOutTradeNo(outTradeNo);
    20. /** 异步通知/查询接口返回的支付宝交易号,如:2020061622001473951448314322 **/
    21. //model.setTradeNo("2020061622001473951448314322");
    22. /** 将业务参数传至request中 **/
    23. request.setBizModel(model);
    24. /** 第三方调用(服务商模式),必须传值与支付接口相同的app_auth_token **/
    25. //request.putOtherTextParam("app_auth_token", "传入获取到的app_auth_token值");
    26. AlipayTradeQueryResponse response = null;
    27. try {
    28. /** 通过alipayClient调用API,获得对应的response类 **/
    29. response = alipayClient.execute(request);
    30. log.info("返回结果:{}", response.getBody());
    31. //参数处理
    32. String tradeQueryResponse = JSON.parseObject(response.getBody()).getString("alipay_trade_query_response");
    33. HashMap<String, String> map = new HashMap<>();
    34. JSONObject jsonObject = JSON.parseObject(tradeQueryResponse);
    35. map.put("out_trade_no", jsonObject.getString("out_trade_no"));
    36. map.put("total_amount", jsonObject.getString("total_amount"));
    37. map.put("trade_no", jsonObject.getString("trade_no"));
    38. map.put("trade_status", jsonObject.getString("trade_status"));
    39. map.put("send_pay_date", jsonObject.getString("send_pay_date"));
    40. return JSON.toJSONString(map);
    41. } catch (AlipayApiException e) {
    42. e.printStackTrace();
    43. }
    44. /** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/101 **/
    45. return null;
    46. }