微信分享网页开发

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QWERTY1994/article/details/88872022

需要分页的网页引入下面jsp

weixin.jsp

<%--
  Created by IntelliJ IDEA.
  User: 
  Date: 2019/2/20
  Time: 15:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--<%@ include file="/WEB-INF/views/modules/cms/front/include/taglib.jsp"%>--%>
<!-- 必须引入的文件-->
<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>

<!-- 组装微信配置信息js文件-->
<%--<script src="${ctxStatic}/weixin/wxShare_data.js"></script>--%>

<!-- 微信分享时调用对应的接口js文件-->
<%--<script src="${ctxStatic}/weixin/wxShare.js"></script>--%>

<script>
    //后台获取授权等信息的接口
    var url = "http://" + window.location.host + "/f/weixinShare/getWxShareData";
    // 分享网页图片地址
    var shareImageUrl="http://xxxx/xxxx.jpg";
    //分享网页后显示的标题
    var title="xxxxx";
    //分享网页的简介
    var desc= "xxxxx";
    //点击分享后页面跳转的页面
    var link="http://xxxxx/f/xxxxx";
    //上面这些数据也可以在后台动态生成
    $.ajax({
        url: url,//后台给你提供的接口
        type: "Post",
        // data: "{ 'url': '"+link+"' }",
        async: false,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (data) {
            wx.config({
                debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId: data.appId, // 必填,公众号的唯一标识
                timestamp: data.timestamp, // 必填,生成签名的时间戳
                nonceStr: data.nonceStr, // 必填,生成签名的随机串
                signature: data.signature,// 必填,签名
                jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareWeibo','onMenuShareAppMessage','onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone'] // 必填,需要使用的JS接口列表
            });
            wx.ready(function () {
                // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,
                // 则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
                //需在用户可能点击分享按钮前就先调用
                // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容
                wx.updateAppMessageShareData({
                    title: title, // 分享标题
                    desc: desc, // 分享描述
                    link: link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 设置成功
                    }
                });
                //自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容
                wx.updateTimelineShareData({
                    title: title, // 分享标题
                    link: link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 设置成功
                    }
                });
                //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
                wx.onMenuShareWeibo({
                    title: title, // 分享标题
                    desc: desc, // 分享描述
                    link: link, // 分享链接
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () {
                        // 用户取消分享后执行的回调函数
                    }
                });

                // 获取“分享给朋友”按钮点击状态及自定义分享内容接口(即将废弃)
                wx.onMenuShareAppMessage({
                    title: title, // 分享标题
                    desc: desc, // 分享描述
                    link: link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: shareImageUrl, // 分享图标
                    type: 'link', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () {
                        // 用户点击了分享后执行的回调函数
                    }
                });
                //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口(即将废弃)
                wx.onMenuShareTimeline({
                    title: title, // 分享标题
                    link: link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 用户点击了分享后执行的回调函数
                    }
                });
                //获取“分享到QQ”按钮点击状态及自定义分享内容接口(即将废弃)
                wx.onMenuShareQQ({
                    title: title, // 分享标题
                    desc: desc, // 分享描述
                    link: link, // 分享链接
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () {
                        // 用户取消分享后执行的回调函数
                    }
                });
                //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口(即将废弃)
                wx.onMenuShareQZone({
                    title: title, // 分享标题
                    desc: desc, // 分享描述
                    link: link, // 分享链接
                    imgUrl: shareImageUrl, // 分享图标
                    success: function () {
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () {
                        // 用户取消分享后执行的回调函数
                    }
                });
            });
            wx.error(function (res) {
                // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
                //alert(res);
            });
        },
        error: function (error) {
            layer.msg(error)
        }
    });

</script>

后台获取签名授权等信息的方法

下面的签名每天获取有次数限制,微信的签名2个小时内有效, 此处我用的是Memcached缓存起来,各位可以自行实现



