暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SpringBoot详细教程 | 第十二篇:SpringBoot整合支付宝,实现手机网页支付,扫码支付

小东IT技术分享 2019-02-26
1585

一.支付宝集成准备工作

1.注册账号 创建应用

1) 右上角免费入住

目前都是支付宝直接扫码登录即可



2) 进入到首页后 开发中心选择网页&移动应用



3) 支付接入


4) 创建你的应用


5) 创建成功后紧接着需要完善应用的信息,如应用图表,需要接入的支付宝功能、以及一些参数配置等,配置完成后【提交审核】,然后等待审核结果 审核通过就是下图这样子 查看详情进行你的配置


6) 添加你的功能

关于功能列表,默认提供 APP支付、手机网站支付、当面付三种功能,如果需要其他更多功能可以通过【添加功能】添加上来,常用的功能有 电脑网站支付、APP支付宝登录、获取会员信息、单笔转账到支付宝账户等



7) 产品签约 填写自己的信息即可 等待审核通过



8) 开发配置 在你的应用详情的应用信息查看





应用网关: 是项目上线对应的域名(如:http://www.xxx.com)

注意在设置应用网关前会先【设置应用公钥】,关于应用公钥的生成可以通过【查看密钥生成方法】来生成,

将生成后的公钥(注意是公钥公钥公钥,重要的事情说三遍,不要复制成私钥了)粘贴过来,然后保存即可

授权回调地址: 是自己项目的一个能访问的url地址,当支付宝支付成功后会异步通知到这个地址上,告诉此次支付的结果是成功还是失败,配置地址(http://www.xxx.com/pay/alipay/notify)

接口加签方式: 当应用网关设置完成后,接口加签方式就不需要设置什么了,这里只是用来查看应用公钥和支付宝公钥的

应用配置就这么多 下面介绍沙箱环境(比较重要)

二.沙箱环境

在签约的时候需要提供经营信息和服务接入渠道对应的信息,经营信息一般需要人事或者老板提供、服务接入渠道一般需要产品来提供,这些资料可能不会立马能给到你,如果签约不成功就没法测试,基于此,支付宝提供了一个【沙箱环境】,所谓的沙箱环境就是支付宝帮你创建了一个临时用于开发测试的应用,称为沙箱应用,并签约了所有功能,并提供一套账号信息(包括卖家账号和买家账号)称之为沙箱账号,还提供一个沙箱支付宝安卓版的应用,可以使用沙箱账号登录沙箱应用来进行支付操作,所有的支付都是假的,你也不用担心你的钱会扣掉,因为登录的是沙箱账号而不是自己的账号,也不用担心买家的钱不够用,因为自己可以随意充值,沙箱环境用于前期的研发以及个人学习研究使用。

【开发中心 / 研发服务 / 沙箱环境 / 沙箱应用】




注意:沙箱环境已经创建好了一个测试应用并签约了所有功能,但是仍然有一些信息还需自己完善,如秘钥、应用网关、授权回调地址(选看部分的RSA(SHA1)密钥、AES密钥不是必须设置的)这些参数在上面已经讲过了,将这些信息配置完成后就可以开发了

APPID: 支付宝分配给开发者的应用ID 一个应用对应一个


支付宝所需要的参数都已经知道了 下面就是看开发文档进行开发

三.开发文档 (https://docs.open.alipay.com/catalog)



阿里提供了非常详细的各种功能的开发文档 蚂蚁开放平台开发文档 https://docs.open.alipay.com/,从开发文档中可以看到支付方式有四种,每一种都有应用的场景

当面付

条码支付
:使用场景为商家使用扫码枪等条码识别设备扫描用户支付宝钱包上的付钱-条码/二维码,完成收款。一般在超市、便利店、店铺等使用。

扫码支付
:使用场景为用户打开支付宝钱包中的“扫一扫”功能,扫描商家展示在某收银场景下的二维码并进行支付的模式。一般在类似于无人售货机上使用,像地铁中的无人售货饮料机、医院中的自助挂号收费机等

声波支付

APP支付
:适用于商家在App应用中集成支付宝支付功能

手机网站支付
:适用于商家在移动端网页应用中集成支付宝支付功能

电脑网站支付
: 用户通过支付宝PC收银台完成支付,交易款项即时给到商户支付宝账户

每种支付方式都提供了SDK&Demo和API列表,集成时我们只需要下载Demo并熟悉好之后将Demo集成到自己的项目中即可

官网的Demo都是之前很久的开发传统的开发方式,我们目前使用SpringBoot如何进行开发呢?

先把官网的Demo以及所需要的SDK下载下来 并看下需要哪些jar包进行开发




最主要的就是

alipay-sdk-java-3.3.0.jar包

我们需要的是maven进行开发 需要将jar打入本地仓库进行开发

把jar包打入本地仓库或者私服

准备工作做好了就是进行开发以及测试

我们重点看下API文档

四.支付宝开发

  1. 手机网页支付

手机网站支付常用于HTML5应用,常见于H5商城以及微信公众号等

1) 手机网站支付的流程图: 用户点击H5应用中的支付按钮 点击支付按钮会请求后台接口,后台接口请求支付宝的支付接口,支付接口会返回一段html代码其中包括一个form表单和一段js代码用于自动提交表单,表单提交后就会自动跳转到支付宝的支付页面(如果手机中装了支付App就去打开APP,如果没有就在网页版支付 支付成功后会调用支付时设置的同步url, 然后跳转到商户的后台系统,一般情况下商户系统会展示一下支付成功,以及购买的商品信息等视图

查看API文档

手机网站支付接口2.0

https://docs.open.alipay.com/api_1/alipay.trade.wap.pay

2) 集成

1.1 创建好SpringBoot工程引入我们的依赖

  1. <!--打入本地仓库的jar-->

  2. <dependency>

  3. <groupId>com.alipay</groupId>

  4. <artifactId>trade-sdk</artifactId>

  5. <version>1.0.0</version>

  6. </dependency>


  7. <dependency>

  8. <groupId>com.alipay.sdk</groupId>

  9. <artifactId>alipay-sdk-java</artifactId>

  10. <version>3.4.49.ALL</version>

  11. </dependency>

1.2 创建类

  1. package com.li.payserver.alipay;


  2. import com.alibaba.fastjson.JSON;

  3. import com.alipay.api.AlipayApiException;

  4. import com.alipay.api.AlipayClient;

  5. import com.alipay.api.DefaultAlipayClient;

  6. import com.alipay.api.domain.AlipayTradePayModel;

  7. import com.alipay.api.internal.util.AlipaySignature;

  8. import com.alipay.api.request.AlipayTradePrecreateRequest;

  9. import com.alipay.api.request.AlipayTradeWapPayRequest;

  10. import com.alipay.api.response.AlipayTradePrecreateResponse;

  11. import com.alipay.api.response.AlipayTradeWapPayResponse;

  12. import com.li.payserver.bo.Order;

  13. import lombok.extern.slf4j.Slf4j;

  14. import org.springframework.stereotype.Controller;

  15. import org.springframework.web.bind.annotation.RequestMapping;

  16. import org.springframework.web.bind.annotation.RequestMethod;

  17. import org.springframework.web.bind.annotation.ResponseBody;


  18. import javax.servlet.http.HttpServletRequest;

  19. import javax.servlet.http.HttpServletResponse;

  20. import javax.swing.filechooser.FileSystemView;

  21. import java.io.File;

  22. import java.io.IOException;

  23. import java.util.HashMap;

  24. import java.util.Iterator;

  25. import java.util.Map;


  26. import static com.li.payserver.utils.QrCodeUtil.createQrCode;


  27. /**

  28. * @ClassName Alipay

  29. * @Author lihaodong

  30. * @Date 2019/2/13 17:59

  31. * @Mail lihaodongmail@163.com

  32. * @Description 支付宝配置

  33. * @Version 1.0

  34. **/

  35. @Slf4j

  36. @Controller

  37. @RequestMapping(value = "/alipay")

  38. public class AlipayUtil {


  39. // 商户appid

  40. private static final String APP_ID = "2016091600522501";

  41. // 私钥 pkcs8格式的

  42. private static final String RSA_PRIVATE_KEY = "";

  43. // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问

  44. private static final String NOTIFY_URL = "你的外网/alipay/notifyUrl";

  45. // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址

  46. private static final String RETURN_URL = "你的外网/alipay/returnUrl";

  47. // 请求网关地址(沙箱环境)

  48. private static final String URL = "https://openapi.alipaydev.com/gateway.do";

  49. // 编码

  50. private static final String CHARSET = "UTF-8";

  51. // 返回格式

  52. private static final String FORMAT = "json";

  53. // 支付宝公钥

  54. private static final String ALIPAY_PUBLIC_KEY = "";

  55. // 日志记录目录

  56. public static final String LOG_PATH = "/log";

  57. // RSA2

  58. private static final String SIGNTYPE = "RSA2";



  59. /**

  60. * 手机网页支付

  61. *

  62. * @return

  63. */

  64. @RequestMapping(value = "/pay")

  65. @ResponseBody

  66. public String pay() {


  67. // 获得初始化的AlipayClient

  68. AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, RSA_PRIVATE_KEY, FORMAT, CHARSET,

  69. ALIPAY_PUBLIC_KEY, SIGNTYPE);


  70. // 创建API对应的request 手机

  71. AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();

  72. // 在公共参数中设置回跳和通知地址

  73. alipayRequest.setReturnUrl(RETURN_URL);

  74. alipayRequest.setNotifyUrl(NOTIFY_URL);


  75. Map<String, String> params = new HashMap<>();


  76. //商户订单号,商户网站订单系统中唯一订单号,必填

  77. String outTradeNo = System.currentTimeMillis()+"";

  78. //付款金额,必填

  79. String totalAmount = "1.00";

  80. //订单名称,必填

  81. String subject = "Iphone6 16G";

  82. //商品描述,可空

  83. String body = "Iphone6 16G 耐克金";

  84. // 该笔订单允许的最晚付款时间,逾期将关闭交易。

  85. // 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。

  86. // 该参数数值不接受小数点, 如 1.5h,可转换为 90m。

  87. String timeoutExpress = "1c";

  88. // 使用官方的model 比较方便

  89. AlipayTradePayModel model = new AlipayTradePayModel();

  90. // 收款方id

  91. model.setSellerId("");

  92. model.setBody(body);

  93. model.setTimeoutExpress(timeoutExpress);

  94. model.setTotalAmount(totalAmount);

  95. model.setOutTradeNo(outTradeNo);

  96. model.setProductCode("QUICK_WAP_PAY");

  97. model.setSubject(subject);


  98. alipayRequest.setBizModel(model);

  99. AlipayTradeWapPayResponse response = null;

  100. String form = "";

  101. try {

  102. response = alipayClient.pageExecute(alipayRequest);

  103. if (response.isSuccess()){

  104. log.info("支付宝预下单成功");

  105. } else {

  106. log.info("支付宝预下单失败");

  107. }

  108. form = response.getBody();

  109. } catch (AlipayApiException e) {

  110. e.printStackTrace();

  111. }

  112. return form;

  113. }


  114. @RequestMapping(value = "/returnUrl", method = RequestMethod.GET)

  115. public void returnUrl(HttpServletRequest request, HttpServletResponse response)

  116. throws IOException, AlipayApiException {

  117. System.out.println("=================================同步回调=====================================");


  118. // 获取支付宝GET过来反馈信息

  119. Map<String, String> params = new HashMap<String, String>();

  120. Map<String, String[]> requestParams = request.getParameterMap();

  121. for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {

  122. String name = (String) iter.next();

  123. String[] values = (String[]) requestParams.get(name);

  124. String valueStr = "";

  125. for (int i = 0; i < values.length; i++) {

  126. valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";

  127. }

  128. // 乱码解决,这段代码在出现乱码时使用

  129. valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");

  130. params.put(name, valueStr);

  131. }


  132. System.out.println(params);

  133. boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGNTYPE);


  134. // ——请在这里编写您的程序(以下代码仅作参考)——

  135. if (signVerified) {

  136. // 商户订单号

  137. String outTradeNo = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");


  138. // 支付宝交易号

  139. String tradeNo = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");


  140. // 付款金额

  141. String totalAmount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");


  142. System.out.println("商户订单号=" + outTradeNo);

  143. System.out.println("支付宝交易号=" + tradeNo);

  144. System.out.println("付款金额=" + totalAmount);


  145. response.getWriter().write(

  146. "trade_no:" + tradeNo + "<br/>out_trade_no:" + outTradeNo + "<br/>total_amount:" + totalAmount);

  147. } else {

  148. response.getWriter().write("验签失败");

  149. }

  150. response.getWriter().flush();

  151. response.getWriter().close();

  152. }


  153. @RequestMapping(value = "/notifyUrl", method = RequestMethod.POST)

  154. public void notifyUrl(HttpServletRequest request, HttpServletResponse response)

  155. throws AlipayApiException, IOException {

  156. System.out.println("支付宝异步回调");


  157. // 获取支付宝POST过来反馈信息

  158. Map<String, String> params = new HashMap<>();

  159. Map<String, String[]> requestParams = request.getParameterMap();

  160. for (String name : requestParams.keySet()) {

  161. String[] values = requestParams.get(name);

  162. String valueStr = "";

  163. for (int i = 0; i < values.length; i++) {

  164. valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";

  165. }

  166. // 乱码解决,这段代码在出现乱码时使用

  167. //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");

  168. params.put(name, valueStr);

  169. }


  170. System.out.println(params);

  171. boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGNTYPE);


  172. // ——请在这里编写您的程序(以下代码仅作参考)——


  173. /*

  174. * 实际验证过程建议商户务必添加以下校验:

  175. * 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,

  176. * 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),

  177. * 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)

  178. * 4、验证app_id是否为该商户本身。

  179. */

  180. // 验证成功

  181. if (signVerified) {

  182. // 商户订单号

  183. String outTradeNo = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");


  184. // 支付宝交易号

  185. String tradeNo = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");


  186. // 交易状态

  187. String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");


  188. System.out.println("商户订单号=" + outTradeNo);

  189. System.out.println("支付宝交易号=" + tradeNo);

  190. System.out.println("交易状态=" + tradeStatus);

  191. if ("TRADE_FINISHED".equals(tradeStatus)) {

  192. // 判断该笔订单是否在商户网站中已经做过处理

  193. // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序

  194. // 如果有做过处理,不执行商户的业务程序


  195. // 注意:

  196. // 退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知

  197. } else if ("TRADE_SUCCESS".equals(tradeStatus)) {

  198. // 判断该笔订单是否在商户网站中已经做过处理

  199. // 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序

  200. // 如果有做过处理,不执行商户的业务程序


  201. // 注意:

  202. // 付款完成后,支付宝系统发送该交易状态通知

  203. }


  204. System.out.println("异步回调验证成功");

  205. response.getWriter().write("success");


  206. } else {

  207. // 验证失败

  208. System.out.println("异步回调验证失败");

  209. response.getWriter().write("fail");


  210. // 调试用,写文本函数记录程序运行情况是否正常

  211. // String sWord = AlipaySignature.getSignCheckContentV1(params);

  212. // AlipayConfig.logResult(sWord);

  213. }

  214. response.getWriter().flush();

  215. response.getWriter().close();

  216. }

  217. }

重点说下两个参数: // 私钥 pkcs8格式的 private static final String RSAPRIVATEKEY = "";

// 支付宝公钥 private static final String ALIPAYPUBLICKEY = ""; 第一参数是 生成 RSA2(SHA256)密钥(推荐) 的私钥

生成密钥

https://docs.open.alipay.com/291/105971

第二参是 生成好的公钥上传到应用公钥生成的支付宝公钥







文章转载自小东IT技术分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论