课程表

Spring Boot课程

工具箱
速查手册

Boot 微信公众号开发

当前位置:免费教程 » Java相关 » Spring Boot
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2020/3/2 16:40:35

微信公众号的开发是很常见的开发任务。如果大家用过其他语言开发,就可以很自然的转到Spring Boot的微信开发。这里给大家整理一条最便捷的方式,让大家迅速入门,避免踩坑。

微信开发官方文档的链接:

https://developers.weixin.qq.com/doc/

在开始微信开发的时候,官方文档可以随时作为查阅和参考资料。

本章节介绍的内容有:1、基本的微信端访问验证;2、公众号关注验证;3、自定义微信分享图标。由于本章节主要是基于上一章节的redis开发,所以除此之外,还大致介绍一下使用数据库进行微信开发的基本思路,具体的代码这里就省略了。


一、基本原理

微信公众号的开发原理是,首先,我们在页面程序上进行判断,有没有地址栏参数“code”,如果没有,我们就把相关参数带上,然后跳转到下面的这个地址获取code:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=【你的微信公众号开发AppId】&redirect_uri=【你的页面地址】&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

微信公众号平台的这个接口地址,会根据你传递的AppId,跳转到你给的页面地址,但是它附带了一个code参数,类似这样:

https://www.w3xue.com/test?code=【微信给你的code】

这个code是干嘛的呢?我们可以用这个code,再加上 AppId 和AppSecret ,来取访问页面的该微信用户对于本公众号的唯一OpenID。这个OpenID 就是一个微信用户在一个公众号的身份ID,它在某一个微信公众号上具有唯一性,一个用户只对应一个OpenID。

然后,我们使用AppId 和 AppSecret 去获取 AccessToken,这里要注意,一个微信公众号获取其 AccessToken 的次数是有限制的(以前上限是2000次/天,现在政策可能变了,不同账号次数不同,但仍然有限制),因此,这是我们在开发过程中需要注意的一个重点。

有了AccessToken,再加上上一步获得的OpenID,我们的程序拿着它们,就可以发送给微信公众号平台,查询一个用户的是否关注等信息了。

另外,我们本章节还将学习如何给页面加上图标,就是用户在分享本页面后,在朋友圈或者聊天记录中显示的那个图标:

示意图.jpg

在上古时代,微信会获取一个页面中的第一个图片作为图标,现在不行了,需要自定义了。其基本的原理是,在页面引用微信官方的一个JS,然后自定义相关的图标和地址,并且最重要的是,要生成一个签名,这样才能自定义成功。

了解完这些基本原理后,就可以思考开发工作了。


二、准备工作

在正式开发之前,我们要确认公众号具有相关权限,并有正确的设置,然后新建相关的工具类,以便引入使用。

1、一个拥有开发权限的微信公众号,以及其开发用的 AppId 和 AppSecret。当然,还需要进行一些设置:

a.在“公众号设置->功能设置”设置“网页授权域名”和“JS接口安全域名”。把你的程序所在域名(二级域名就用二级域名)加入这2个名单备用,设置这2个可能需要管理员扫码。

b.设置IP白名单,在“开发配置->基本配置->IP白名单把你的服务器IP加进你的微信公众号IP白名单。

2、在utils文件夹新建2个类:HttpClientUtil类Encrypt类HttpClientUtil类用来处理相关与 http请求相关的业务。Encrypt类用来提供几个加密相关的函数。代码提供了下载链接,但具体就不贴出来了(如有红字,用Alt+Enter引入包即可):

HttpClientUtil.java下载  Encrypt类下载

3、在utils文件夹下面新建一个Wechat类,用来向微信公众平台发送信息并获取相关信息:

