这两天做微信支付开发。碰到大坑。纠结死我了。好不容做完。

后台java:直接上代码:注意区分前后端的变量大小写。。。

@RequestMapping(value = "/index")
public Model index(@RequestParam(value = "openid", required = true) String openid ,Model model,HttpServletRequest request) throws Exception{
logger.info("************openid***********为:"+openid);
//获取prepayid
Map<String ,String > map=new HashMap<String,String>();
WeiXinConfig wcf=weiXinBaseService.getWeiXinConfig();
String nonceStr=UUID.randomUUID().toString().substring(0, 32); oauthService.shareFactory(request);
String appid=wcf.getAppid();
long timestamp = System.currentTimeMillis() / 1000;
map.put("appid", appid );
map.put("mch_id", WebConfig.get("pay.mch_id"));
map.put("nonce_str",nonceStr);
map.put("body", WebConfig.get("pay.body"));
map.put("out_trade_no", payWxUtil.orderNum());
map.put("total_fee", WebConfig.get("pay.price"));
map.put("spbill_create_ip",request.getRemoteAddr());
map.put("notify_url", WebConfig.get("hostAddress")+request.getContextPath()+"/babyShow/payInfo/info");
map.put("trade_type", "JSAPI");
map.put("openid", openid);
String paySign=SignUtil.getPayCustomSign(map,WebConfig.get("pay.key"));
map.put("sign",paySign);
String xml= CommonUtil.ArrayToXml(map);
String prepayid= payWxUtil.getPrepayid(xml);
logger.info("prepareid*****************************="+prepayid);
//封装h5页面调用参数
Map<String ,String > signMap=new HashMap<String ,String >();
signMap.put("appId", appid);
logger.info("appId="+appid);
signMap.put("timeStamp", timestamp+"");
logger.info("timeStamp="+timestamp);
signMap.put("package", "prepay_id="+prepayid);
logger.info("package="+"prepay_id="+prepayid);
signMap.put("signType", "MD5");
logger.info("singType="+"MD5");
signMap.put("nonceStr", nonceStr);
logger.info("nonceStr="+nonceStr);
model.addAttribute("paytimestamp", timestamp);
model.addAttribute("paypackage", "prepay_id="+prepayid);
model.addAttribute("paynonceStr", nonceStr);
model.addAttribute("paysignType", "MD5");
String paySign2=SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"));
model.addAttribute("paySign",paySign2 );
logger.info("paySign="+paySign2);
return model; }

以上代码获取openid需要根据网页授权来获取。这里就不多讲了。主要讲讲获取prepayid和生成h5页面所需参数,

这里面比较麻烦的就是签名的获取

查看方法SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"))

代码如下

  /**
* 获取支付所需签名
* @param ticket
* @param timeStamp
* @param card_id
* @param code
* @return
* @throws Exception
*/
public static String getPayCustomSign(Map<String, String> bizObj,String key) throws Exception { String bizString = CommonUtil.FormatBizQueryParaMap(bizObj,
false);
logger.info(bizString);
return MD5SignUtil.sign(bizString, key);
}

其中CommonUtil.FormatBizQueryParaMap是用来做字典排序的。有参考了网上的例子。就没单独做。

public static String FormatBizQueryParaMap(Map<String, String> paraMap,
boolean urlencode) throws Exception { String buff = "";
try {
List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
paraMap.entrySet()); Collections.sort(infoIds,
new Comparator<Map.Entry<String, String>>() {
public int compare(Map.Entry<String, String> o1,
Map.Entry<String, String> o2) {
return (o1.getKey()).toString().compareTo(
o2.getKey());
}
}); for (int i = 0; i < infoIds.size(); i++) {
Map.Entry<String, String> item = infoIds.get(i);
//System.out.println(item.getKey());
if (item.getKey() != "") { String key = item.getKey();
String val = item.getValue();
if (urlencode) {
val = URLEncoder.encode(val, "utf-8"); }
buff += key + "=" + val + "&"; }
} if (buff.isEmpty() == false) {
buff = buff.substring(0, buff.length() - 1);
}
} catch (Exception e) {
throw new Exception(e.getMessage());
}
return buff;
}

