广东品牌网站建设多少钱,青岛企业建站,wordpress 响应式模板下载,绵阳定制网站建设pi支付流程图#xff1a; 使用Pi SDK功能发起支付由 Pi SDK 自动调用的回调函数#xff08;让您的应用服务器知道它需要发出批准 API 请求#xff09;从您的应用程序服务器到 Pi 服务器的 API 请求以批准付款#xff08;让 Pi 服务器知道您知道此付款#xff09;Pi浏览器向…pi支付流程图 使用Pi SDK功能发起支付由 Pi SDK 自动调用的回调函数让您的应用服务器知道它需要发出批准 API 请求从您的应用程序服务器到 Pi 服务器的 API 请求以批准付款让 Pi 服务器知道您知道此付款Pi浏览器向用户显示付款详细信息页面我们正在等待用户签署交易由 Pi SDK 自动调用的回调函数让您的应用服务器知道它需要发出完整的 API 请求从您的应用服务器到 Pi 服务器的 API 请求以完成付款让 Pi 服务器知道您已完成此付款 引入依赖 dependencygroupIdcom.squareup.okhttp3/groupIdartifactIdokhttp/artifactIdversion4.10.0-RC1/version/dependencydependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.0.M4/version/dependencydependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.13/version/dependencydependencygroupIdcommons-lang/groupIdartifactIdcommons-lang/artifactIdversion2.6/version/dependency
配置api密钥
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;/*** 服务器端key* author ThinkPad*/
Configuration
Data
public class CommonConfig {Value(${sdk.serverAccessKey})private String serverAccessKey;
} 接收和返回数据对象
loginVO接收pi中心来的用户信息
import lombok.Data;/*** author wzx* 登录数据封装类*/
Data
public class LoginVO {private String userId;private String userName;private String accessToken;
}
paymentVO接收支付授权的信息
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;/*** author ThinkPad*/
Data
AllArgsConstructor
NoArgsConstructor
public class PaymentVO {private String paymentId;// 交易金额private BigDecimal amount;// 名片对应的用户数据private String shopUserId;// 商品idprivate String shopId;// 当前账号用户的idprivate String userId;}
completeVO接收支付完成的信息
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author ThinkPad*/
Data
NoArgsConstructor
AllArgsConstructor
public class CompleteVO {// PI支付IDprivate String paymentId;// txIdprivate String txId;// 订单ID【余额支付参数】private String orderId;// 支付方式0PI钱包 1余额支付private String payType;
}
incompleteVO接收未完成订单的信息
/*** author ThinkPad*/
Data
NoArgsConstructor
AllArgsConstructor
public class IncompleteVO {private String identifier;private TransactionVO transaction;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** author ThinkPad*/
Data
NoArgsConstructor
AllArgsConstructor
public class TransactionVO {private String txid;private String _link;
}
工具类
发起http请求工具类
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;/*** author Ashy.Cheung* http 请求工具类* date 2017.11.10*/
public class HttpClientUtil {public static String sendGet(String url) {CloseableHttpClient httpclient HttpClients.createDefault();HttpGet httpget new HttpGet(url);CloseableHttpResponse response null;try {response httpclient.execute(httpget);} catch (IOException e1) {e1.printStackTrace();}String result null;try {HttpEntity entity response.getEntity();if (entity ! null) {result EntityUtils.toString(entity);}} catch (ParseException | IOException e) {e.printStackTrace();} finally {try {response.close();} catch (IOException e) {e.printStackTrace();}}return result;}/**** param url* param charsetName 返回字符集* return*/public static String sendGet(String url, String charsetName) {InputStream inputStream null;HttpURLConnection urlConnection null;try {URL url1 new URL(url);urlConnection (HttpURLConnection) url1.openConnection();// 将返回的输入流转换成字符串inputStream urlConnection.getInputStream();// 指定编码格式if (StringUtils.isBlank(charsetName)) {charsetName UTF-8;}InputStreamReader inputStreamReader new InputStreamReader(inputStream, charsetName);BufferedReader in new BufferedReader(inputStreamReader);String jsonUserStr in.readLine();return jsonUserStr;} catch (Exception e) {throw new RuntimeException(e);} finally {try {if (null ! inputStream) {inputStream.close();}urlConnection.disconnect();} catch (Exception e) {}try {if (null ! urlConnection) {urlConnection.disconnect();}} catch (Exception e) {}}}/*** 发送HttpPost请求参数为String* 接收端以流形式接收*/public static String sendPost(String url, String param) {CloseableHttpClient httpclient HttpClients.createDefault();StringEntity strEntity null;try {strEntity new StringEntity(param, UTF-8);strEntity.setContentType(application/json);} catch (Exception e1) {e1.printStackTrace();}HttpPost httppost new HttpPost(url);httppost.setEntity(strEntity);CloseableHttpResponse response null;String result null;try {response httpclient.execute(httppost);HttpEntity entity1 response.getEntity();result EntityUtils.toString(entity1);} catch (IOException e) {// e.printStackTrace();} finally {try {response.close();} catch (Exception e) {}}return result;}/*** 发送不带参数的HttpPost请求*/public static String sendPost(String url) {CloseableHttpClient httpclient HttpClients.createDefault();HttpPost httppost new HttpPost(url);CloseableHttpResponse response null;try {response httpclient.execute(httppost);} catch (IOException e) {e.printStackTrace();}HttpEntity entity response.getEntity();String result null;try {result EntityUtils.toString(entity);} catch (ParseException | IOException e) {e.printStackTrace();} finally {try {response.close();} catch (Exception e) {}}return result;}} 分布式锁工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
Component
public class RedisLockUtil {private static final Logger log LoggerFactory.getLogger(RedisLockUtil.class);ResourceRedisTemplateString, Object redisTemplate;/*** 释放锁脚本原子操作lua脚本*/private static final String UNLOCK_LUA;static {StringBuilder sb new StringBuilder();sb.append(if redis.call(\get\,KEYS[1]) ARGV[1] );sb.append(then );sb.append( return redis.call(\del\,KEYS[1]) );sb.append(else );sb.append( return 0 );sb.append(end );UNLOCK_LUA sb.toString();}/*** 获取分布式锁原子操作** param lockKey 锁* param lockValue 唯一ID* param leaseTime 过期时间 秒* return 是否枷锁成功*/public boolean tryLock(String lockKey, String lockValue, long leaseTime) {try {RedisCallbackBoolean callback (connection) - connection.set(lockKey.getBytes(StandardCharsets.UTF_8),lockValue.getBytes(StandardCharsets.UTF_8), Expiration.seconds(leaseTime),RedisStringCommands.SetOption.SET_IF_ABSENT);return redisTemplate.execute(callback);} catch (Exception e) {log.error(redis lock error ,lock key: {}, value : {}, error info : {}, lockKey, lockValue, e);}return false;}/*** 释放锁** param lockKey 锁* param lockValue 唯一ID* return 执行结果*/public boolean unlock(String lockKey, String lockValue) {RedisCallbackBoolean callback (connection) - connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN, 1, lockKey.getBytes(StandardCharsets.UTF_8), lockValue.getBytes(StandardCharsets.UTF_8));return redisTemplate.execute(callback);}/*** 获取分布式锁该方法不再使用** param lockKey 锁* param lockValue 唯一ID* param waitTime 等待时间 秒* param leaseTime 过期时间 秒* return 是否枷锁成功*/Deprecatedpublic boolean tryLock(String lockKey, String lockValue, long waitTime, long leaseTime) {try {RedisCallbackBoolean callback (connection) - connection.set(lockKey.getBytes(StandardCharsets.UTF_8),lockValue.getBytes(StandardCharsets.UTF_8), Expiration.seconds(leaseTime),RedisStringCommands.SetOption.SET_IF_ABSENT);return redisTemplate.execute(callback);} catch (Exception e) {log.error(redis lock error ,lock key: {}, value : {}, error info : {}, lockKey, lockValue, e);}return false;}
}
生成uuid工具类
import java.text.SimpleDateFormat;
import java.util.Date;public class UUID {public static String randomUUID() {SimpleDateFormat sdf new SimpleDateFormat(yyyyMMddTHHHmmMssSSSS);String id sdf.format(new Date()) (int) ((Math.random() * 9 1) * 100000000) (int) ((Math.random() * 9 1) * 10);return id;}public static String randomQr() {String id (int) ((Math.random() * 9 1) * 1000) - (int) ((Math.random() * 9 1) * 1000) - (int) ((Math.random() * 9 1) * 1000);return id;}}
信息返回的枚举
import lombok.AllArgsConstructor;import lombok.Getter;/*** author ThinkPad*/Getter
AllArgsConstructor
public enum PaymentEnum {PAYMENT_ENUM_1(1, 订单不存在,失败),PAYMENT_ENUM_2(2,订单不是待支付状态,失败),PAYMENT_ENUM_3(3,支付金额少于订单金额,失败),PAYMENT_ENUM_4(4,调用太快,失败),PAYMENT_ENUM_5(5,余额不足,请前往充值,失败),PAYMENT_ENUM_6(6,支付成功,成功),PAYMENT_ENUM_7(7,处理成功,失败),PAYMENT_ENUM_8(8,处理失败,失败);private final Integer code;private final String msg;private final String status;public static String getMsgByCode(Integer code) {for (PaymentEnum value : PaymentEnum.values()) {if (value.getCode().equals(code)) {return value.getMsg();}}return null;}public static String getStatusByCode(Integer code) {for (PaymentEnum value : PaymentEnum.values()) {if (value.getCode().equals(code)) {return value.getStatus() ;}}return null;}}
支付的controller层 /*** 处理未完成的订单 这部十分重要会影响到后面的操作*/PostMapping(payOrder/incomplete)ApiOperation(处理未完成的订单)ApiImplicitParam(name Authorization, value 传入你的令牌,required true, dataType String,paramTypeheader)public ResponseVO incomplete(RequestBody IncompleteVO incompleteVO) {try {return orderInfoService.incomplete(incompleteVO);} catch (Exception e) {log.error(报错如下{}, e.getMessage());throw new BusinessException(支付失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}}/*** 前端请求支付授权,在本地订单创建后调*/PostMapping(payOrder/approve)ApiOperation(前端请求支付授权,在本地订单创建后调)ApiImplicitParam(name Authorization, value 传入你的令牌,required true, dataType String,paramTypeheader)public ResponseVOString approve(RequestBody PaymentVO paymentVO) {try {String orderId orderInfoService.approve(paymentVO);return ResponseVO.getSuccessResponseVo(orderId);} catch (Exception e) {log.error(报错如下{}, e.getMessage());throw new BusinessException(支付失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}}/*** 前端支付完成,余额支付直接调用此方法*/PostMapping(payOrder/complete)ApiOperation(前端支付完成,余额支付直接调用此方法)ApiImplicitParam(name Authorization, value 传入你的令牌,required true, dataType String,paramTypeheader)public ResponseVO complete(RequestBody CompleteVO completeVO) {try {return orderInfoService.complete(completeVO);} catch (Exception e) {log.error(报错如下{}, e.getMessage());throw new BusinessException(支付失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}}/*** 取消支付,订单关闭*/PostMapping(payOrder/cancelled)ApiOperation(取消支付,订单关闭)ApiImplicitParam(name Authorization, value 传入你的令牌,required true, dataType String,paramTypeheader)public ResponseVOString cancelled(RequestBody String orderId) {try {Boolean order orderInfoService.cancelled(orderId);
// if (!order){throw new BusinessException(取消订单失败);}return ResponseVO.getSuccessResponseVo(取消订单成功);} catch (Exception e) {log.error(报错如下{}, e.getMessage());throw new BusinessException(取消失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}}
支付的service层 /*** 请求支付授权创建order。返回orderId* param paymentVO* return*/OverrideTransactional(rollbackFor Exception.class)public String approve(PaymentVO paymentVO) {log.error(approve-------------------------------------------------------------);OrderInfo orderInfo;log.error(paymentVO----------------------------------paymentVO);//获取付款信息OkHttpClient client new OkHttpClient();Request request new Request.Builder().url(https://api.minepi.com/v2/payments/ paymentVO.getPaymentId()).addHeader(Authorization, Key commonConfig.getServerAccessKey()).build();try (Response response client.newCall(request).execute()) {if (!response.isSuccessful()) {String string response.body().string();JSONObject jsonObject1 JSON.parseObject(string);log.error(!response-------------------------------------------------------------commonConfig.getServerAccessKey());throw new RuntimeException(payments error jsonObject1.getString(error_message));}String string response.body().string();log.error(response-------------------------------------------------------------string);JSONObject jsonObject1 JSON.parseObject(string);//校验实际支付金额BigDecimal userFinalPrice paymentVO.getAmount();if (userFinalPrice.compareTo(jsonObject1.getBigDecimal(amount)) 0) {log.error(userFinalPriceresponse-------------------------------------------------------------jsonObject1.getBigDecimal(amount));throw new RuntimeException(支付金额少于订单金额);}} catch (Exception e) {throw new BusinessException(支付失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}OkHttpClient client1 new OkHttpClient();//信息真实通知PI我准备好了可以付款了Request request1 new Request.Builder().url(https://api.minepi.com/v2/payments/ paymentVO.getPaymentId() /approve).addHeader(Content-Type, application/json).addHeader(Access-Control-Allow-Origin, *).addHeader(Authorization, Key commonConfig.getServerAccessKey()).post(RequestBody.create(, MediaType.parse(application/json))).build();try (Response response1 client1.newCall(request1).execute()) {if (!response1.isSuccessful()) {throw new RuntimeException(approve error: );}log.error(response1-------------------------------------------------------------);//更新支付报文
// tMerStoreGoodsOrderEntity.setPayOrderId(paymentDto.getPaymentId());
// tMerStoreGoodsOrderEntity.setPayStatusType(10007002);//支付中
// itMerStoreGoodsOrderService.updateById(tMerStoreGoodsOrderEntity);log.error(return-------------------------------------------------------------);} catch (RuntimeException | IOException e) {log.error(error-------------------------------------------------------------);e.printStackTrace();}// 生成订单orderInfo new OrderInfo();orderInfo.setOrderId(StringUtil.generateShortId());orderInfo.setShopId(paymentVO.getShopId());orderInfo.setUserId(paymentVO.getUserId());orderInfo.setShopUserId(paymentVO.getShopUserId());orderInfo.setAmount(paymentVO.getAmount());orderInfoMapper.insert(orderInfo);log.error(生成订单-------------------------------------------------------------);return orderInfo.getOrderId();}/*** 前端支付完成,余额支付直接调用此方法*/OverrideTransactional(rollbackFor Exception.class)public ResponseVO complete(CompleteVO completeVO) {String payType completeVO.getPayType();log.error(complete------------------------------------------------------------completeVO);if (1.equals(payType)) {//余额支付String orderId completeVO.getOrderId();String lockName access:lock:complete: orderId;String lockId UUID.randomUUID();if (!redisLockUtil.tryLock(lockName, lockId, 20L)) {// 调用太快return new ResponseVO(PaymentEnum.getStatusByCode(4),4,PaymentEnum.getMsgByCode(4));}// 获取订单信息OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, orderId));if ((orderInfo.getOrderStatus() ! 0)) {// 订单不是待支付状态return new ResponseVO(PaymentEnum.getStatusByCode(2),2,PaymentEnum.getMsgByCode(2));}String userId orderInfo.getUserId();AccountInfo accountInfo accountInfoMapper.selectOne(new QueryWrapperAccountInfo().eq(user_id, userId));BigDecimal balance accountInfo.getPiBalance();if (balance.compareTo(orderInfo.getAmount()) 0) {// 余额不足请前往充值return new ResponseVO(PaymentEnum.getStatusByCode(5),5,PaymentEnum.getMsgByCode(5));}int update orderInfoMapper.update(null,new UpdateWrapperOrderInfo().eq(order_id,orderId).set(order_status,1));balancebalance.subtract(orderInfo.getAmount());int update1 accountInfoMapper.update(null, new UpdateWrapperAccountInfo().eq(user_id, userId).set(pi_balance, balance));// 支付成功return new ResponseVO(PaymentEnum.getStatusByCode(6),6,PaymentEnum.getMsgByCode(6));}//PI钱包支付String paymentId completeVO.getPaymentId();//PI订单号String lockName access:lock:complete: paymentId;String lockId UUID.randomUUID();log.error(paymentId-----------------lockName---------------------lockId);if (!redisLockUtil.tryLock(lockName, lockId, 20L)) {// 调用太快log.error(!RedisLockUtil---------------------------------------------------------调用太快);return new ResponseVO(PaymentEnum.getStatusByCode(4),4,PaymentEnum.getMsgByCode(4));}OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, completeVO.getOrderId()));log.error(orderId--------------------------------------------------------------orderInfo);if (null orderInfo) {// 订单不存在log.error(!orderinfo--------------------------------------------------------不存在);return new ResponseVO(PaymentEnum.getStatusByCode(1),1,PaymentEnum.getMsgByCode(1));}log.error(orderinfo------------------------------------------------------------------orderInfo);if (orderInfo.getOrderStatus() ! 0) {// 订单不是待支付状态log.error(!order---------------------------------------------------------pay);return new ResponseVO(PaymentEnum.getStatusByCode(2),2,PaymentEnum.getMsgByCode(2));}//通知PI完成交易JSONObject jsonObject new JSONObject();jsonObject.put(txid, completeVO.getTxId());MapString, String heads new HashMap();heads.put(Content-Type, application/json;charsetUTF-8);heads.put(Authorization, Key commonConfig.getServerAccessKey());log.error(pi-----------------------------------------jsonObject);try {HttpResponse response HttpRequest.post(https://api.minepi.com/v2/payments/ paymentId /complete).headerMap(heads, false).body(String.valueOf(jsonObject)).timeout(5 * 60 * 1000).execute();String body response.body();JSONObject jsonObject1 JSON.parseObject(body);String error jsonObject1.getString(error);if (!StringUtils.isEmpty(error)) {log.error(!strinutils-----------------------------body);throw new RuntimeException(订单完成异常!);}orderInfo.setOrderStatus(1);// 更新订单orderInfoMapper.updateById(orderInfo);log.error(支付成功------------------------------------------------------);// 支付成功return new ResponseVO(PaymentEnum.getStatusByCode(6),6,PaymentEnum.getMsgByCode(6));} catch (Exception e) {throw e;}}OverrideTransactional(rollbackFor Exception.class)public Boolean cancelled(String orderId) {int update orderInfoMapper.update(null, new UpdateWrapperOrderInfo().eq(order_id, orderId).set(order_status, 3));return update 0;}Overridepublic ResponseVO incomplete(IncompleteVO incompleteVO) {log.error(incomplete--------------------------------);try {//先处理未完成的订单String oldpaymentId incompleteVO.getIdentifier();TransactionVO transaction incompleteVO.getTransaction();log.error(?transation--------------------transaction);log.error(?oldpaymentId------------------oldpaymentId);if (null ! transaction) {log.error(transation--------------------transaction);log.error(oldpaymentId------------------oldpaymentId);String txid transaction.getTxid();String txURL transaction.get_link();// OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, oldpaymentId));
// if (null orderInfo) {
// log.error(order-----------------null);
// throw new RuntimeException(旧订单不存在);
// }
//
// if (orderInfo.getOrderStatus()1) {
// log.error(orderStatus---------------------orderInfo.getOrderStatus());
// throw new RuntimeException(订单是已支付状态);
// }String get HttpClientUtil.sendGet(txURL);JSONObject jsonObject1 JSON.parseObject(get);String piOrderId jsonObject1.getString(memo);//我方订单IDlog.error(memo---------------------piOrderId);JSONObject jsonObject new JSONObject();jsonObject.put(txid, txid);MapString, String heads new HashMap();heads.put(Content-Type, application/json;charsetUTF-8);heads.put(Authorization, Key commonConfig.getServerAccessKey());try {HttpResponse response HttpRequest.post(https://api.minepi.com/v2/payments/ piOrderId /complete).headerMap(heads, false).body(String.valueOf(jsonObject)).timeout(5 * 60 * 1000).execute();String body response.body();JSONObject jsonObject2 JSON.parseObject(body);String error jsonObject2.getString(error);if (!StringUtils.isEmpty(error)) {log.error(!response------------------error);throw new RuntimeException(订单完成异常!);}return new ResponseVO(PaymentEnum.getStatusByCode(7),7,PaymentEnum.getMsgByCode(7));} catch (Exception e) {throw e;}}} catch (Exception e) {return new ResponseVO(PaymentEnum.getStatusByCode(8),8,PaymentEnum.getMsgByCode(8));}return new ResponseVO(PaymentEnum.getStatusByCode(8),8,PaymentEnum.getMsgByCode(8));} 前端代码
前端路由
API
// 授权
import request from /api/http;
import axios from axios;// 支付授权
export function payAuth(data){return request({url: /api/order/payOrder/approve,method: post,data,});
}//未完成订单
export function payIncomplete(data){return request({url: /api/order/payOrder/incomplete,method: post,data,});
}//支付成功
export function payDone(data){return request({url: /api/order/payOrder/complete,method: post,data,});
}
//支付取消
export function payCancel(data){return request({url: /api/order/payOrder/cancelled,method: post,data,})
}
支付前端代码 test(){const pay_message this.pay_messagelet orderid console.log({amount: pay_message.amount,shopUserId: pay_message.shopUserId,shopId: pay_message.shopId,userId: pay_message.userId})Pi.createPayment({// Amount of π to be paid:amount: 3.14,// An explanation of the payment - will be shown to the user:memo: 购买特殊数据, // e.g: Digital kitten #1234,// An arbitrary developer-provided metadata object - for your own usage:metadata: { productID : apple_pie_1 }, // e.g: { kittenId: 1234 }}, {// Callbacks you need to implement - read more about those in the detailed docs linked below:// 授权async onReadyForServerApproval(paymentId) {console.log(paymentId,paymentId)payAuth({paymentId: paymentId,amount: pay_message.amount,shopUserId: pay_message.shopUserId,shopId: pay_message.shopId,userId: pay_message.userId}).then((data) {orderid data.dataconsole.log(orderId,orderid)}).catch(error {console.log(error)})},//支付成功onReadyForServerCompletion: function(paymentId, txid) {alert(1111)console.log(paymentId, paymentId, txid, txid,orderid,orderid )payDone({paymentId: paymentId, txId: txid, orderId: orderid,payType:0}).then(res {console.log(res)// if (res res.code 0) {// this.payDoneJump();// }})},//支付取消onCancel: function(orderid) {console.log(onCancel orderid)payCancel(orderid).then((data) {console.log(data)})},//支付失败onError: function(error, payment) {console.log(error:,error);console.log(payment:,payment)}});},
登录自动调用未支付订单这个十分重要因为会影响支付授权。
const loginFun () {Pi.init({ version: 2.0, sandbox: true });const scopes [payments, username, wallet_address];function onIncompletePaymentFound(payment) {alert(1111111)console.log(payment, payment);return payIncomplete({identifier:payment.identifier,transaction:{_link:payment.transaction._link,txid:res.transaction.txid}})}Pi.authenticate(scopes, onIncompletePaymentFound).then(function (auth) {console.log(auth, auth);let userInfo {accessToken: auth.accessToken,userId: auth.user.uid,userName: auth.user.username,};// userGetPush().then((data) {// console.log(data);// userStore().userGetPush data.data;// });Login(userInfo).then((data) {console.log(data);if (data.status success) {// 将用户信息存入piniauserStore().userInfoChange(data.data);// 发布消息到socket Login() 存入userId// this.$socket.emit(login, data.data.userInfo.userId);router.push(/home);}});}).catch(function (error) {console.error(error);});
};
详细流程
使用Pi-SDK功能发起支付 由Pi SDK自动调用的回调函数发出支付批准请求 路由到后端的支付授权接口 后端服务器向Pi服务器发起支付授权 OverrideTransactional(rollbackFor Exception.class)public String approve(PaymentVO paymentVO) {log.error(approve-------------------------------------------------------------);OrderInfo orderInfo;log.error(paymentVO----------------------------------paymentVO);//获取付款信息OkHttpClient client new OkHttpClient();Request request new Request.Builder().url(https://api.minepi.com/v2/payments/ paymentVO.getPaymentId()).addHeader(Authorization, Key commonConfig.getServerAccessKey()).build();try (Response response client.newCall(request).execute()) {if (!response.isSuccessful()) {String string response.body().string();JSONObject jsonObject1 JSON.parseObject(string);log.error(!response-------------------------------------------------------------commonConfig.getServerAccessKey());throw new RuntimeException(payments error jsonObject1.getString(error_message));}String string response.body().string();log.error(response-------------------------------------------------------------string);JSONObject jsonObject1 JSON.parseObject(string);//校验实际支付金额BigDecimal userFinalPrice paymentVO.getAmount();if (userFinalPrice.compareTo(jsonObject1.getBigDecimal(amount)) 0) {log.error(userFinalPriceresponse-------------------------------------------------------------jsonObject1.getBigDecimal(amount));throw new RuntimeException(支付金额少于订单金额);}} catch (Exception e) {throw new BusinessException(支付失败请联系后台人员e.getLocalizedMessage()e.toString()e.getCause().toString());}OkHttpClient client1 new OkHttpClient();//信息真实通知PI我准备好了可以付款了Request request1 new Request.Builder().url(https://api.minepi.com/v2/payments/ paymentVO.getPaymentId() /approve).addHeader(Content-Type, application/json).addHeader(Access-Control-Allow-Origin, *).addHeader(Authorization, Key commonConfig.getServerAccessKey()).post(RequestBody.create(, MediaType.parse(application/json))).build();try (Response response1 client1.newCall(request1).execute()) {if (!response1.isSuccessful()) {throw new RuntimeException(approve error: );}log.error(response1-------------------------------------------------------------);//更新支付报文
// tMerStoreGoodsOrderEntity.setPayOrderId(paymentDto.getPaymentId());
// tMerStoreGoodsOrderEntity.setPayStatusType(10007002);//支付中
// itMerStoreGoodsOrderService.updateById(tMerStoreGoodsOrderEntity);log.error(return-------------------------------------------------------------);} catch (RuntimeException | IOException e) {log.error(error-------------------------------------------------------------);e.printStackTrace();}// 生成订单orderInfo new OrderInfo();orderInfo.setOrderId(StringUtil.generateShortId());orderInfo.setShopId(paymentVO.getShopId());orderInfo.setUserId(paymentVO.getUserId());orderInfo.setShopUserId(paymentVO.getShopUserId());orderInfo.setAmount(paymentVO.getAmount());orderInfoMapper.insert(orderInfo);log.error(生成订单-------------------------------------------------------------);return orderInfo.getOrderId();}
PI游览器向用户显示付款详细信息页面我们等待用户签署交易 由Pi SDK自动调用完成的回调函数 从你的后端服务器到Pi服务器的API请求以完成付款让pi服务器知道你完成此付款 /*** 前端支付完成,余额支付直接调用此方法*/OverrideTransactional(rollbackFor Exception.class)public ResponseVO complete(CompleteVO completeVO) {String payType completeVO.getPayType();log.error(complete------------------------------------------------------------completeVO);if (1.equals(payType)) {//余额支付String orderId completeVO.getOrderId();String lockName access:lock:complete: orderId;String lockId UUID.randomUUID();if (!redisLockUtil.tryLock(lockName, lockId, 20L)) {// 调用太快return new ResponseVO(PaymentEnum.getStatusByCode(4),4,PaymentEnum.getMsgByCode(4));}// 获取订单信息OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, orderId));if ((orderInfo.getOrderStatus() ! 0)) {// 订单不是待支付状态return new ResponseVO(PaymentEnum.getStatusByCode(2),2,PaymentEnum.getMsgByCode(2));}String userId orderInfo.getUserId();AccountInfo accountInfo accountInfoMapper.selectOne(new QueryWrapperAccountInfo().eq(user_id, userId));BigDecimal balance accountInfo.getPiBalance();if (balance.compareTo(orderInfo.getAmount()) 0) {// 余额不足请前往充值return new ResponseVO(PaymentEnum.getStatusByCode(5),5,PaymentEnum.getMsgByCode(5));}int update orderInfoMapper.update(null,new UpdateWrapperOrderInfo().eq(order_id,orderId).set(order_status,1));balancebalance.subtract(orderInfo.getAmount());int update1 accountInfoMapper.update(null, new UpdateWrapperAccountInfo().eq(user_id, userId).set(pi_balance, balance));// 支付成功return new ResponseVO(PaymentEnum.getStatusByCode(6),6,PaymentEnum.getMsgByCode(6));}//PI钱包支付String paymentId completeVO.getPaymentId();//PI订单号String lockName access:lock:complete: paymentId;String lockId UUID.randomUUID();log.error(paymentId-----------------lockName---------------------lockId);if (!redisLockUtil.tryLock(lockName, lockId, 20L)) {// 调用太快log.error(!RedisLockUtil---------------------------------------------------------调用太快);return new ResponseVO(PaymentEnum.getStatusByCode(4),4,PaymentEnum.getMsgByCode(4));}OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, completeVO.getOrderId()));log.error(orderId--------------------------------------------------------------orderInfo);if (null orderInfo) {// 订单不存在log.error(!orderinfo--------------------------------------------------------不存在);return new ResponseVO(PaymentEnum.getStatusByCode(1),1,PaymentEnum.getMsgByCode(1));}log.error(orderinfo------------------------------------------------------------------orderInfo);if (orderInfo.getOrderStatus() ! 0) {// 订单不是待支付状态log.error(!order---------------------------------------------------------pay);return new ResponseVO(PaymentEnum.getStatusByCode(2),2,PaymentEnum.getMsgByCode(2));}//通知PI完成交易JSONObject jsonObject new JSONObject();jsonObject.put(txid, completeVO.getTxId());MapString, String heads new HashMap();heads.put(Content-Type, application/json;charsetUTF-8);heads.put(Authorization, Key commonConfig.getServerAccessKey());log.error(pi-----------------------------------------jsonObject);try {HttpResponse response HttpRequest.post(https://api.minepi.com/v2/payments/ paymentId /complete).headerMap(heads, false).body(String.valueOf(jsonObject)).timeout(5 * 60 * 1000).execute();String body response.body();JSONObject jsonObject1 JSON.parseObject(body);String error jsonObject1.getString(error);if (!StringUtils.isEmpty(error)) {log.error(!strinutils-----------------------------body);throw new RuntimeException(订单完成异常!);}orderInfo.setOrderStatus(1);// 更新订单orderInfoMapper.updateById(orderInfo);log.error(支付成功------------------------------------------------------);// 支付成功return new ResponseVO(PaymentEnum.getStatusByCode(6),6,PaymentEnum.getMsgByCode(6));} catch (Exception e) {throw e;}}
注意如果用户有未处理的订单会导致用户重新创建支付失败需要有个接口去处理未完成的订单
前端一初始化就去执行处理未完成的订单 路由到后端的接口 后端接口代码
Overridepublic ResponseVO incomplete(IncompleteVO incompleteVO) {log.error(incomplete--------------------------------);try {//先处理未完成的订单String oldpaymentId incompleteVO.getIdentifier();TransactionVO transaction incompleteVO.getTransaction();log.error(?transation--------------------transaction);log.error(?oldpaymentId------------------oldpaymentId);if (null ! transaction) {log.error(transation--------------------transaction);log.error(oldpaymentId------------------oldpaymentId);String txid transaction.getTxid();String txURL transaction.get_link();// OrderInfo orderInfo orderInfoMapper.selectOne(new QueryWrapperOrderInfo().eq(order_id, oldpaymentId));
// if (null orderInfo) {
// log.error(order-----------------null);
// throw new RuntimeException(旧订单不存在);
// }
//
// if (orderInfo.getOrderStatus()1) {
// log.error(orderStatus---------------------orderInfo.getOrderStatus());
// throw new RuntimeException(订单是已支付状态);
// }String get HttpClientUtil.sendGet(txURL);JSONObject jsonObject1 JSON.parseObject(get);String piOrderId jsonObject1.getString(memo);//我方订单IDlog.error(memo---------------------piOrderId);JSONObject jsonObject new JSONObject();jsonObject.put(txid, txid);MapString, String heads new HashMap();heads.put(Content-Type, application/json;charsetUTF-8);heads.put(Authorization, Key commonConfig.getServerAccessKey());try {HttpResponse response HttpRequest.post(https://api.minepi.com/v2/payments/ piOrderId /complete).headerMap(heads, false).body(String.valueOf(jsonObject)).timeout(5 * 60 * 1000).execute();String body response.body();JSONObject jsonObject2 JSON.parseObject(body);String error jsonObject2.getString(error);if (!StringUtils.isEmpty(error)) {log.error(!response------------------error);throw new RuntimeException(订单完成异常!);}return new ResponseVO(PaymentEnum.getStatusByCode(7),7,PaymentEnum.getMsgByCode(7));} catch (Exception e) {throw e;}}} catch (Exception e) {return new ResponseVO(PaymentEnum.getStatusByCode(8),8,PaymentEnum.getMsgByCode(8));}return new ResponseVO(PaymentEnum.getStatusByCode(8),8,PaymentEnum.getMsgByCode(8));}
文章转载自: http://www.morning.qhydkj.com.gov.cn.qhydkj.com http://www.morning.jynzb.cn.gov.cn.jynzb.cn http://www.morning.nrfrd.cn.gov.cn.nrfrd.cn http://www.morning.lnwdh.cn.gov.cn.lnwdh.cn http://www.morning.yqgbw.cn.gov.cn.yqgbw.cn http://www.morning.qkcyk.cn.gov.cn.qkcyk.cn http://www.morning.qqzdr.cn.gov.cn.qqzdr.cn http://www.morning.lmxzw.cn.gov.cn.lmxzw.cn http://www.morning.ntzbr.cn.gov.cn.ntzbr.cn http://www.morning.ldpjm.cn.gov.cn.ldpjm.cn http://www.morning.rshs.cn.gov.cn.rshs.cn http://www.morning.mpgfk.cn.gov.cn.mpgfk.cn http://www.morning.rbgqn.cn.gov.cn.rbgqn.cn http://www.morning.pxwjp.cn.gov.cn.pxwjp.cn http://www.morning.ngpdk.cn.gov.cn.ngpdk.cn http://www.morning.jpjxb.cn.gov.cn.jpjxb.cn http://www.morning.hfxks.cn.gov.cn.hfxks.cn http://www.morning.txrq.cn.gov.cn.txrq.cn http://www.morning.xnpml.cn.gov.cn.xnpml.cn http://www.morning.qwwcf.cn.gov.cn.qwwcf.cn http://www.morning.sgmis.com.gov.cn.sgmis.com http://www.morning.qfqld.cn.gov.cn.qfqld.cn http://www.morning.wyctq.cn.gov.cn.wyctq.cn http://www.morning.fyglr.cn.gov.cn.fyglr.cn http://www.morning.crfyr.cn.gov.cn.crfyr.cn http://www.morning.ydrn.cn.gov.cn.ydrn.cn http://www.morning.mnlk.cn.gov.cn.mnlk.cn http://www.morning.lqypx.cn.gov.cn.lqypx.cn http://www.morning.dmzzt.cn.gov.cn.dmzzt.cn http://www.morning.jfnlj.cn.gov.cn.jfnlj.cn http://www.morning.wlbwp.cn.gov.cn.wlbwp.cn http://www.morning.zfcfk.cn.gov.cn.zfcfk.cn http://www.morning.nwqyq.cn.gov.cn.nwqyq.cn http://www.morning.lynkz.cn.gov.cn.lynkz.cn http://www.morning.zwhtr.cn.gov.cn.zwhtr.cn http://www.morning.ptdzm.cn.gov.cn.ptdzm.cn http://www.morning.gqfbh.cn.gov.cn.gqfbh.cn http://www.morning.cprbp.cn.gov.cn.cprbp.cn http://www.morning.ldcrh.cn.gov.cn.ldcrh.cn http://www.morning.ymwrs.cn.gov.cn.ymwrs.cn http://www.morning.jbblf.cn.gov.cn.jbblf.cn http://www.morning.gwjnm.cn.gov.cn.gwjnm.cn http://www.morning.tqjks.cn.gov.cn.tqjks.cn http://www.morning.cknws.cn.gov.cn.cknws.cn http://www.morning.ttryd.cn.gov.cn.ttryd.cn http://www.morning.pqhgn.cn.gov.cn.pqhgn.cn http://www.morning.krxzl.cn.gov.cn.krxzl.cn http://www.morning.gwsdt.cn.gov.cn.gwsdt.cn http://www.morning.spwln.cn.gov.cn.spwln.cn http://www.morning.thpzn.cn.gov.cn.thpzn.cn http://www.morning.bdgb.cn.gov.cn.bdgb.cn http://www.morning.gfhng.cn.gov.cn.gfhng.cn http://www.morning.bgzgq.cn.gov.cn.bgzgq.cn http://www.morning.xhpnp.cn.gov.cn.xhpnp.cn http://www.morning.cqrenli.com.gov.cn.cqrenli.com http://www.morning.yldgw.cn.gov.cn.yldgw.cn http://www.morning.tzmjc.cn.gov.cn.tzmjc.cn http://www.morning.gyfhk.cn.gov.cn.gyfhk.cn http://www.morning.wjzzh.cn.gov.cn.wjzzh.cn http://www.morning.gbwfx.cn.gov.cn.gbwfx.cn http://www.morning.zwppm.cn.gov.cn.zwppm.cn http://www.morning.xnnxp.cn.gov.cn.xnnxp.cn http://www.morning.dmchips.com.gov.cn.dmchips.com http://www.morning.rkxdp.cn.gov.cn.rkxdp.cn http://www.morning.gjssk.cn.gov.cn.gjssk.cn http://www.morning.brzlp.cn.gov.cn.brzlp.cn http://www.morning.jrlxz.cn.gov.cn.jrlxz.cn http://www.morning.zcmpk.cn.gov.cn.zcmpk.cn http://www.morning.zztmk.cn.gov.cn.zztmk.cn http://www.morning.jkcpl.cn.gov.cn.jkcpl.cn http://www.morning.bkwd.cn.gov.cn.bkwd.cn http://www.morning.qxdrw.cn.gov.cn.qxdrw.cn http://www.morning.ynlbj.cn.gov.cn.ynlbj.cn http://www.morning.xbbrh.cn.gov.cn.xbbrh.cn http://www.morning.fqtdz.cn.gov.cn.fqtdz.cn http://www.morning.cknws.cn.gov.cn.cknws.cn http://www.morning.lwhsp.cn.gov.cn.lwhsp.cn http://www.morning.khxwp.cn.gov.cn.khxwp.cn http://www.morning.wmmqf.cn.gov.cn.wmmqf.cn http://www.morning.rtjhw.cn.gov.cn.rtjhw.cn