微信分享

微信分享後臺功能處理:

1、獲取微信jsapi_ticket,以及加密的基礎類

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; 
@Component
public class PublicJsapiTicketURL {
    @Autowired
    WeixinConfig weixinConfig;
 
    /**
     * 獲取jsapi_ticket,jsapi_ticket是公衆號用於調用微信JS接口的臨時票據
     * @param access_token
     */
    public String getJsapiTicketUrl(String access_token){
        return weixinConfig.getApiHost()+"/cgi-bin/ticket/getticket?access_token="+access_token+"&type=jsapi";
    }
 
}
 
 
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
 
 
@Component
public class PublicJsapiTicketAPI {
 
    @Autowired
    PublicAPI publicAPI;
 
    @Autowired
    PublicJsapiTicketURL publicJsapiTicketURL;
 
    public JSONObject getJsapiTicket(WXAccount wxAccount) throws WeixinRequestException, ParseException {
        JSONObject jsonObject = WeixinUtil.doGetStr(publicJsapiTicketURL.getJsapiTicketUrl(publicAPI.getAccess_token(wxAccount)));
        Integer errorCode = WeixinUtil.hasWxError(jsonObject);
        if (errorCode != null) {
            throw new WeixinRequestException(wxAccount.getAppId(), errorCode);
        }
        return jsonObject;
    }
 
    public static Map<String, String> sign(String jsapi_ticket, String url) {
        Map<String, String> ret = new HashMap<String, String>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";
 
        //注意這裏參數名必須全部小寫,且必須有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        System.out.println(string1);
 
        try
        {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
 
        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);
 
        return ret;
    }
 
    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }
 
    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }
 
    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
 
 
}

2、因爲sapi_ticket是公衆號用於調用微信JS接口的臨時票據。正常情況下,jsapi_ticket的有效期爲7200秒,通過access_token來獲取。由於獲取jsapi_ticket的api調用次數非常有限,頻繁刷新jsapi_ticket會導致api調用受限,影響自身業務,開發者必須在自己的服務全局緩存jsapi_ticket。

Map<String,String> shareContent = new HashMap<String, String>();
shareContent.put("title","我申請了免費試用");//分享的title
shareContent.put("link","www.baidu.com");//分享的鏈接
shareContent.put("imgUrl","http://img.xxx.com/shop/images/201610/466_G_1476655499133.png");//分享的圖標

url = "http://beta.weixin.xxx.com/xx.html";//當前的頁面地址,測試地址,正式得獲取當前的url
String appId = wxConfig.getAppid();//公衆號的appId
ModuleRedisWeiXinPrefix.Prefix prefix = ModuleRedisWeiXinPrefix.Prefix.JSAPITICKET;
String jsApiTicket = redisSession.get(prefix.getCode());
if (StringUtils.isEmpty(jsApiTicket)){
    WXAccount wxAccount = storeService.getWXAccountFromAppId(appId);
 JSONObject jsonObject = publicJsapiTicketAPI.getJsapiTicket(wxAccount);
 jsApiTicket = (String)jsonObject.get("ticket");
 redisSession.set(prefix.getCode(),jsApiTicket,prefix.getTime());//把jsApiTicket存緩存
}

Map<String,String> signMap = PublicJsapiTicketAPI.sign(jsApiTicket, url);
signMap.put("appId",appId);
model.addAttribute("signMap", signMap);
model.addAttribute("shareContent",shareContent);

微信分享前臺處理:

業務需求:分享後臺設置的特定的分享鏈接,分享標題,分享圖標到朋友圈。

結合微信JS-SDK文檔:

1、在微信的公衆號管理平臺進行設置,進行了的設置後,才能改域名下進行微信開發的JS接口調用:

2、在需要調用微信JS的頁面引入下面的js文件:

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>

3、

