一.最近要开发支付,考虑到以后接入的支付类型比较多,如常用的,微信,支付宝,银联,以及后期需要接入qq,京东,易宝支付等。为了以后统一管理支付,就考虑使用ping++ 支付,提供了统一的支付接口。
下面我介绍下,利用ping++ 接入支付宝的支付功能。
二.请求服务器 支付接口 orderpay.
1.配置:ping++ api key ,appId,webhooksParse
2.在ping++ 官网 找到 rsa private key ,官网提供的是rsc pacs#1 ,这里需要转成 pkcs8,我是利用在线的一个网站转换 : http://tool.chacuo.net/cryptrsapkcs1pkcs8
3.创建charge对象,这里着重要说明的是 获取客户端ip,这也是官网demo 未强调的点,对于不了解代理请求转发的小伙伴来说,这里又会遇到大坑,项目不上线 不知道,一上线支付就调用不起来,根源就在
x-forwarded-for 获取客户端IP这里。给一个地址介绍下x-forwarded-for :http://www.360doc.com/content/12/0409/15/1073512_202198496.shtml,他最终结果是将所有的代理过的ip地址全拼接在一起,而我 们需要的是最开始发起支付请求的客户端IP。下面是代码部分:
一.最近要开发支付,考虑到以后接入的支付类型比较多,如常用的,微信,支付宝,银联,以及后期需要接入qq,京东,易宝支付等。为了以后统一管理支付,就考虑使用ping++ 支付,提供了统一的支付接口。
下面我介绍下,利用ping++ 接入支付宝的支付功能。
二.请求服务器 支付接口 orderpay.
1.配置:ping++ api key ,appId,webhooksParse
2.在ping++ 官网 找到 rsa private key ,官网提供的是rsc pacs#1 ,这里需要转成 pkcs8,我是利用在线的一个网站转换 : http://tool.chacuo.net/cryptrsapkcs1pkcs8
3.创建charge对象,这里着重要说明的是 获取客户端ip,这也是官网demo 未强调的点,对于不了解代理请求转发的小伙伴来说,这里又会遇到大坑,项目不上线 不知道,一上线支付就调用不起来,根源就在
x-forwarded-for 获取客户端IP这里。给一个地址介绍下x-forwarded-for :http://www.360doc.com/content/12/0409/15/1073512_202198496.shtml,他最终结果是将所有的代理过的ip地址全拼接在一起,而我 们需要的是最开始发起支付请求的客户端IP。下面是代码部分:
三.创建支付对象 charge
1.指定 支付使用的appid
2.调用 charge对象的create 方法,创建支付对象。
public Charge createCharge(String orderId,int price,String orderNo,String channel,String clent_ip,String subject,String body){
//String appId = PingppTestData.getAppID();
String appId = Cont.API_ID;
Charge charge = null;
Map<String, Object> chargeMap = new HashMap<String, Object>();
chargeMap.put("amount", price);//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100)
chargeMap.put("currency", "cny");
chargeMap.put("subject", subject);
chargeMap.put("body", body);
chargeMap.put("order_no", orderNo);// 推荐使用 8-20 位,要求数字或字母,不允许其他字符
chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 5);//5分钟失效
long timestamp = cal.getTimeInMillis()/ 1000L;
chargeMap.put("time_expire", timestamp);
Timer timer = new Timer();
//发起一个定时任务,半小时后自动触发,取消订单流程
//以"X"结尾,则标识需求订单,
if(orderNo.endsWith("X")){
//需求订单
timer.schedule(new DemandlobbyNoPayCancel(Long.valueOf(orderId)), 1000 * 60 * 5);
}else{
//普通订单
timer.schedule(new OrderNoPayCancel(Long.valueOf(orderId)), 1000 * 60 * 5);
}
chargeMap.put("client_ip", clent_ip); // 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1
Map<String, String> app = new HashMap<String, String>();
app.put("id", appId);
chargeMap.put("app", app);
Map<String, Object> extra = new HashMap<String, Object>();
// extra.put("success_url", "http://127.0.0.1/succeeded");
chargeMap.put("extra", extra);
try {
// 发起 charge 创建请求
charge = Charge.create(chargeMap);
} catch (APIConnectionException e) {
e.printStackTrace();
} catch (ChannelException e) {
e.printStackTrace();
} catch (RateLimitException e) {
e.printStackTrace();
} catch (AuthenticationException e) {
e.printStackTrace();
} catch (APIException e) {
e.printStackTrace();
} catch (InvalidRequestException e) {
e.printStackTrace();
}
return charge;
}
四.支付回调方法
1.回调地址,是在ping++ 官网配置,官网提供 test 和 live 两版本,开发过程先用test 做回调地址配置,测通后,项目正式上线改成live模式.
2.回调地址进行业务处理,回调方法获取event type类型,是支付成功,还是退款成功或者红包发送成功..... 具体可参考 ping++ 开发api: https://www.pingxx.com/api#events-事件
3.贴出我的回调处理方法代码,这里主要会发生的签名验签的错误,那么遇到这种情况,你还是要核对下,是否直接使用了ping++的私钥 并没有转成 pkcs8 加密方式,或者直接拷入了ping++的公钥....
public String webhooksParseCharge(){
HttpServletRequest request = getRequest();
HttpServletResponse response = getResponse();
try {
request.setCharacterEncoding("UTF8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
//获取头部所有信息
Enumeration<String> headerNames = request.getHeaderNames();
String signature=null;
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
if("x-pingplusplus-signature".equals(key)){
signature=value;
}
}
// 获得 http body 内容
StringBuffer eventJson=new StringBuffer();
BufferedReader reader= null;
try {
reader = request.getReader();
do{
eventJson.append(reader.readLine());
}while(reader.read()!=-1);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
JSONObject event=JSONObject.fromObject(eventJson.toString());
System.out.println("=========event=========== "+event);
boolean verifyRS=false;
try {
PublicKey publicKey = WebhooksVerifyService.getPubKey();
System.out.println("============公钥============"+publicKey);
verifyRS = WebhooksVerifyService.verifyData(eventJson.toString(),signature,publicKey);
System.out.println("============== 是否签名验证成功! "+ verifyRS);
//verifyRS = true;
} catch (Exception e) {
e.printStackTrace();
}
if(verifyRS) {
// charge.succeeded 支付对象,支付成功时触发。
// refund.succeeded 退款对象,退款成功时触发。
if ("charge.succeeded".equals(event.get("type"))) {
JSONObject data = JSONObject.fromObject(event.get("data").toString());
JSONObject object = JSONObject.fromObject(data.get("object").toString());
String channel = (String) object.get("channel");
String payType = null;
int amountFen = (int) object.get("amount");
//交易流水号
String transaction_no = object.get("transaction_no")+"";
Double amountYuan = amountFen * 1.0 / 100;//ping++扣款,精确到分,而数据库精确到元
Double weiXinInput = null;
Double aliPayInput = null;
Double bankCardInput = null;
if ("wx".equals(channel)) {
payType = "2";//支付类型(1:支付宝2微信)
weiXinInput = amountYuan;
} else if ("alipay".equals(channel)) {
payType = "1";
aliPayInput = amountYuan;
}
String orderNo = (String) object.get("order_no");
// 支付成功业务处理
}else if("refund.succeeded".equals(event.get("type"))){//退款事件
// 退款业务处理
}
}else{
System.out.println("签名验证失败");
setJsonString(AppJSON.errReq("签名验证失败!"));
}
return "ajax";
}