最近本人刚做了手机APP支付宝支付功能,主要分为六步,在这里主要记录代码部分。
第一步:创建应用并获取APPID
要在您的应用中接入支付宝App支付能力,需要通过创建应用的方式接入蚂蚁相关接口并进行开发,基于对行业及业务场景痛点的理解,创造能够满足市场需要的解决方案,以应用的形式服务用户。
若还未成为开放平台的入驻服务商或者商户, 请完成入驻指引。入驻完成后,您需要去蚂蚁金服开放平台(open.alipay.com),在开发者中心中创建您的应用,会为您生成应用唯一标识(APPID),并且可以申请开通开放产品使用权限,通过APPID您的应用才能调用开放产品的接口能力。需要详细了解开放平台创建应用步骤请参考《开放平台应用创建指南》。
在创建应用后即生成应用的标识APPID,使用支付宝账号登录开放平台后,在“我的应用”中按下图方式查看APPID。
第二步:配置应用
应用创建完成后,需要给应用添加App支付功能,这样就可以在你的应用里使用App支付能力。此时该应用为开发中状态,只能在沙箱环境下进行调试。应用开发完成后,请开发者自行进行验收和安全性检查(安全性检查可参考《开放平台第三方应用安全开发指南》),验收检查完成后可申请上线。应用申请上线后,会同时申请此列表的功能,接口即生效,这个状态下的应用能够调用生产环境的接口。
签约
在使用这些能力的时候,需要在开放平台里进行签约,这时候约定的合同就生效了。也可以代替商户签约。
配置密钥
为了保证交易双方(商户和支付宝)的身份和数据安全,开发者在调用接口前,需要配置双方密钥,对交易数据进行双方校验。
1、了解下支付宝密钥处理体系:
2、密钥包含:
应用公钥:由商户自己生成的RSA公钥(与应用私钥必须匹配),商户需上传应用公钥到支付宝开放平台,以便支付宝使用该公钥验证该交易是否是商户发起的。
应用私钥:由商户自己生成的RSA私钥(与应用公钥必须匹配),商户开发者使用应用私钥对请求字符串进行加签。
支付宝公钥:支付宝的RSA公钥,商户使用该公钥验证该结果是否是支付宝返回的。
生成密钥后在开放平台开发者中心进行密钥配置,配置完成后可以获取支付宝公钥。具体方法流程请参见上传应用公钥并获取支付宝公钥。
3、配置生成的密钥等应用信息。配置的详细步骤请参考《配置应用环境》。
注:签名验签常见问题排查
支付宝开放平台SDK封装了签名和验签过程,只需配置账号及密钥参数,强烈建议使用。更多签名问题的自助排查流程,可以参考支付宝验签专区的未使用开放平台SDK的自助排查流程。关于同步通知和异步通知的验签规则,可参考验签教程。
更多关于签名教程和签名工具下载等问题,请参见签名专区。
第三步:集成和开发
接入移动支付需要集成两个SDK,客户端SDK需要集成在商户自己的APP中,用于唤起支付宝APP并发送交易数据,并在支付宝APP返回商户APP时获得支付结果。服务端SDK需要商户集成在自己的服务端系统中,用于协助解析并验证客户端同步返回的支付结果和异步通知。
第四步:调用接口
为了避免在线上生产环境联调过程中遇到问题,建议在沙箱环境中联调通过后再在线上生产环境进行联调,具体操作步骤见沙箱联调指南。如果需要在线上调用接口,需要参考下面第六步:应用上线后再进行接口调用,不然会报出“无权限错误”。
系统交互流程:
如图,以Android平台为例:
图中虚线标识商户链路,实线标识支付宝链路。
第4步:调用支付接口:此消息就是本接口所描述的支付宝客户端SDK提供的支付对象PayTask,将商户签名后的订单信息传进payv2方法唤起支付宝收银台,交易数据格式具体参见请求参数说明。
第5步:支付请求:支付宝客户端SDK将会按照商户客户端提供的请求参数发送支付请求。
第8步:接口返回支付结果:商户客户端在第4步中调用的支付接口,会返回最终的支付结果(即同步通知),参见客户端同步返回。
第13步:用户在支付宝APP或H5收银台完成支付后,会根据商户在手机网站支付API中传入的前台回跳地址return_url自动跳转回商户页面,同时在URL请求中附带上支付结果参数。同时,支付宝还会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统,详情见支付结果异步通知。
除了正向支付流程外,支付宝也提供交易查询、关闭、退款、退款查询以及对账等配套API。
特别注意:
- 构造交易数据并签名必须在商户服务端完成,商户的应用私钥绝对不能保存在商户APP客户端中,也不能从服务端下发。
- 同步返回的数据,只是一个简单的结果通知,商户确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断。
- 商户系统接收到通知以后,必须通过验签(验证通知中的sign参数)来确保支付通知是由支付宝发送的。建议使用支付宝提供的SDK来完成,详细验签规则参考异步通知验签。
使用SDK快速接入
App支付API必须通过支付宝提供的移动端SDK来调用。
交易操作
以下大致记录针对alipay.trade.app.pay接口的相关代码:
1.APP客户端调用应用服务端,应用服务端通过alipay.trade.app.pay接口传入订单参数,将alipay.trade.app.pay接口返回的AlipayTradeAppPayResponse返回给APP客户端,由APP唤起支付宝客户端。
package com.lvqutour.service.aliService.impl;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.lvqutour.api.LvQuResult;
import com.lvqutour.mapper.AlipayFeedbackMapper;
import com.lvqutour.pojo.AlipayFeedback;
import com.lvqutour.result.AlipayResultInfo;
import com.lvqutour.service.aliService.IAliPayService;
import com.lvqutour.service.aliService.IAliResultComparisonService;
import com.lvqutour.utils.payLogUtil.MdcPut;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
/**
* Created with IntelliJ IDEA.
* Date: 2018/3/13 17:04
* User: pc
* Description:
*/
public class AliPayServiceImpl implements IAliPayService {
static Logger logger = Logger.getLogger(AliPayImpl.class);
@Autowired
private AlipayFeedbackMapper alipayFeedbackMapper;
@Autowired
IAliResultComparisonService aliResultComparison;
//正式环境
//appid
public static String APP_ID="2017112000054898";
//pkcs8的私钥
public static String APP_PRIVATE_KEY="WXMMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGyZ8uny8HuYqyff5e4AgIVJZYaUndxDKWF18DnfcliR0xO941P2OXtNh/vSxrq8ifv4EdoTBI1QLOXA3LtfHgXIMUCWAYJn+bf1I5u/UKe3SMhYmEPX74qQNceqG3Wa5MB6/6XvzXK1fajCgAV6zhtCw13kqcJ9ayIWVcB4jnjBsGpyL6Fok3CJl2CwgWm5eT1NL/jShHHjnWmA5bjMOZbSr1wYMthxZUeL3A8QBd4KOoFq7Uge6qlrv1uagIA45l69TttSQYJUaYMfwLgyZnOr9KkImTVdSxnsmkAYoIEVEn3qj+vaEKVOB+9vGKG1yAP3zX7D5H4q2d/9WWti4dAgMBAAECggEAbyRh9fecuCnujDAISANDnFrjfhOTrSHS9KBg4IKpAHKHd8l9+TpDzRx6SRqcPkxwKgmnVd9MCUJcBf0yAwAMaozeKO9yJXfZUUczbhfmfrY97IFQW5K52CDFfMRCBQYWCutr2G/q3SIIV1Wqxl2FWLdQnTqnGwxepJOVGMW9xe8tPmQlOXWU8F9EpGSlixlhZPPhJTEw7Gj/jCohpyxnqe7K38PJGmpEwH33rKc76bnOVtYBxLUxs740bnytv/bNvGB81u8MsRX/qPb7T9KIn5zzdxjFjULW/crNqWi6zlAdmAjvafbu+TEaD8Q4JsQCrkFdArStTJn/zngb5M+JAQKBgQDvU7Wdw42QgiJcdQQ7iAAe+/adpPv+vbADut5i/qEL+FORBBmVIN1CqyzELn0zimRbW5F8LttuiC2WnIMk1VcdMRr/pdp1KesOW1Etg13tiiQfE6VAwg87CjEyohFxXzpRR4ayOd+TVm05/bnB15frQYQS/L2vi/MRUIOC9HGV5QKBgQCQLX+exHyzP+OGF3S7Rt8sWcQufTuFo9YSFLTKeI64ssSJKXxhkhX0DQfyjG6HlQpmKMzIta+kNW+Wc4vzu4oBA3stn5HALGexjcIz879jc11nib5kMGXFHq8jBSq0T4Ax5pqNlrc0KyGUsFD4Ka63ARdM4giLxaQikpLmEjOz2QKBgQC6vNY5AxyyZNfqzGNBEB0IEBGdb94wJlHwlx5un7+JV3nc7RYJBlueaXHEoYGPdaxYnFooS2dsF1V67yRk2RHf9TDbyM1sHgkKarYsjRP9BIyqsul+Xe0EZC9/EnYJwAQA545yAjYxAH65gQAv/8jKB5TGO+7Fyq0eFXSH+bOnAQKBgEae0qUM71vJjoOu15Gn7EbIDW0MEGysTH38wHVwSdA0WEorFO6h5Lju7RakLLuiiD5z+6LQQ6E2P1s9a67ODJHkh6BYSccMuRniKt7RpMxsxLKjaKugfSjpl7WaoUlCq7NFliyGR2R5P/CZ0H9Nw3OGSEhzauYzv+rjSqsA/Ww5AoGAYE91J5oxiTkFYE09fyAKWpq+hGH1a4i0+EwU71R71zWUFGX4kerVyQRStzIRlHWV1CSOZoT4Wt8PeWMRMLhsvRo9S9cVc0pUSPAwNMfcyWdBj2Ytl+jakH1HuRuBCGXnA+Lv+Kyvd6XL02EOE4XRpJmhJng+Rma43SvhyUCxCm8=";
//支付宝公钥
public static String ALIPAY_PUBLIC_KEY="WXMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkonhwBFgSsQu9omd4q0JE4JgVeJc321yo8it27L2ZdJ9qdRUqR9Me6pgc1lYPbUuRycmFSPY8mjSyNhavVxK5G7+9zIFfaIzC0bBSFVnrRL3JbI8gyLaRzh9cT8Hpp0bYUCbZzpdZ8tKP2eMc2HoynVR9lwX/hZrijYwlWGXbxYif1TMRIZEpPDTfw+4KbJ4I1rBx6qDf4jZLVnKuP11meAoR8VvrkF+Le717prWoleXp0yHUF2SoDzKh3OPEqZKKECe5Mr30BnFUCcLhSaxhbkMtAje9MPvsVSniAldGeZqwMzG3SvkauoB/AYWhrTN7NH1fapvN/f/lUPlgnuV7wIDAQAB";
//签名方式
public static String sign_type="RSA2";
//编码格式
public static String CHARSET="utf-8";
//正式环境支付宝网关
public static String url="https://openapi.alipay.com/gateway.do";
//实例化客户端
AlipayClient alipayClient = new DefaultAlipayClient(url, APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY,sign_type);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//调用支付宝客户端
@Override
public LvQuResult alipay(String body, String subject, String totalAmount, int userId, int member_id, String outTradeNo) {
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody(body);//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body
model.setSubject(subject);//商品的标题/交易标题/订单标题/订单关键字等
model.setTotalAmount(totalAmount);//订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
model.setProductCode("QUICK_MSECURITY_PAY");//销售产品码,商家和支付宝签约的产品码
model.setOutTradeNo(outTradeNo);//商户网站唯一订单号,请保证OutTradeNo值每次保证唯一
model.setTimeoutExpress("30m");//该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
request.setBizModel(model);
request.setNotifyUrl("http://www.lvqutour.com:8081/lvqutour/notify/aliPaynotify_url.jsp");//商户外网可以访问的异步地址
AlipayTradeAppPayResponse response;
try {
response = alipayClient.sdkExecute(request);//这里和普通的接口调用不同,使用的是sdkExecute
return LvQuResult.ok(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
} catch (AlipayApiException e) {
e.printStackTrace();
String massage = "alipay.trade.app.pay接口:订单签名错误";
MdcPut.mdcPut(outTradeNo,new Date(),massage);
logger.error("订单号:" + outTradeNo + massage);
return LvQuResult.msg(false, "订单号:" + outTradeNo + massage);
}
}
}
2.支付宝客户端支付后,支付宝服务端会发起异步通知到应用服务端(http://www.lvqutour.com:8081/lvqutour/notify/aliPaynotify_url.jsp),服务端进行解签校验,确认支付状态。应用服务端回调页代码如下:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.alipay.api.*"%>
<%@ page import="com.alipay.api.internal.util.*"%>
<%@ page import="org.springframework.web.context.support.WebApplicationContextUtils" %>
<%@ page import="org.springframework.web.context.WebApplicationContext" %>
<%@ page import="com.alibaba.druid.support.json.JSONUtils" %>
<%@ page import="org.apache.commons.logging.Log" %>
<%@ page import="org.apache.commons.logging.LogFactory" %>
<%@ page import="com.lvqutour.utils.payLogUtil.MdcPut" %>
<%@ page import="com.lvqutour.pojo.*" %>
<%@ page import="com.lvqutour.mapper.*" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%
/* *
* 功能:支付宝服务器异步通知页面
* 日期:2017-03-30
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*************************页面功能说明*************************
* 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。
* 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
* 如果没有收到该页面返回的 success
* 建议该页面只做支付成功的业务逻辑处理,退款的处理请以调用退款查询接口的结果为准。
*/
Log log= LogFactory.getLog("aliPaynotify_url.jsp");
//正式环境支付宝公钥
String ALIPAY_PUBLIC_KEY="WXMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkonhwBFgSsQu9omd4q0JE4JgVeJc321yo8it27L2ZdJ9qdRUqR9Me6pgc1lYPbUuRycmFSPY8mjSyNhavVxK5G7+9zIFfaIzC0bBSFVnrRL3JbI8gyLaRzh9cT8Hpp0bYUCbZzpdZ8tKP2eMc2HoynVR9lwX/hZrijYwlWGXbxYif1TMRIZEpPDTfw+4KbJ4I1rBx6qDf4jZLVnKuP11meAoR8VvrkF+Le717prWoleXp0yHUF2SoDzKh3OPEqZKKECe5Mr30BnFUCcLhSaxhbkMtAje9MPvsVSniAldGeZqwMzG3SvkauoB/AYWhrTN7NH1fapvN/f/lUPlgnuV7wIDAQAB";
//编码格式
String CHARSET="utf-8";
WebApplicationContext context=WebApplicationContextUtils.getWebApplicationContext(this.getServletConfig().getServletContext());
OrderMapper orderMapper = (OrderMapper)context.getBean("orderMapper");
AlipayFeedbackMapper alipayFeedbackMapper = (AlipayFeedbackMapper)context.getBean("alipayFeedbackMapper");
MemberMapper memberMapper = (MemberMapper)context.getBean("memberMapper");
MemberTypeMapper memberTypeMapper = (MemberTypeMapper)context.getBean("memberTypeMapper");
NotificationMapper notificationMapper = (NotificationMapper)context.getBean("notificationMapper");
//解签结果
boolean signVerified;
//异步通知解签结果
boolean result = true;
//异步通知的验证结果
boolean verificationResult = false;
//异步通知存入数据库结果
boolean insertResult = false;
//用户
int userId = 1;
//会员类型(会员表)
byte memberTypeId = 1;
//该笔订单
Order order = null;
//商户订单号、商户金额、卖家支付宝用户号、商户本身appid
String out_trade_no = request.getParameter("out_trade_no");
String total_amount = request.getParameter("total_amount");
String seller_id = request.getParameter("seller_id");
String app_id = request.getParameter("app_id");
//request转换为Map
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator 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] + ",";
}
params.put(name, valueStr);
}
/*实际验证过程建议商户务必添加以下校验:
1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
4、验证app_id是否为该商户本身。*/
try {
signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET,"RSA2");
if(signVerified) {//解签成功
AlipayFeedback alipayFeedback = new AlipayFeedback();
OrderExample orderExample = new OrderExample();
orderExample.createCriteria().andOrderNumEqualTo(out_trade_no);
order = orderMapper.selectByExample(orderExample).get(0);
if(order != null && order.getPrice() == Double.valueOf(total_amount).doubleValue() && seller_id.equals("2088821541811607") && app_id.equals("2017112000054898")){
//将异步通知获得到的Map转换成String,并存入数据库
String notification = JSONUtils.toJSONString(params);
String id = params.get("out_trade_no");
alipayFeedback.setOutTradeNo(id);
alipayFeedback.setNotification(notification);
if(alipayFeedbackMapper.insertSelective(alipayFeedback) != 1){
insertResult = false;
//记录日志---"支付宝服务端异步通知数据存储异常";
MdcPut.mdcPut(out_trade_no,new Date(),"支付宝服务端异步通知数据存储异常");
log.error("订单号:" + out_trade_no + "支付宝服务端异步通知数据存储异常");
}else{
insertResult = true;
}
verificationResult = true;
//insertResult/verificationResult/result均为true,再为userId和memberTypeId赋值
userId = order.getUserId();
memberTypeId = order.getMemberId().byteValue();
}else{
verificationResult = false;
//记录日志---"支付宝服务端异步通知数据与商户系统中数据不匹配,或商户系统数据查询出现异常");
MdcPut.mdcPut(out_trade_no,new Date(),"支付宝服务端异步通知数据与商户系统中数据不匹配,或商户系统数据查询出现异常");
log.error("订单号:" + out_trade_no + "支付宝服务端异步通知数据与商户系统中数据不匹配,或商户系统数据查询出现异常");
}
}else {//解签失败
result = false;
//记录日志---"解签失败";
MdcPut.mdcPut(out_trade_no,new Date(),"解签失败");
log.error("订单号:" + out_trade_no + "解签失败");
}
} catch (AlipayApiException e) {
result = false;
e.printStackTrace();
}
//根据回调数据结果,插入购买的会员信息
if(result && verificationResult & insertResult) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
order.setPayType(1);
order.setState((byte) 3);
order.setUpdateTime(new Date());
if (orderMapper.updateByPrimaryKeySelective(order) != 0){
Member member = new Member();
Date beginTime;
Date overTime;
//查询是否已经是会员
MemberExample memberExample = new MemberExample();
memberExample.createCriteria().andUserIdEqualTo(userId);
List<Member> members = memberMapper.selectByExample(memberExample);
if (members.size() != 0) { //已经是会员
member = members.get(0);
member.setUpdateTime(new Date());
beginTime = member.getOverTime();
//使用Calendar类的add方法进行年度和月度的推进
Calendar calendar = Calendar.getInstance();
calendar.setTime(beginTime);
if (memberTypeId == 2) {
calendar.add(Calendar.YEAR, +1);//日期加1年
overTime = calendar.getTime();
member.setOverTime(overTime);
} else if (memberTypeId == 1) {
calendar.add(Calendar.MONTH, +1);//日期加1个月
overTime = calendar.getTime();
member.setOverTime(overTime);
}
if (memberMapper.updateByPrimaryKeySelective(member) != 0) {
//记录日志---"会员购买成功");
MdcPut.mdcPut(out_trade_no, new Date(), "会员购买成功");
log.error("订单号:" + out_trade_no + "会员购买成功");
MemberType memberType = memberTypeMapper.selectByPrimaryKey(order.getMemberId());
Notification notification = new Notification();
notification.setUserId(userId);
notification.setNotification("尊敬的用户,你在"+order.getUpdateTime()+"购买的"+memberType.getName()+",购买成功!VIP有效日期截止至:"+simpleDateFormat.format(member.getOverTime()));
notification.setCreateTime(order.getUpdateTime());
notification.setIsRead(0);
notificationMapper.insertSelective(notification);
out.print("success");
} else {
//记录日志---"会员购买失败");
MdcPut.mdcPut(out_trade_no, new Date(), "会员购买失败,原因:会员信息存入数据库失败!");
log.error("订单号:" + out_trade_no + "会员购买失败,原因:会员信息存入数据库失败!");
}
} else { //不是会员
beginTime = new Date();
//使用Calendar类的add方法进行年度和月度的推进
Calendar calendar = Calendar.getInstance();
calendar.setTime(beginTime);
member.setUserId(userId);
member.setMemberTypeId(memberTypeId);
member.setBeginTime(beginTime);
member.setCreateTime(new Date());
if (memberTypeId == 2) {
calendar.add(Calendar.YEAR, +1);//日期加1年
overTime = calendar.getTime();
member.setOverTime(overTime);
} else if (memberTypeId == 1) {
calendar.add(Calendar.MONTH, +1);//日期加1个月
overTime = calendar.getTime();
member.setOverTime(overTime);
}
if (memberMapper.insertSelective(member) != 0) {
//记录日志---"会员购买成功";
MdcPut.mdcPut(out_trade_no, new Date(), "会员购买成功");
log.error("订单号:" + out_trade_no + "会员购买成功");
MemberType memberType = memberTypeMapper.selectByPrimaryKey(order.getMemberId());
Notification notification = new Notification();
notification.setUserId(userId);
notification.setNotification("尊敬的用户,你在"+order.getUpdateTime()+"购买的"+memberType.getName()+",购买成功!VIP有效日期截止至:"+simpleDateFormat.format(member.getOverTime()));
notification.setCreateTime(order.getUpdateTime());
notification.setIsRead(0);
notificationMapper.insertSelective(notification);
out.print("success");
} else {
//记录日志---"会员购买失败");
MdcPut.mdcPut(out_trade_no, new Date(), "会员购买失败,原因:会员信息存入数据库失败!");
log.error("订单号:" + out_trade_no + "会员购买失败,原因:会员信息存入数据库失败!");
}
}
}else{
//记录日志---"订单状态修改失败");
MdcPut.mdcPut(out_trade_no, new Date(), "订单状态修改失败,数据库通讯异常");
log.error("订单号:" + out_trade_no + "订单状态修改失败,数据库通讯异常");
}
}else{
//记录日志---"会员信息存入数据库失败");
MdcPut.mdcPut(out_trade_no,new Date(),"验证异常或数据库通讯失败");
log.error("订单号:" + out_trade_no + "验证异常或数据库通讯失败");
out.print("fail");
}
%>
3.支付宝支付完成后,APP客户端携带支付宝返回的数据,再次请求应用服务端,应用服务端将此数据与支付宝的异步通知数据进行对比,返回给APP客户端最终的支付状态:
//将异步通知从数据库取出与客户端返回的请求数据做比较
@Override
public Boolean getClientFeedback(AlipayResultInfo alipayResultInfo) {
String out_trade_no = alipayResultInfo.getAlipay_trade_app_pay_response().getOut_trade_no();
Boolean result;
//将异步通知从数据库取出
AlipayFeedback alipayFeedback;
alipayFeedback = alipayFeedbackMapper.selectByPrimaryKey(out_trade_no);
if(alipayFeedback == null){
MdcPut.mdcPut(out_trade_no, new Date(), "appFeedback的值为空");
logger.error("从数据库取出的appFeedback的值为空");
result = false;
}else{
result = aliResultComparison.comparison(alipayFeedback,alipayResultInfo);
}
return result;
}
}
其中aliResultComparison.comparison(alipayFeedback,alipayResultInfo)方法代码如下:
//APP客户端返回信息与支付宝服务端返回信息对比
@Override
public Boolean comparison(AlipayFeedback alipayFeedback, AlipayResultInfo alipayResultInfo) {
Boolean result = false;
String app_id = alipayResultInfo.getAlipay_trade_app_pay_response().getApp_id();
String total_amount = alipayResultInfo.getAlipay_trade_app_pay_response().getTotal_amount();
String seller_id = alipayResultInfo.getAlipay_trade_app_pay_response().getSeller_id();
String trade_no = alipayResultInfo.getAlipay_trade_app_pay_response().getTrade_no();
Map alipayFeedbackMap = JSON.parseObject(alipayFeedback.getNotification());
if (alipayFeedbackMap.get("trade_no").equals(trade_no) && alipayFeedbackMap.get("total_amount").equals(total_amount) && alipayFeedbackMap.get("app_id").equals(app_id) && alipayFeedbackMap.get("seller_id").equals(seller_id)) {
if (alipayFeedbackMap.get("trade_status").equals("TRADE_FINISHED")) {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
result = false;
} else if (alipayFeedbackMap.get("trade_status").equals("TRADE_SUCCESS")) {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
//注意:
//付款完成后,支付宝系统发送该交易状态通知
/*int payResult = orderMapper.updateByPrimaryKeySelective(order);
if(payResult == 1){
result = true;
//记录日志
}else{
result = false;
//记录日志
}*/
result = true;
}
}
return result;
}
具体可参见蚂蚁金服开放平台文档中心快速接入
第五步:调试应用
支付能力直接涉及到交易与资金,为了方便开放者调试支付能力,我们已经准备好沙箱环境,包括沙箱环境账号和沙箱版支付宝钱包,这样就可以在沙箱环境调试了。具体操作步骤见沙箱联调指南。
第六步:上线应用
商户本身应用上线时候,也要把支付宝开放平台的应用上线。