微信H5网页公众号支付教程附demo

微信H5网页公众号支付教程附demo

开发之前请详细阅读微信公众号支付开发文档,并配置好服务器信息。
微信支付开发文档

1.微信支付申请,开通微信商户平台。
这里写图片描述

2.开发配置,填写服务器地址。
这里写图片描述
这里写图片描述

3.在开发电脑上安装证书,用于设置获取商户秘钥。
这里写图片描述

4.设置获取秘钥。
这里写图片描述

开始开发
1.用户点击下面页面自动跳转到微信授权链接。
index.html

<!DOCTYPE HTML>
<html>
  <head>
  	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
  </head>
  <body>
  <script type="text/javascript">
		//用户点击跳转地址(非静默授权) 参数appid为公众号的id redirect_uri为微信回调接口 state为可携带的参数
		window.location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=http://你的域名/weChatpay/mainServlet&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect";

  </script>

  </body>
</html>

2.微信回调处理函数。
MainServlet.java

package com.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import com.utils.CommonUtil;

public class MainServlet extends HttpServlet {

	//网页授权获取用户信息
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		String appid = "";//公众号appid
		String appsecret = "";//公众号秘钥
		//微信返回的code
		String code = request.getParameter("code");
		
		//获取openId和access_token(获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder)
		String openId = "";
		String access_token = "";
		String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appid+"&secret="+appsecret+"&code="+code+"&grant_type=authorization_code";
		JSONObject jsonObject = CommonUtil.httpsRequest(URL, "GET", null);
		if (null != jsonObject) {
			openId = jsonObject.getString("openid");
			access_token = jsonObject.getString("access_token");
		}
		request.getSession().setAttribute("openId", openId);
		
		//获取用户信息
		String nickname = "";
		String headimgurl = "";
		String userURL = "https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+openId+"";
		JSONObject userJson = CommonUtil.httpsRequest(userURL, "GET", null);
		if (null != jsonObject) {
			nickname = userJson.getString("nickname");
			headimgurl = userJson.getString("headimgurl");
		}
		request.getSession().setAttribute("nickname", nickname);
		request.getSession().setAttribute("headimgurl", headimgurl);
		
		response.sendRedirect("shop/index.jsp");//跳转到支付页面
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
}