import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.thinkgem.jeesite.common.config.Global;
import com.thinkgem.jeesite.common.memcached.MemcachedUtil;
import com.thinkgem.jeesite.common.utils.CacheUtils;
import com.thinkgem.jeesite.common.web.BaseController;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信分享
 */
@Controller
@RequestMapping(value = "/f/weixinShare")
public class CourseWeixinShare extends BaseController {
    // 微信分享入口
    @RequestMapping(value = "getWxShareData")
    @ResponseBody
    public Map getWxShareData(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String,Object> returnMap = new HashMap<>();

        String ticket = "";
        String[] wxInfo = new String[]{Global.getConfig("appId"),Global.getConfig("appsecret")};//设置appid 和 appsecret

        String ticketResString = this.getShareJsapiTicket(wxInfo);

        if (StringUtils.isNotEmpty(ticketResString)) {
          //  JSONObject ticketJSONObject = JSONObject.fromObject(ticketResString);

            Gson gson =new Gson();
            Map<String,Object> ticketJSONObject = gson.fromJson(ticketResString,Map.class);
            if ((Double)ticketJSONObject.get("errcode") == 0) {
//                ticket = JSONObject.fromObject(ticketResString).optString("ticket", "");
                if(ticketJSONObject.get("ticket")!=null){
                    ticket = (String) ticketJSONObject.get("ticket");
                }

            }
        }

        if (StringUtils.isEmpty(ticket)) {
            returnMap.put("errcode", "10002");
            returnMap.put("errmsg", "ticket_error");
//            this.responseWrite(jsonObject.toString());
            return returnMap;
        }

        String noncestr = this.createNonceStr();
        int timestamp = this.createTimestamp();
        String requestRefererURL = request.getHeader("referer");
        logger.warn("requestRefererURL: " + requestRefererURL);

        String signature = this.createSignature(noncestr, ticket, timestamp, requestRefererURL);

        returnMap.put("errcode", 0);
        returnMap.put("errmsg", "");
        returnMap.put("appId", wxInfo[0]); // appId
        returnMap.put("timestamp", timestamp);
        returnMap.put("nonceStr", noncestr);
        returnMap.put("signature", signature);
        return returnMap;

    }

    /**
     * 微信分享,获取Js api Ticket
     * @param wxInfo
     * @return
     * @throws Exception
     */
    private String getShareJsapiTicket(String[] wxInfo) throws Exception {

        String jsapiTicket = null;
        if(CacheUtils.get("jsapiTicket_addTime") !=null &&( System.currentTimeMillis() - (Long) CacheUtils.get("jsapiTicket_addTime"))<7080*1000){//不超过2个小时的缓存有效
            jsapiTicket = (String) CacheUtils.get("jsapiTicket");
            this.logger.warn(" from memcached jsapiTicket: " + jsapiTicket);
            return jsapiTicket;
        }else{
            String accessToken = this.getWeiXinAccessToken(wxInfo);
            if (StringUtils.isEmpty(accessToken)) { // 获取 accessToken 失败
                this.logger.warn(" accessToken is empty.");
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("errcode", "10000");
                jsonObject.addProperty("errmsg", "access_error");
                return jsonObject.toString();
            }

            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken + "&type=jsapi";
            jsapiTicket = this.httpReqExecute(url);
            this.logger.warn(" from weixin api jsapiTicket is: " + jsapiTicket);

            if(StringUtils.isNotEmpty(jsapiTicket)) {
                // 向memcached里写内容,第二个参数为过期时间,单位为:秒 两个小时失效
//            remoteMemcachedClient.set(siteId + "_jsapiTicket", 7200, jsapiTicket);
                CacheUtils.put("jsapiTicket",jsapiTicket);
                CacheUtils.put("jsapiTicket_addTime",System.currentTimeMillis());//设置 缓存的时间
                return jsapiTicket;
            }
            return null;
        }
    }