package com.w3xue.jiaocheng.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class Wechat {
    //获取微信用户授权信息
 public static String getBaseInfo(String code, String appid, String secret)
    {
        return HttpClientUtil.getInstance().sendHttpPost("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code", code);
    }

    //无时间间隔的获取全局access_token,每天有次数限制,慎用!
 public static String getAccessToken(String appid, String secret)
    {
        String sGetStr = HttpClientUtil.getInstance().sendHttpsGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret);
        JSONObject jsonResult = JSON.parseObject(sGetStr);
        return jsonResult.getString("access_token");
     }

    //无时间间隔的获取jsapi_ticket,有次数限制,慎用!
 public static String getJsapiTicket(String access_token)
    {
        String sGetStr = HttpClientUtil.getInstance().sendHttpPost("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi", "");
        JSONObject jsonResult = JSON.parseObject(sGetStr);
        return jsonResult.getString("ticket");
    }

    //获取用户常用信息,部分公众号没有此权限
    public static String getUserSetInfo(String access_token, String openid)//string appid, string secret,
    {
        return HttpClientUtil.getInstance().sendHttpsGet("https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+openid+"&lang=zh_CN");
    }

    //获取用户综合信息
     public static String getUserInfo(String access_token, String openid)//string appid, string secret,
     {
        return HttpClientUtil.getInstance().sendHttpsGet("https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + access_token + "&openid=" + openid+"&lang=zh_CN");//
     }
 
    //在获取用户综合信息的基础上获取关注标识(1:已关注 0:未关注)
     public static String getSubscribe(String access_token, String openid) //string appid, string secret,
     {
        String sGetStr = getUserInfo(access_token,  openid);
        JSONObject jsonResult = JSON.parseObject(sGetStr);
        return jsonResult.getString("subscribe");
     }

}

这里的方法基本机构我已经标出来了,基本的微信开发需要的方法都在这里。

4、在MainController类中添加如下方法(需要引用 com.w3xue.jiaocheng.utils.HttpClientUtil类):

final String strAppid="wx8bda2539bda48d1a";
final String strAppSecret="506044e1986e2576b0ef4de3f8e3ceea";
@Autowired
StringRedisTemplate redisTemplate;//引入redis
@RequestMapping(value = "/getToken2Ticket")
public String getToken2Ticket(String key) {
    String reStr = null;
    if (redisTemplate.hasKey(key)) {
        reStr = redisTemplate.opsForValue().get(key);
    } else {
        if (key.equals("ticketKey")) {
            String tmpToken=getToken2Ticket("cgi-token");
            String sGetStr = HttpClientUtil.getInstance().sendHttpPost("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + tmpToken + "&type=jsapi", "");
            JSONObject result2 = JSON.parseObject(sGetStr);
            if (result2.containsKey("ticket")) {
                reStr = result2.getString("ticket");
                redisTemplate.opsForValue().set(key, reStr);
                redisTemplate.expire(key, 2000, TimeUnit.SECONDS);
            }
        }
        else {
            String sGetStr = HttpClientUtil.getInstance().sendHttpsGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + strAppid + "&secret=" + strAppSecret);
            JSONObject result2 = JSON.parseObject(sGetStr);
            if (result2.containsKey("access_token")) {
                reStr = result2.getString("access_token");
                redisTemplate.opsForValue().set(key, reStr);
                redisTemplate.expire(key, 2000, TimeUnit.SECONDS);
            }
        }
    }
    return reStr;
}

因为上一节中我们已经介绍了如何添加StringRedisTemplate对象,这里就不多解释了。

这个方法的作用,是把AccessToken和Ticket的值,存在Redis里面,时间间隔设置为2000秒。这样,当这个值过期之后,该方法就会调用微信服务器的接口获取数据,并将其保存在Redis中。因为代码很简单,这里就不再详细说明。

5、添加模板文件wechat.html。代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>首页 - w3xue教程,Spring Boot微信开发</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <script src="https://cdn.bootcss.com/jquery/2.1.2/jquery.js"></script>
</head>

<body>

<p th:utext="${openid}"></p>
<p th:utext="${token}"></p>
<p th:utext="${guanzhu}"></p>

</body>
</html>


三、获取OpenID和关注信息

在做好上一节的基本工作后,我们就可以获取一个用户在某个公众号的OpenID了。之前说过,OpenID就是一个微信账号在某个微信公众号的唯一标识码,它是不会重复的,因此可以用在程序逻辑上,作为身份验证的工具。此外,获取AccessToken后,将OpenID、AccessToken一起发送到微信接口,就可以取得该用户的关注信息(即其是否关注了本公众号)。

有了这些理论基础,我就不再多BB了,直接上代码,一会来解释某些细节:

@RequestMapping("/wechat")
public ModelAndView wechat(ModelAndView mv, @RequestParam(value="code",defaultValue = "",required = false) String pCode, @RequestParam(value="from",defaultValue = "",required = false) String from, @RequestParam(value="isappinstalled",defaultValue = "",required = false) String isappinstalled, @RequestParam(value="tdsourcetag",defaultValue = "",required = false) String tdsourcetag,HttpSession session) {

        //微信相关开始
        StringBuilder sbUrl=new StringBuilder();
        if (!(tdsourcetag+"dsa").equals("dsa")) //tdsourcetag为360浏览器常见的自带参数,此处判断其若不为空
            sbUrl.append("?tdsourcetag="+tdsourcetag);
        else { //from、isappinstalled都是微信端常见的自添加参数,这是微信为了统计网页来源添加的,但会影响程序图标的使用
            if (!(from + "dsa").equals("dsa") && (isappinstalled + "dsa").equals("dsa")) //from不为空,isappinstalled为空
                sbUrl.append("?from=" + from);
            else if (!(from + "dsa").equals("dsa") && !(isappinstalled + "dsa").equals("dsa")) //都不为空
                sbUrl.append("?from=" + from + "&isappinstalled=" + isappinstalled);
            else if ((from + "dsa").equals("dsa") && !(isappinstalled + "dsa").equals("dsa"))
                sbUrl.append("?isappinstalled=" + isappinstalled);
        }
        final String strUrl="http://www.xxx.com/jiaocheng/wechat/"+sbUrl.toString();  //请把引号里的内容替换成你服务器上本页面的网址,注意路径后面带斜杠

        String OpenID="";
        try { //OpenID不为空
            OpenID = session.getAttribute("openid").toString();
        }
        catch (Exception e)
        { //OpenID为空
            if((pCode+"dsa").equals("dsa")) {//code为空
                return new ModelAndView("redirect:https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + strAppid + "&redirect_uri=" + strUrl + "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect");
            }
            else
            { //code不为空
                String sBaseInfo = Wechat.getBaseInfo(pCode, strAppid, strAppSecret);
                JSONObject jsonResult = JSON.parseObject(sBaseInfo);
                OpenID = jsonResult.getString("openid");
                session.setAttribute("openid",OpenID);
                return new ModelAndView("redirect:/wechat/"); //注意路径后面带斜杠
            }
        }
        String sAccessToken=getToken2Ticket("cgi-token"); //如果这个方法放在其他类里面,有可能因为自动装配不能使用
        session.setAttribute("token",sAccessToken);
        String guanzhu=Wechat.getSubscribe(sAccessToken,OpenID); //取关注信息

        mv.addObject("openid", OpenID);
        mv.addObject("token", sAccessToken);
        mv.addObject("guanzhu", guanzhu);
        //微信相关结束

        mv.setViewName("wechat");
        return mv;
}

如果你关注了该公众号,guanzhu这个变量的值就是1,否则就是0。这里分别打印了用户的openid、用户获取的accessToken、还有用户关注信息。使用二维码生成工具,把该路由地址生成二维码,用微信扫描后,如果一切正常,会出现类似如下的内容:

oWaL9jek7hDlGSei-PlU75jBT1mE

18_Jzbf1VC_L6Jx0F84ERWEknaryTp3cg_loap8btVO-rTq0R45cEKSf4Lj8NzTchS4y_L9E6LsAygaLETEkon5OgRYl9EJP0GyZPBApJ_q2-5A1-mh4JU-c_M1gAxOFfLnEM6mcz4-NLfTyySZCRcAAAEHW

1

四、自定义微信分享图标

如果我们点击微信右上角的分享图标会发现,分享出去的图标,是很丑的别针图标,这是微信通用的链接图标。我们如何更改呢?

首先,我们在的<head>标签内引用微信官方的JS库:

<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

然后,我们在刚才的引用代码下面添加如下代码:

<script th:inline="javascript">
    var shareImgUrl = "http://替换成你服务器上的绝对图片地址.png";  //注意必须是绝对路径
    var shareLink = "http://www.xxx.com/jiaocheng/wechat/";   //同样,必须是绝对路径,替换成你服务器上的分享出去的地址,注意网址后面带斜杠
    var shareDes = 'w3xue教程,让人人享有平等学习机会。'; //分享给朋友或朋友圈时的文字简介
    var shareTitle = document.title;  //分享title
    var appid = ''; //apiID,可留空
    wx.config({
        debug: false,
        appId:/*[[${appid}]]*/ null,
        timestamp: 1553071742,  /*生成签名的时间戳 */
        nonceStr: 'W3FlX1tOkHGP9zga',  /*生成签名的随机串 */
        signature: /*[[${qianming}]]*/ null,
        jsApiList: [ /**/
            'checkJsApi',
            'onMenuShareTimeline',
            'onMenuShareAppMessage',
            'onMenuShareQQ',
            'onMenuShareWeibo',
            'onMenuShareQZone'
        ]
    });

    wx.ready(function(){
        wx.onMenuShareTimeline({
            title:shareTitle, // 分享标题
            link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
            imgUrl: shareImgUrl, // 分享图标
            success: function () {
                // 用户确认分享后执行的回调函数
            },
            cancel: function () {
                // 用户取消分享后执行的回调函数
            }
        });

        wx.onMenuShareAppMessage({
            title:shareTitle, // 分享标题
            desc: shareDes, // 分享描述
            link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
            imgUrl:shareImgUrl, // 分享图标
            type: '', // 分享类型,music、video或link,不填默认为link
            dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
            success: function () {
                // 用户确认分享后执行的回调函数
            },
            cancel: function () {
                // 用户取消分享后执行的回调函数
            }
        });
    });

    wx.error(function(res){
        alert('分享出错!'); //错误提示
    });

</script>

wx.onMenuShareTimeline方法是分享到朋友圈的自定义方法,wx.onMenuShareAppMessage是分享给微信朋友的自定义方法。

这里需要注意,这段JS代码用了 th:inline 标签,里面出现了2个变量,一个是appid,另一个是qianming。appid只需要将我们的开发appid输入即可。但qianming变量,则是需要一套加密方法进行加密的。需要首先取得ticket信息,在之前我们已经在MainController类中添加了getToken2Ticket方法,这里直接取就可以了。取得ticket后,要对信息进行排列,然后使用Encrypt类里面的方法进行SHA1加密,具体请见如下代码:

//微信分享图标开始
String sTicket =getToken2Ticket("ticketKey");   //取得ticket
String sTimestamp = "1553071742";  //时间戳,跟前端页面保持一致
String sNonceStr = "W3FlX1tOkHGP9zga";  //生成签名的随机串,跟前端页面保持一致
String string1 = "jsapi_ticket=" + sTicket + "&noncestr=" + sNonceStr + "&timestamp=" + sTimestamp + "&url=" + strUrl; //排列字符串
mv.addObject("appid", strAppid);
String sQianming=Encrypt.makeSHA1(string1).toUpperCase(); // 进行SHA1加密
mv.addObject("qianming", sQianming); //绑定签名
//微信分享图标结束

把这段代码加在wechat路由方法底下。这样,我们打包上传到服务器,然后再分享给朋友,或者分享到朋友圈,就会出现你的自定义图标了。会出现如下图的效果:

1.png


注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue  发布时间:2020/3/2 16:40:35
 友情链接: NPS  问卷模板