3.支付页面ajax请求接口获取微信网页调起微信支付的相关参数(详见文档),用户点击购买的时候,请求接口获取支付参数。
shop/index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>
<% String path=request.getContextPath(); String basePath=request.getScheme()+ "://"+request.getServerName()+ ":"+request.getServerPort()+path+ "/"; %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>    
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
        <title>微信商城</title>
        
        <link href="css/style.css" rel="stylesheet">
        <link rel="stylesheet" type="text/css" href="touchTouch/touchTouch.css">
        <link rel="stylesheet" href="css/pintuer.css">
        <script type="text/javascript" src="js/jquery.min.js"></script>
        <script src="js/script.js"></script>
        <script src="js/jquery.js"></script>
        <script src="js/jquery-1.7.1.min.js"></script>
        <script src="touchTouch/touchTouch.jquery.js"></script>
        <script type="text/javascript" src="js/jquery.Spinner.js"></script>
        
        <script type="text/javascript">//参与人数加减
          $(function() {
            $("#d").Spinner();
            $('.thumbs-img').each(function() {
              $(this).children('a').touchTouch();
            });
          });

          //点击图片
          $('.thumbs-img').each(function() {
            9 * $(this).children('a').touchTouch();
          });
		</script>
      </head>
      
      <body>
        <section>
          <banner>
            <img src="img/ban.jpg">
            <yiny></yiny>
          </banner>
          <div class="jindutiao">
            <p>第一期:上海迪士尼门票</p>
            <!--进度条-->
            <progress value="" max=""></progress>
            <div class="canshu">
              <div class="canshu_l">
                <font></font>
                <p>已参与人次</p>
              </div>
              <div class="canshu_z">
                <font></font>
                <p>总需人次</p>
              </div>
              <div class="canshu_r">
                <font></font>
                <p>剩余人次</p>
              </div>
            </div>
          </div>
          <div class="centerq">
            <!--参与人数加减 开始-->
            <div class="center">
              <p>我要参与</p>
              <div id="d" class="Spinner"></div>
              <p>人购买人次越多获得几率越大哦!</p>
            </div>
            <!--参与人数加减 结束-->
            <div class="canyu">
              <p>购买</p>
            </div>
          </div>
          <!--三个切换卡-->
          <div id="cen_right_top">
            <h3 class="active">商品介绍</h3>
            <h3>夺宝记录</h3>
            <h3>用户晒单</h3>
            <!--商品介绍-->
            <div style="display:block" class="tab_show">
              <div class="know">
                <p>您需要知道的"香港迪士尼乐园"</p>
                <ul>
                  <li>
                    <span>特色1</span>&nbsp;&nbsp;迪士尼全球的第十一个主题乐园</li>
                  <li>
                    <span>特色2</span>&nbsp;&nbsp;根据加州迪士尼为蓝本的主题乐园</li>
                  <li>
                    <span>特色3</span>&nbsp;&nbsp;欣赏百老汇式精彩表演</li>
                  <li>
                    <span>特色4</span>&nbsp;&nbsp;畅玩乐趣无穷的动感机动游戏</li></ul>
                <p>香港迪士尼乐园简介</p>
                <ul>
                  <li>香港迪士尼乐园度假区位于香港大屿山,于2005年9月开幕,为宾客提供奇妙迪士尼体验。</li>
                  <li>香港迪士尼乐园分七大主题园区,他们是美国小镇大街、幻想世界、明日世界、探险世界、2011年11月开幕的反斗奇兵大本营、2012年7月开幕的灰熊山谷以及2013年5月开幕的迷离庄园。代表不同年代不同时空的迪士尼体验。</li></ul>
                <div class="jianjie">
                  <h4>&middot;香港迪士尼乐园10周年庆典多个全新精彩演出的体验</h4>
                  <font>香港迪士尼乐园踏入10周年,整个乐园将化身成为耳目一新的华丽大舞台;全新的音乐剧“迪士尼魔法书房”、崭新的影像投影展现“星梦奇缘”烟花表演、全新座落于幻想世界的“童话园林”,以及多款精美礼品、美食和更多精彩活动,诚邀您和挚爱一起投入香港迪士尼乐园10周年庆典,缔造Happily Ever After的时光。</font></div>
                <div class="jianjie">
                  <h4>&middot;全新百老汇式音乐剧迪士尼魔法书房</h4>
                  <font>万众期待的全新音乐剧“迪士尼魔法书房”是特别为香港而创作、乐园历年最大型的娱乐表演制作,由米奇老鼠和高飞带领宾客穿梭7个迪士尼故事,透过华丽表演与崭新舞台技术,投入一个新层次的奇妙旅程。不论音乐、编舞、服饰及舞台设计等都融入了经典及现代元素。
                    <br/>“迪士尼魔法书房”长达28分钟,将于幻想世界的迪士尼故事剧场上演,故事发生于一间魔法书房内,米奇老鼠与高飞好奇打开魔法书,因而令人见人爱的雪人小白从故事书中跌了出来。为了在小白溶化之前带他回到自己的故事,米奇老鼠、高飞及小白踏上奇妙的历险旅程,穿梭于7个迪士尼故事,包括:《小泰山》、《小鱼仙》、《魔发奇缘》、《勇敢传说之幻险森林》、《阿拉丁》、《公主与青蛙》及《魔雪奇缘》。
                    <br/>而为庆祝乐园10周年特别创作的主题歌曲《Happily Ever After》更会压轴登场,为华丽的演出带来圆满的结局。</font>
                  <div class="anli">
                    <img class="left" style="float:left;" src="img/dishini.jpg">
                    <img class="right" style="float:right" src="img/aa.jpg"></div>
                </div>
                <div class="jianjie">
                  <h4>&middot;全新百老汇式音乐剧迪士尼魔法书房</h4>
                  <font>万众期待的全新音乐剧“迪士尼魔法书房”是特别为香港而创作、乐园历年最大型的娱乐表演制作,由米奇老鼠和高飞带领宾客穿梭7个迪士尼故事,透过华丽表演与崭新舞台技术,投入一个新层次的奇妙旅程。不论音乐、编舞、服饰及舞台设计等都融入了经典及现代元素。
                    <br/>“迪士尼魔法书房”长达28分钟,将于幻想世界的迪士尼故事剧场上演,故事发生于一间魔法书房内,米奇老鼠与高飞好奇打开魔法书,因而令人见人爱的雪人小白从故事书中跌了出来。为了在小白溶化之前带他回到自己的故事,米奇老鼠、高飞及小白踏上奇妙的历险旅程,穿梭于7个迪士尼故事,包括:《小泰山》、《小鱼仙》、《魔发奇缘》、《勇敢传说之幻险森林》、《阿拉丁》、《公主与青蛙》及《魔雪奇缘》。
                    <br/>而为庆祝乐园10周年特别创作的主题歌曲《Happily Ever After》更会压轴登场,为华丽的演出带来圆满的结局。</font>
                  <div class="anli">
                    <img class="left" style="float:left;" src="img/dishini.jpg">
                    <img class="right" style="float:right" src="img/aa.jpg"></div>
                </div>
              </div>
            </div>
            <!--夺宝记录-->
            <div class="tab_show">
              <div class="knowq"></div>
            </div>
            <!--用户晒图-->
            <div class="tab_show">
              <div class="know">
               	<div class="tupp" style="width:70%;margin:100px auto 50px auto;">
                	<img src="img/dengdai.png" style="width:100%;">
                </div>
            </div>
          </div>
        </section>
      </body>
      
      <script type="text/javascript">
      //初始化调用方法
      $(function() {
          var openId = '<%=session.getAttribute("openId")%>';
          var headimgurl = '<%=session.getAttribute("headimgurl")%>';
          var nickname = '<%=session.getAttribute("nickname")%>';
          $.ajax({
          	//请求接口获取个人购买记录,返回code开奖编码,timeStr购买时间,status是否中奖(0未开奖,1已中奖,2未中奖)
            url: "http://你的域名/weChatpay/recodeServlet?flag=1&openId=" + openId,
            type: "get",
            dataType: "json",
            success: function(data) {
              //将开奖编码循环写到页面上
              $.each(data,
              function(i, list) {
                var str = "";
                $.each(list,
                function(j, item) {
                  //status=1表示该编码中奖,加上中奖啦图片	
                  if (item.status == 1) {
                    str += "<div class=\"know\">" + "<div class=\"know_l\">" + "<div class=\"touxiang\"><img src=" + headimgurl + "></div><font>" + nickname + "</font></div>" + "<div class=\"know_z\"><font>" + item.code + "</font></div>" + "<div class=\"know_r\"><font id=\"riqi\">" + item.timeStr + "<div class=\"zhang\"><img src=\"img/zhongjiangla.png\"></div></font></div>" + "</div>";
                  } else {
                    str += "<div class=\"know\">" + "<div class=\"know_l\">" + "<div class=\"touxiang\"><img src=" + headimgurl + "></div><font>" + nickname + "</font></div>" + "<div class=\"know_z\"><font>" + item.code + "</font></div>" + "<div class=\"know_r\"><font id=\"riqi\">" + item.timeStr + "</font></div>" + "</div>";

                  }
                });

                $(".tab_show .knowq").html(str);

              });

            }

          });

        });
      </script>
      
      <script type="text/javascript">
      //点击购买按钮调用方法
      $(".canyu").click(function() {
          //获取进度条元素
          var progress = $("progress");
          //进度条不满10人时执行下面代码,若等于10为待开奖状态,则什么也不执行
          if (progress.val() != 10) {

            var openId = '<%=session.getAttribute("openId")%>';
            //num购买数量,money总金额(单位分)
            var num = $(".Amount").val();
            var money = num * 100;
            //防止并发超卖,购买前先增加订单数量判断是否小于10,支付成功后再发放中奖码,若支付失败再减去相应订单数量
            $.ajax({
              url: "http://你的域名/weChatpay/recodeServlet?flag=3&num=" + num,
              type: "get",
              dataType: "json",
              success: function(data) {
              	//error=1 增加订单后总订单数小于等于10
                if (data.error == 1) {
                  //调用支付接口
                  $.ajax({
                    url:"http://你的域名/weChatpay/topayServlet?openId="+openId+"&money="+money,
                    type: "get",
                    dataType: "json",
                    success: function(json) {
                      WeixinJSBridge.invoke('getBrandWCPayRequest', {
                        "appId": json.appId,
                        "timeStamp": json.timeStamp,
                        "nonceStr": json.nonceStr,
                        "package": json.packages,
                        "signType": "MD5",
                        "paySign": json.sign
                      },
                      //调起微信支付成功
                      function(res) {
                        WeixinJSBridge.log(res.err_msg);
                        if (res.err_msg == "get_brand_wcpay_request:ok") {
                          //alert("微信支付成功!");
                          //跳转到生成开奖编码的servlet
                          window.location.href = "http://你的域名/weChatpay/resultServlet?openId=" + openId + "&num=" + num;
                          //	            		}else if(res.err_msg == "get_brand_wcpay_request:cancel"){  
                          //alert("用户取消支付!");  
                        } else {
                          //支付失败或取消,恢复到原来的订单量
                          $.ajax({
                            url: "http://你的域名/weChatpay/recodeServlet?flag=4&num=" + num,
                            type: "get",
                            dataType: "json"
                          });
                        }
                      });
                    },
                    //调起微信支付失败,恢复到原来的订单量
                    error:function(){
                    	$.ajax({
                            url: "http://你的域名/weChatpay/recodeServlet?flag=4&num=" + num,
                            type: "get",
                            dataType: "json"
                         });
                    }
                  });
                //error=0 表示增加订单后总订单数大于10
                } else {
                  alert("库存不足");
                }

              }

            });

          }

        });
    </script>   
    </html>

