Boot 微信公众号开发
注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue 发布时间:2020/9/22 16:42:11
微信公众号的开发是很常见的开发任务。如果大家用过其他语言开发,就可以很自然的转到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,我们的程序拿着它们,就可以发送给微信公众号平台,查询一个用户的是否关注等信息了。
另外,我们本章节还将学习如何给页面加上图标,就是用户在分享本页面后,在朋友圈或者聊天记录中显示的那个图标:

在上古时代,微信会获取一个页面中的第一个图片作为图标,现在不行了,需要自定义了。其基本的原理是,在页面引用微信官方的一个JS,然后自定义相关的图标和地址,并且最重要的是,要生成一个签名,这样才能自定义成功。
了解完这些基本原理后,就可以思考开发工作了。
二、准备工作
在正式开发之前,我们要确认公众号具有相关权限,并有正确的设置,然后新建相关的工具类,以便引入使用。
1、一个拥有开发权限的微信公众号,以及其开发用的 AppId 和 AppSecret。当然,还需要进行一些设置:
a.在“公众号设置->功能设置”设置“网页授权域名”和“JS接口安全域名”。把你的程序所在域名(二级域名就用二级域名)加入这2个名单备用,设置这2个可能需要管理员扫码。
b.设置IP白名单,在“开发配置->基本配置->IP白名单”把你的服务器IP加进你的微信公众号IP白名单。
2、在utils文件夹新建2个类:HttpClientUtil类和Encrypt类,HttpClientUtil类用来处理相关与 http请求相关的业务。Encrypt类用来提供几个加密相关的函数。代码提供了下载链接,但具体就不贴出来了(如有红字,用Alt+Enter引入包即可):
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 + "×tamp=" + sTimestamp + "&url=" + strUrl; //排列字符串
mv.addObject("appid", strAppid);
String sQianming=Encrypt.makeSHA1(string1).toUpperCase(); // 进行SHA1加密
mv.addObject("qianming", sQianming); //绑定签名
//微信分享图标结束把这段代码加在wechat路由方法底下。这样,我们打包上传到服务器,然后再分享给朋友,或者分享到朋友圈,就会出现你的自定义图标了。会出现如下图的效果:

注意:本页面内容为W3xue原创,未经授权禁止转载,违者必究!
来源:W3xue 发布时间:2020/9/22 16:42:11


优化或报错有奖