小程序支付类型接入京东支付

一、情景描述

当前项目想在微信小程序付款时添加上京东支付支付类型,效果如下
https://img-blog.csdnimg.cn/direct/c5fd36bcc199465cbb5ecfbb3b440b1c.png
普通的付款方式可以直接付款就能完成支付,但京东支付无法在小程序上直接付款,他需要复制生成的链接,然后打开京东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("京东支付订单不可为空!");}// 得到openidString 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());//openidrequestParam.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)验证通过后编写付款后的业务逻辑

当然,还有退款接口,下载账单接口等,文档中都提供了,可以根据项目情况类比去开发

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/449427.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络异常案例六_IP冲突

问题现象 同一个局域网下&#xff0c;一个路由器带几十台终端设备&#xff0c;存在终端设备获取到了相同IP的场景。该路由器也是DHCP Server。 有两个设备终端&#xff0c;都显示获取到了192.168.11.177这个ip。 抓包分析 抓包过程中&#xff0c;看到的一些问题。 ps&#x…

使用ngrok内网穿透

没有服务器和公网IP&#xff0c;想要其他人访问自己做好的网站&#xff0c;使用这款简单免费的内网穿透小工具——ngrok&#xff0c;有了它轻松让别人访问你的项目~ 一、下载ngrok 官网地址&#xff1a;ngrok | Unified Application Delivery Platform for Developers&#x…

[N-137]基于springboot,vue运动会报名管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 项目采用前后端分离 前端技术&#xff1a;vueAvueElementUI 服务端技术&#xff1a;springbootmybatis 本项目分为用户和管理员两种角…

07 SB3之@HttpExchange(TBD)

HttpExchange是SpringBoot3的新特性. Spring Boot3 提供了新的 HTTP 的访问能力&#xff0c;封装了Http底层细节. 通过接口简化 HTTP远程访问&#xff0c;类似 Feign 功能。 SpringBoot 中定义接口提供 HTTP 服务 --> 框架生成的代理对象实现此接口 --> 框架生成的代理…

Docker 阿里云镜像仓库CR使用实践

一、使用容器镜像&#xff0c;查看镜像&#xff0c;创建&#xff0c;推送&#xff0c;拉取阿里云镜像 CR镜像管理&#xff08;阿里云容器镜像服务&#xff08;Container Registry&#xff09;&#xff09; 登录实例 未创建的镜像名称也可以push、docker的私有仓库需要提起创建…

LangGPT-人人都可以写高质量的prompt

使用 LangGPT&#xff0c;可以在几分钟内轻松上手大模型指令编写。 网址&#xff1a;https://github.com/EmbraceAGI/LangGPT/tree/main 手册&#xff1a;⭐LangGPT 结构化提示词 模版 # Role: 角色名## Profile - Author: 西堂 - Version: 0.1 - Language: 中文 - Descripti…

C++ cin 的过程

从一段代码开始&#xff1a; int main() {int a, b;cin >> a >> b; }首先阻塞在 cin >> a >> b 中&#xff0c;等待用户输入&#xff0c;用户可以一直输入&#xff0c;直到输入了回车&#xff0c;这时一个以 \n 结尾的字符串就会输入到cin 的 charact…

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效…

【AI绘画UI+Windows部署】Fooocus:Controlnet原作者结合了sd的开源和Midjourney重新设计的UI

代码&#xff1a;https://github.com/lllyasviel/Fooocus windows一键启动包下载&#xff1a;https://github.com/lllyasviel/Fooocus/releases/download/release/Fooocus_win64_2-1-831.7z B站视频教程&#xff1a;AI绘画入门神器&#xff1a;Fooocus | 简化SD流程&#xff0c…

uni-app 经验分享,从入门到离职(三)——关于 uni-app 生命周期快速了解上手

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是生命周期&#x1f9e9;应用生命周期&#x1f4cc; 关于 App.vue/App.uvue &#x1f9e9;页面生命周期&#x1f4cc;关于 onShow 与 onLoad 的区别 &#x1f9e9;组件生命周期 &#x1f4dd;最后 &#x1f4cb;前言 这…

Maven的安装以及配置(超级详细版)

前言 至于什么是Maven&#xff0c;大家可以理解为之前的Vue一样&#xff0c;也是通过操控对象映射来使用的 他内部还有很多的插件用于实现对应的功能&#xff0c;例如打包插件&#xff0c;或是测试 maven下载 Maven – Download Apache Maven apache下的开源项目&#xff0c…

k8s kubeadm部署安装详解

目录 kubeadm部署流程简述 环境准备 步骤简述 关闭 防火墙规则、selinux、swap交换 修改主机名 配置节点之间的主机名解析 调整内核参数 所有节点安装docker 安装依赖组件 配置Docker 所有节点安装kubeadm&#xff0c;kubelet和kubectl 定义kubernetes源并指定版本…