4.处理支付的接口
TopayServlet.java

package com.servlet;

import java.io.IOException;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import com.utils.GetWxOrderno;
import com.utils.RequestHandler;
import com.utils.Sha1Util;
import com.utils.TenpayUtil;

public class TopayServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		request.setCharacterEncoding("UTF-8");
		JSONObject json = new JSONObject();
		
		//网页授权后获取传递的参数
		String money = request.getParameter("money");//分为单位
		String openId = request.getParameter("openId");
		
		//金额转化为分为单位
//		float sessionmoney = Float.parseFloat(money);
//		String finalmoney = String.format("%.2f", sessionmoney);
//		finalmoney = finalmoney.replace(".", "");
		int intMoney = Integer.parseInt(money);
		
		//商户相关资料 
		String appid = "";//公众号appid
		String appsecret = "";//公众号秘钥
		String partner = "";//商户号
		String partnerkey = "";//商户API秘钥
	
		//用于获取随机数
		String currTime = TenpayUtil.getCurrTime();//获取当前时间
		String strTime = currTime.substring(8, currTime.length());//8位日期
		String strRandom = TenpayUtil.buildRandom(4) + "";//四位随机数
		String strReq = strTime + strRandom;//10位序列号,可以自行调整
		
		String orderNo=appid+Sha1Util.getTimeStamp();//随机生成了一个订单号
				
				//商户号
				String mch_id = partner;
				
				//子商户号  非必输
				//String sub_mch_id="";
				
				//设备号   非必输
				String device_info="WEB";
				
				//随机数 
				String nonce_str = strReq;
				
				//商品描述
				String body = "一元夺宝";
				
				//附加数据
				String attach = "xx科技有限公司";
				
				//商户订单号
				String out_trade_no = orderNo;
				
				//总金额以分为单位,不带小数点
				int total_fee = intMoney;
				
				//订单生成的机器 IP
				String spbill_create_ip = request.getRemoteAddr();
				
				//订 单 生 成 时 间   非必输
