1. 程式人生 > >java實現微信公眾號支付

java實現微信公眾號支付


前面做了app微信支付的回撥處理,現在需要做微信公眾號的支付,花了一天多時間,終於折騰出來了!鑑於坑爹的微信官方沒有提供java版的demo,所以全靠自己按照同樣坑爹的文件敲敲敲,所以記錄下來,以供自己及後來人參考,不足之處,還請指正。

首先,我們貼出呼叫支付介面的H5頁面,當然,在這個頁面之前,還需要做很多其他的操作,我們一步一步的來。

坑爹的官方文件給了兩個不同的支付介面,在微信公眾平臺開發中文件的“微信JS-SDK說明文件”中,給出的支付方式是下面被遮蔽的那一部分,而在商戶平臺的“H5調起支付API”中,又給了一份不同的介面,即下面未遮蔽正常使用的介面。關於坑爹的微信提供了兩個不同的支付介面,網上搜索結果也是眾說紛紛,所以,只有自己試了。當然,為了簡單,我直接試了下面這一種,然後奇蹟般的成功了。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
 <!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>微信網頁支付</title>
		<!-- <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> -->
		<!-- <script type="text/javascript" src=" https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> -->
		<script type="text/javascript">
			/* wx.config({
			    debug: true, // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。
			    appId: appid, // 必填,公眾號的唯一標識
			    timestamp: timestamp, // 必填,生成簽名的時間戳
			    nonceStr: nonceStr, // 必填,生成簽名的隨機串
			    signature: '',// 必填,簽名,見附錄1
			    jsApiList: [chooseWXPay] // 必填,需要使用的JS介面列表,所有JS介面列表見附錄2
			}); */
		
			// config資訊驗證後會執行ready方法,所有介面呼叫都必須在config介面獲得結果之後,config是一個客戶端的非同步操作
			//所以如果需要在頁面載入時就呼叫相關介面,則須把相關介面放在ready函式中呼叫來確保正確執行
			//wx.ready(function(){
				//引數是後臺傳過來的,簽名加密,隨機數,時間戳等全部後臺處理好
				var appId="${appId}";
				var timeStamp="${timeStamp}";
				var nonceStr="${nonceStr}";
				var prepay_id="${prepay_id}";//之前引數名叫package,對應api介面,因為package是關鍵字,被坑了一次
				var sign="${paySign}";
				//支付介面
				function onBridgeReady(){
					   WeixinJSBridge.invoke(
					       'getBrandWCPayRequest', {
					           "appId" : appId,     //公眾號名稱,由商戶傳入 
					           "timeStamp" : timeStamp, //時間戳,自1970年以來的秒數 (java需要處理成10位才行,又一坑)
					           "nonceStr" : nonceStr, //隨機串
					           "package" : prepay_id, //拼裝好的預支付標示
					           "signType" : "MD5",//微信簽名方式
					           "paySign" : sign //微信簽名
					       },
					       function(res){
					       		//使用以下方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回    ok,但並不保證它絕對可靠。
					           if(res.err_msg == "get_brand_wcpay_request:ok" ) {     
									alert("支付成功");      		
					           }else{
					           		alert("支付失敗");
					           }
					       }
					   ); 
				}
				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();
				}
			//});
			//究竟哪個是支付介面
			/* wx.chooseWXPay({
			    timestamp: timestamp, // 支付簽名時間戳,注意微信jssdk中的所有使用timestamp欄位均為小寫。但最新版的支付後臺生成簽名使用的timeStamp欄位名需大寫其中的S字元
			    nonceStr: nonceStr, // 支付簽名隨機串,不長於 32 位
			    package: 'prepay_id', // 統一支付介面返回的prepay_id引數值,提交格式如:prepay_id=***)
			    signType: 'MD5', // 簽名方式,預設為'SHA1',使用新版支付需傳入'MD5'
			    paySign: sign, // 支付簽名
			    success: function (res) {
			        // 支付成功後的回撥函式
			        //使用以下方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回    ok,但並不保證它絕對可靠。
					if(res.err_msg == "get_brand_wcpay_request:ok" ) {     
							           		
					} 
			    }
			}); */
		</script>
	</head>
	<body>
		
	</body>
</html>

上面h5頁面中,支付介面所需的引數都是由後臺傳過來的,除此之外,在進行上面一步之前,我們還需要獲取一個預支付標識,下面貼上後臺傳參,及獲取預支付標識和引數加密等方法(獲取預支付標識之前需要網頁授權獲取使用者openid,鑑於這個比較簡單,所以不貼程式碼了)