其中MD5SignUtil.sign(bizString, key)方法如下

public static String sign(String content, String key)
throws Exception{
String signStr = "";
signStr = content + "&key=" + key; return MD5Util.MD5(signStr).toUpperCase(); }
其中MD5Util.MD5(signStr)方法如下
    public final static String MD5(String s) {
char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
byte[] btInput = s.getBytes();
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
CommonUtil.ArrayToXml(map)方法如下
public static String ArrayToXml(Map<String, String> arr) {
String xml = "<xml>"; Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, String> entry = iter.next();
String key = entry.getKey();
String val = entry.getValue();
if (IsNumeric(val)) {
xml += "<" + key + ">" + val + "</" + key + ">"; } else
xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
} xml += "</xml>";
return xml;
}
public static boolean IsNumeric(String str) {
if (str.matches("\\d *")) {
return true;
} else {
return false;
}
}

 

发送请求到微信获取prepayid代码如下

public static String URL="https://api.mch.weixin.qq.com/pay/unifiedorder";
@SuppressWarnings("deprecation")
public JSONObject getPrepayJson(String xml){
HttpClient httpClient = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );
InputStream is = null;
PostMethod method=null;
try {
String url =URL;
method = HttpClientUtils.postMethod(url);
method.setRequestBody(xml);
httpClient.executeMethod(method);
//读取响应
is = method.getResponseBodyAsStream();
JSONObject o =Xml2JsonUtil.xml2JSON(is);
return o;
} catch (Exception e) {
e.printStackTrace();
}finally{
if(method!=null){
method.releaseConnection();
}
if(is!=null){
try {
is.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return null;
}
public String getPrepayid(String xml){
try {
JSONObject jo=getPrepayJson(xml);
JSONObject element=jo.getJSONObject("xml");
String prepayid=((JSONArray)element.get("prepay_id")).get(0).toString();
return prepayid;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String orderNum(){
String chars = "0123456789";
String order = System.currentTimeMillis()+"";
String res = "";
for (int i = 0; i < 19; i++) {
Random rd = new Random();
res += chars.charAt(rd.nextInt(chars.length() - 1));
}
order+=res;
return order;
}

xml转json方法Xml2JsonUtil.xml2JSON(is);。摘自网络

 /**
* 转换一个xml格式的字符串到json格式
*
* @param xml
* xml格式的字符串
* @return 成功返回json 格式的字符串;失败反回null
*/
@SuppressWarnings("unchecked")
public static JSONObject xml2JSON(InputStream is) {
JSONObject obj = new JSONObject();
try {
SAXReader sb = new SAXReader();
Document doc = sb.read(is);
Element root = doc.getRootElement();
obj.put(root.getName(), iterateElement(root));
return obj;
} catch (Exception e) {
log.error("传入XML后转换JSON出现错误===== Xml2JsonUtil-->xml2JSON============>>",e);
return null;
}
} /**
* 一个迭代方法
*
* @param element
* : org.jdom.Element
* @return java.util.Map 实例
*/
@SuppressWarnings("unchecked")
private static Map iterateElement(Element element) {
List jiedian = element.elements() ;
Element et = null;
Map obj = new HashMap();
List list = null;
for (int i = 0; i < jiedian.size(); i++) {
list = new LinkedList();
et = (Element) jiedian.get(i);
if (et.getTextTrim().equals("")) {
if (et.elements().size() == 0)
continue;
if (obj.containsKey(et.getName())) {
list = (List) obj.get(et.getName());
}
list.add(iterateElement(et));
obj.put(et.getName(), list);
} else {
if (obj.containsKey(et.getName())) {
list = (List) obj.get(et.getName());
}
list.add(et.getTextTrim());
obj.put(et.getName(), list);
}
}
return obj;
}
 

服务端基本这么多

前端被微信和我自己挖了大坑,整整搞了两天,擦

先是看的微信文档jssdk文档(开始埋坑。。)

页面引入js

加入

    wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '${appid}', // 必填,公众号的唯一标识
timestamp: '${timestamp}', // 必填,生成签名的时间戳
nonceStr: '${nonceStr}', // 必填,生成签名的随机串
signature: '${signature}',// 必填,签名,见附录1
jsApiList: [
'chooseWXPay'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });

嗯。配置好了。如果传入jsconfig的参数。。。

然后看到jssdk里面有发送一个微信支付请求?

嗯加进去


function pay(){
wx.chooseWXPay({
timestamp: ${paytimestamp}, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: '${paynonceStr}', // 支付签名随机串,不长于 32 位
package: '${paypackage}', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: '${paysignType}', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: '${paySign}', // 支付签名
success: function (res) {
alert("支付成功");
// 支付成功后的回调函数
}
});
}

 

然后发布,执行调试。。尼玛。怎么样都支付不了。一会儿报订单信息错误、一会儿报签名错误。。。找了N多资料均不对

后来想啊。大不了用商户平台提供的文档写接口什么的。于是加入了代码

      function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : "${appid}", //公众号名称,由商户传入
"timeStamp":"${paytimestamp}", //时间戳,自1970年以来的秒数
"nonceStr" : "${paynonceStr}", //随机串
"package" : "${paypackage}",
"signType" : "${paysignType}", //微信签名方式:
"paySign" : "${paySign}" //微信签名
},
function(res){
alert(res.err_msg); // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返 }
);
}
function pay2(){
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();
}
}

