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

一、情景描述

当前项目想在微信小程序付款时添加上京东支付支付类型,效果如下
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("京东支付订单不可为空!");
        }
        // 得到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)验证通过后编写付款后的业务逻辑

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue(二十):ElementUI 扩展实现表格组件的拖拽行

效果 源码 注意&#xff1a; 表格组件必须添加 row-key 属性&#xff0c;用来优化表格的渲染 <template><el-row :gutter"10"><el-col :span"12"><el-card class"card"><el-scrollbar><span>注意: 表格组件…

c++设计模式之观察者模式(发布-订阅模式)

介绍 观察者模式主要关注于对象的一对多关系&#xff0c;其中多个对象都依赖于一个对象&#xff0c;当该对象的状态发生改变时&#xff0c;其余对象都能接收到相应的通知。 如&#xff0c;现在有 一个数据对象三个画图对象&#xff0c;分别wield曲线图、柱状图、饼状图三个对象…

AI Prompt工程师 学习整理

前言 如果说Al大语言模型(LLM,Large Language Model)是宝藏我,那么Prompt提示词就是打开宝藏的钥匙。 最新一代的Al大语言模型具备出色的创作能力,能够生成富有人类感情、严谨逻辑、多场景应用的内容,而如何获得高质量的回答,正确学习使用Prompt提示词是关键。 &#x1f4a5…

详解WebRTC rtc::Thread实现

rtc::Thread介绍 rtc::Thread类不仅仅实现了线程这个执行器&#xff08;比如posix底层调用pthread相关接口创建线程&#xff0c;管理线程等&#xff09;&#xff0c;还包括消息队列&#xff08;message_queue)的实现&#xff0c;rtc::Thread启动后就作为一个永不停止的event l…

2023爱分析·知识库问答市场厂商评估报告:爱数

01 研究范围定义 研究范围&#xff1a; 大模型是指通过在海量数据上依托强大算力资源进行训练后能完成大量不同下游任务的模型。2023年以来&#xff0c;ChatGPT引爆全球大模型市场。国内众多大模型先后公测&#xff0c;众多互联网领军者投身大模型事业&#xff0c;使得大模型…

【Linux】环境基础开发工具的使用之gcc详解(二)

前言&#xff1a;上一篇文章中我们讲解了Linux下的vim和yum的工具的使用&#xff0c;今天我们将在上一次的基础上进一步的讲解开放工具的时候。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:Linux的深度刨析 &#x1f448; &#x1f4a…

贰[2],Xamarin生成APK

1&#xff0c;生成改为Release版本 2&#xff0c;选中****.Android项目 3&#xff0c;点击生成&#xff0c;选择存档 4&#xff0c;点击分发 5&#xff0c;选择临时 6&#xff0c;添加签名标识 7&#xff0c;选择对应的签名标识&#xff0c;点击另存为

文献阅读:金鱼端脑细胞类型图谱揭示了空间结构和细胞类型进化的多样性

文献介绍 「文献题目」 A telencephalon cell type atlas for goldfish reveals diversity in the evolution of spatial structure and cell types 「研究团队」 Amit Zeisel&#xff08;以色列理工学院&#xff09;、Ronen Segev&#xff08;本古里安大学&#xff09; 「发表…

认识“协议”

协议 协议的概念结构化数据的传输将结构化的数据组合成一个字符串序列化和反序列化协议定制客户端代码服务线程执行例程 协议的概念 协议&#xff0c;网络协议的简称&#xff0c;网络协议是通信计算机双方必须共同遵从的一组约定&#xff0c;比如怎么建立连接、怎么互相识别等…

H12-811_503

503.如下图所示&#xff0c;下列说法正确是&#xff1f;( ) A.主机A和主机B的广播地址相同 B.主机A可以ping通主机B C.主机A和主机B不能获取对方的MAC地址 D.主机A的ARP缓存中存在如下条目10.0.12.5 MAC-B 答案&#xff1a;C 注释&#xff1a; 两个主机IP地址的网…

Elasticsearch:Geoshape query