首先是後臺引數封裝並對其簽名(關鍵部分程式碼):

if(payway.equals("1")){
			System.out.println("----------支付寶支付-------------");
			request.setAttribute("WIDout_trade_no", WIDout_trade_no);//訂單號
			request.setAttribute("WIDsubject", WIDsubject);//訂單名稱
			request.setAttribute("WIDtotal_fee", WIDtotal_fee);//付款金額
			request.setAttribute("WIDshow_url", WIDshow_url);//商品連結
			request.setAttribute("WIDbody", "");//商品描述,可空
			return "alipayapi";
		}else if(payway.equals("2")){
			System.out.println("----------微信支付-------------");
			//1、通過網頁授權介面,獲取到的openid
			String openid=request.getSession().getAttribute("openid")+"";
			//處理價格單位為:分(請自行處理)
			WIDtotal_fee="1";
			String preid=getPrepayid(WIDout_trade_no, WIDtotal_fee, openid);//獲取預支付標示
			System.out.println("預支付標示:----------------"+preid);
			//APPID
			String appId=Common.appid;
			request.setAttribute("appId", appId);
			//時間戳
			String timeStamp=(System.currentTimeMillis()/1000)+"";
			request.setAttribute("timeStamp", timeStamp);
			//隨機字串
			String nonceStr=Common.randString(16).toString();
			request.setAttribute("nonceStr", nonceStr);
			//預支付標識
			request.setAttribute("prepay_id", "prepay_id="+preid);
			//加密方式
			request.setAttribute("signType", "MD5");
			
			//組裝map用於生成sign
			Map<String, String> map=new HashMap<String, String>();
			map.put("appId", appId);
			map.put("timeStamp", timeStamp);
			map.put("nonceStr", nonceStr);
			map.put("package", "prepay_id="+preid);
			map.put("signType", "MD5");
			
			request.setAttribute("paySign", Common.sign(map, Common.MchSecret));//簽名
			return "weixinpay";
		}else {
			return "error";
		}

接下是獲取預支付標識的方法getPrepayid:
/**
	 * 微信統一下單介面,獲取預支付標示prepay_id
	 * @param out_trade_no1 商戶訂單號
	 * @param total_fee1 訂單金額(單位:分)
	 * @param openid1 網頁授權取到的openid
	 * @return
	 */
	@ResponseBody
	public String getPrepayid(String out_trade_no1,String total_fee1,String openid1){
		
		String result = "";
		
		String appid = Common.appid;
		String mch_id = Common.mch_id;
		String nonce_str = Common.randString(16);//生成隨機數,可直接用系統提供的方法
		String body = "E光學-商品訂單";
		String out_trade_no = out_trade_no1;
		String total_fee = total_fee1;
		String spbill_create_ip = "xxx.xxx.38.47";//使用者端ip,這裡隨意輸入的
		String notify_url = "http://www.xxxxxxx.cn/egxwx/wxpay_notify_url.jsp";//支付回撥地址
		String trade_type = "JSAPI";
		String openid = openid1;
		
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("appid", appid);
		map.put("mch_id", mch_id);
		map.put("attach", "支付測試");
		map.put("device_info", "WEB");
		map.put("nonce_str", nonce_str);
		map.put("body", body);
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", total_fee);
		map.put("spbill_create_ip", spbill_create_ip);
		map.put("trade_type", trade_type);
		map.put("notify_url", notify_url);
		map.put("openid", openid);
		String sign = Common.sign(map, Common.MchSecret);//引數加密
		System.out.println("sign祕鑰:-----------"+sign);
		map.put("sign", sign);
		//組裝xml(wx就這麼變態,非得加點xml在裡面)
		String content=Common.MapToXml(map);
		//System.out.println(content);
		String PostResult=HttpClient.HttpsPost("https://api.mch.weixin.qq.com/pay/unifiedorder", content);
		JSONObject jsonObject=XmlUtil.XmlToJson(PostResult);//返回的的結果
		if(jsonObject.getString("return_code").equals("SUCCESS")&&jsonObject.getString("result_code").equals("SUCCESS")){
			result=jsonObject.get("prepay_id")+"";//這就是預支付id
		}
		return result;
	}

