您的位置:首页 > 移动开发 > 微信开发

调用微信扫码接口动态生成支付二维码(java)

2018-01-02 15:31 579 查看
**

前言

**

刚入职的时候接到一个需求,做一个动态生成微信支付二维码的网络接口,网上有许多很好的例子,官方文档也写的很详细,最后成功的实现了,当然后来想了一下,既然是网络通用接口,也许接口调用返回的不是一张二维码图片,而是一个字符串比较好。后面这个我会慢慢解释,我们来看一下具体是怎么实现的。

实现步骤

一、开发前准备

工具 eclipse 开源免费

项目类型 maven

参考实现链接:http://www.demodashi.com/demo/10268.html 我就是参考这个链接做出来的。

要实现这个支付接口的调用,需要用到已认证的服务号。个人的订阅号和公众测试号是没有这个权限的。

二、开发步骤

*1、首先先到微信官方文档链接https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1查看所需要的东西,对流程和原理有清晰的认识。我这里选择的是模式二。*

2、开发过程中需要的参数如下图所示,我也会解释这些参数在哪里可以找到。



appid 服务号公众平台的appid

登录微信公众平台https://mp.weixin.qq.com/

开发——基本配置——公众号开发信息——开发者ID(AppID)

商户号

微信公众平台——微信支付——商户信息——基本信息——商户号

notify_url 扫码支付回调接口

微信商户平台——产品中心——开发配置——支付配置——扫码支付

trade_type 交易类型

这个一般写个 NATIVE 既可以

ufdoder_url 请求的微信支付接口

填写 https://api.mch.weixin.qq.com/pay/unifiedorder这个即可。

api_key 密钥

微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>密钥设置

secertKey 网络接口调用密钥 增加其安全性。

作为一个网络接口,要被调用不仅仅需要一些基本参数,还需要用于验证身份的加密串和时间戳,避免被别人抓取数据包,解析请求地址和参数,从而不断的发起请求,不仅浪费我们的服务器资源,而且容易搞挂服务器。

以上这七个参数基本是固定的。基本是不会改变的,商品名称和金额这里可以写多个,一个商品名称和金额一一对应,每次生成一个二维码取一个组合即可。

个人建议:在编码的时候,对于一些常数参数最好写进配置文件,然后调用的时候把他们写成全局静态变量,这样一来可以方便修改,比如说部署到生产服务器的时候,如果你需要修改参数值,只需要修改配置文件即可,也不需要重新编译和重启服务器,但是你如果是硬编码(在代码中写死)的话,那么你每次修改都得替换class文件和重启服务器;二来可以提高服务器响应速度。比如说要用到notify_url 扫码支付回调接口这个参数值,可以写成

private static String NOTIFYURL = Constants.getProValue(“notify_url “);

3、配置log4j

以前我们本地调试,输出打印的时候,一般使用System.out.println()这样的方式,但是部署到线上服务器的时候,就没有这种待遇了。所以建议大家养成使用log4j写日志的习惯,一旦发现问题,可以通过查看当天的日志,查看具体的参数,从而定位和解决问题。这里有两个比较好的文章log4j.properties配置详解与实例 http://blog.csdn.net/dr_guo/article/details/50718063 和 Log4j 日志文件存放位置设置 http://hbiao68.iteye.com/blog/1947618 看过这两个文章,你将会喜欢上log4j。

我是这样配置log4j的



我的建议是配置文件最好都放在conf这个包下,规范,统一,不过当时抄别人的代码没改。



这是web.xml中的配置,webAppRootKey 和 log4jConfigLocation就是设置生成的文件放置位置的。



log4j还有个特性,这也是我测试的效果,如果你设置的是按天生成日志,那么他当天先会生成一个临时文件,我这里生成的是weixin_pay_,等到了第二天 这个文件名字会变成20180102(weixin_pay_yyyy-MM-dd’.log’ )。

还有,以前是每个类定义日志属性我是使用

private static Logger logger = Logger.getLogger(UserController.class);也就是里面放置类名,现在有一种通用的写法: private static Logger Log = Logger.getLogger(“sysLog”);这样不管你是哪个类,都适用。

三、代码运行逻辑

1、访问控制器controller/UserController.java,下面是参数获取

String productId = request.getParameter(“productId”);

String phone = request.getParameter(“phone”);

String isnotify = request.getParameter(“isnotify”);

String timestamp = request.getParameter(“timestamp”);

