微信刷卡支付API详解

最近因项目需要微信支付,通过扫码抢扫描微信付款码,调用微信刷卡支付API完成扣费,过程中遇到了遇到了一些问题,填了很多坑,所以把自己的经验分享给大家,本篇文章介绍如何使用刷卡支付API。

场景:

收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。首先我们看一下微信官方提供的支付demo,链接:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=5_1#

*对于一些必选参数,即使没什么用,也一定要传。

map.put("appid","你的公众号appid");
map.put("mch_id", "微信支付商户号");
map.put("sub_mch_id", "微信支付分配的子商户号,服务商必填");
map.put("device_info", "终端设备号"));
map.put("body", "商品名称");
map.put("detail", "单品优惠功能字段");
map.put("attach","附加数据");
map.put("out_trade_no", "订单号,要求32个字符内");
map.put("total_fee","支付金额"));
map.put("fee_type","默认人民币:CNY");
map.put("spbill_create_ip",InetAddress.getLocalHost().getHostAddress().toString());//获取调用支付接口的机器终端ip
map.put("goods_tag",  "");
map.put("limit_pay",  "");
map.put("time_start", "");
map.put("auth_code","付款码" );
map.put("scene_info","");
map.put("nonce_str", "");
sign = APIUtil.createSign(map, apikey, "utf-8");
logger.info("sign:"+sign);
map.put("sign",sign);
xml = APIUtil.buildXML(map);
try {
    if(visitUrl!=""||visitUrl!=null) {
        reStr= APIUtil.post(visitUrl, xml);
        System.out.println("reStr:"+reStr);
        if (reStr != null ) {
            xmlMap = APIUtil.reqMsg2Map(reStr);
            String reSign = APIUtil.createSign(xmlMap, apikey, "utf-8");
            logger.info(xmlMap.toString());
            if (reSign.toLowerCase().equals(xmlMap.get("sign").toString().toLowerCase())) {
                logger.info("reSign", true);
            }
        }
    }
    logger.info("接口返回数据=" + reStr);
} catch (Exception e) {
    // TODO Auto-generated catch block
    logger.error(e.getMessage());
}
return xmlMap;

1.首先要明确微信支付是使用MD5进行签名的,这个是进行两次验签的,一次支付前进行验签,一次接收微信返回数据后进行验签,目的是确保这是一次交易。验签我们必须明确:

当然按ASCII排序直接一个TreeMap搞定(不熟悉TreeMap的孩纸们自行查阅资料)。

2. 我们要知道你发过去的数据是个XML,所以必须用把你的参数构造成XML形式。

3. 返回给你的数据也是XML,所以你得转两次。

4. 发送数据了,你发现返回给你签名错误,这时候从哪儿找问题呢?

(1)你的那些参数中有没有中文,有的话进行编码设置,可能你的数据已经乱码

(2)你的商户号和子商户号有没有写对(首先要明确一点,你是服务商还是特约客户,特约客户就是子商户,如果你是服务商,这两个参数你都应该有,如果没有请登陆商户平台进行查询)

(3) 你的密钥是否正确,加密的时候是拼接key的,所以确保你的key正确无误,如果不确定key,可以登陆商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

(4)还有一种,这个就是我说的坑(话说微信的接口文档真叫一个烂),如果你确定你的密钥、商户号、子商户号、appid这些都正确的话,还报签名错误,那么你可以去他们官方的签名校验工具(https://pay.weixin.qq.com/wiki/doc/api/micropay_sl.php?chapter=20_1)检验下你的签名算法是否正确,如果计算出来的签名和你的签名算法算出来一样,那么恭喜你,踩坑了,重置你的密钥再试试(有可能会重置好几次哦,做好准备)。

(5) 如果很幸运,你成功调用了接口,这时候你高兴的递交了代码,静等测试给你反馈了,你觉得没问题,很完美。好了,梦醒了,继续测吧,bug很多:

① 你发现钱扣了,但是返回失败,为什么呢?

明确一个很重要的点,return_code是通信表示,他返回成功知识说明你接口调通了,不能说明业务成功,业务成功看result_code。

② 你的用户有可能开通了免密支付,如果免密支付,那你这个代码很成功,no bug。如果你的用户设置了非免密支付,那么bug来了。这时候result_code也是FAIL,但是钱扣了,怎么办?如果你用debug调试,你会发现 err_code是USERPAYING,这就表明用户在输入密码,所以你得调查询订单接口,去查询订单,不要立即去查,每隔10秒。

如果这个时候result_code和rade_state都返回成功,这才表示用户支付成功了。

下来就是你根据自己的业务进行的一些操作,就不表述了,下来咋们看微信退款,支付是不需要证书的,但是退款需要双向证书。你先要想一想你把证书放哪儿,两个建议,第一种放数据库(以二进制的形式存在BLOB类型),第二种放在resource里面单独建一个文件夹。

我是以第二种形式存放的。

但是记得在pom.xml中配置。

微信退款和支付传参、加密等一摸一样,就不多说了,我只说重点,怎么加载呢?明确一下,咋们是不需要解析证书的!而且证书默认密码是你的商户号。

加载:

KeyStore keyStore  = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File("文件目录"));//P12文件目录
try {
    keyStore.load(instream, "商户号".toCharArray());//这里写密码..默认是你的MCHID
} finally {
    instream.close();
}
SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "商户号".toCharArray())//这里也是写密码的
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