//				String time_start ="";
				
				//订单失效时间      非必输
//				String time_expire = "";
				
				//商品标记   非必输
//				String goods_tag = "";
				
				//支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等:http://*/weChatpay/notifyServlet
				String notify_url ="http://你的域名/weChatpay/notifyServlet";
				
				String trade_type = "JSAPI";
				
				String openid = openId;
				
				//非必输
//				String product_id = "";
				
				//获取sign(统一下单接口签名)
				//第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),
				//使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
				//第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,
				//再将得到的字符串所有字符转换为大写,得到sign值signValue。
				SortedMap<String, String> packageParams = new TreeMap<String, String>();
				packageParams.put("appid", appid);  
				packageParams.put("mch_id", mch_id);  
				packageParams.put("nonce_str", nonce_str);  
				packageParams.put("body", body);  
				packageParams.put("attach", attach);  
				packageParams.put("out_trade_no", out_trade_no);  
				packageParams.put("total_fee", money);  
				packageParams.put("spbill_create_ip", spbill_create_ip);  
				packageParams.put("notify_url", notify_url);  
				packageParams.put("trade_type", trade_type);  
				packageParams.put("openid", openid);  
				RequestHandler reqHandler = new RequestHandler(request, response);
				reqHandler.init(appid, appsecret, partnerkey);
				String sign = reqHandler.createSign(packageParams);
				
				//统一下单接口携带参数(xml格式),接口地址https://api.mch.weixin.qq.com/pay/unifiedorder
				String xml="<xml>"+
						"<appid>"+appid+"</appid>"+
						"<mch_id>"+mch_id+"</mch_id>"+
						"<nonce_str>"+nonce_str+"</nonce_str>"+
						"<sign>"+sign+"</sign>"+
						"<body><![CDATA["+body+"]]></body>"+
						"<attach>"+attach+"</attach>"+
						"<out_trade_no>"+out_trade_no+"</out_trade_no>"+
						//金额,这里写的1 分到时修改,测试用
