微信js-sdk分享链接自定义图片描述标题

首先需求是:将微信扫一扫的分享功能 回形针图片 描述 标题 换成自定义的
在这里插入图片描述
大概是从上往下的这个效果。
好了需求已经很明确了,接下来说一下实现过程。先贴两个很有用的帖子可以借鉴参考:
http://www.jjyc.org/a/d/182281
https://www.jianshu.com/p/922b0986d1b0
除了这两篇帖子外的需要做的还有一个全局缓存,因为jsapi_ticket有个7200的失效时间,而微信对这个调用微信JS接口的临时票据有调用限制。因此redis最好缓存一下,能增大对外的用户使用次数(后面会把做法详细说)。

我这边静态页面是写在后端,用调接口渲染出的静态页面,谁知道后面加了需求要对接jssdk,只能一点点append。。。真是太惨了。。大致是下面这样:在这里插入图片描述
仔细看过流程的人就会发现:在这里插入图片描述
上面的接口是从ajax请求返回的结果里取出来的。这三个参数作为请求wx官方的参数,是很重要的,时间戳、随机字符串都很好获取,最主要的是signature这个签名。下面来说怎么获取。
说之前提一下为什么多了这步:
在这里插入图片描述
其实没有这步,直接在后端获取再把值赋上去,而不用用ajax返回的对象data一个个去拿值,也能达到效果,但是只能转发一个用户,当这个用户用自己的链接再转发给其他人时就失效了,因为微信转发时会自动拼接一串字符,这些是未知的,所以请求的页面url不是固定的(一个素材id转发不是只有一个用户转发),这时只能用js的var url = location.href.split(’#’)[0];方法即时获取当前地址,不同用户不同的。【当前url是post请求求参数,返回jssdk的请求参数】后端代码如下:

@ApiOperation("获取推广微信JS-SDK请求参数")
@GetMapping("/pub/html/wxJSSdk")
@ResponseBody
public WxShareSignParam getWXjsSdkResult(@RequestParam("url") String url) {
    try {
        return wxShareSupport.getSignParam(url);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

顺便把拼接的前端代码放一下,虽然丑陋。。。

 /**
     * @param accountId  用户id标识
     * @param title      推广文章标题
     * @param updateTime 推广页面展示:更新时间
     * @param content    推广页面展示:内容
     * @param QRUrl      推广页面展示:注册入口二维码
     * @param imgUrl     缩略图地址
     * @param link       跳转链接
     * @return
     */
    public String buildHtml(Long accountId, String title, String updateTime, String content, String QRUrl, String imgUrl, String link, String descLimit) {

        String url = spreadRegHtmlUrl + "/#/register?id=" + accountId;

        StringBuffer builder = new StringBuffer();
        builder.append("<html>");
        builder.append("<head>");
        builder.append("<meta charset=\"utf-8\">");
        builder.append("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">");
        builder.append("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">");
        builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + publicCssFileUrl + "\" />");
        builder.append("<title>" + title + "</title>");
        builder.append("<style>");
        builder.append("*{\n" +
                "        margin: 0;padding:0;\n" +
                "      }" +
                "      .title{\n" +
                "        margin: 0;font-size: 24px;font-family: PingFang SC;font-weight:bold;color:rgba(0,0,0,1);margin-bottom: 20px !important;\n" +
                "      }\n" +
                "      .avater{\n" +
                "        width: 36px !important;display: inline-block;vertical-align: middle;margin-bottom: 17px;margin-right: 10px;\n" +
                "      }\n" +
                "      .avater-right{\n" +
                "        display: inline-block;vertical-align: middle;margin-bottom: 17px;\n" +
                "      }\n" +
                "      .avater-name{\n" +
                "        margin: 0;font-size:16px;font-family:PingFang SC;font-weight:bold;color:rgba(0,0,0,1);\n" +
                "      }\n" +
                "      .time{\n" +
                "        margin: 0;font-size:12px;font-family:PingFang SC;font-weight:400;color:rgba(0,0,0,1);\n" +
                "      }\n" +
                "      .fix-bot{\n" +
                "        width:100px;\n" +
                "        position: fixed;\n" +
                "        bottom: 70px;\n" +
                "        right: 0;\n" +
                "      }");
        builder.append("</style>");
        builder.append("</head>");
        builder.append("<body>");
        builder.append("<div class=\"ql-container ql-snow\">");
        builder.append("<div class=\"ql-editor\">");
        builder.append("<p class=\"title\">" + title + "</p>");
        builder.append("<img class=\"avater\" src=" + spreadHtmlTitleUrl + " />");
        builder.append("<div class=\"avater-right\">");
        builder.append("<p class=\"avater-name\">" + spreadHtmlAuthor + "</p>");
        builder.append("<p class=\"time\">" + updateTime + "</p>");
        builder.append("</div>");
        builder.append(content);
        builder.append("<img data-v-569dfcf0 src=\"" + QRUrl + "\"/>");
        builder.append("</div>");
        builder.append("</div>");
        builder.append("<img onclick='window.location.href=\"" + url + "\"' class=\"fix-bot\" src=\"" + regBtnUrl + "\" />");

        builder.append("<script src = \"http://res.wx.qq.com/open/js/jweixin-1.2.0.js\"></script>");
        builder.append("<script src=\"https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js\"></script>");
        builder.append("<script>");
        builder.append("    $(function () {\n" +
                "        var url = location.href.split('#')[0];\n" +
                "        $.ajax({\n" +
                "            url: \"http://qiandun-spread-test.rrgs2.cn" + "/spread/pub/html/wxJSSdk\"" + ",\n" +
                "            data: {\n" +
                "                \"url\": url\n" +
                "            },\n" +
                "            dataType: \"json\",\n" +
                "            timeout: 5000,\n" +
                "            error: function (XMLHttpRequest, textStatus, errorThrown) {\n" +
                "                if (textStatus == \"timeout\") {\n" +
                "                } else {\n" +
                "                }\n" +
                "            },\n" +
                "            success: function (data, textStatus) {\n" +
                "                if (textStatus == \"success\") {\n" +
                "                    wx.config({\n" +
                "                        debug: true,\n" +
                "                        appId: 'wx3fa8908cb1f9409b',\n" +
                "                        timestamp: data.timestamp,\n" +
                "                        nonceStr: data.nonceStr,\n" +
                "                        signature: data.signature,\n" +
                "                        jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo']\n" +
                "                    });\n" +
                "                    wx.ready(function () {\n" +
                "                        wx.onMenuShareTimeline({\n" +
                "                            imgUrl:'" + imgUrl + "',\n" +
                "                            title:'" + title + "',\n" +
                "                            desc: '" + descLimit + "',\n" +
                "                            link:'" + link + "',\n" +
                "                        });\n" +
                "                        wx.onMenuShareAppMessage({\n" +
                "                            imgUrl:'" + imgUrl + "',\n" +
                "                            title:'" + title + "',\n" +
                "                            desc: '" + descLimit + "',\n" +
                "                            link:'" + link + "',\n" +
                "                        });\n" +
                "                    });\n" +
                "                }\n" +
                "            }\n" +
                "        });\n" +
                "    });");
        builder.append("</script>");
        builder.append("</body>");
        builder.append("</html>");
        return builder.toString();
    }

这些写在前端就会清楚很多,只不过跟我们公司的需求有关,原本只是简单拼接一个html,标题内容时间这些内容。谁知道后面加需求了,只能在原来的代码上加。。加上负责这块的同事刚离职,,真是雪上加霜。。。
前端就差不多了,后面主要讲签名怎么获取。前端这里还有一个注意事项:
config里的配置在这里插入图片描述
参数名是固定的(严格区分大小写,千万别写错了),后面jsapilist是指定分享的程序,比如发给朋友,朋友圈,微博,qq等。
下面是获取签名的代码:

public WxShareSignParam getSignParam(String url) {
    try {
    //随机字符串
        String nonceStr = getNonceStr();
        //时间戳
        String timeStamp = getTimeStampSecond();
        //获取加密签名
        String signature = SHA1("jsapi_ticket=" + getTicketWithCache() + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url);

        return new WxShareSignParam(timeStamp, nonceStr, signature);
    } catch (Exception e) {
        logger.info("获取微信分享 WxShareSignParam 异常 url:{}", url, e);
    }
    return null;
}

/**
 * 获取随机字符串,16位
 *
 * @return
 */
private static String getNonceStr() {
    return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
}

/**
 * 获取时间戳,秒
 *
 * @return
 */
private static String getTimeStampSecond() {
    return String.valueOf(System.currentTimeMillis() / 1000);//时间戳
}

在这里插入图片描述
将参数拼成字符串,其中jsapi_ticket处理成缓存,url是ajaxs请求来的当前随机地址

/**
 * 同步关键字防止并发问题
 * 分布式环境仍然可能出现问题,但是概率小且无影响,暂不处理
 * @return
 */
private synchronized String getTicketWithCache() {
    String ticket = getTicket();
    if (StringUtils.isNotBlank(ticket)) {
        return ticket;
    }
    String accessToken = getAccessToken();
    ticket = getTicket(accessToken);
    return ticket;
}

    private String getTicket(){
    try {
    //private StringRedisTemplate stringRedisTemplate;
       return stringRedisTemplate.boundValueOps(WX_SHARE_TICKET_CACHE_KEY).get();
    }catch (Exception e){
        logger.error("redis error");
    }
    return "";
}

private void setTicket(String ticket, long expireTime){
    if(expireTime < 0){
        return ;
    }
    try {
        stringRedisTemplate.boundValueOps(WX_SHARE_TICKET_CACHE_KEY).set(ticket,expireTime, TimeUnit.SECONDS);
    }catch (Exception e){
        logger.error("redis error");
    }
}

//缓存里没有的话 则重新请求
    /**
 * 每次获取accessToken都会导致上一个失效
 * 目前只有这里用到,所以不做缓存,每次都重新获取
 * @return
 */
public static String getAccessToken() {
    String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + "&appid=" + APP_ID + "&secret=" + SECRET;
    try {
        JSONObject demoJson = HttpClientUtils.httpGet(url);
        logger.info("获取微信分享 key 结果:{}", demoJson);
        String accessToken = demoJson.getString("access_token");
        if (StringUtils.isBlank(accessToken)) {
            throw new SpreadRuntimeException(SpreadErrorCode.SPREAD_WX_JsSDK_ACCESS_TOKEN_ERROR2);
        }
        return accessToken;
    } catch (Exception e) {
        logger.error("获取微信分享 key 异常", e);
        throw new SpreadRuntimeException(SpreadErrorCode.SPREAD_WX_JsSDK_ACCESS_TOKEN_ERROR1);
    }
}

public static String SHA1(String decript) {
    try {
        MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
        digest.update(decript.getBytes());
        byte messageDigest[] = digest.digest();
        // Create Hex String
        StringBuffer hexString = new StringBuffer();
        // 字节数组转换为 十六进制 数
        for (int i = 0; i < messageDigest.length; i++) {
            String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
            if (shaHex.length() < 2) {
                hexString.append(0);
            }
            hexString.append(shaHex);
        }
        return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
        throw new SpreadRuntimeException(SpreadErrorCode.SPREAD_WX_JsSDK_SHA1_ERROR);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值