一、情景描述
当前项目想在微信小程序付款时添加上京东支付支付类型,效果如下
普通的付款方式可以直接付款就能完成支付,但京东支付无法在小程序上直接付款,他需要复制生成的链接,然后打开京东app然后在京东平台上付款。
所以,我们首先需要了解京东支付的支付流程
二、京东支付实现流程
京东支付跟普通支付不同之处就是无法在当前平台完成支付,需要复制口令前往京东app,在京东app里进行支付操作
具体可查看开放文档:
https://mer.jd.com/open/
文档中也提供了大部分接口demo,可以下载参考
简单概括步骤分为3步:
1、下单接口
调用这个接口,成功的话在响应体中有一个我们需要的数据pay_url,支付链接,我尝试了一下,点击可以进入到京东付款页面,但是我们不要直接使用,要把这个字段封装成金口令。
(注意:设置的请求体中有一个字段callbackUrl回调路径,设置这个值在支付完成后京东会调用这个路径的接口,见3、编写回调方法验证支付订单)
下单方法代码参考如下
//京东下单支付生成金口令
public static ReturnValueDomain<String> pay(Tcorderinfo tcorderinfo ) throws Exception {
ReturnValueDomain<String> ret = new ReturnValueDomain<String>();
logger.debug("========进入京东支付方法,进入pay=========");
if (NonUtil.isNon(tcorderinfo)) {
return ret.setFail("京东支付订单不可为空!");
}
// 得到openid
String openid = tcorderinfo.getOpenid();
int fee = 0;
// 得到小程序传过来的价格,注意这里的价格必须为整数,1代表1分,所以传过来的值必须*100;
if (NonUtil.isNon(tcorderinfo.getAdvancepay())) {
fee = Integer.parseInt(tcorderinfo.getOrderfee());
} else {
fee = Integer.parseInt(tcorderinfo.getAdvancepay());
}
double total_amount = MathHelper.div(fee, 100, 2);
logger.debug("==========支付费用/元=={}=====", total_amount);
// 订单编号
String did = tcorderinfo.getOrderid();
// 订单标题-商品名称
String title = tcorderinfo.getTradename();
Map<String, Object> requestParam = new HashMap<>();
//代理商号
// requestParam.put("agentNum", agentNum);
//商户号
requestParam.put("customerNum", customerNum);
//店铺号
// requestParam.put("shopNum", shopNum);
//机具号
// requestParam.put("machineNum", machineNum);
// requestParam.put("requestNum", generateId());//订单号
requestParam.put("requestNum", tcorderinfo.getOrderid());//订单号
requestParam.put("authCode", tcorderinfo.getOpenid());//openid
requestParam.put("bankType", bankType);//支付类型
requestParam.put("orderAmount", total_amount+"");//支付金额
requestParam.put("callbackUrl", callbackUrl);
requestParam.put("source", source);
requestParam.put("orderType", orderType);
requestParam.put("payModel", payModel);
requestParam.put("payType", payType);
requestParam.put("subOrderType", subOrderType);
requestParam.put("businessType", businessType);
requestParam.put("paySource", paySource);
requestParam.put("version", "V4.0");
requestParam.put("completeUrl", completeUrl);//支付自定义页面
Map<String, String> extraMap = new HashMap<>();
extraMap.put("userAgent", "UnionPay / 1.0 CEBBANK");
requestParam.put("extraInfo", JSON.toJSON(extraMap));
String response = OpenapiRequestUtil.postOpenapi(api_order,
accessKey,
secretKey, requestParam);
JSONObject res = JSONObject.parseObject(response);
//添加判断
if (!(Boolean) res.get("success")){
logger.error("京东下单接口失败:{}",response);
return ret.setFail((String) res.get("msg"));
}
//解析
String qrCode = JSONObject.parseObject(res.get("bankRequest").toString()).get("PAY_URL").toString();
requestParam = new HashMap<>();
JSONObject reqData = new JSONObject();
JSONObject request = new JSONObject();
request.put("url",qrCode+"&sourceID=xxx");
request.put("keyChannel",keyChannel);
request.put("sourceCode",sourceCode);
request.put("deviceInfo","");
reqData.put("request",request);
Map<String,Object> map = new HashMap<>();
String url = prize_url;//金口令地址
map.put("reqData",reqData);
System.out.println("金口令请求体"+map);
String str = HttpUtil.postFormData(url, map);
System.out.println("金口令返回1"+str);
res = JSONObject.parseObject(str);
//添加判断
String code = JSONObject.parseObject(res.get("resultData").toString()).get("code").toString();
if (code!=null && "000".equals(code)){
} else {
String msg = JSONObject.parseObject(res.get("resultData").toString()).get("msg").toString();
logger.debug("调用金口令接口出现异常:{}",msg);
ret.setFail("京东支付生成金口令出现异常");
}
//解析
String data = JSONObject.parseObject(JSONObject.parseObject(res.get("resultData").toString()).get("data").toString()).get("code").toString();
logger.debug("获取金口令:{}",data);
return ret.setSuccess("生成金口令响应",str);
}
httpUtil工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Set;
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
public static String postFormData(String url, Map<String, Object> map) throws Exception {
BufferedReader in = null;
URL urls = new URL(url);
HttpURLConnection connection = null;
OutputStream outputStream = null;
String rs = "";
try {
connection = (HttpURLConnection) urls.openConnection();
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=----footfoodapplicationrequestnetwork");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
connection.setRequestProperty("Accept", "*/*");
connection.setRequestProperty("Range", "bytes=" + "");
connection.setConnectTimeout(8000);
connection.setReadTimeout(20000);
connection.setRequestMethod("POST");
StringBuffer buffer = new StringBuffer();
outputStream = connection.getOutputStream();
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
// 每次都清空buffer,避免写入上次的数据
buffer.delete(0, buffer.length());
buffer.append("------footfoodapplicationrequestnetwork\r\n");
Object value = entry.getValue();
if (!(value instanceof File)) {
buffer.append("Content-Disposition: form-data; name=\"");
buffer.append(entry.getKey());
buffer.append("\"\r\n\r\n");
buffer.append(entry.getValue());
buffer.append("\r\n");
outputStream.write(buffer.toString().getBytes());
} else {
buffer.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + ((File) entry.getValue()).getName() + "\"\r\n");
buffer.append("Content-Type: " + "zip" + "\r\n\r\n");
outputStream.write(buffer.toString().getBytes());
File file = (File) entry.getValue();
DataInputStream ins = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = ins.read(bufferOut)) != -1) {
outputStream.write(bufferOut, 0, bytes);
}
// 文件流后面添加换行,否则文件后面的一个参数会丢失
outputStream.write("\r\n".getBytes());
}
}
if (entries != null && map.size() > 0) {
buffer.delete(0, buffer.length());
buffer.append("------footfoodapplicationrequestnetwork--\r\n");
}
outputStream.write(buffer.toString().getBytes());
try {
connection.connect();
if (connection.getResponseCode() == 200) {
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String line = "";
while ((line = in.readLine()) != null) {
rs += line;
}
}
} catch (Exception e) {
logger.error("发生异常",e);
rs = null;
}
return rs;
} finally {
try {
outputStream.close();
if (in != null){
in.close();
}
} catch (Exception e) {
logger.error("发生异常",e);
}
outputStream = null;
if (connection != null)
connection.disconnect();
connection = null;
}
}
}
2、生成金口令
将下单接口返回的pay_url,拼接上sourceID(京东工作人员会提供)作为url字段参数,去调用金口令接口
调用成功后,可以将生成的金口令响应给前端
3、编写回调方法验证支付订单
在京东平台付款成功后,京东平台会调用这个接口,我们需要做的2步:
(1)验证签名
通过签名验证订单身份,保证订单是自己的订单
(验证签名的demo京东线上文档中也提供了,可以下载参考)
(2)验证通过后编写付款后的业务逻辑
当然,还有退款接口,下载账单接口等,文档中都提供了,可以根据项目情况类比去开发