这篇文章主要给大家结合微信支付接口开发的实践,从获取用户授权到各主要接口的使用方法等方面介绍微信支付的关键点技术,有需要的小伙伴可以参考下

最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时间,也只是达到了实现功能的水平,并没有太多考虑到性能问题,所以这篇文章比较适合初学者。
微信公众号支付的总体其实很简单,大致就分为三步。
   第一步需要获取用户授权;
   第二步调用统一下单接口获取预支付id;
   第三步H5调起微信支付的内置的js。
下面介绍具体每一步的开发流程。

一、    首先要明确微信公众号支付属于网页版支付,所以相较于app的直接调取微信支付要多一步微信授权。也就是需要获取用户的openid。微信公众号使用的交易类型是JSAPI,所以统一下单接口的文档明确的写到

因此我们必须去获取openid,同时也可以处理一些我们需要的逻辑。获取用户授权有两种方式:1.scope=snsapi_base;2.scope=snsapi_userinfo.我使用的是snsapi_base  //具体可参照官方文档
Scope为snsapi_base
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf4bd796d62cb1bb5&redirect_uri=http://www.muguaerp.com/mcc/mobile/shop/product/pay.jhtml&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
注意:这是发起支付前的操作。这里的 redirect_uri需要填写你要发起支付的页面
参数详解:
首先appid就不多说了就是你微信公众号的appid固定写死的,redirect_uri这个参数是最重要的,这个地址是访问你处理的接口地址。你可以在这个链接上拼接上你所需要的参数,一般你是要把订单的金额传到这个接口里的,访问这个链接的时候微信会给你code你需要用它去获取openid,记得要对其进行urlencode处理。state参数可以理解为扩展字段,其他的参数都是固定写法就不在多做介绍了。下面是获取openid的代码片段。
//第1步 获取openId
  HttpClientUtil util = HttpClientUtil.getInstance();Map<String, String> map = new HashMap<String, String>();map.put("appid", Configure.getAppid());map.put("secret",Configure.getAppsecret());map.put("code", code);map.put("grant_type", Configure.getGrant_type());String returnStr = util.getResponseBodyAsString("https://api.weixin.qq.com/sns/oauth2/access_token", map);AccessToken at = JSON.parseObject(returnStr, AccessToken.class);System.out.println(at);
//工具类
AccessToken.javapublic class AccessToken {private String access_token;private String expires_in;private String refresh_token;private String openid;private String scope;private String unionid;public String getAccess_token() {return access_token;}public void setAccess_token(String access_token) {this.access_token = access_token;}public String getExpires_in() {return expires_in;}public void setExpires_in(String expires_in) {this.expires_in = expires_in;}public String getRefresh_token() {return refresh_token;}public void setRefresh_token(String refresh_token) {this.refresh_token = refresh_token;}public String getOpenid() {return openid;}public void setOpenid(String openid) {this.openid = openid;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}public String getUnionid() {return unionid;}public void setUnionid(String unionid) {this.unionid = unionid;}@Overridepublic String toString() {return "AccessToken [access_token=" + access_token + ", expires_in="+ expires_in + ", refresh_token=" + refresh_token + ", openid="+ openid + ", scope=" + scope + ", unionid=" + unionid + "]";}}

二、    我们获取了openid后,就可以进行下一步的统一下单的开发了。微信上统一下单接口的文档写的比较详细了,具体的参数含义我就不多做介绍了。下面直接贴最直观的代码,特别提醒的是一定要注意签名的正确。签名所使用的key并不是AppSecret而是你申请时自己定义的商户key。

//第2步 统一下单

 String strAttach = "微信支付";//strAttach = new String(strAttach.getBytes("gbk"),"utf-8");String strBody = "微信公众号支付";//strBody = new String(strBody.getBytes("gbk"),"utf-8");Order order= orderService.findBySn(sn);String ip = request.getRemoteAddr();WxPaySendData data = new WxPaySendData();data.setAppid(Configure.getAppid());data.setAttach(URLEncoder.encode(strAttach, "UTF-8"));data.setBody(URLEncoder.encode(strBody, "UTF-8"));data.setMch_id(Configure.getMchid());data.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));data.setNotify_url(Configure.getNotify_url());data.setOut_trade_no(UtilDate.getOrderNum());data.setTotal_fee((order.getAmount().multiply(new BigDecimal(100)).intValue()));//单位:分data.setTrade_type("JSAPI");data.setSpbill_create_ip(ip);data.setOpenid(at.getOpenid());String returnXml = UnifiedorderService.unifiedOrder(data,Configure.getKey());WxPayReturnData reData = new WxPayReturnData();XStream xs1 = new XStream(new DomDriver());xs1.alias("xml", WxPayReturnData.class);reData = (WxPayReturnData) xs1.fromXML(returnXml);