发布调试。。。还是不对。。两个按钮pay()和pay2()均不对。pay方法还是一会儿订单信息错误一会儿签名错误。pay2()方法则一直报签名错误。。。尼玛。吧经历放后台签名。。怎么改都不行。签名明明对的啊。可以获取prepayid的。为毛封装h5参数时就出错了呢。。。折腾啊。。。搞了N久。。就尼玛不对。。。后来一个小错误pay方法js报错了。。结果pay2方法确可以执行了。。。吧pay的js报错去了之后pay2又不能用了。。我擦。。哥有预感。。难道两种方式冲突了??于是我把config和pay方法删除了再试试。。。尼玛果然可以了。不能加入config和pay。。。果然可以了。。。我擦。折腾的。。微信啃爹啊。第一种方式无法用有没有,误导人啊。。。正确结果就是商品平台的文档使用方法js如下:

      function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : "${appid}", //公众号名称,由商户传入
"timeStamp":"${paytimestamp}", //时间戳,自1970年以来的秒数
"nonceStr" : "${paynonceStr}", //随机串
"package" : "${paypackage}",
"signType" : "${paysignType}", //微信签名方式:
"paySign" : "${paySign}" //微信签名
},
function(res){
alert(res.err_msg); // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返 }
);
}
function pay(){
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();
}
}

至此。终于把微信支付搞定了。留着博客。防止后人走弯路(config里面不能加入chooseWXPay方法。。切记)