String authenticator = request.getParameter(“auth”);

其实如果只为了显示一个二维码,是不需要那么多参数的,不过作为一个网络接口,安全性是不得不考虑的问题。phone 号码isnotify 通知标志,是用来发送成功短信的,也许对于你来说用不上。productId 产品id,用来获取对应的商品名称和金额,比如说001来获取 #商品名称title_wx_51talk_001,fee_wx_51talk_001 在配置文件中对应的值。timestamp ,authenticator 是用来鉴权的,timestamp 时间戳,你可以生成11位毫秒数或者13位微妙数用来判断参数中的时间戳是否过时,比如说超过两小时,那么你这个就是无效请求,不会往下执行。authenticator身份验证加密串,我这里是使用下面的方式加密,先用先将参数按一定顺序排列,中间用 $ 隔开,再加上密钥,进行md5加密,然后再用base64加密,这样生成的字符串安全性还是比较好的。到时候我们只要对比字符串是否一样就可以了。

String beforeAuth = productId + “符号(比如%)” + phone + “符号(比如%)” + isnotify + “符号(比如%)” + timestamp + “符号(比如%)” + secertKey;

String auth = Tools.getBase64Code(Tools.GetMD5Codes(beforeAuth));

2、请求参数的校验。

我是使用 if (productId != null && timestamp != null && isnotify != null && authenticator != null) 这样的方式来校验是否为null避免空指针的,不过这样还需要判断是否为”“,比较麻烦。推荐大家使用下面这个方法,

public static String GetString(Object Obj, String defaultVal) {

try {

if (Obj == null || StringUtil.isEmptyString(Obj.toString()))

return defaultVal;

return Obj.toString();

} catch (Exception e) {

return defaultVal;

}

}

String phoneNum = Tools.GetString(request.getParameter(“phoneNum”), “”);

使用这个工具类就无需每次都去都要判断是否为null,主要是用于避免空指针异常。

3、请求响应

我这里使用的是 String resResult = “{\”returnCode\”:\”-1\”,\”returnMsg\”:\”productId is error\”}”;和 outPrint(response, resResult);这种方式来响应请求,其实这样不是很好。我觉得我这个网络接口还可以早做一次优化,其实如果调用微信支付接口成功,他将会给你返回一个字符串,然后你在制作成二维码。那么响应这里就可以统一响应一个字符串,让调用接口的项目自己去制作二维码,这样一方面可以提高响应速度(返回一个字符串应该比返回一张图片速度更快),一方面代码也可以得到优化。

请求响应的话,建议可以使用实体,然后封装成json数据,这是我目前觉得最好的选择。比如,当然这里没有get set方法,也不是很好,不过可以用。

public class ResultEntity {

public int resultCode = 0;

public int id = 0;

public T resultData;

public String errorMsg = "";


}

使用这个包

import com.alibaba.fastjson.JSON;

写法:

ResultEntity result = new ResultEntity();

result.resultCode = 9999;

result.errorMsg = “操作代码为空”;

返回类型 String

return JSON.toJSONString(result);

使用上面的写法,比我在项目的写法好的多,也方便修改。

4、请求参数校验通过

请求通过后,获取配置文件的参数值,调用 PayToolUtil.createSign(“UTF-8”, packageParams, key) 生成签名。



下面这两个很重要的链接

获取制作微信二维码的字符串https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

发送请求获取到二维码字符串之后,使用谷歌的工具包,将字符串制作成二维码,有效期两个小时。

如果支付成功,将会给你在商户平台设置的支付回调接口地址发送xml结果,这个时候你只需要响应正常即可。

支付成功返回结果通知:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7

最后,制作二维码和返回结果通知已经完成,成功生成二维码。其实这里还有个小问题,那就是支付成功之后,如果在客户端进行页面跳转提示用户,我参考的链接使用的是ajax轮询的方式,不过考虑到用户可能会关闭浏览器啥的;类似于京东或者其他公司,他们是使用支付后自动跳转的方式,不过听说这种对服务器有要求,所以我这里最后使用了将jar包制作成windows服务的方式,也就是启动一个线程,不断去查询数据库,如果有满足条件的用户,就给他发送支付成功短信,同时将通知标志改为1(已通知)。后面我将会写一遍如何制作windows服务的博客,欢迎大家来指点指点。

源代码下载链接:

http://download.csdn.net/download/qq_32574435/10184815

大家只需要将数据库配置和微信相关配置改为自己的即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: