redis缓存access_token,jsapi_ticket,实现微信公众号分享自定义缩略图和标题

官网地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

(1)项目搭建 。。。。。

(2)WxShareController

import com.adbj.service.WxPublicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Map;

/**
 * @Description: 微信分享
 * @Author: ZhaoLinXuan
 * @Date: 2019/8/27 9:56
 */
@Controller
@RequestMapping(value = "/wxShare")
public class WxShareController {
    @Autowired
    private WxPublicService wxPublicService;

    /**
     * @param url
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/getSignature",method = RequestMethod.GET)
    @ResponseBody
    public Map<String,Object> getSignature(String url) throws Exception {
        Map<String,Object> config = wxPublicService.getSignature(url);
        return config;
    }

    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public String index() throws Exception {
        return "index";
    }
}

(3)WxPublicService,RedisService

import org.springframework.data.repository.query.Param;

import java.util.Map;

/**
 * @Description: 微信分享后台配置
 * @Author: ZhaoLinXuan
 * @Date: 2019/8/27 10:32
 */
public interface WxPublicService {

    /**
     * fetch data by rule url
     *
     * @param url rule url
     * @return Map<String,Object>
     */
    Map<String,Object> getSignature(@Param("url") String url);
}
/**
 * redis操作Service,
 * 对象和数组都以json形式进行存储
 *
 * @author zlx
 * @date 2019/08/10
 */
public interface RedisService {
    /**
     * 存储数据
     */
    void set(String key, String value);

    /**
     * 获取数据
     */
    String get(String key);

    /**
     * 设置超期时间
     */
    boolean expire(String key, long expire);

    /**
     * 删除数据
     */
    void remove(String key);

    /**
     * 自增操作
     * @param delta 自增步长
     */
    Long increment(String key, long delta);