<script>
    wx.config({
        debug: true// 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
        appId:'${signMap.appId}'// 必填,公衆號的唯一標識
        timestamp: '${signMap.timestamp}' // 必填,生成簽名的時間戳
        nonceStr: '${signMap.nonceStr}'// 必填,生成簽名的隨機串
        signature: '${signMap.signature}',// 必填,簽名,見附錄1
        jsApiList: [
            'checkJsApi',
            'hideMenuItems',
            'onMenuShareTimeline'// 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
    });
 
    wx.ready(function () {
        wx.checkJsApi({
            jsApiList: ['onMenuShareTimeline','hideOptionMenu','hideMenuItems'], // 需要檢測的JS接口列表,所有JS接口列表見附錄2,
            success: function(res) {
                // 以鍵值對的形式返回,可用的api值true,不可用爲false
                // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
            }
        });
        wx.hideMenuItems({
            menuList: ['menuItem:share:appMessage',
                        'menuItem:share:qq',
                        'menuItem:share:weiboApp',
                        'menuItem:favorite',
                        'menuItem:share:facebook',
                        'menuItem:share:QZone',
                        'menuItem:editTag','menuItem:delete','menuItem:copyUrl','menuItem:originPage','menuItem:readMode',
                        'menuItem:openWithQQBrowser','menuItem:openWithSafari','menuItem:share:email','menuItem:share:brand'
                        // 要隱藏的菜單項,只能隱藏“傳播類”和“保護類”按鈕,所有menu項見附錄3
        });
 
        //// config信息驗證後會執行ready方法,所有接口調用都必須在config接口獲得結果之後,
        // config是一個客戶端的異步操作,所以如果需要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。
        // 對於用戶觸發時才調用的接口,則可以直接調用,不需要放在ready函數中。
        wx.onMenuShareTimeline({
            title: '${shareContent.title}'// 分享標題
            link: '${shareContent.link}'// 分享鏈接
            imgUrl: '${shareContent.imgUrl}'// 分享圖標
            success: function () {
                alert("分享成功1");
                // 用戶確認分享後執行的回調函數
            },
            cancel: function () {
                alert("取消了分享1")
                // 用戶取消分享後執行的回調函數
            }
        });
 
    });
 
 
    wx.error(function(res){
 
        // config信息驗證失敗會執行error函數,如簽名過期導致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數中查看,對於SPA可以在這裏更新簽名。
 
    });
 
 
 
</script>

該文中涉及的工具類如下:


import com.thoughtworks.xstream.XStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class WeixinUtil {
    @Autowired
    WeixinConfig weixinConfig;

    public WeixinUtil() {
    }

    public static Integer hasWxError(JSONObject jsonObject) {
        Object o = jsonObject.get("errcode");
        if(o != null && NumberUtil.isNumber(o.toString())) {
            Integer errorCode = Integer.valueOf(Integer.parseInt(o.toString()));
            return errorCode.intValue() == 0?null:errorCode;
        } else {
            return null;
        }
    }


    public static JSONObject doGetStr(String url) throws ParseException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;

        try {
            CloseableHttpResponse e = httpClient.execute(httpGet);
            HttpEntity entity = e.getEntity();
            if(entity != null) {
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
            }
        } catch (Exception var15) {
            var15.printStackTrace();
        } finally {
            httpGet.abort();

            try {
                httpClient.close();
            } catch (IOException var14) {
                var14.printStackTrace();
            }

        }

        return jsonObject;
    }

    public static String doPostStr(String outStr, String url) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(new StringEntity(outStr, "UTF-8"));
        String result = null;

        try {
            CloseableHttpResponse e = httpClient.execute(httpPost);
            result = EntityUtils.toString(e.getEntity(), "UTF-8");
        } catch (Exception var14) {
            var14.printStackTrace();
        } finally {
            httpPost.abort();

            try {
                httpClient.close();
            } catch (IOException var13) {
                var13.printStackTrace();
            }

        }

        return result;
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章