支付宝支付相比于微信支付要简单点,支付流程如下所示,之前介绍过微信支付(一)、(二)、(三),在此基础上继续完善支付宝支付。
一、前期准备工作
首先根据支付宝官方文档拿到一些参数,主要是APPID,商户应用私钥和公钥,支付宝公钥,授权回调地址。
这里对于准备工作省略!
二、Springboot后端
导入依赖
<!--支付宝支付SDK-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.21.10.ALL</version>
</dependency>
WxPayController
/**
* 支付宝下单
* @return
* @throws Exception
*/
@ApiOperation("调用统一下单API,生成支付宝下单的请求")
@PostMapping("/alipay/order")
public R AliPay() throws Exception {
log.info("发起支付宝支付请求 Alipay");
//返回支付所需要的参数给Android端
String resultdata = wxPayService.aliPay();
log.info("map====>{}",resultdata);
return R.ok().data("result",resultdata);
}
/**
* 支付宝支付通知
* 微信支付通过支付通知接口将用户支付成功消息通知给商户
*/
@ApiOperation("支付通知")
@PostMapping("/app/alinotify")
public String AliNotify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
//获取支付宝POST过来反馈信息
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] + ",";
}
//乱码解决,这段代码在出现乱码时使用。
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//异步验签:切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
//公钥证书模式验签,alipayPublicCertPath是支付宝公钥证书引用路径地址,需在对应应用中下载
//boolean signVerified= AlipaySignature.rsaCertCheckV1(params, alipayPublicCertPath, "GBK","RSA2");
//普通公钥模式验签,切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
boolean flag = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, "UTF-8","RSA2");
/* 实际验证过程建议商户务必添加以下校验:
1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
4、验证app_id是否为该商户本身。
*/
if(flag) {//验证成功
//商户订单号
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");
}
return null;
}
/**
* 支付宝查单
* @param orderNo
* @param
* @return
* @throws Exception
*/
@ApiOperation("支付宝查单")
@GetMapping("/queryali/{orderNo}")//也可以用微信的订单号查询
public R queryAliOrder(@PathVariable String orderNo) throws Exception {
log.info("查询支付宝订单");
String result = wxPayService.queryAliOrder(orderNo);
return R.ok().setMessage("查询成功").data("result", result);
}
WxPayService
/**
* 支付宝支付
* @return
*/
String aliPay() throws AlipayApiException;
/**
* 支付宝查单
* @param orderNo
* @param
* @return
*/
String queryAliOrder(String orderNo) throws AlipayApiException;
WxPayServiceImpl
/**
* 支付宝支付
* @return
*/
@Override
public String aliPay() throws AlipayApiException {
/** 支付宝网关 **/
String URL = "https://openapi.alipay.com/gateway.do";
/** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
String APP_ID = "写自己的";
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
String APP_PRIVATE_KEY = "写自己的";
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
String ALIPAY_PUBLIC_KEY = "写自己的";
/** 初始化 **/
AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,"json","UTF-8",ALIPAY_PUBLIC_KEY,"RSA2");
/** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称: alipay.trade.app.pay(app 支付接口) **/
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
/** 设置业务参数 **/
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
/** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
model.setOutTradeNo(OrderNoUtils.getOrderNo());
/** 订单标题 **/
model.setSubject("whq烤肉byali");
/** 销售产品码,固定值:QUICK_MSECURITY_PAY **/
model.setProductCode("QUICK_MSECURITY_PAY");
/** 订单金额,精确到小数点后两位 **/
model.setTotalAmount("0.01");
/** 订单描述 **/
model.setBody("订单描述");
/** 业务扩展参数 **/
//ExtendParams extendParams = new ExtendParams();
/** 花呗分期参数传值前提:必须有该接口花呗收款准入条件,且需签约花呗分期 **/
/** 指定可选期数,只支持3/6/12期,还款期数越长手续费越高 **/
// extendParams.setHbFqNum("3");
/** 指定花呗分期手续费承担方式,手续费可以由用户全承担(该值为0),也可以商户全承担(该值为100),但不可以共同承担,即不可取0和100外的其他值。 **/
//extendParams.setHbFqSellerPercent("0");
//model.setExtendParams(extendParams);
/** 将业务参数传至request中 **/
request.setBizModel(model);
/** 异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
request.setNotifyUrl("写自己的");
/**第三方调用(服务商模式),传值app_auth_token后,会收款至授权token对应商家账号,如何获传值app_auth_token请参考文档:https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
//request.putOtherTextParam("app_auth_token", "传入获取到的app_auth_token值");
AlipayTradeAppPayResponse response = null;
try {
/** 通过alipayClient调用API,获得对应的response类 **/
response = alipayClient.sdkExecute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
}
/** response.getBody()打印结果就是orderString,可以直接给客户端请求,无需再做处理。 如果传值客户端失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/89 **/
System.out.println(response.getBody());
return response.getBody();
}
/**
* 支付宝查单
* @param orderNo
* @param
* @return
*/
@Override
public String queryAliOrder(String orderNo) throws AlipayApiException {
/** 支付宝网关 **/
String URL = "https://openapi.alipay.com/gateway.do";
String APP_ID = "写自己的";
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
String APP_PRIVATE_KEY = "写自己的";
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
String ALIPAY_PUBLIC_KEY = "写自己的";
AlipayClient alipayClient = new DefaultAlipayClient(URL ,APP_ID ,APP_PRIVATE_KEY,"json","UTF-8",ALIPAY_PUBLIC_KEY,"RSA2");
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", orderNo);
//bizContent.put("trade_no", "2014112611001004680073956707");
request.setBizContent(bizContent.toString());
AlipayTradeQueryResponse response = alipayClient.execute(request);
log.info("明文数据 ===> {}", response.getBody());
if(response.isSuccess()){
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
return response.getBody();
}
在这里也可以将申请到的参数放在配置文件中,我测试时直接写在代码中了。
三、Android端
Android端按照文档导入SDK。下面直接放代码
PayResult
public class PayResult {
private String resultStatus;
private String result;
private String memo;
public PayResult(Map<String, String> rawResult) {
if (rawResult == null) {
return;
}
for (String key : rawResult.keySet()) {
if (TextUtils.equals(key, "resultStatus")) {
resultStatus = rawResult.get(key);
} else if (TextUtils.equals(key, "result")) {
result = rawResult.get(key);
} else if (TextUtils.equals(key, "memo")) {
memo = rawResult.get(key);
}
}
}
@Override
public String toString() {
return "resultStatus={" + resultStatus + "};memo={" + memo
+ "};result={" + result + "}";
}
/**
* @return the resultStatus
*/
public String getResultStatus() {
return resultStatus;
}
/**
* @return the memo
*/
public String getMemo() {
return memo;
}
/**
* @return the result
*/
public String getResult() {
return result;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WeChatPay">
<Button
android:id="@+id/wechatpay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微信支付"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.322" />
<Button
android:id="@+id/aliPay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="支付宝支付"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/wechatpay"
app:layout_constraintVertical_bias="0.197" />
</android.support.constraint.ConstraintLayout>
WeChatPay
public class WeChatPay extends AppCompatActivity {
private Button wechatpay;
private Button Alipay;
// private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
private IWXAPI msgApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_we_chat_pay);
wechatpay = findViewById(R.id.wechatpay);
Alipay = findViewById(R.id.aliPay);
//初始化操作
msgApi = WXAPIFactory.createWXAPI(this, null);
msgApi.registerApp(Constants.APP_ID);
wechatpay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getWeChatPayData();
}
});
Alipay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getAliPayData();
}
});
}
private void getWeChatPayData(){
new Thread(new Runnable() {
@Override
public void run() {
MediaType JSON = MediaType.parse("application/json;charset=utf-8");
JSONObject jsonObject = new JSONObject();
//创建OkHttp对象
OkHttpClient httpClient = new OkHttpClient();
try {
// jsonObject.put("productId",1);
RequestBody requestBody = RequestBody.create(JSON, String.valueOf(jsonObject));
String url = "写自己的";
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
//发送请求获取返回数据
Response response = httpClient.newCall(request).execute();
Log.d("WcChatPay","请求APP下单");
//处理返回的数据
String resData = response.body().string();
Message message = new Message();
message.what = 1;
message.obj = resData;
wechathandeler.sendMessage(message);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
private void getAliPayData(){
new Thread(new Runnable() {
@Override
public void run() {
MediaType JSON = MediaType.parse("application/json;charset=utf-8");
JSONObject jsonObject = new JSONObject();
//创建OkHttp对象
OkHttpClient httpClient = new OkHttpClient();
try {
// jsonObject.put("productId",1);
RequestBody requestBody = RequestBody.create(JSON, String.valueOf(jsonObject));
String url = "写自己的";
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
//发送请求获取返回数据
Response response = httpClient.newCall(request).execute();
Log.d("AliPay","请求APP下单");
//处理返回的数据
String resData = response.body().string();
Message message = new Message();
message.what = 2;
message.obj = resData;
wechathandeler.sendMessage(message);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
/**
* 支付宝支付
* @param orderInfo
*/
private void AliPay(String orderInfo) {
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(WeChatPay.this);
Map<String, String> result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.what = 3;
msg.obj = result;
wechathandeler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
@SuppressLint("HandlerLeak")
Handler wechathandeler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
//微信
try {
JSONObject jsonObject = new JSONObject(msg.obj.toString());
JSONObject resultData = new JSONObject(jsonObject.getString("data"));
// JSONObject resultData = data.getJSONObject("result");
String appid = resultData.getString("appid");
String partnerid = resultData.getString("partnerid");
String noncestr = resultData.getString("noncestr");
String packagevalue = resultData.getString("packagevalue");
String prepayid = resultData.getString("prepayid");
String sign = resultData.getString("sign");
String timestamp = resultData.getString("timestamp");
//调起支付
PayReq request = new PayReq();
request.appId = Constants.APP_ID;
request.partnerId = partnerid;
request.prepayId = prepayid;
request.packageValue = packagevalue;
request.nonceStr = noncestr;
request.timeStamp = timestamp;
request.sign = sign;
Log.d("WcChatPay","sign====>"+sign);
msgApi.sendReq(request);
Log.d("WcChatPay","调起支付");
} catch (JSONException e) {
e.printStackTrace();
}
break;
case 2:
try {
JSONObject jsonObject = new JSONObject(msg.obj.toString());
String paydata = jsonObject.getString("data");
JSONObject returndata = new JSONObject(paydata);
String resultdata = returndata.getString("result");
AliPay(resultdata);
} catch (JSONException e) {
e.printStackTrace();
}
break;
case 3:
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
/**
* 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
Toast.makeText(WeChatPay.this,"支付成功",Toast.LENGTH_LONG).show();
Log.d("AliPay","支付成功"+payResult);
} else {
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
Toast.makeText(WeChatPay.this,"支付失败",Toast.LENGTH_LONG).show();
Log.d("AliPay","支付失败"+payResult);
}
}
}
};
}
四、测试