隨筆-12  評論-6  文章-0  trackbacks-0
          需求描述:公司通過APP產品分享出去的需求和簡歷是做了一個H5頁面作為分享的鏈接,通過APP分享出去自然是沒問題,也是第一次分享,之后通過微信打開H5頁面后想再次分享出去時候就變成了一個鏈接了,而不是自己定制的卡片模式,初次分享后如下:
          但是打開以后的H5頁面再分享出去就變成這個樣子了:

          也就是說需要在H5頁面做微信分享的相關工作,JS-SDK上場了,首先看看JS-SDK的官方說明文檔:https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
          按照文檔說明一步一步的做下去就可以出結果了,在這里詳細說一下每一步如何操作以及如何避坑,重點在于如何避坑。
          1. 綁定域名
            1. 先登錄微信公眾平臺進入“公眾號設置”的“功能設置”里填寫“JS接口安全域名”。
            2. 上面是說明文檔的原話,這里我介紹一下在開發階段如何測試。
              1. 首先你得有一個微信公眾平臺測試賬號,總不能用公司的公眾賬號進行開發測試吧,當然你有自己的公眾號是最好的,沒有的話就快速的申請一個接口測試號吧
              2. 訪問微信公眾平臺測試版系統:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
              1. 主要是獲取到測試號的appID和appsecret以及綁定J接口的安全域名:
              1. 綁定域名這塊其實有蠻多坑的,就將我遇到的坑給大家說一下,希望遇到的人能夠很好的解決:
                1. 域名不能加http://或者https://前綴,直接test.wxwx.com好了,否則回報invalid domain url無效的域
                2. 可以加端口號比如:test.wxwx.com:8888
                3. 也可以是一個ip地址比如:123.45.24.37
                4. 如何在本地進行測試?請下載一個代理服務器工具Fiddler:https://www.telerik.com/download/fiddler然后選擇選項Tools->HOSTS
                1. 前面是你自己機器的Ip地址,后面是你自己定義的一個地址,然后在公眾號里面添加wxwuwei.ceshiweixin.com:8888,Fiddler的端口是8888,然后保證你的機器和你的手機在同一個局域網下,進入手機設置你的網絡連接如下圖所示:
                1. 這個手機設置的ip一定要和你的PC的ip一樣,這樣前期環境準備工作就完成了,就可以開始編碼部分了~
          1. 頁面引入JS文件http://res.wx.qq.com/open/js/jweixin-1.0.0.js,這個就不多說了
          2. 通過config接口注入配置信息,微信需要去驗證的, 如果驗證通過了會執行wx.ready方法,這個JS-SDK文檔有詳細說明,這里主要說一下后臺如何生成config中需要的配置信息:
            1 wx.config({
            2     debug: true// 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時才會打印。
            3     appId: '', // 必填,公眾號的唯一標識
            4     timestamp: , // 必填,生成簽名的時間戳
            5     nonceStr: '', // 必填,生成簽名的隨機串
            6     signature: '',// 必填,簽名,見附錄1
            7     jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
            8 });
          1. appId我們已經獲取到了,timestamp時間戳是到秒的,千萬別到毫秒,可以new Date().getTime()/1000獲取一個就可以了,nonceStr是咱們自己定義的一個串,可以是隨機串也可以是一個固定的字符串,signature是根據當前的jsapi_ticket、nonceStr、timestamp、url(當前網頁的url,不包含#及其后面部分)四個字段拼串(需要按照ASCII碼從小到大排序進行拼串abcdefg的順序)進行SHA1加密生成的,這些都是需要在服務器端實現。
          2. access_token的獲取https://mp.weixin.qq.com/wiki/15/54ce45d8d30b6bf6758f68d2e95bc627.html
            1. 需要緩存,因為這個接口的調用是有次數限制的,可以放在redis中
          3. 卡券 api_ticket的獲取:根據獲取到的access_token來獲取api_ticket
            1. 獲取url:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
            2. 需要緩存,也是有次數限制的,可以放在redis中
          4. 常見錯誤及解決方法:見說明文檔的附錄5-常見錯誤及解決方法,其中的紅字部分是你需要注意的坑,也是你解決微信多次分享的關鍵之處:確保你獲取用來簽名的url是動態獲取的,動態頁面可參見實例代碼中php的實現方式。如果是html的靜態頁面在前端通過ajax將url傳到后臺簽名,前端需要用js獲取當前頁面除去'#'hash部分的鏈接(可用location.href.split('#')[0]獲取,而且需要encodeURIComponent),因為頁面一旦分享,微信客戶端會在你的鏈接末尾加入其它參數,如果不是動態獲取當前鏈接,將導致分享后的頁面簽名失敗
          下面根據上面描述的步驟貼出部分代碼(Java版的),僅供參考!
          首先寫一個WeixinUtils.java類:
            1 package com.freekeer.c.util;
            2 
            3 import java.security.MessageDigest;
            4 import java.util.Formatter;
            5 import java.util.HashMap;
            6 import java.util.Map;
            7 import java.util.Properties;
            8 
            9 import org.apache.commons.lang3.StringUtils;
           10 
           11 import com.alibaba.fastjson.JSONObject;
           12 
           13 public class WeiXinUtils {
           14 
           15     // 微信appId
           16     private static String APPID;
           17     // 微信公眾號唯一密鑰
           18     private static String APPSECRET;
           19     // 獲取acc_token的接口
           20     private static String ACC_TOKEN_URL;
           21     // 獲取jsapi_ticket url
           22     private static String JSAPI_TICKET_URL;
           23     // 生成簽名的隨機串
           24     private static String NONCE_STR;
           25 
           26     static {
           27         Properties prop = AppPropTools.getProperties("/weixin.properties");
           28         APPID = prop.getProperty("APPID");
           29         APPSECRET = prop.getProperty("APPSECRET");
           30         ACC_TOKEN_URL = prop.getProperty("ACC_TOKEN_URL"+ "&appid=" + APPID
           31                 + "&secret=" + APPSECRET;
           32         JSAPI_TICKET_URL = prop.getProperty("JSAPI_TICKET_URL");
           33         NONCE_STR = prop.getProperty("NONCE_STR");
           34     }
           35 
           36     // 私有構造方法
           37     private WeiXinUtils() {
           38 
           39     }
           40 
           41     /**
           42      * 獲取微信acc_token
           43      * 
           44      * @return
           45      * @throws Exception
           46      */
           47     public static String getAccToken() throws Exception {
           48         // 先從redis取,取不到再從微信里面取
           49         String weixin_acc_token = RedisHelper.getStringValue(
           50                 "weixin_acc_token"2);
           51         if (StringUtils.isEmpty(weixin_acc_token)) {
           52             String resultStr = HttpURLConnectionUtil
           53                     .getWebHTMLCode(ACC_TOKEN_URL);
           54             JSONObject resultObj = JSONObject.parseObject(resultStr);
           55             String accToken = resultObj.getString("access_token");
           56             int expiresIn = resultObj.getIntValue("expires_in");
           57             // 寫進redis
           58             RedisHelper.setStringValue("weixin_acc_token", accToken, expiresIn,
           59                     2);
           60             return accToken;
           61         }
           62         return weixin_acc_token;
           63 
           64     }
           65 
           66     /**
           67      * 獲取微信票據
           68      * 
           69      * @return
           70      * @throws Exception
           71      */
           72     public static String getTicket() throws Exception {
           73         // 先從redis中取ticket,沒有再從這里取
           74         String weixin_js_api_tiket = RedisHelper.getStringValue(
           75                 "weixin_js_api_tiket"2);
           76         if (StringUtils.isEmpty(weixin_js_api_tiket)) {
           77 
           78             String accToken = getAccToken();
           79             String resultStr = HttpURLConnectionUtil
           80                     .getWebHTMLCode(JSAPI_TICKET_URL + accToken);
           81             JSONObject resultObj = JSONObject.parseObject(resultStr);
           82             if (resultObj.getIntValue("errcode"== 0) {
           83                 String ticket = resultObj.getString("ticket");
           84                 int expires_in = resultObj.getIntValue("expires_in");
           85                 // 寫入redis
           86                 RedisHelper.setStringValue("weixin_js_api_tiket", ticket,
           87                         expires_in, 2);
           88                 return ticket;
           89             }
           90             return null;
           91         }
           92         return weixin_js_api_tiket;
           93     }
           94 
           95     /**
           96      * 獲取簽名
           97      * 
           98      * @param timeStamp
           99      * @param requestUrl
          100      * @return
          101      * @throws Exception
          102      */
          103     public static String getSignature(Long timeStamp, String requestUrl)
          104             throws Exception {
          105         String ticket = getTicket();
          106         StringBuffer allStr = new StringBuffer("jsapi_ticket=");
          107         allStr.append(ticket).append("&noncestr=").append(NONCE_STR)
          108                 .append("&timestamp=").append(timeStamp).append("&url=")
          109                 .append(requestUrl);
          110         MessageDigest crypt = MessageDigest.getInstance("SHA-1");
          111         crypt.reset();
          112         crypt.update(allStr.toString().getBytes("UTF-8"));
          113         String signature = byteToHex(crypt.digest());
          114         return signature;
          115     }
          116 
          117     /**
          118      * SHA1加密
          119      * 
          120      * @param hash
          121      * @return
          122      */
          123     private static String byteToHex(final byte[] hash) {
          124         Formatter formatter = new Formatter();
          125         for (byte b : hash) {
          126             formatter.format("%02x", b);
          127         }
          128         String result = formatter.toString();
          129         formatter.close();
          130         return result;
          131     }
          132 
          133     /**
          134      * 獲取微信JS頁面Config所需參數
          135      * 
          136      * @param timeStamp
          137      * @param requestUrl
          138      * @return
          139      * @throws Exception
          140      */
          141     public static Map<String, Object> getConfig(long timeStamp,
          142             String requestUrl) throws Exception {
          143         Map<String, Object> map = new HashMap<String, Object>();
          144         String signature = getSignature(timeStamp, requestUrl);
          145         map.put("signature", signature);
          146         map.put("nonceStr", NONCE_STR);
          147         map.put("timestamp", timeStamp);
          148         map.put("appId", APPID);
          149         return map;
          150     }
          151 
          152 }
          153

          再寫一個接口類返回config中的參數:

           1 package com.freekeer.c.controller;
           2 
           3 import java.util.Date;
           4 import java.util.Map;
           5 
           6 import javax.servlet.http.HttpServletRequest;
           7 import javax.servlet.http.HttpServletResponse;
           8 
           9 import org.slf4j.Logger;
          10 import org.slf4j.LoggerFactory;
          11 import org.springframework.web.bind.annotation.RequestMapping;
          12 import org.springframework.web.bind.annotation.RequestMethod;
          13 import org.springframework.web.bind.annotation.RequestParam;
          14 import org.springframework.web.bind.annotation.RestController;
          15 
          16 import com.freekeer.c.util.WeiXinUtils;
          17 
          18 /**
          19  * 熱搜詞控制層
          20  * 
          21  * @author WuWei
          22  */
          23 @RestController
          24 public class WeixinController extends BaseController {
          25 
          26     @SuppressWarnings("unused")
          27     private static Logger log = LoggerFactory.getLogger(WeixinController.class);
          28 
          29     @RequestMapping(value = "/wx-config", method = { RequestMethod.GET })
          30     public Map<String, Object> getConfig(HttpServletRequest request,
          31             HttpServletResponse response, @RequestParam(value="url", required=true) String url) throws Exception {
          32         long timeStamp = new Date().getTime()/1000;
          33         Map<String, Object> result = WeiXinUtils.getConfig(timeStamp, url);
          34         return result;
          35     }
          36     
          37 }
          38

          JS端通過ajax調用

           1 function weixinShareZp(demandData) {
           2     var title = demandData.profession;
           3     var desc = demandData.projectName+",在"+demandData.workCityName+"招聘"+title+demandData.requireStaffCount+"";
           4     var url = "../wx-config?url="+encodeURIComponent(window.location.href);
           5     var logoUrl = "http://xxx-resource-public.oss-cn-beijing.aliyuncs.com/share_img/logo.png";
           6     $.get(url,[],function(data) {
           7         wx.config({
           8             debug:true,
           9             appId:data.appId,
          10             timestamp:data.timestamp,
          11             nonceStr:data.nonceStr,
          12             signature:data.signature,
          13             jsApiList: [
          14                 'onMenuShareTimeline', 
          15                 'onMenuShareAppMessage', 
          16                 'onMenuShareQQ',
          17                 'onMenuShareWeibo',
          18                 'onMenuShareQZone'
          19             ]
          20         });
          21         wx.ready(function(){ 
          22             // 獲取“分享到朋友圈”按鈕點擊狀態及自定義分享內容接口 
          23             wx.onMenuShareTimeline({ 
          24                 imgUrl:logoUrl,
          25                   link:window.location.href,
          26                   desc:desc,
          27                   title:title,
          28                   type:"link"
          29             }); 
          30             // 獲取“分享給朋友”按鈕點擊狀態及自定義分享內容接口 
          31             wx.onMenuShareAppMessage({ 
          32                 imgUrl: logoUrl,
          33                   link: window.location.href,
          34                   desc: desc,
          35                   title: title,
          36                   type: "link"
          37             });
          38             wx.onMenuShareQQ({
          39                 title: title,
          40                 desc: desc,
          41                 link: window.location.href,
          42                 imgUrl: logoUrl
          43             });
          44             wx.onMenuShareWeibo({
          45                 title: title,
          46                 desc: desc,
          47                 link: window.location.href,
          48                 imgUrl: logoUrl,
          49             });
          50             wx.onMenuShareQZone({
          51                 title: title,
          52                 desc: desc,
          53                 link: window.location.href,
          54                 imgUrl: logoUrl,
          55             });
          56         });
          57 
          58     });
          59 }
          開始通過微信分享進行測試吧!
          posted on 2016-12-16 17:05 小人物_Amor 閱讀(3559) 評論(0)  編輯  收藏 所屬分類: javaweb
          主站蜘蛛池模板: 军事| 乐平市| 晋城| 和林格尔县| 新平| 子洲县| 南康市| 永善县| 阿鲁科尔沁旗| 彩票| 温泉县| 大兴区| 玛多县| 定西市| 广安市| 绵竹市| 荣成市| 赤城县| 托克托县| 长兴县| 永清县| 县级市| 边坝县| 景德镇市| 锡林郭勒盟| 汕尾市| 新乐市| 井研县| 翁牛特旗| 江川县| 盘锦市| 新蔡县| 中西区| 阜新市| 兰西县| 建阳市| 枣阳市| 甘孜县| 田阳县| 四川省| 澄城县|