    Boolean hasKey(String key);
}

(4)WxPublicServiceImpl (AppId,AppSecret需要自己的),RedisServiceImpl

import com.adbj.service.RedisService;
import com.adbj.service.WxPublicService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import utils.WxAccessTokenSinglenton;
import utils.WxJsapiticketSinglenton;
import utils.WxSign;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description:
 * @Author: ZhaoLinXuan
 * @Date: 2019/8/27 10:35
 */
@Service
public class WxPublicServiceImpl implements WxPublicService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WxPublicServiceImpl.class);

    private static final int OUT_TIME=600;
    private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=AppId&secret=AppSecret";
    private static final String TICKETURL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=";
    @Autowired
    private RedisService redisService;
    @Override
    public Map<String, Object> getSignature(String url) {
        Long date = (Long) (System.currentTimeMillis()/1000);
        LOGGER.info("date:{}",date);
        Map<String,Object> map = new LinkedHashMap<>();
        if(StringUtils.isNotBlank(url)){
     
         String access_token=getAccessTokenByRedis(date);
            if(access_token.equals("null")||StringUtils.isBlank(access_token)){
                map.put("signature","获取签名失败,获取token的IP地址未授权");
                return map;
            }
         //获取ticket的链接
         String jsapi_ticket=getJsapiticketByRedis(access_token,date);
         //根据参数进行sha1签名
         Map<String, String> result = WxSign.sign(jsapi_ticket,url);
         map.put("appId","AppId");
         map.put("url",result.get("url"));
         map.put("timestamp",result.get("timestamp"));
         map.put("nonceStr",result.get("nonceStr"));
         map.put("signature",result.get("signature"));
        }else{
            map.put("signature","获取签名失败");
        }
        return map;
    }


    public  String getAccessTokenByRedis(Long date) {
        String result = "";

        if(redisService.hasKey("access_token")){
            String access_token = redisService.get("access_token");
            JSONObject outcome=JSON.parseObject(access_token);
            String time = outcome.getString("time");
            String token = outcome.getString("token");
            LOGGER.info("redis查询token:{},time:{},NEW_DATE:{},剩余时间:{}",token,time,date,date - Long.parseLong(time));
            if (token != null && time != null && (date - Long.parseLong(time)) <OUT_TIME) {
                LOGGER.info("redis查询 token:{},nowDate:{},time:{},剩余时间:{}",token,date,time,date - Long.parseLong(time));
                result = token;
            }else {
                redisService.remove("access_token");
                //获取token的链接
              
                Map<String,Object> tokenBackMap = new RestTemplate().getForObject(TOKEN_URL,Map.class);
                //获取到的token
                token = String.valueOf(tokenBackMap.get("access_token"));
                String time_remaining=String.valueOf(tokenBackMap.get("expires_in"));
                JSONObject json=new JSONObject();
                json.put("time", date + "");
                json.put("token", token);
                redisService.set("access_token",json.toJSONString());
                LOGGER.info("过期初始化 token:{},nowDate:{},剩余时间:{}",token,date,time_remaining);
                result = token;
            }
        }else {
            redisService.remove("access_token");
            //获取token的链接
            Map<String,Object> tokenBackMap = new RestTemplate().getForObject(TOKEN_URL,Map.class);
            //获取到的token
            String token = String.valueOf(tokenBackMap.get("access_token"));
            String time_remaining=String.valueOf(tokenBackMap.get("expires_in"));
            JSONObject json=new JSONObject();
            json.put("time",  date+ "");
            json.put("token", token);
            redisService.set("access_token",json.toJSONString());

            LOGGER.info("初始化   》》》accessToken:{},nowDate:{},剩余时间:{}",token,date,time_remaining);
            result = token;
        }
        return result;
    }

    public  String getJsapiticketByRedis(String access_token,Long date) {
        String result = "";

        LOGGER.info("ticket:{}",redisService.hasKey("ticket"));

        if(redisService.hasKey("ticket")){
            String ticket = redisService.get("ticket");
            JSONObject outcome=JSON.parseObject(ticket);
            String time = outcome.getString("time");
            String jsapi_ticket = outcome.getString("jsapi_ticket");

            
            LOGGER.info("jsapi_ticket:{},time:{},nowDate:{},剩余时间:{}",jsapi_ticket,time,date,date - Long.parseLong(time));
            if (ticket != null && time != null && (date - Long.parseLong(time)) < OUT_TIME) {
                LOGGER.info("redis查询 jsapi_ticket:{},nowDate:{},time:{},剩余时间:{}",jsapi_ticket,date,time,date - Long.parseLong(time));
                result = jsapi_ticket;
            }else {
                LOGGER.info("删除ticket:{}",ticket);
                redisService.remove("ticket");
                String getTicketUrl = TICKETURL+access_token+"&type=jsapi";
                Map<String,Object> ticketBackMap = new RestTemplate().getForObject(getTicketUrl,Map.class);
                //获取到的ticket
                jsapi_ticket = String.valueOf(ticketBackMap.get("ticket"));
                String time_remaining=String.valueOf(ticketBackMap.get("expires_in"));
                JSONObject json=new JSONObject();
                json.put("time",  date+ "");
                json.put("jsapi_ticket", jsapi_ticket);
                redisService.set("ticket",json.toJSONString());

                LOGGER.info("过期初始化   》》》ticket:{},nowDate:{},剩余时间:{}",jsapi_ticket,date,time_remaining);
                result = jsapi_ticket;
            }
        }else {
            redisService.remove("ticket");
            String getTicketUrl = TICKETURL+access_token+"&type=jsapi";
            Map<String,Object> ticketBackMap = new RestTemplate().getForObject(getTicketUrl,Map.class);
            //获取到的ticket
            String jsapi_ticket = String.valueOf(ticketBackMap.get("ticket"));
            String time_remaining=String.valueOf(ticketBackMap.get("expires_in"));
            JSONObject json=new JSONObject();
            json.put("time",  date+ "");
            json.put("jsapi_ticket", jsapi_ticket);
            redisService.set("ticket",json.toJSONString());
            LOGGER.info("初始化   》》》ticket:{},nowDate:{},剩余时间:{}",jsapi_ticket,date,time_remaining);
            result = jsapi_ticket;
        }

        return result;
    }
}
import com.adbj.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * redis操作Service的实现类
 *
 * @author zlx
 * @date 2019/08/14
 */
