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

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

我这边静态页面是写在后端,用调接口渲染出的静态页面,谁知道后面加了需求要对接jssdk,只能一点点append。。。真是太惨了。。大致是下面这样:微信js-sdk分享链接自定义图片描述标题_第2张图片
仔细看过流程的人就会发现:微信js-sdk分享链接自定义图片描述标题_第3张图片
上面的接口是从ajax请求返回的结果里取出来的。这三个参数作为请求wx官方的参数,是很重要的,时间戳、随机字符串都很好获取,最主要的是signature这个签名。下面来说怎么获取。
说之前提一下为什么多了这步:
微信js-sdk分享链接自定义图片描述标题_第4张图片
其实没有这步,直接在后端获取再把值赋上去,而不用用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("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("" + title + "");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("
"); builder.append("
"); builder.append("

" + title + "

"); builder.append(""); builder.append("
"); builder.append("

" + spreadHtmlAuthor + "

"); builder.append("

" + updateTime + "

"); builder.append("
"); builder.append(content); builder.append(""); builder.append("
"); builder.append("
"); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); builder.append(""); return builder.toString(); }

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

public WxShareSignParam getSignParam(String url) {
    try {
    //随机字符串
        String nonceStr = getNonceStr();
        //时间戳
        String timeStamp = getTimeStampSecond();
        //获取加密签名
        String signature = SHA1("jsapi_ticket=" + getTicketWithCache() + "&noncestr=" + nonceStr + "×tamp=" + 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);
    }
}

你可能感兴趣的:(经验)