    /**
     * 微信分享,获取access_token
     * 先从memcached获取
     * @param wxInfo 0:appId 1:secret
     * @return
     * @throws Exception
     */
    private String getWeiXinAccessToken(String[] wxInfo) throws Exception {
        String access_token = MemcachedUtil.get("ParentsSpace_access_token");
        if(StringUtils.isNotBlank(access_token)){
            return  access_token;
        }
       /* if( CacheUtils.get("access_token_addTime")!=null && (System.currentTimeMillis() - (Long)CacheUtils.get("access_token_addTime")) <7080*1000 ){//不超过2个小时的缓存有效
            return (String) CacheUtils.get("access_token");
        }*/else{//失效了 就重新请求
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wxInfo[0] + "&secret=" + wxInfo[1];

            String result = this.httpReqExecute(url);
            this.logger.warn("from weixin api accessToken: " + result);
            try {
                if(StringUtils.isNotEmpty(result)) {
                    // 解析respContent,并获取其中的更新的key,
                    Gson gson =new Gson();
                    Map<String,String> resultMap =  gson.fromJson(result,Map.class);

//                String accessToken = JSONObject.fromObject(result).optString("access_token", "");
                    String accessToken = "";
                    if(resultMap.get("access_token")!=null){
                        accessToken = resultMap.get("access_token");
                        //缓存起来
                      /*  CacheUtils.put("access_token_addTime",System.currentTimeMillis());
                        CacheUtils.put("access_token",accessToken);*/
                      //缓存118分钟
                        MemcachedUtil.set("ParentsSpace_access_token",accessToken,118*60);
                    }
                    return accessToken;
                }
            } catch (Exception e) {
                logger.error("getAccessToken error in WeiXinShareAction", e);
            }
            return null;
        }
    }

    /**
     * 数据签名
     * @param nocestr
     * @param ticket
     * @param timestamp
     * @param url
     * @return
     */
    private String createSignature(String nocestr, String ticket, int timestamp, String url) {
        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        String s = "jsapi_ticket=" + ticket + "&noncestr=" + nocestr + "&timestamp=" + timestamp + "&url=" + url;
        return DigestUtils.sha1Hex(s);
    }

    /**
     * 创建随机串 自定义个数0 < ? < 32
     * @return
     */
    private String createNonceStr() {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String nonceStr = "";
        for (int i = 0; i < 16; i++) {
            int beginIndex = (int) Math.round(Math.random() * 10);
            nonceStr += str.substring(beginIndex, beginIndex + 1);
        }
        return nonceStr;
    }

    /**
     * 创建时间戳
     * @return
     */
    private int createTimestamp() {
        return Calendar.getInstance().get(Calendar.SECOND);
    }

    // 输出信息
    /*private void responseWrite(String content) {
        try {
            getResponse().setCharacterEncoding("utf-8");
            getResponse().getWriter().write(content);
        } catch (Exception e) {
            logger.error("responseWrite error in WeiXinShareAction", e);
        }
    }*/

    // HTTP远程调用
    private String httpReqExecute(String url) {
        String result = "";
//        DefaultHttpClient httpclient = null ;
        HttpClient httpclient = null ;
        try {
            httpclient = HttpClientBuilder.create().build();//获取DefaultHttpClient请求
            HttpPost httppost = new HttpPost(url);
            // 执行
            org.apache.http.HttpResponse response = httpclient.execute(httppost);
            HttpEntity entity = response.getEntity();
            if(entity != null && response.getStatusLine().getStatusCode() == 200){
                result =  EntityUtils.toString(entity, "UTF-8");
            }
        } catch (Exception e) {
            logger.error(" WeiXinShareAction 调用微信 API 失败!", e);
        } finally { // 关闭连接,释放资源
            httpclient.getConnectionManager().shutdown();
        }
        return result;
    }
}

猜你喜欢

转载自blog.csdn.net/QWERTY1994/article/details/88872022