接下是簽名的方法(MD5加密是呼叫微信一個jar裡面的,你也可以自己寫一個,網上很多參考):
/**
	 * 生成簽名sign
	 * 第一步:非空引數值的引數按照引數名ASCII碼從小到大排序,按照鍵值對的形式。生成字串StringA
	 * stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";
	 * 第二部:拼接API金鑰,這裡的祕鑰是微信商戶平臺的祕鑰,是自己設定的,不是公眾號的祕鑰
	 * stringSignTemp="stringA&key=192006250b4c09247ec02edce69f6a2d"
	 * 第三部:MD5加密
	 * sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"
	 * 
	 * @param map 不包含空字串的map
	 * @return
	 */
	public static String sign(Map<String, String> map,String key) {
		//排序
		String sort=sortParameters(map);
		//拼接API祕鑰
		sort=sort+"&key="+key;
		//System.out.println(sort);
		//MD5加密
		String sign=MD5.MD5Encode(sort).toUpperCase();
		return sign;
	}
	
	/**
     * 對引數列表進行排序,並拼接key=value&key=value形式
     * @param map
     * @return
     */
    private static String sortParameters(Map<String, String> map) {
        Set<String> keys = map.keySet();
        List<String> paramsBuf = new ArrayList<String>();
        for (String k : keys) {
            paramsBuf.add((k + "=" + getParamString(map, k)));
        }
        // 對引數排序
        Collections.sort(paramsBuf);
        String result="";
        int count=paramsBuf.size();
        for(int i=0;i<count;i++){
        	if(i<(count-1)){
        		result+=paramsBuf.get(i)+"&";
        	}else {
				result+=paramsBuf.get(i);
			}
        }
        return result;
    }
    /**
     * 返回key的值
     * @param map
     * @param key
     * @return
     */
    private static String getParamString(Map map, String key) {
        String buf = "";
        if (map.get(key) instanceof String[]) {
            buf = ((String[]) map.get(key))[0];
        } else {
            buf = (String) map.get(key);
        }
        return buf;
    }
    /**
     * 字串列表從大到小排序
     * @param data
     * @return
     */
    private static List<String> sort(List<String> data) {
        Collections.sort(data, new Comparator<String>() {
            public int compare(String obj1, String obj2) {
                return obj1.compareTo(obj2);
            }
        });
        return data;
    }

Map轉XML的方法:
/**
     * Map轉Xml
     * @param arr
     * @return
     */
    public static String MapToXml(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;
    }
    private static boolean IsNumeric(String str) {
        if (str.matches("\\d *")) {
            return true;
        } else {
            return false;
        }
    }

以上就是java實現微信H5支付的主要程式碼了,大部分都有註釋,也沒有什麼好解釋的了。當然,僅供參考,僅供參考,僅供參考!!!

相關推薦

java實現公眾支付

前面做了app微信支付的回撥處理,現在需要做微信公眾號的支付,花了一天多時間,終於折騰出來了!鑑於坑爹的微信官方沒有提供java版的demo,所以全靠自己按照同樣坑爹的文件敲敲敲,所以記錄下來,以供自己及後來人參考,不足之處,還請指正。 首先,我們貼出呼叫支付介面的H5頁

java實現公眾房卡牛牛六人平臺開發搭建文章采集接口程序