注意:这里腾讯用的是xml格式的参数因此需要把参数转成xml格式。这里用的是XStream,并且需要把sendData 和 returnData 封装成class

//工具类
UnifiedorderService.java
public class UnifiedorderService {private final static Logger logger = LoggerFactory.getLogger(UnifiedorderService.class);public static String unifiedOrder(WxPaySendData data,String key){//统一下单支付String returnXml = null;try {//生成sign签名SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();parameters.put("appid", data.getAppid()); parameters.put("attach", data.getAttach());parameters.put("body", data.getBody());parameters.put("mch_id", data.getMch_id());parameters.put("nonce_str", data.getNonce_str());parameters.put("notify_url", data.getNotify_url());parameters.put("out_trade_no", data.getOut_trade_no());parameters.put("total_fee", data.getTotal_fee());parameters.put("trade_type", data.getTrade_type());parameters.put("spbill_create_ip", data.getSpbill_create_ip());parameters.put("openid", data.getOpenid());parameters.put("device_info", data.getDevice_info());logger.info("SIGN:"+WxSign.createSign(parameters,key));data.setSign(WxSign.createSign(parameters,key));XStream xs = new XStream(new DomDriver("UTF-8",new XmlFriendlyNameCoder("-_", "_")));xs.alias("xml", WxPaySendData.class);String xml = xs.toXML(data);logger.info("统一下单xml为:\n" + xml);HttpClientUtil util = HttpClientUtil.getInstance();returnXml = util.doPostForString("https://api.mch.weixin.qq.com/pay/unifiedorder", null, xml);logger.info("返回结果:" + returnXml);} catch (Exception e) {e.printStackTrace();} return returnXml;}}
//工具类
WxSign.java
public class WxSign {private static String characterEncoding = "UTF-8";@SuppressWarnings("rawtypes")public static String createSign(SortedMap<Object,Object> parameters,String key){ StringBuffer sb = new StringBuffer(); Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序) Iterator it = es.iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); String k = (String)entry.getKey(); Object v = entry.getValue(); if(null != v && !"".equals(v)  && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + key);String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); return sign; }public static String getNonceStr() {Random random = new Random();return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");}public static String getTimeStamp() {return String.valueOf(System.currentTimeMillis() / 1000);}}
//md5.java
package com.pawpaw.plugin.tencentpay;import java.security.MessageDigest;/**
* User: rizenguo
* Date: 2014/10/23
* Time: 15:43
*/
public class MD5 {private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7","8", "9", "a", "b", "c", "d", "e", "f"};/*** 转换字节数组为16进制字串* @param b 字节数组* @return 16进制字串*/public static String byteArrayToHexString(byte[] b) {StringBuilder resultSb = new StringBuilder();for (byte aB : b) {resultSb.append(byteToHexString(aB));}return resultSb.toString();}/*** 转换byte到16进制* @param b 要转换的byte* @return 16进制格式*/private static String byteToHexString(byte b) {int n = b;if (n < 0) {n = 256 + n;}int d1 = n / 16;int d2 = n % 16;return hexDigits[d1] + hexDigits[d2];}/*** MD5编码* @param origin 原始字符串* @return 经过MD5加密之后的结果*/public static String MD5Encode(String origin) {String resultString = null;try {resultString = origin;MessageDigest md = MessageDigest.getInstance("MD5");resultString = byteArrayToHexString(md.digest(resultString.getBytes()));} catch (Exception e) {e.printStackTrace();}return resultString;}}
//WxPaySendData.java
package com.pawpaw.entity;public class WxPaySendData {//公众号IDprivate String appid;//附加参数private String attach;//商品名称private String body;//商户IDprivate String mch_id;//随机支付串private String nonce_str;//通知地址,不能携带参数,直接就能访问private String notify_url;//用户订单号private String out_trade_no;//总金额 以分为单位private int total_fee;//交易类型private String trade_type;//终端IPprivate String spbill_create_ip;//openIDprivate String openid;//签名private String sign;public String getAppid() {return appid;}public void setAppid(String appid) {this.appid = appid;}public String getAttach() {return attach;}public void setAttach(String attach) {this.attach = attach;}public String getBody() {return body;}public void setBody(String body) {this.body = body;}public String getMch_id() {return mch_id;}public void setMch_id(String mch_id) {this.mch_id = mch_id;}public String getNonce_str() {return nonce_str;}public void setNonce_str(String nonce_str) {this.nonce_str = nonce_str;}public String getNotify_url() {return notify_url;}public void setNotify_url(String notify_url) {this.notify_url = notify_url;}public String getOut_trade_no() {return out_trade_no;}public void setOut_trade_no(String out_trade_no) {this.out_trade_no = out_trade_no;}public int getTotal_fee() {return total_fee;}public void setTotal_fee(int total_fee) {this.total_fee = total_fee;}public String getTrade_type() {return trade_type;}public void setTrade_type(String trade_type) {this.trade_type = trade_type;}public String getSpbill_create_ip() {return spbill_create_ip;}public void setSpbill_create_ip(String spbill_create_ip) {this.spbill_create_ip = spbill_create_ip;}public String getOpenid() {return openid;}public void setOpenid(String openid) {this.openid = openid;}public String getSign() {return sign;}public void setSign(String sign) {this.sign = sign;}}
//WxPayReturnData.java
package com.pawpaw.entity;public class WxPayReturnData {//业务结果private String return_code;//消息private String return_msg;//公众号IDprivate String appid;//商户IDprivate String mch_id;//随机支付串private String nonce_str;//签名private String sign;//业务结果private String result_code;//预支付IDprivate String prepay_id;//交易类型private String trade_type;public String getReturn_code() {return return_code;}public void setReturn_code(String return_code) {this.return_code = return_code;}public String getReturn_msg() {return return_msg;}public void setReturn_msg(String return_msg) {this.return_msg = return_msg;}public String getAppid() {return appid;}public void setAppid(String appid) {this.appid = appid;}public String getMch_id() {return mch_id;}public void setMch_id(String mch_id) {this.mch_id = mch_id;}public String getNonce_str() {return nonce_str;}public void setNonce_str(String nonce_str) {this.nonce_str = nonce_str;}public String getSign() {return sign;}public void setSign(String sign) {this.sign = sign;}public String getResult_code() {return result_code;}public void setResult_code(String result_code) {this.result_code = result_code;}public String getPrepay_id() {return prepay_id;}public void setPrepay_id(String prepay_id) {this.prepay_id = prepay_id;}public String getTrade_type() {return trade_type;}public void setTrade_type(String trade_type) {this.trade_type = trade_type;}}

最后要提一下的是NOTIFY_URL回调地址,接收微信支付异步通知回调地址。

三    通过上面的操作我们获得了预支付交易会话标识prepay_id,这样我们就可以进行最后一步的操作了。使用H5调起支付api。

//第3步 数据传到前端,H5调起支付
  model.addAttribute("appId", reData.getAppid());model.addAttribute("timeStamp", Wxsign.getTimeStamp());model.addAttribute("nonceStr", reData.getNonce_str());model.addAttribute("Package", "prepay_id="+reData.getPrepay_id());model.addAttribute("signType", "MD5");SortedMap<Object,Object> signMap = new TreeMap<Object,Object>();signMap.put("appId", reData.getAppid()); signMap.put("timeStamp", Wxsign.getTimeStamp());signMap.put("nonceStr", reData.getNonce_str());signMap.put("package", "prepay_id="+ reData.getPrepay_id());signMap.put("signType", "MD5");model.addAttribute("paySign", Wxsign.createSign(signMap,Configure.getKey()));model.addAttribute("numb", order.getSn());model.addAttribute("order", order);

将需要的参数传给页面后,使用微信提供方法调起支付。

<script type="text/javascript">
$(function(){
//这里是调用微信内置浏览器的微信支付
$("#anniu_z").click(function(){
callPay();
});function onBridgeReady() {WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId" : "${appId}",//"wx2421b1c4370ec43b", //公众号名称,由商户传入   "timeStamp" : "${timeStamp}",//"1395712654", //时间戳,自1970年以来的秒数   "nonceStr" : "${nonceStr}",//"e61463f8efa94090b1f366cccfbbb444", //随机串   "package" : "${Package}",//"prepay_id=u802345jgfjsdfgsdg888","signType" : "${signType}",//"MD5", //微信签名方式:   "paySign" : "${paySign}"//"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 }, function(res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回  ok,但并不保证它绝对可靠。  //alert(res.err_msg);if (res.err_msg == "get_brand_wcpay_request:ok") {//alert("支付成功");//这里是商品入库$.ajax({url:'${base}/mobile/shop/product/returnPay.jhtml',type:'post',dataType:'json',success:function(message){$.message(message);if("${productCategory.name}"=="教育文库"){setTimeout('location.href="${base}/mobile/shop/product/searchWord.jhtml?id=${product.id}"',3000);}else {setTimeout('location.href="${base}/mobile/shop/product/search.jhtml?id=${product.id}"',3000);}}});                }if (res.err_msg == "get_brand_wcpay_request:cancel") {alert("交易取消");}if (res.err_msg == "get_brand_wcpay_request:fail") {alert("支付失败");}});}function callPay() {if (typeof WeixinJSBridge == "undefined") {if (document.addEventListener) {document.addEventListener('WeixinJSBridgeReady', onBridgeReady,false);} else if (document.attachEvent) {document.attachEvent('WeixinJSBridgeReady', onBridgeReady);document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}} else {onBridgeReady();}}});
</script>
在返回结果的地方可以自定义一些自己的返回页面。
   总结:由于我也是第一次做,写这篇文章是想记录一下自己的工作成果,和分享给一下也是新手的朋友们可以有一些帮助,最后希望有好的见解朋友可以留言讨论,大家一起学习进步。
以上就是关于java开发微信公众支付的所有内容了,希望大家能够喜欢。

补充一下:微信公众号开发用到的所有工具类

java开发微信公众号支付相关推荐

  1. Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

    在前几节文章中我们讲述了微信公众号环境的搭建.如何接入微信公众平台.以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装:接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这 ...

  2. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  3. 微信公众号页面支付接口java,[Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付...

    [Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付 0 2015-09-15 15:00:30 一.调用微信的JS文件 1.首先要绑定[JS接口安全域名],"公众号设置&q ...

  4. Java开发微信公众号之被动回复用户消息-回复图片消息

    一.前言 hello小伙伴们,大家好,做微信开发两年了,最近看到微信方面的文章阅读量和关注量上升的比较快速,激发了我满满的动力啊,所以就滋生了一个想法,从头开始整理一下微信公众号开发,写一个简易的教程 ...

  5. java版微信公众号支付

    前言 今天是2020-4-1愚人节,好久没写博客了,今天准备写一篇微信公众号支付,刚好公司给了我账户,让我有参数测试,由于以前对于支付是小白,所以把这个功能打通花了2天,一天8小时,首先看官网文档,其 ...

  6. Java开发微信公众号之整合weixin-java-tools框架开发微信公众号

    微信开发者接入文档 : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319 微信公众平台测试账号申请: http ...

  7. java开发微信公众号(SpringMVC)1-简述

    很久之前就想了解并真正着手去做微信公众号的开发,在这一个多月终于有时间去看微信的开发文档,并利用自己的熟悉语言java去做这方面的一些东西. 要想真正去了解微信公众号的提供的接口的功能,开发文档虽然写 ...

  8. 用java开发微信公众号:测试公众号与本地测试环境搭建(一)

    本文为原创,原始地址为:http://www.cnblogs.com/fengzheng/p/5023678.html 俗话说,工欲善其事,必先利其器.要做微信公众号开发,两样东西不可少,那就是要有一 ...

  9. java开发微信公众号(SpringMVC)2-消息管理功能

    微信移动端软件,可以向公众号发送消息,如文字,语音,图片等等,在这个过程中,微信端服务器首先要接受到你发送的消息,然后根据你发送的消息会产生不同的回应. 这个回应要想自己设定内容(微信公众号管理界面可 ...

最新文章

  1. 以金山界面库(openkui)为例思考和分析界面库的设计和实现——代码结构(完)
  2. 在不同浏览器中,input里面的输入光标大小表现形式却大不相同
  3. 今天犯的一个错误,导致method GET must not have a request body
  4. 基于Orangpi Zero和Linux ALSA实现WIFI无线音箱(三)
  5. Synchronized 天天用,实现原理你懂吗?
  6. springCloud(22):Eureka总结提升
  7. poj 1979 Red and Black(BFS)
  8. [转] 有什么郁闷的就看看这驴!
  9. 自然语言处理(1)-概述
  10. asp.net生产环境和开发环境的错误日志包装策略
  11. Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简述及技术选型介绍
  12. Mysql 数字类型转换函数
  13. 强烈推荐:事情污,但算法不污,每个想称为大牛的码农都该看,深受启发!...
  14. 向日葵如何远程桌面Linux,最快的远程桌面向日葵软件
  15. mac鼠须管 在简体字模式如何繁体字
  16. 换服务器影响网站排名,网站更换服务器空间会影响排名吗
  17. java 绝对路径双斜线_路径分隔符:正斜线/、反斜线\、双反斜线\\的区别
  18. 【排序】详细聊聊归并排序(含非递归)
  19. php获取访客精确ip,PHP获取访客IP、地区位置等技巧分享
  20. 深圳09年各行薪水大全

热门文章

  1. 求伯君—— 一个你必须知道的程序员
  2. 谈谈对K8S CNI、CRI和CSI插件的理解
  3. 目前学UI设计好就业吗?做UI设计还会有发展潜力?
  4. 2022.9.28号,C语言学习小记
  5. python代码代写_python代写代码
  6. 【本周Python热点回顾】画一棵漂亮的樱花树,Python3*和**运算符,Python入门,这就是Python3.8么,i了
  7. 发邮件窗体【支持编辑邮件模板,使用wse多线程上传附件及发邮件(带附件)】以及在服务器端自动发邮件...
  8. Android适合手机开发的又一力证——安卓街机
  9. 充值10万跌成860元,YAM一日崩盘记
  10. linux最新官方回应只峰身份,Linux的用户认证和授权研究.doc