开发支付宝支付接口
使用springboot做一个简单的支付宝扫码支付功能,用的是测试环境下的沙箱环境
首先需要登录支付宝开发平台注册一个自己的账号,并打开沙箱环境配置一些数据


这里进行配置的时候需要进行登录,登录成功后才能继续配置

这里需要下载一个支付宝的插件RSA签名验签工具
生成密钥
不需要改其他的配置,直接点击生成就行,然后复制公钥到开发平台上添加上去



准备工作结束,之后就可以开始做项目并开发接口了
这是支付接口
/**
*@Author XXX
*@Description //TODO Administrator
*@Date 17:05 2019/5/28
*@Param []
*@return java.lang.String
**/
@RequestMapping("dopay")
public void dapay(HttpServletRequest httpRequest, HttpServletResponse httpResponse,String goodsId,int countNum) {
//根据商品id获取到商品的详细信息
//根据商品的价格和订购的总数算出总价
//在订单表中插入一条数据,状态为未支付
String oid = UUID.randomUUID().toString();
AlipayClient alipayClient = new DefaultAlipayClient(alipayUrl,
alipayUtils.APP_ID, alipayUtils.APP_PRIVATE_KEY, "json", "UTF-8", alipayUtils.ALIPAY_PUBLIC_KEY, "RSA2"); //获得初始化的AlipayClient
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
//支付完成后,浏览器跳转的地址
alipayRequest.setReturnUrl("http://www.xuyuanzeng.cn/demo_vuetest/alipay/return.html");
//支付完成后,通知后台是否完成本次支付
alipayRequest.setNotifyUrl("http://www.xuyuanzeng.cn/demo_vuetest/alipay/alipaynotifyUrl");//在公共参数中设置回跳和通知地址
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no",oid);
jsonObject.put("product_code","FAST_INSTANT_TRADE_PAY");
jsonObject.put("total_amount",0.1);
jsonObject.put("subject","我是商品名称");
// alipayRequest.setBizContent("{" +
// " \"out_trade_no\":\"20150320010101001\"," +//商户订单id
// " \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +//销售产品码。
// " \"total_amount\":88.88," +//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
// " \"subject\":\"Iphone6 16G\"," +//订单标题
// " \"body\":\"Iphone6 16G\"," +//商品描述
// " \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
// " \"extend_params\":{" +
// " \"sys_service_provider_id\":\"2088511833207846\"" +
// " }"+
// " }");//填充业务参数
alipayRequest.setBizContent(jsonObject.toString());
String form="";
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
try {
httpResponse.setContentType("text/html;charset=UTF-8");
httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}catch (Exception e){
//写进日志记录
e.printStackTrace();
}
}
这是支付宝开发文档中代码,我只是把它拿到业务场景中来细致化了一点,还有一些更加细腻的判断,日后根据需求自己添加,这里要说的,这段代码中,首先接受的参数有:1.商品ID 2.购买的数量,需要注意的是,不能够将商品的价格也当做参数传递过来,这是为了防止某些黑客抓取到具体的价格参数后,进行修改,来达到一些不法的目的,以后做的所有的支付方面的东西,价格一类敏感的数据都只能去后台获取,而不能从前台传递
这里简单说下需要给支付宝传递的参数:
- alipayUrl:https://openapi.alipaydev.com/gateway.do 这是支付宝提供的请求地址,这是测试环境下的地址
- APP_ID:2014072300007148 支付宝分配给开发者的应用ID
- APP_PRIVATE_KEY:xxxxxx…xxxx 开发者私钥
- json 数据格式
- charset:编码格式
- ALIPAY_PUBLIC_KEY:xxxxxx…xxxx 支付宝提供的公钥,并不是应用公钥
- sign_type:RSA2 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
- returnUrl:http://www.xuyuanzeng.cn/demo_vuetest/alipay/return.html 支付完成后,浏览器跳转的地址
- alipaynotifyUrl:http://www.xuyuanzeng.cn/demo_vuetest/alipay/alipaynotifyUrl 支付完成后,通知后台是否完成本次支付
参数设置完成后,当用户点击支付的时候,后台调用这个dopay方法去请求支付宝的服务端并将一些具体的商品信息携带上,并生成html信息发送给前台,让用户确认输入支付密码,支付密码确认以后,返回后台系统,这时候支付宝就会通过我们之前提到的alipaynotifyUrl设置好的地址返回给我们支付消息。
下面是接受通知的代码
/**
*@Author XXX
*@Description //TODO Administrator
*@Date 21:36 2019/5/28
*@Param [request]
*@return java.lang.String
* 支付宝回调时返回的参数,需要将其转化成json数据
**/
@RequestMapping("alipaynotifyUrl")
public String alipaynotifyUrl(HttpServletRequest request){
try {
InputStream inStream = request.getInputStream();
//把消息流转换成文本类型
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
String result = new String(outSteam.toByteArray(), "UTF-8");
System.out.println("result==="+result);
JSONObject jsonObject = JSONObject.fromObject(result);
JSONObject alipayResponse = (JSONObject) jsonObject.get("alipay_trade_page_pay_response");
String trade_no = (String) alipayResponse.get("trade_no");//订单ID
String total_amount = (String) alipayResponse.get("total_amount");//价格
String msg = (String) alipayResponse.get("msg");//返回的状态
//判断返回状态是否成功
//拿着订单号往数据库查询,查询回来订单表数据后,比较价格是否一致,如果一致,说明支付没有问题
//更新订单表的状态,更改为已支付,更改物流表状态,往物流表插入数据,开始发货
}catch (Exception e){
}
return "";
}
判断返回来的msg是否==success,如果相同证明支付成功,则进行下面的判断,判断支付金额与数据库中的数据是否相同,相同的话,更新订单表状态,并开始发货,并且返回给前台提示操作是否完成。到这里支付基本完成,不过在验证这里还需要注意的一点是,要考虑到支付的一些并发情况,如支付的幂等性。
什么是支付的幂等性?
1)用户多次请求造成出现多个订单
2)支付完成后,被拦截或网络不好,造成收不到回调通知或是收到了回调通知,但是这个回调通知的金额和支付信息不匹配,说明数据有问题
如何保证支付的幂等性呢,有很多的办法,这里采用一种很简单的方法:
(1)提交时的幂等性,做个token拦截,防止用户重复提交
①cookie和redis中放一个都放一个token
②提交到后台后,获取cookie中的token,比较redis当中的token,把token删除掉,防止用户重复提交
(2)支付宝通知时防止的幂等性
①根据支付宝自己提供的校验,把返回来的参数进行校验
具体实施步骤:采用异步通知的办法
Map<String, String> paramsMap = ... //将异步通知中收到的所有参数都存放到map中
boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE) //调用SDK验证签名
if(signVerfied){
// TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
}else{
// TODO 验签失败则记录异常日志,并在response中返回failure.
异步验证的流程(开发文档上介绍的很详细,具体还看自己的需求)
商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。注意:状态TRADE_SUCCESS的通知触发条件是商户签约的产品支持退款功能的前提下,买家付款成功;交易状态TRADE_FINISHED的通知触发条件是商户签约的产品不支持退款功能的前提下,买家付款成功;或者,商户签约的产品支持退款功能的前提下,交易已经成功并且已经超过可退款期限。

本文介绍使用Spring Boot开发支付宝测试环境下的扫码支付接口。先在支付宝开发平台注册账号、配置沙箱环境,生成密钥。开发接口时,注意价格等敏感数据从后台获取。支付完成后,通过异步通知判断支付结果。同时,还提到了支付幂等性问题及解决办法。
9550

被折叠的 条评论
为什么被折叠?