package ecs util 系統 public address 用戶id 狀態 get 日誌實體類,用戶記錄用戶登錄登出 LogRec.javapackage q.dms.test; import java.util.Date; /** 實體類 包含用戶登錄的id,

java實現公眾授權登入獲取使用者資訊流程

參考地址微信公眾號開發文件:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 前提:需要申請認證的微信公眾號;獲取對應的APPID和APPSECRET;並且還需要獲取到使用者資訊許可權

laravel使用easyWeChat實現公眾支付

網上看了很多資料,沒有找到合適自己的,就乾脆自己寫一個吧 框架為laravel5.4,easyWeChat是4.0版本。 使用composer require "overtrue/larav

公眾支付開發全過程(java版)

sdk 命令 所有 data 權限 {} servle res ast 文章有不當之處,歡迎指正,如果喜歡微信閱讀,你也可以關註我的微信公眾號:好好學java,獲取優質學習資源。 一、微信官方文檔微信支付開發流程(公眾號支付) 首先我們到微信支付的官方文檔的開發步驟部分查

公眾支付/退款(java環境)開發介紹

開發之前翻閱了很多帖子,結合自己的實際開發情況,將微信支付/退款 流程以及code貼出,希望通過這一篇帖子就能解決你的問題,有不清楚的直接留言,我會及時回覆(ง •̀_•́)ง   一些說明:xxxUtils為工具類,Constant為常量類 為方便開發,所用和微信支付相關co

JAVA帶你一步一步實現公眾開發(一)--接入微公眾平臺

(一)接入流程解析 在我們的開發過程中無論如何最好的參考工具當然是我們的官方文件了:http://mp.weixin.qq.com/wiki/8/f9a0b8382e0b77d87b3bcc1ce6fbc104.html 通過上面我們可以看出其中接入微信公眾平臺開發,開發者需要按照如下

java公眾開發三(支付

步驟一:我們需要將微信支付所需要的引數組裝好,然後傳送請求。 所需要的引數在微信支付開發文件中就可以找到我們所必須的11個引數。 步驟二:然後在回撥函式中處理我們支付後的業務邏輯。 /** * * 獲得威微信支付的相關引數

公眾支付java版本

回撥函式 @RequestMapping("/toPay") public String toPay(HttpServletRequest request, HttpServletResponse response, Model model){ System.out.print

java 公眾支付demo 企業支付到個人使用者、公眾企業付款到個人零錢,提現到零錢

微信提現到零錢(微信內部交易,不需要手續費)價格格式錯誤:可能是價格經過計算後.doubleValue了一下 最後價格是 200.00 企業付款簽名錯誤:和支付的時候簽名的引數有出入(搞了半天,最後到看了一段php程式碼後做了一下調整。OK了) 參考PHP部落格:http:

公眾支付開發 --Java

/** * 付款頁面 * @param request * @param response * @return * @throws Exception */ @RequestMapping("/callback") public

支付開發(二)----支付開發之公眾支付JAVA

一、開通微信公眾號 1.1公眾平臺帳號型別 微信公眾平臺分為服務號、企業號、訂閱號。 1、訂閱號:主要偏於為使用者傳達資訊(類似報紙雜誌),認證前後都是每天只可以群發一條訊息; 2、服務號:主要

java公眾支付

最近公司突然叫我開發微信公眾號相關的東西鳥,作為一個新人(其實也不怎麼新了但是很菜就對了),開發過程還是有點坎坷的~~ 現在開發完啦,決定寫下來供大家參考參考~ 因為比較粗心,估計還是有不少可以優化的地方,也可能有一些寫得不好的地方,歡迎指正~ 一.準備

公眾支付開發全過程----JAVA

1、生成統一下單介面,獲取prepay_id.需要的引數 ==名稱==從哪裡找到他們:微信官方給了個引數的詳細說明。https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1 部分引數,仍然不知道哪裡找的小夥伴們請繼續向下看appid ==應用ID

公眾支付報文示例

cda 響應 xca mes amp 鏈接 返回值 col http 請求報文: 1 <xml> 2 <body><![CDATA[狄克酸奶店]]></body> 3 <callback_url&

個體戶沒有組織機構代碼證如何開通公眾支付

jpg alt 註意 方法 .com str 工作人員 個體工商戶 log 個體工商戶開通微信支付最新流程: 一、準備資料1.營業執照:有效期內的個體戶執照;2.身份證:經營者個人身份證照片;3.收款銀行賬戶:提現用的銀行賬號;4.手機號碼:客服人員的聯系手機號;5.郵箱

php公眾支付接口開發demo

targe param pre space secret 修改 pen host field 本支付接口使用Yii2框架,所以控制器的格式都是該框架的,不過放到其他框架都差不多,根據對應的規則修改一下控制器的方法名字就行了,親測有效,比較簡單,沒有封裝,想了解微信支付實現

公眾支付--錯誤記錄

二次 數組 格式轉換 println equals sig col package reat 微信公眾號支付調用統一下單接口時,微信返回的數據一定要二次組裝再給前臺,否則會有問題的,正確示範如下: /** * 獲取weixin支付的返回信息 * @pa

支付公眾支付) [記錄]

scope err question dir rec package ready fad span 後臺   先獲取code code有效5min     public string GetCodeUrl(string Appid, string redirect

基於java公眾二次開發視頻教程

質量 經典 數據分析 大數據 spark leet hadoop 專家 擴展 query 詳情請交流 QQ 709639943 00、基於java的微信公眾號二次開發視頻教程 00、leetcode 算法 面試 00、北風網 零基礎到數據(大數據)分析專家-首席分