这样你发现,加载成功了,但是你还是没有调用成功,因为你没设置响应头信息,传过去是乱码!!!!相信我,你需要它,在你加载证书的工具类里把这些东西加上就完美了:

try {
    HttpPost httpost = new HttpPost(url); // 设置响应头信息
    httpost.addHeader("Connection", "keep-alive");
    httpost.addHeader("Accept", "*/*");
    httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    httpost.addHeader("Host", "api.mch.weixin.qq.com");
    httpost.addHeader("X-Requested-With", "XMLHttpRequest");
    httpost.addHeader("Cache-Control", "max-age=0");
    httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
    httpost.setEntity(new StringEntity(data, "UTF-8"));
    CloseableHttpResponse response = httpclient.execute(httpost);
    try {
        HttpEntity entity = response.getEntity();
        String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
        EntityUtils.consume(entity);
        return jsonStr;
    } finally {
        response.close();
    }
} finally {
    httpclient.close();
}

这样微信支付就完了,建议不要用撤销接口,没必要,以前一直给你们提供代码,现在发现思路更重要,所以就不提供源码了,有啥问题可以留言或者Email我,programmerSuperLuo@163.com.后面带你们踩踩支付宝的坑和银联的坑。

原文发布于微信公众号 - Java大联盟(javaunion)

原文发表时间:2018-06-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

从零开始创建一个基于Go语言的web service

20个小时的时间能干什么?也许浑浑噩噩就过去了,也许能看一些书、做一些工作、读几篇博客、再写个一两篇博客,等等。而黑客马拉松(HackAthon),其实是一种自...

3499
来自专栏咸鱼不闲

科大讯飞语音识别和语音播放dome

首先登陆科大讯飞开发者平台,注册账号,(走你->http://www.xfyun.cn/) 可以根据功能(语音识别,语音播放等),平台(java,window等...

865
来自专栏Hans362 's Lab

UTF8-BOM编码导致Html顶部白条问题

自从给博客加上了Google Adsense的广告,就出现了一个很困扰我的问题:网页顶部莫名空出了一个白条。虽然对于网页的访问没有什么影响,但是...强迫症不能...

761
来自专栏熊二哥

快速入门系列--WCF--08扩展与新特性

最后一章将进行WCF扩展和新特性的学习,这部分内容有一定深度,有一个基本的了解即可,当需要自定义一个完整的SOA框架时,可以再进行细致的学习和实践。 ? 服务...

1997
来自专栏Golang语言社区

转--在学Go语言

开始学点儿Go语言,这语言据说在国内比在国外火,社区上褒贬不一,不过“小马过河”嘛,总要先自己试试再来下结论。 环境准备: 1.在Golang中国下载安装go语...

3417
来自专栏极客编程

用go语言创建区块链

本文你将用Go语言创建自己的区块链、理解哈希函数是如何保持区块链的完整性、掌握如何创造并添加新的块、实现多个节点通过竞争生成块、通过浏览器来查看整个链、了解所有...

662
来自专栏FreeBuf

crossdomain.xml文件配置不当利用手法

不恰当的crossdomain.xml配置对存放了敏感信息的域来说是具有很大风险的。可能导致敏感信息被窃取和请求伪造。攻击者不仅仅可以发送请求,还可以读取服务器...

2867
来自专栏刘望舒

Android P 适配指南

Google自 android L (5.0) 以来就持续对安装系统进行 安全 以及 性能上的升级,此次的 android P (9.0)也不例外, 更大程度...

2312
来自专栏Jerry的SAP技术分享

SAP产品的Field Extensibility

SAP开发人员的工作职责,除了实现软件的功能性需求外,还会花费相当的精力实现一些非功能性需求,来满足所谓的SAP Product Standard(产品标准)。...

971
来自专栏程序员互动联盟

【专业技术】OpenStack的架构详解

OpenStack既是一个社区,也是一个项目和一个开源软件,它提供了一个部署云的操作平台或工具集。其宗旨在于,帮助组织运行为虚拟计算或存储服务的云,为公有云、私...

3558

扫码关注云+社区