25-javaweb接入支付宝支付接口
想熟悉支付宝接口支付,后面可能会用,不如在课设中试试手。好吧听说支付宝不微信支付要简单些,就拿支付宝的先练下手吧。
基本学习流程,百度一下,找篇博客看下。
推荐下面这个篇博客,讲的挺好的,复制过来。
当然在最后我会把我遇到的问题写出来,避免后人在走弯路,并将支付宝的demo整合到我的ssm项目中,同时,会详细讲下如何将demo中的jsp跟据需求改为contral层。
比较可以的操作流程:别人写的很好了,我就不想写了:https://github.com/OUYANGSIHAI/sihai-maven-ssm-alipay
一、支付宝测试环境代码测试
1.下载电脑网站的官方demo:
下载地址:https://docs.open.alipay.com/270/106291/
2.下载解压导入eclipse
readme.txt请好好看一下。
只有一个Java配置类,其余都是JSP。
3.配置AlipayConfig
(1).注册蚂蚁金服开发者账号(免费,不像苹果会收取费用)
注册地址:https://open.alipay.com ,用你的支付宝账号扫码登录,完善个人信息,选择服务类型(我选的是自研)。
(2).设置app_id和gatewayUrl
其中密钥需要自己生成,appID和支付宝网关是已经给好的,网关有dev字样,表明是用于开发测试。
(3).设置密钥
点击“生成方法”,打开界面如下:
下周密钥生成工具,解压打开后,选择2048位生成密钥:
如果没有设置过,此时显示文本是“设置应用公钥”,我这里是已经设置过得。
设置方法,“打开密钥文件路径”:
复制应用公钥2048.txt中的内容到点击“设置应用公钥”的弹出框中,保存:
商户私钥(merchant_private_key)
复制 应用私钥2048.txt 中的内容到merchant_private_key中。
支付宝公钥(alipay_public_key)
点击如上图链接,复制弹出框里面的内容到alipay_public_key。
如果这个设置不对,结果是:支付成功,但是验签失败。
如果是正式环境,需要上传到对应的应用中:
(4).服务器异步通知页面路径(notify_url)
如果没有改名,修改IP和端口号就可以了,我自己的如下:
http://localhost:8080/alipay.trade.page.pay-JAVA-UTF-8/notify_url.jsp
(5).页面跳转同步通知页面路径(return_url)
http://localhost:8080/alipay.trade.page.pay-JAVA-UTF-8/return_url.jsp
4.测试运行
测试用的支付宝买家账户可以在“沙箱账号”这个页面可以找到:
支付成功后,验签结果:
好吧,要是你成功跑起来的那么你很幸运,没有到什么坑,我遇到了如下坑点。记录一下,以供参考:
1.代码中:
要填写公钥,注意这个不是生成器中的公钥,所以不能从那个里面或者从txt中粘贴,而要重网站上那个查看公钥处粘贴:
2. 支付宝网关要改,注意测试环境中是alipaydev:
3. 从官网下载的沙箱版支付宝怎么登入:
登入的账号去沙箱账号中看,注意不是你的支付宝账号,也不需要重新注册!!!!
注意打支付宝很人性话的给了我们许多钱,可以肆意的花费了,最后会从你的买家余额到买家余额中。
好的,基本注意这些,demo是可以跑起来的了。
下面讲下如何加入到ssm框架中,随意控制呢:
你得先对支付宝的流程有一个大致的了解,整体上了有把握,能使你思路清晰,请看图:
这是支付宝提供的图片,大致过程都表达出来了。
其实到这里不禁要问,那个同步和异步是干嘛的呀,我也不知道,百度啊!!!
我找到了,比较新的解释:
支付宝同步回调和异步回调
当一个支付请求被发送到支付渠道方,支付渠道会很快返回一个结果。但是这个结果,只是告诉你调用成功了,不是扣款成功,这叫同步调用。
很多新手会拿这个结果 当作支付成功了,那就会被坑死,结果就是支付成功率特别高,伴随着一堆无法解释的坏账率,测试人员尤其要注意测试数据的篡改:金额,同步返回结果,订单号等。
同步请求参数里面会有一个回调地址,这个地址是支付渠道在扣款成功后调用的,这叫异步调用。
一般同步接口仅检查参数是否正确,签名是否无误等。异步接口才告诉你扣款结果。
一般异步接口有5秒以内的延迟。调用不成功会重试。有时候是这边成功了,但支付渠道侧没收到返回,于是会继续调。
当天的支付到第二天还在 被异步调用也都是正常的。这也是开发人员需要特别注意的地方,不要当做重复支付。
测试人员也要对重复回调进行测试,应只有一次有效。这还不是最坑的,一般 支付渠道侧,只有支付成功了才通知你。
要是支付失败了,压根儿都不告诉你。
另一方面,如何老收不到异步结果呢?那就得查查了。同步结果不可靠,异步调用不可靠,那怎么确定支付结果?最终的杀招就是查单了,
反查,一般支付渠道侧都 会提供反查接口,定时获取DB中待支付的订单调用支付渠道侧的反查接口,最终把支付渠道侧扣款成功的订单完成掉。
当然,这个没有将过多细节,更多内容可以参考其他的文档,大致就是说,同步通知可以作为支付成功参考,但是准确得出结论还得靠异步的回复
好吧,由于异步必须在服务器上才能测试,所以这里我暂时是以同步的作为判断依据:
开始整合:
思路大致是这样子:
在一个支付页面 --》》》 点击支付 ----》》》 跳转到处理函数 -----》 在这个函数里面设置你真正要想支付宝请求的一些参数,以及同步异步回调地址!!! ----》 然后他在封装好信息后发送给支付宝
------》》》 页面会弹出一个支付宝二维码,你扫码付钱完 -------》》》 支付宝会向你给的同步异步回调地址发送请求(也就是你要写个接收请求的函数咯,在里面可以写一些你要的逻辑了) ------》》》
根据回调结果,挑战页面给出回调结果 ------ 》》》 finish ! ! !!!!
具体的:
1. 支付请求给个post的地址:也就是你处理支付的函数:
2.在contral里面写对应 的处理函数里咯:
函数里面其实就是把支付宝demo的jsp处理粘过来了:
- @ResponseBody
- @RequestMapping(value = "/goods/alipay2")
- public String alipay(
- HttpServletRequest request
- ) throws AlipayApiException, IOException {
- System.out.println("-------------------/goods/alipay2-----------------------");
- //获得初始化的AlipayClient
- AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
- //设置请求参数
- AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
- alipayRequest.setReturnUrl(AlipayConfig.return_url);
- alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
- //商户订单号,商户网站订单系统中唯一订单号,必填
- String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"),"UTF-8");
- //付款金额,必填
- String total_amount = new String(request.getParameter("WIDtotal_amount").getBytes("ISO-8859-1"),"UTF-8");
- //订单名称,必填
- String subject = new String(request.getParameter("WIDsubject").getBytes("ISO-8859-1"),"UTF-8");
- //商品描述,可空
- String body = new String(request.getParameter("WIDbody").getBytes("ISO-8859-1"),"UTF-8");
- alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
- + "\"total_amount\":\""+ total_amount +"\","
- + "\"subject\":\""+ subject +"\","
- + "\"body\":\""+ body +"\","
- + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
- //若想给BizContent增加其他可选请求参数,以增加自定义超时时间参数timeout_express来举例说明
- //alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
- // + "\"total_amount\":\""+ total_amount +"\","
- // + "\"subject\":\""+ subject +"\","
- // + "\"body\":\""+ body +"\","
- // + "\"timeout_express\":\"10m\","
- // + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
- //请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节
- //请求
- String result = alipayClient.pageExecute(alipayRequest).getBody();
- //输出
- System.out.print("trade.page:----" + result);
- return result;
- }
2.处理回调地址:
就是一个请求的处理函数,不清楚他们为什么要在请求后面加一个.action, 反正我没加。。。
3.写处理函数咯:也是把支付宝的jsp中对应的一个粘过来,
- /* *
- * 功能:支付宝服务器同步通知页面
- * 日期:2017-03-30
- * 说明:
- * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
- * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
- *************************页面功能说明*************************
- * 该页面仅做页面展示,业务逻辑处理请勿在该页面执行
- */
- @RequestMapping(value = "/goods/alipayReturnNotice")
- public ModelAndView alipayReturnNotice(
- HttpServletRequest request,
- HttpServletRequest response)
- throws Exception {
- System.out.println("-------------------alipayReturnNotice--------------------------");
- //获取支付宝GET过来反馈信息
- //获取支付宝GET过来反馈信息
- Map<String,String> params = new HashMap<String,String>();
- Map<String,String[]> requestParams = request.getParameterMap();
- for (Iterator<String> 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] + ",";
- }
- //乱码解决,这段代码在出现乱码时使用
- valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
- params.put(name, valueStr);
- }
- boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
- ModelAndView mv = new ModelAndView("/goods/alipaySuccess");
- //——请在这里编写您的程序(以下代码仅作参考)——
- if(signVerified) {
- //商户订单号
- String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
- //支付宝交易号
- String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
- //付款金额
- String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
- mv.addObject("out_trade_no", out_trade_no);
- mv.addObject("trade_no", trade_no);
- mv.addObject("total_amount", total_amount);
- mv.addObject("productName", "name");
- System.out.println("验签成功");
- System.out.println("trade_no:"+trade_no+" out_trade_no:"+out_trade_no+" total_amount:"+total_amount);
- // out.println("trade_no:"+trade_no+"<br/>out_trade_no:"+out_trade_no+"<br/>total_amount:"+total_amount);
- }else {
- // out.println("验签失败");
- System.out.println("验签失败");
- }
- //——请在这里编写您的程序(以上代码仅作参考)——
- return mv;
- }
4.
- /**
- *
- * @Title: AlipayController.java
- * @Package com.sihai.controller
- * @Description: 支付宝异步 通知页面
- * Copyright: Copyright (c) 2017
- * Company:FURUIBOKE.SCIENCE.AND.TECHNOLOGY
- *
- * @author sihai
- * @date 2017年8月23日 下午8:51:13
- * @version V1.0
- */
- @RequestMapping(value = "/goods/alipayNotifyNotice")
- @ResponseBody
- public String alipayNotifyNotice(
- HttpServletRequest request,
- HttpServletRequest response)
- throws Exception {
- /*************************页面功能说明*************************
- * 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。
- * 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
- * 如果没有收到该页面返回的 success
- * 建议该页面只做支付成功的业务逻辑处理,退款的处理请以调用退款查询接口的结果为准。
- */
- System.out.println("-----------------alipayNotifyNotice--------------------------");
- //获取支付宝POST过来反馈信息
- Map<String,String> params = new HashMap<String,String>();
- Map<String,String[]> requestParams = request.getParameterMap();
- for (Iterator<String> 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] + ",";
- }
- //乱码解决,这段代码在出现乱码时使用
- valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
- params.put(name, valueStr);
- }
- boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
- //——请在这里编写您的程序(以下代码仅作参考)——
- /* 实际验证过程建议商户务必添加以下校验:
- 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
- 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
- 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
- 4、验证app_id是否为该商户本身。
- */
- if(signVerified) {//验证成功
- //商户订单号
- String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
- //支付宝交易号
- String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
- //交易状态
- String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
- if(trade_status.equals("TRADE_FINISHED")){
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
- //如果有做过处理,不执行商户的业务程序
- //注意:
- //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
- }else if (trade_status.equals("TRADE_SUCCESS")){
- //判断该笔订单是否在商户网站中已经做过处理
- //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
- //如果有做过处理,不执行商户的业务程序
- //注意:
- //付款完成后,支付宝系统发送该交易状态通知
- }
- System.out.println("success");
- }else {//验证失败
- System.out.println("fail");
- //调试用,写文本函数记录程序运行情况是否正常
- //String sWord = AlipaySignature.getSignCheckContentV1(params);
- //AlipayConfig.logResult(sWord);
- }
- //——请在这里编写您的程序(以上代码仅作参考)——
- return "success";
- }
5.可以了给测试的jsp,和从成功的jsp吧:
alipay.jsp:
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <form name=alipayment action= "${pwd }/goods/alipay2" method=post
- target="_blank">
- <div id="body1" class="show" name="divcontent">
- <dl class="content">
- <dt>商户订单号 :</dt>
- <dd>
- <input id="WIDout_trade_no" name="WIDout_trade_no" />
- </dd>
- <hr class="one_line">
- <dt>订单名称 :</dt>
- <dd>
- <input id="WIDsubject" name="WIDsubject" />
- </dd>
- <hr class="one_line">
- <dt>付款金额 :</dt>
- <dd>
- <input id="WIDtotal_amount" name="WIDtotal_amount" />
- </dd>
- <hr class="one_line">
- <dt>商品描述:</dt>
- <dd>
- <input id="WIDbody" name="WIDbody" />
- </dd>
- <hr class="one_line">
- <dt></dt>
- <dd id="btn-dd">
- <span class="new-btn-login-sp">
- <button class="new-btn-login" type="submit"
- style="text-align: center;">付 款</button>
- </span> <span class="note-help">如果您点击“付款”按钮,即表示您同意该次的执行操作。</span>
- </dd>
- </dl>
- </div>
- </form>
- </body>
- </html>
alipaySuccess.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
- <html>
- <head>
- <title>支付成功!</title>
- </head>
- <body>
- <h1 style="color: green;">购买成功</h1>
- <table>
- <tr>
- <td>
- 订单编号: ${out_trade_no }
- </td>
- </tr>
- <td>
- 支付宝交易号: ${trade_no }
- </td>
- <tr>
- </tr>
- <td>
- 实付金额: ${total_amount }
- </td>
- <tr>
- </tr>
- <td>
- 购买产品:${productName }
- </td>
- </tr>
- </table>
- </body>
- </html>
当然你可以你要写一个跳转,到达支付页面:
好了可以吧:看下框图吧:
好,感觉已经将清楚了,注意复制jsp页面时看清楚导入的包,不出意外,可以成功的。
25-javaweb接入支付宝支付接口的更多相关文章
- thinkphp3.2接入支付宝支付接口(PC端)
下载支付宝接口包 点击这里 提取密码:aryp 整个接口核心类文件 alipay.config.php是相关参数的配置文件 alipayapi.php 是支付宝接口入口文件 not ...
- Android 接入支付宝支付实现
接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...
- Android接入支付宝支付实现
接上篇android接入微信支付文章,这篇我们带你来接入支付宝支付服务 简介 首先要说明的是个人感觉接入支付宝比微信简单多了,很轻松的,所以同学们不要紧张~ 当然还是老规矩啦,上来肯定的贴上官网地址, ...
- python调用支付宝支付接口
python调用支付宝支付接口详细示例—附带Django demo代码 项目演示: 一.输入金额 二.跳转到支付宝付款 三.支付成功 四.跳转回自己网站 在使用支付宝接口的前期准备: 1.支付宝公 ...
- python调用支付宝支付接口详细示例—附带Django demo代码
项目演示: 一.输入金额 二.跳转到支付宝付款 三.支付成功 四.跳转回自己网站 在使用支付宝接口的前期准备: 1.支付宝公钥 2.应用公钥 3.应用私钥 4.APPID 5.Django 1.11. ...
- thinkphp5.0 微信公众号接入支付宝支付
---恢复内容开始--- 真是无力吐槽这个需求了,想骂客户,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内 ...
- 客服端与服务端APP支付宝支付接口联调的那些坑
根据支付宝官方提供的文档的建议: TIPS:这一步应在商户服务端完成,商户服务端直接将组装和签名后的请求串orderString传给客户端,客户端直接传给SDK发起请求.文档和Demo是为了示例效果在 ...
- php 微信公众号接入支付宝支付
真是无力吐槽这个需求了,好端端的非要在微信公众号接入支付宝,都知道微信公众号是拒绝支付宝的,屏蔽了支付宝,所以在微信公众号接入支付宝的话就必须手动复制链接跳出微信内置浏览器,强制性打开web浏览器完成 ...
- ThinkPHP接入支付宝支付功能
最近做系统,需要实现在线支付功能,毫不犹豫,选择的是支付宝的接口支付功能.这里我用的是即时到帐的接口,具体实现的步骤如下: 一.下载支付宝接口包 下载地址:https://b.alipay.com/o ...
随机推荐
- 【Codeforces】CF 911 D. Inversion Counting(逆序对+思维)
题目 传送门:QWQ 分析 思维要求比较高. 首先我们要把原图的逆序对q算出来. 这个树状数组或归并排序都ok(树状数组不用离散化好评) 那么翻转$[l,r]$中的数怎么做呢? 暴力过不了,我试过了. ...
- laravel 5.3 ——路由(资源,别名)
laravel的路由定义中,其中route:resoure(),可以直接定义类似restful风格的URL 例如:Route::resource('system/role','System\RoleC ...
- Lunce编程模型
问题的场景: 解决方案:都是来自于科技论文 ============================================================================== ...
- python中__name__的使用
这几天开始学习Python,遇到一些问题,也解决了一些问题. 其中if __name__ == '__main__':这句估计很多和我一样的初学者都是不求甚解.这里作一下解释: 1:__name__是 ...
- Spring Boot: Cannot determine embedded database driver class for database type NONE
配置启动项时提示如下: 原因是:springboot启动时会自动注入数据源和配置jpa 解决: 1 在@SpringBootApplication中排除其注入 @SpringBootApplicati ...
- openStack 租户控制台修改虚拟机账户密码
- cloud-init方式 该种方式需要虚拟机镜像安装cloud-init,将重置密码脚本注入到虚拟机中.nova boot –image=image-id –nic net-id=net-id – ...
- 代码:css小图标
向下小箭头 .icon-tip{ border-color: transparent transparent #bb0808 transparent; border-style:solid; bord ...
- OpenACC 绘制曼德勃罗集
▶ 书上第四章,用一系列步骤优化曼德勃罗集的计算过程. ● 代码 // constants.h ; ; ; ; const double xmin=-1.7; ; const double ymin= ...
- 编写jQuery插件(一)——插件约定及插件中的闭包
编写插件的目的是给已经有的一系列方法或函数做一个封装,以便在其他地方重复使用,提高开发效率和方便后期维护. 在编写jQuery插件的时候,我们一般会遵循一些约定: jQuery插件推荐命名为:jque ...
- JDK和Tomcat部署时,版本不同的问题解决
问题: 在以Tomcat作为Web容器,启动java Web工程时,遇到下面问题:org.eclipse.jdt.internal.compiler.classfmt.ClassFormatExcep ...