Geoshape 查询可以用于过滤使用 geo_shape 或 geo_point 类型索引的文档。 geo_shape 查询使用与 geo_shape 或 geo_point 映射相同的索引来查找具有与查询形状相关的形状的文档&#xff0c;并使用指定的空间关系&#xff1a;相交&#xff08;intersect&#xff09;、包含(con…

【代码随想录20】669.修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

目录 669.修剪二叉搜索树题目描述参考代码 108.将有序数组转换为二叉搜索树题目介绍参考代码 538.把二叉搜索树转换为累加树题目描述参考代码 669.修剪二叉搜索树 题目描述 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树…

Map和Set讲解

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f4d5;格言&#xff1a;那些在暗处执拗生长的花&#xff0c;终有一日会馥郁传香欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 集合框架 模型 Set 常见方法和说明 Set总结 Map说明 Map常见方法和说明 Map 中HashMap的 …

SpringMVC入门学习(十)----mvc:annotation-driven标签介绍

目录 1、关于mvc:annotation-driven作用2、mvc:annotation-driven在什么时候必须配置3、关于mvc:annotation-driven配合使用的几种情况 回到顶部 1、关于mvc:annotation-driven作用 [1]、<mvc:annotation-driven /> 会自动向容器中注册如下组件&#xff0c;并且会代替…

2024 美国大学生数学建模竞赛 美赛(D题)五大湖水资源调配问题 国际大学生数学建模竞赛| 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍希望大家都能轻松建模呀&#xff0c;华数杯也会持续给大家放送思路滴~ 抓紧小秘籍&#xff0c;我们出发吧~ 完整内容可以在文章末尾领取&#xff01; 问题一&#xff1a;建立一个包括五大湖和连接从苏必利尔湖到大西洋的河流的…

2024Node.js零基础教程(小白友好型),nodejs新手到高手,(四)NodeJS入门——http协议

041_网络基础概念_IP的介绍 hello&#xff0c;大家好&#xff0c;我们来一起认识一下IP。 在开始介绍 IP 之前&#xff0c;我们首先来介绍一个场景&#xff0c;方便大家去理解 IP 这个概念。比如这会儿强哥正在成都&#xff0c;然后还有另外一个小伙伴&#xff0c;谁呢&#x…

基于OpenCV灰度图像转GCode的单向扫描实现

基于OpenCV灰度图像转GCode的单向扫描实现 引言单向扫描存在的问题灰度图像单向扫描代码示例结论 基于OpenCV灰度图像转GCode的单向扫描实现 本文将介绍如何使用OpenCV库将灰度图转换为GCode&#xff0c;并通过单向扫描实现对图像的激光雕刻。GCode是一种用于控制数控机床和…

史诗级明星联动 酱香珍品醉龙酿让中国酒文化走向世界

史诗级明星联动 酱香珍品醉龙酿让中国酒文化走向世界 秉承百年酱香工艺&#xff0c;融合全球一流酿造技术&#xff0c;酱香珍品醉龙酿全力推动中国酱香风味走向世界&#xff0c;持续引领全球酱香新变革。卓越口感在征服全球各大商业精英、政府人员、明星达人的同时&#xff0c…

Qt5 基于OpenGL实现六轴机械臂三维仿真

需求 在Qt中通过OPenGL方式加载三维模型STL文件&#xff0c;然后将多个结构的STL文件类型的模型进行组装&#xff0c;形成6轴机械臂三维模型的显示&#xff0c;并且可以对每个关节进行关节角度的控制。 新建一个C类STLFileLoader&#xff0c;用于加载STL文件&#xff0c;并进…

pytorch_car_caring 排坑记录

pytorch_car_caring 排坑记录 任务踩坑回顾简单环境问题代码版本问题症状描述解决方法 cuda问题&#xff08;异步问题&#xff09;症状描述解决方法 任务 因为之前那个MPC代码跑出来的效果不理想&#xff0c;看了一天代码&#xff0c;大概看明白了&#xff0c;但要做改进还要有…
最新文章