1、 首先受權配置javascript
公衆號設置 --》功能設置 設置業務域名!
這裏的MP_verify_w7tdZrafqhkK9Mcj.txt文件,須要放到你項目的根目錄下,例子:你的項目war包叫 test.war ,裏面包含了src,WEB-INFO兩個文件夾,則把MP_verify_w7tdZrafqhkK9Mcj.txt放到這兩個文件夾的同級目錄下;即如今test.war下有兩個文件夾一個txt文件:src,WEB-INFO,MP_verify_w7tdZrafqhkK9Mcj.txt.
後面就須要配置js接口安全域名和網頁受權域名了,最好和業務域名配置爲同樣就行了。
2、開發中的配置
在開發目錄下的基本配置中進行配置。
基本配置–》開發者ID–》AppID(應用ID),AppSecret(應用密鑰);
基本配置–》微信開放平臺帳號綁定
這裏須要綁定微信開放平臺,若不綁定,在獲取用戶信息的時候就只能獲取到用戶的openId,不能獲取到unionId.
注意:定義菜單的時候有講究了,
若是你想在用戶點這個菜單的時候就拿到用戶的微信基本信息(性別,暱稱,openId,unionId),這裏直接能夠配置成爲受權連接,受權連接回調url直接寫成你後臺的一個接口地址,而後由這個接口來跳轉到其它頁面.
例子:H5受權的連接:
http://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxx&redirect_uri=http://xxxx.com/test/login&response_type=code&scope=snsapi_userinfo&state=xxx&connect_redirect=1#wechat_redirect
微信回調的url是一個接口地址:http://xxxx.com/test/login,不能回調網頁,由於存在跨域錯誤。
state的值是能夠自定義的。
這裏的scope是用的snsapi_userinfo,這樣能夠直接在後臺拿到用戶信息。
微信回調這個接口的時候會把code和state的值返回,接口就能夠經過code去拿用戶的信息了。
若要用code去拿用戶的信息,又會去作一堆事情,這些事情確實麻煩;推薦直接使用第三方的jar包,一步就拿到了。
推薦的jar包:weixin-Java-mp-2.5.0.jar,weixin-java-common-2.5.0.jar;
maven地址html
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-mp</artifactId> <version>2.5.0</version> </dependency>
在作微信支付的時候有可能會用到xstream的包,有須要也拿去 xstream-1.4.7.jar,xxp3_min-1.1.4.jar,xmlpull-1.1.3.1.jar maven地址
<dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.4.7</version> </dependency> <dependency> <groupId>xpp3</groupId> <artifactId>xpp3</artifactId> <version>1.1.4c</version> </dependency> <dependency> <groupId>xmlpull</groupId> <artifactId>xmlpull</artifactId> <version>1.1.3.1</version> </dependency>
這裏說下weixin-java-mp-2.5.0.jar的使用方法,
1.weixin-java-mp-2.5.0.jar裏面最重要的類是
WxMpInMemoryConfigStorage和WxMpService;
WxMpInMemoryConfigStorage是用來存微信公衆號的基本信息的,
在spring+SpringMvc中的使用方法例子:前端
@Configuration @PropertySource( value={"classpath:wxProperties.properties"}, ignoreResourceNotFound = true) //@DependsOn("propertyPlaceholderConfigurer") public class WeixinConfig { //直接獲取資源文件中的配置的值 @Value("${wxProperties.appid}") private String appid;//appId @Value("${wxProperties.appsecret}") private String appsecret;//Appsecret @Value("${wxProperties.token}") private String token;//Token @Value("${wxProperties.aeskey}") private String aesKey;//aeskey,有就填,沒有就不填 @Value("${wxProperties.partener_id}") private String partenerId;//商戶號 @Value("${wxProperties.partener_key}") private String partenerKey;//商戶祕鑰 @Value("${wxProperties.notify_url}") private String notifyUrl;//支付後臺通知接口地址 @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); ppc.setIgnoreUnresolvablePlaceholders(true); return ppc; } @Bean public WxMpConfigStorage wxMpConfigStorage() { WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage(); configStorage.setAppId(this.appid); configStorage.setSecret(this.appsecret); configStorage.setToken(this.token); configStorage.setAesKey(this.aesKey); configStorage.setPartnerId(this.partenerId); configStorage.setPartnerKey(this.partenerKey); configStorage.setNotifyURL(this.notifyUrl); return configStorage; } @Bean public WxMpService wxMpService() { WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); return wxMpService; } }
這裏是配置微信公衆號的基本信息,其它地方要使用就直接使用:java
@Autowired protected WxMpService wxMpService;
2.獲取微信用戶基本信息示例代碼:jquery
WxMpOAuth2AccessToken accessToken; WxMpUser wxMpUser = null; accessToken = this.wxMpService.oauth2getAccessToken(code); wxMpUser = this.wxMpService.getUserService().userInfo(accessToken.getOpenId(), null); //用戶的基本信息就在wxMpUser中了,須要的就拿去用了。(注意:微信用戶的性別:0:未知,1:男 2:女)
3.H5若要使用微信封裝好的js,則須要一些基本的配置信息,徹底能夠從後天臺獲取而後返回,示例代碼:git
public StatusResult<Map<String, Object>> createJsapiSignature(String url) { Map<String, Object> result = new HashMap<String, Object>(); try { WxJsapiSignature wxJsapiSignature = wxMpService.createJsapiSignature(url); String getJsapiTicket = wxMpService.getJsapiTicket(); result.put("wxJsapiSignature", wxJsapiSignature); return StatusResult.success(result, ""); } catch (WxErrorException e) { return StatusResult.failed("未知錯誤出現", result); } }
這裏的url是H5用js代碼獲取的:github
var url = location.href.split('#')[0];
4.公衆號支付
流程:
頁面發起–>後臺下單後返回前端所須要的參數–>頁面發起支付–>用戶輸入密碼付款成功–>微信回調後臺通知接口–>業務處理完成
H5頁面發起支付:
微信公衆號的頁面支付首先要配置微信公衆號:
微信支付–>開發配置–>支付受權目錄(正式、測試的目錄必需要不同,不然有你好看的,)
注意:設置受權目錄的時候必需要精確到須要支付頁面的目錄文件夾;
例子:須要支付的H5頁面 http://xxxxx.com/test/html/pay/pay.html
則受權目錄配置爲 http://xxxxx.com/test/html/pay/
配置完成後就能夠發起下單了,
後臺下單代碼示例:spring
public StatusResult<Map<String, String>> getJSSDKPayInfo(HttpServletResponse response, HttpServletRequest request) { StatusResult<Map<String, String>> result = null; String spbill_create_ip = request.getRemoteAddr();//訂單生成的機器 IP Map<String, String> map = new HashMap<String, String>(); WxMpConfigStorage wx= wxMpService.getWxMpConfigStorage(); WxPayUnifiedOrderRequest prepayInfo = new WxPayUnifiedOrderRequest(); //TODO change all request parameters to a VO class prepayInfo.setOpenid("openId"); prepayInfo.setOutTradeNo("out_trade_no");//設置訂單商戶號 int total_fee = 0.01 * 100; total_fee = 1; prepayInfo.setTotalFee(Integer.valueOf(total_fee));//設置支付金額 單位爲分 prepayInfo.setBody("xxxxx");//支付的內容簡介 prepayInfo.setTradeType("JSAPI");//渠道:公衆號支付 prepayInfo.setSpbillCreateIp(spbill_create_ip);//終端ip //TODO(user) 填寫通知回調地址 prepayInfo.setNotifyURL(wx.getNotifyURL()); try { 兩種下單方式,若是報錯請先仔細檢查微信配置的各類參數 //WxPayUnifiedOrderResult wxPayUnifiedOrderResult= wxMpService.getPayService().unifiedOrder(prepayInfo); Map<String, String> payInfo = this.wxMpService.getPayService().getPayInfo(prepayInfo); if(payInfo != null){ //業務代碼 } result = StatusResult.success(payInfo); return result; } catch (WxErrorException e) { log.error(e.getError().toString()); map.put("error", e.getError().toString()); return StatusResult.failed("微信下單失敗",map); } }
H5頁面支付js代碼(須要引入微信js哈):後端
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(); } } function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":appId, //公衆號名稱,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr":nonceStr, //隨機串 "package":package, "signType":"MD5", //微信簽名方式: "paySign":paySign //微信簽名 }, function(res){ if (res.err_msg == "get_brand_wcpay_request:ok") { alert("微信支付成功!"); } else if (res.err_msg == "get_brand_wcpay_request:cancel") { alert("用戶取消支付!"); } else { alert("支付失敗!"); } // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。 } ); }
微信回調後臺通知接口代碼示例:api
public void getJSSDKCallbackData(HttpServletRequest request,
HttpServletResponse response) {
try {
synchronized (this) {
Map<String, String> kvm = XMLUtil.parseRequestXmlToMap(request); System.out.println("微信通知返回結果:\t"+kvm.toString()); WxPayOrderQueryResult wxPayOrderQueryResult = wxMpService.getPayService().queryOrder("", kvm.get("out_trade_no"));//用訂單號去查詢訂單狀態,冗餘代碼可看可刪 // if (this.wxMpService.getPayService().checkSign(kvm, kvm.get("sign"))) { System.out.println("查詢訂單返回結果:\t"+wxPayOrderQueryResult.getTradeState()); if ("SUCCESS".equals(wxPayOrderQueryResult.getTradeState())) { if (kvm.get("result_code").equals("SUCCESS")) { //TODO(user) 微信服務器通知此回調接口支付成功後,通知給業務系統作處理 log.info("out_trade_no: " + kvm.get("out_trade_no") + " pay SUCCESS!"); String out_trade_no = kvm.get("out_trade_no"); //支付訂單號,接下來寫業務代碼 } } } log.info("已經支付的訂單詳情\t"+aleadyPayOrder); response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[ok]]></return_msg></xml>"); } else { log.error("out_trade_no: " + kvm.get("out_trade_no") + " result_code is FAIL"); response.getWriter().write( "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[result_code is FAIL]]></return_msg></xml>"); } } else { response.getWriter().write( "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[check signature FAIL]]></return_msg></xml>"); log.error("out_trade_no: " + kvm.get("out_trade_no") + " check signature FAIL"); } } } catch (Exception e) { e.printStackTrace(); } }
到此爲止公衆號支付完成。
3、微信js中接口使用
分享等很常見的,須要初始化微信的js,須要利用到上面寫的createJsapiSignature後臺接口。
公衆號的分享給朋友、朋友圈、QQ空間等方法在微信js中是能夠直接調用的,分享的內容能夠本身改變的,可是分享出去的按鈕只能是微信右上角的分享,開發者不能自定義分享按鈕。。。這一點讓人很是不爽。
H5頁面js的代碼示例:
引入微信的js,而後初始化,而後微信會自動執行wx.ready中的方法
wx.config({
debug: false, //開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: appId, //必填,公衆號的惟一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: nonceStr, //必填,生成簽名的隨機串 signature: signature, // 必填,簽名 jsApiList: [//須要多少接口就寫多少接口 'checkJsApi',//判斷當前客戶端是否支持指定JS接口 'onMenuShareAppMessage'//獲取「分享給朋友」按鈕點擊狀態及自定義分享內容接口 ] //必填,須要使用的JS接口列表,全部JS接口列表 }); wx.ready(function () { var title = "xxxx"; var desc = "xxxx"; var imgUrl = "http://xxx.com/test/picture/xxxxx.png"; wx.onMenuShareAppMessage({ title: title, // 分享標題 desc: desc, // 分享描述 link: url, // 分享連接,h5網頁的地址或者其它 imgUrl: imgUrl, trigger: function(res) { alert('用戶點擊發送給朋友'); }, success: function(res) { alert('已分享'); }, cancel: function(res) { alert('已取消'); }, fail: function(res) { alert(JSON.stringify(res)); } }); });
調用微信js中的方法流程:
初始化config–>執行wx.ready
開發者須要更多的功能就依照葫蘆畫瓢了,或者去微信js sdk文檔去copy方法了。
讓人不愉快的事情又發生了,微信在4月29日開始限制自定義分享的連接啦,必需要是安全域名下的連接才能夠分享。
詳情請看:
JSSDK自定義分享接口的策略調整
這樣致使不能直接分享本身想要的連接了,可是解決方法仍是有的:
在你的域名下新建一個H5頁面,在這個H5頁面的js代碼中作一個跳轉就好啦(可是若是你分享出去的是支付頁面,那多半是支付不了地)!
4、處理微信直接能夠分享頁面問題
有時候業務須要不能把當前的頁面分享出去,可是微信自帶的分享、複製連接按鈕是能夠在任何頁面拿到當前頁面的地址,若是別人點擊就會進入。爲了不這個狀況發生,有幾種處理方法:
1.後端足夠強大,頁面跳轉徹底由後端完成,在加入了權限驗證的狀況下就不怕這個的,後端會攔截請求驗證,驗證不過就跳指定的error頁面就好。
2.前端作驗證
jsp能夠用session,判斷session中的一個全局參數便可。
H5可使用cookie,在項目的開始頁寫入cookie,在js中寫一個驗證方法,每一個頁面都調用這個驗證方法進行驗證,雖然有冗餘代碼,可是這個是能夠實現地,簡單粗暴,速度快。
設置cookie的方法:
jquery(function() { var expiresDate= new Date(); expiresDate.setTime(expiresDate.getTime() + (30 * 60 * 1000));//半小時 jquery.cookie("openId",'${openId}', { path : '/',//cookie的做用域爲根目錄,任何頁面都是有效的 expires : expiresDate });//cookie裏面保存openId });
而後在js中寫一個方法每一個頁面都調用判斷。