微信分享

微信分享后台功能处理:

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;
    }
}


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