@Service
public class RedisServiceImpl implements RedisService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    @Override
    public boolean expire(String key, long expire) {
        return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public void remove(String key) {
        stringRedisTemplate.delete(key);
    }

    @Override
    public Long increment(String key, long delta) {
        return stringRedisTemplate.opsForValue().increment(key,delta);
    }

    @Override
    public Boolean hasKey(String key) {

       return stringRedisTemplate.hasKey(key);
    }
}

(5)WxSign(微信提供)

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Description:
 * @Author: ZhaoLinXuan
 * @Date: 2019/8/27 11:01
 */
public class WxSign {
    public static void main(String[] args) {
        String jsapi_ticket = "jsapi_ticket";

        // 注意 URL 一定要动态获取,不能 hardcode
        String url = "http://example.com";
        Map<String, String> ret = sign(jsapi_ticket, url);
        for (Map.Entry entry : ret.entrySet()) {
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
    };

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

(6)html页面

<html>
<head>
    <title>二笔的微信分享啊!!!</title>
</head>
<body>
<img src="http://www.adbj.vip/img/aa.jpg" alt="logo" style="position: absolute; visibility: hidden;">
跨域请求调用,实现微信分享小图显示测试页
</body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script type="text/javascript">
    $(function () {
        var shareUrl = window.location.href.split("#")[0];
        var appId;
        var timestamp;
        var nonceStr;
        var signature;
        var shareTitle = document.title;
        var desc = "朋友圈分享功能!!!!!";
        var imgUrl = document.getElementsByTagName("img")[0].getAttribute("src");
        if(document.getElementsByTagName("img").length>1){
            imgUrl = document.getElementsByTagName("img")[1].getAttribute("src");
        }
        $.ajax({
                type: "GET",
                url: "/wxShare/getSignature",
                data: { url: shareUrl },
                dataType: "json",
                success: function (data) {
                    //这里只需要提供当前页面链接的URL,剩下数据全部由后端签名返回,后端可相应调整接口参数
                    console.log(JSON.stringify(data.result));
                    appId = data.appId;
                    timestamp = data.timestamp;
                    nonceStr = data.nonceStr;
                    signature = data.signature;
                    wechatJSDKSignature (appId,timestamp,nonceStr,signature,shareTitle,desc,shareUrl,imgUrl);
                }
            }
        );
    });
    function wechatJSDKSignature (appId,timestamp,nonceStr,signature,shareTitle,desc,shareUrl,imgUrl){
        wx.config({
            debug: true,//开启微信调试模式,微信成功分享带图后可关闭
            appId: appId,
            timestamp: timestamp,
            nonceStr: nonceStr,
            signature: signature,
            jsApiList: [
                "updateAppMessageShareData",
                "updateTimelineShareData",
                 "onMenuShareWeibo",
               /* "onMenuShareTimeline",
                "onMenuShareAppMessage",
                "getLocation"*/
            ]
        });
        wx.ready(function () {
            wx.updateAppMessageShareData({
                title: shareTitle,
                desc: desc,
                link: shareUrl,
                imgUrl: imgUrl,
                success: function () {
                    console.log("调用分享给朋友成功");
                }
            });
            wx.updateTimelineShareData({
                title: shareTitle,
                link: shareUrl,
                imgUrl: imgUrl,
                success: function () {
                    console.log("调用分享到朋友圈成功");
                }
            });
           /* wx.onMenuShareTimeline({
                title: shareTitle,
                desc: desc,
                link: shareUrl,
                imgUrl: imgUrl,
                success: function () {
                    console.log("调用即将废弃的分享给朋友成功");
                }
            });
            wx.onMenuShareAppMessage({
                title: shareTitle,
                link: shareUrl,
                imgUrl: imgUrl,
                success: function () {
                    console.log("调用即将废弃的分享到朋友圈成功");
                }
            });*/
            wx.onMenuShareWeibo({
                title: shareTitle, // 分享标题
                desc: desc, // 分享描述
                link: shareUrl, // 分享链接
                imgUrl: imgUrl, // 分享图标
                success: function () {
                    console.log("调用分享给微博成功");
                },
                cancel: function () {
                    // 用户取消分享后执行的回调函数
                }
            });
        });
        wx.error(function (res) {
            console.log("程序错误");
        });
    }
</script>
</html>

(7)结果

发布了50 篇原创文章 · 获赞 25 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zhaolinxuan1/article/details/100731330