//						"<total_fee>"+1+"</total_fee>"+
						"<total_fee>"+total_fee+"</total_fee>"+
						"<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
						"<notify_url>"+notify_url+"</notify_url>"+
						"<trade_type>"+trade_type+"</trade_type>"+
						"<openid>"+openid+"</openid>"+
						"</xml>";
				System.out.println(xml);
				
				String allParameters = "";//没用
				try {
					allParameters =  reqHandler.genPackage(packageParams);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				//请求微信统一下单接口,成功后返回预支付交易会话标识prepay_id
				String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
				String prepay_id = "";
				try {
					prepay_id = new GetWxOrderno().getPayNo(createOrderURL, xml);
					if(prepay_id.equals("")){
						request.setAttribute("ErrorMsg", "统一支付接口获取预支付订单出错");
						response.sendRedirect("error.jsp");
					}
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				
				//生成H5调起微信支付API相关参数(前端页面js的配置参数)
				SortedMap<String, String> finalpackage = new TreeMap<String, String>();
				String timestamp = Sha1Util.getTimeStamp();//当前时间的时间戳
				String packages = "prepay_id="+prepay_id;;//订单详情扩展字符串
				finalpackage.put("appId", appid);//公众号appid  
				finalpackage.put("timeStamp", timestamp);  
				finalpackage.put("nonceStr", strReq); //随机数 
				finalpackage.put("package", packages);  
				finalpackage.put("signType", "MD5");//签名方式
				String finalsign = reqHandler.createSign(finalpackage);//签名

				json.put("appId", appid);
				json.put("timeStamp", timestamp);
				json.put("nonceStr", strReq);
				json.put("packages", packages);
				json.put("sign", finalsign);
				response.getWriter().append(json.toString());
				
				//response.sendRedirect("shop/index.jsp?appid="+appid+"&timeStamp="+timestamp+"&nonceStr="+strReq+"&package="+packages+"&sign="+finalsign);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

开发前最好详细阅读微信支付开发文档,理解所用接口,以及相关签名、参数等。
代码中用的其他类以及完整demo见下面链接,demo中有需要修改参数的说明文档。
源码链接
链接:https://pan.baidu.com/s/1vqamVIALHecPr7fbZysMeQ
提取码:82ye

  • 75
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值