公众号通过H5跳转小程序


前言

我们通过调用公众号接口是可以直接跳转小程序的,但是有时我们的需求并非如此,比如,我们需要跳转到某个H5页面,再从H5页面中跳转到指定的小程序。接下来请看下面的代码。


一、参考文档

JS-SDK说明文档跳转小程序的标签获取公众号token签名算法
我就是根据上面这四篇官方文档来实现该功能的。

二、后端springboot代码

1.导入依赖

        <!--http工具包-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.12</version>
            <scope>compile</scope>
        </dependency>
        <!--json解析-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>

2.H5页面跳转小程序所需的各种数据

代码如下(示例):

@Controller
public class TestController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * @作者 yangs
     * @日期 2022/5/17
     * @描述 H5跳转小程序需要的数据
     */
    @RequestMapping("/getData")
    public HashMap<String, String> getData() {
        String jsapi_ticket = getJsApiTicket();
        String nonceStr = UUID.randomUUID().toString();

        String timestamp = "1647935255";
        //这里填写你的H5页面的url
        String url = "http://351s3728.51vip.biz/toWx";

        String[] arr = new String[]{jsapi_ticket, nonceStr, timestamp, url};
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            if (i != 0) {
                content.append("&");
            }
            String s = arr[i];
            if (s.equals(nonceStr)) {
                content.append("noncestr=");
            } else if (s.equals(jsapi_ticket)) {
                content.append("jsapi_ticket=");
            } else if (s.equals(timestamp)) {
                content.append("timestamp=");
            } else if (s.equals(url)) {
                content.append("url=");
            }
            content.append(arr[i]);
        }
        System.out.println("准备签名的字符串-->" + content);
        // 签名规则 请参考 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
        String signature = hexSHA1(content.toString());

        HashMap<String, String> map = new HashMap<>();
        //支付签名时间戳
        map.put("timestamp", timestamp);
        //生成签名的随机串
        map.put("nonceStr", nonceStr);
        //签名
        map.put("signature", signature);
        return map;
    }


    /**
     * @作者 yangs
     * @日期 2022/5/17
     * @描述 获取小程序jsapi_ticket
     */
    public String getJsApiTicket() {
        HashMap<String, String> map = new HashMap<>();
        // 公众号的accessToken直接从redis读取了
        String token = AppRedisUtil.get("accessToken");
        map.put("access_token", token);
        map.put("type", "jsapi");
        String s = sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", map);
        return s;
    }


    /**
     * @描述 每隔60分钟获取access_token并存入redis
     * @参考文档 https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
     * @作者 yangs
     * @日期 2022/5/17
     */
    @Scheduled(initialDelay = 1000, fixedRate = 1000 * 60 * 60)
    public void queryTokenToRedis() {
        String path = "?grant_type={grant_type}&appid={appid}&secret={secret}";
        Map<String, String> params = new HashMap<>(3);
        params.put("grant_type", "client_credential");
        params.put("appid", "你公众号的appid");
        params.put("secret", "你公众号的secret");
        ResponseEntity<String> forObject = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/token" + path, String.class, params);
        JSONObject jsonObject = JSONObject.parseObject(forObject.getBody());
        String accessToken = jsonObject.getString("access_token");
        if (accessToken != null) {
            //有效期设置65分钟
            AppRedisUtil.set("accessToken", 65 * 60, accessToken);
        } else {
            AppRedisUtil.set("accessToken", forObject.getBody());
        }
    }



    /**
     * @作者 yangs
     * @日期 2022/3/22
     * @描述 sha1算法签名
     */
    private String hexSHA1(String value) {
        try {
            MessageDigest md = MessageDigest.getInstance("sha1");
            md.update(value.getBytes("utf-8"));
            byte[] digest = md.digest();
            return String.valueOf(Hex.encodeHex(digest));
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }


    /**
     * 下面是封装的一些发送http请求的公共方法,当然你也可以使用你自己的
     */
    private String sendGet(String reqUrl, Map<String, String> params) {
        InputStream inputStream = null;
        HttpGet request = new HttpGet();
        try {
            String url = buildUrl(reqUrl, params);
            HttpClient client = new DefaultHttpClient();
            request.setHeader("Accept-Encoding", "gzip");
            request.setURI(new URI(url));
            HttpResponse response = client.execute(request);
            inputStream = response.getEntity().getContent();
            return getJsonStringFromGZIP(inputStream);
        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
                request.clone();
            } catch (IOException | CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private String getJsonStringFromGZIP(InputStream is) {
        String jsonString = null;
        try {
            BufferedInputStream bis = new BufferedInputStream(is);
            bis.mark(2);
            // 取前两个字节
            byte[] header = new byte[2];
            int result = bis.read(header);
            // reset输入流到开始位置
            bis.reset();
            // 判断是否是GZIP格式
            int headerData = getShort(header);
            // Gzip 流 的前两个字节是 0x1f8b
            if (result != -1 && headerData == 0x1f8b) {
                is = new GZIPInputStream(bis);
            } else {
                is = bis;
            }
            InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
            char[] data = new char[100];
            int readSize;
            StringBuilder sb = new StringBuilder();
            while ((readSize = reader.read(data)) > 0) {
                sb.append(data, 0, readSize);
            }
            jsonString = sb.toString();
            bis.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jsonString;
    }

    private static int getShort(byte[] data) {
        return (data[0] << 8) | data[1] & 0xFF;
    }

    /**
     * @描述 构建get方式的url
     * @作者 yangs
     * @日期 2021/8/14
     */
    private String buildUrl(String reqUrl, Map<String, String> params) {
        StringBuilder query = new StringBuilder();
        Set<String> set = params.keySet();
        for (String key : set) {
            query.append(String.format("%s=%s&", key, params.get(key)));
        }
        return reqUrl + "?" + query.toString();
    }

}

三、前端HTML代码

<html>
<head>
    <title>跳转小程序测试</title>
    <%--需要导入微信提供的这个js文件--%>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
    <script src="${pageContext.request.contextPath}/js/jQ.js"></script>
</head>
<body>
跳转小程序
<wx-open-launch-weapp
        id="launch-btn"
        username="gh_a26325160123"
        path="/pages/home/homeHome/homeHome">
    <script type="text/wxtag-template">
        <style>.btn {
            padding: 12px
        }</style>
        <button class="btn" id="btn">打开小程序</button>
    </script>
</wx-open-launch-weapp>
<script>
    wx.config({
        debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印
        appId: 'wx56327e8a9e43f215', // 必填,公众号的唯一标识
        timestamp: ${timestamp}, // 必填,生成签名的时间戳,后端读取
        nonceStr: '${nonceStr}', // 必填,生成签名的随机串,后端读取
        signature: '${signature}',// 必填,签名,后端读取
        jsApiList: ['updateAppMessageShareData'], // 必填,需要使用的JS接口列表
        openTagList: ['wx-open-launch-weapp'] // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
    });

    wx.ready(function () {
        // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中
        console.log("验证成功!");

        var btn = document.getElementById('launch-btn');
        btn.addEventListener('launch', function (e) {
            console.log('success');
        });

        btn.addEventListener('error', function (e) {
            console.log('fail', e.detail);
        });


    });

    wx.error(function (res) {
        // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名
        console.log("验证失败!");
    });

</script>
</body>
</html>

总结

以上就是H5页面跳转小程序的全部代码。另外各位大佬,请允许我打个小小的广告,下面是我开发的关于做人做饭的食谱小程序,感兴趣的扫描下方二维码去看看吧。
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在浏览器中跳转小程序是一个比较特殊的需求,需要使用微信提供的 JSSDK 来实现。以下是一个简单的示例代码,可以在uniapp中使用H5页面跳转小程序: 1. 首先需要在H5页面中引入微信JSSDK: ```html <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> ``` 2. 在 `mounted` 生命周期函数中初始化 JSSDK: ```javascript mounted() { this.initJSSDK(); }, methods: { initJSSDK() { // 发起GET请求获取access_token和jsapi_ticket uni.request({ url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET', success: (res) => { // 获取access_token和jsapi_ticket成功后,初始化JSSDK wx.config({ debug: false, // 是否开启调试模式 appId: 'YOUR_APPID', // 公众号的唯一标识 timestamp: Math.floor(new Date().getTime() / 1000), // 生成签名的时间戳 nonceStr: 'RANDOM_STR', // 生成签名的随机串 signature: 'YOUR_SIGNATURE', // 签名 jsApiList: ['chooseWXPay', 'openLocation', 'getLocation', 'onMenuShareAppMessage'] // 需要使用的JS接口列表 }); } }); } } ``` 其中,`YOUR_APPID` 和 `YOUR_SIGNATURE` 分别是你在微信公众平台上注册的小程序的AppID和签名(签名的生成方式可以参考微信官方文档)。 3. 在需要跳转小程序的地方,调用 `wx.miniProgram.navigateTo` 方法: ```javascript // 在浏览器中打开小程序 wx.miniProgram.navigateTo({ appId: 'wx1234567890', // 小程序的appId path: '/pages/index/index', // 小程序页面路径 extraData: { // 额外的数据,可选 foo: 'bar' }, success(res) { // 跳转成功的回调函数 console.log(res); }, fail(res) { // 跳转失败的回调函数 console.log(res); } }); ``` 需要注意的是,跳转小程序需要在微信中打开H5页面才能生效。在其他浏览器或者APP中,该代码会无效。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小Y先生。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值