微信支付开发h5调用的更多相关文章

  1. 微信支付开发h5发起支付再次签名,返回给h5前端

    注意:参数区分大小写.

  2. 微信支付开发(7) H5支付

    关键字:微信支付 微信支付v3 H5支付 wap支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3_h5.html 本文 ...

  3. 微信支付之H5支付

    HoJe男孩子你要加油阿 前言准备材料H5支付请求的参数返回结果统一下单回调接口用到的工具类886 . 前言 大家好,分享是快乐的,也见证了个人成长历程,文章大多都是工作经验总结以及平时学习积累,基于 ...

  4. PHP微信支付开发实例

    这篇文章主要为大家详细介绍了PHP微信支付开发过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 PHP微信支付开发过程,分享给大家,供大家参考,具体内容如下 1.开发环境 Thinkphp 3. ...

  5. 微信支付开发(11) Native支付

    关键字:微信公众平台 微信支付 Native原生支付作者:方倍工作室原文:http://www.cnblogs.com/txw1958/p/wxpay-native.html 由于微信支付接口更新,本 ...

  6. PHP微信支付开发之扫描支付(模式二)后如何回调

    其实在写这篇文章的时候感觉自己已经落伍了,不过笔者在百度上搜索"微信支付开发之扫描支付(模式二)后如何回调"寻找答案时,发现依旧有很多朋友没有解决这个问题,所以就把自己的解决思路分 ...

  7. PHP微信支付开发

    此链接https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_2,是微信官方的示例,无效,报错. 1.申请微信支付的开通条件?什么样的账号可以 ...

  8. 微信支付开发 c# SDK JSAPI支付开发的流程和微信大坑

    微信支付开发流程 1. 开通微信支付功能 省略 2. 下载微信的C#版的微信SDK 下载连接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chap ...

  9. Android开发 --微信支付开发(转载!)(开发工具:Eclipse)

    Android_APP 微信支付接口开发 日期:2015-10-06 12:47:33 作者: 来源: 人气:3549 1.首先说一下我们在开发微信支付接口的时候遇到最多和最疑惑的问题,那就是明明 a ...

随机推荐

  1. Xshell5配置ssh免密码登录-公钥与私钥登录linux服务器(xshell如何登陆上阿里云服务器)

    原文地址:https://blog.csdn.net/longgeaisisi/article/details/78680180 ssh登录提供两种认证方式:口令(密码)认证方式和密钥认证方式.其中口 ...

  2. Linux system basic 2 + add kernel for Jupyter

    Linux install LibreOffice: install LibreOffice: install command: sudo apt install ./XXX.deb PS: don' ...

  3. SpringMVC:Controller配置总结

    西部开源-秦疆老师:SpringMVC系列博客 , 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringMVC:Controlle ...

  4. shiro中setUnauthorizedUrl("/403")不起作用

    最近学习shiro框架,在用户没有权限的情况下想让其跳转到403页面,结果非自己预想的效果.后来找到一个解决办法如下: 转载来源 SpringBoot中集成Shiro的时候, 配置setUnautho ...

  5. sql server和eclipse连接代码

    新建java程序:必须添加sql server驱动程序(上篇博文中有详细过程) package asd; import java.sql.*; //创建数据库连接类 public class DBCo ...

  6. L2-3 名人堂与代金券

    题解 这题的话,每一个人都要占一个排名,即使排名并列了. 对于最后一个排名来说,即使人数超过了指定的k,也要加入. 代码 #include <bits/stdc++.h> using na ...

  7. 题解 【Codeforces489B】 BerSU Ball

    本题是排序基础题. 我们可以将a[i].b[i]分别从小到大排序后,依次枚举比较两两组合是否符合要求,最后输出答案ans即可. AC代码: #include <bits/stdc++.h> ...

  8. xshell配置---文件上传命令rz和下载命令sz

    1.下载安装包 方法一:手动下载安装 1)下载安装包:lrzsz-0.12.20.tar.gz 官网下载地址:http://www.ohse.de/uwe/releases/lrzsz-0.12.20 ...

  9. Unity Coroutine详解(二)

    •        介绍•        Part 1. 同步等待•        Part 2. 异步协程•        Part 3. 同步协程•        Part 4. 并行协程 1.介绍 ...

  10. 使用Eclipse远程调试云服务器上的微信公众项目

    云服务器系统:centos 7.3 如何在Eclipse上调试我们在云服务器上的项目呢,下面介绍一下步骤:   1.因为root账号不支持远程调试,首先需要在linux上创建一个新的用户,然后用该用户 ...