调用微信扫码接口动态生成支付二维码(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”);这样不管你是哪个类,都适用。
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 {
}
使用这个包
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
大家只需要将数据库配置和微信相关配置改为自己的即可。
前言
**刚入职的时候接到一个需求,做一个动态生成微信支付二维码的网络接口,网上有许多很好的例子,官方文档也写的很详细,最后成功的实现了,当然后来想了一下,既然是网络通用接口,也许接口调用返回的不是一张二维码图片,而是一个字符串比较好。后面这个我会慢慢解释,我们来看一下具体是怎么实现的。
实现步骤
一、开发前准备工具 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
大家只需要将数据库配置和微信相关配置改为自己的即可。
相关文章推荐
- java微信小程序调用支付接口
- java调用微信v3版本支付接口
- 微信扫码支付第一种场景(先生成产品二维码,用户扫码生成交易)JAVA开发总结
- 【java微信开发】红包接口调用
- php调用google接口生成二维码示例
- JAVA版 微信js-sdk接口调用demo
- 调用谷歌接口生成二维码
- 长链接生成短链接Java源码(调用百度接口)
- java调用第三方支付接口
- 微信支付配置信息,JSAPI接口,H5调用微信js接口支付,微信公众号支付
- Linux中关于JAVA调用C生成的.so动态链接库
- java源码动态生成编译,以及方法调用
- java生成二维码 并调用二维码打印机
- [实例]JAVA调用微信接口发送图文消息,不用跳到详情页
- JAVA 调用接口或读取某网站源代码进行动态解析
- 微信卡券【生成卡券二维码】接口 说明文档有错误
- 微信支付配置信息,JSAPI接口,H5调用微信js接口支付,微信公众号支付
- javaweb之生成微信二维码
- java中调用C/C++编写的生成的动态连接库dll文件接口的简单例子
- java通过jacob调用word (根据Word模板生成动态内容)