目录
从零接入微信公众号
一、微信测试号的申请与关注
1.申请
2.访问域名配置
3.关注
二、测试号快速生成底部导航栏
1.获取 access_token
2.自定义菜单
三、微信公众号网页授权
1.网页授权原理
2.代码实现
1)NetUtil.java
2)Oauth2Token.java
3)WxUserDO.java
4)WxController
3.测试
4.整合
四、公众号视频资源分享
提前准备:
1.一台云服务器(配置好web项目环境)
2.一个域名(https 或者 http)
关于服务器的,如果你是小白可以看我的其他博客:
CentOS 服务器配置 jdk +Tomcat + mysql
基于腾讯云的域名绑定和 tomcat 部署
腾讯云申请免费 ssl 证书+tomcat配置https
本文是直接上代码,有些需要修改和解释都会说明。
刚刚开始做微信公众号的时候,我们建议选择微信测试号就好,等熟悉了之后,微信公众号的配置什么的,跟测试号是一样的。
接下来就交大家怎么来申请测试号。
首先进入微信公众号的开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
找到 JS 接口安全域名修改 填写上自己的域名。然后考虑我们会在测好中里面进行网页的跳转操作,所以我们需要在网页账号功能这边填上授权的域名,如下图。
登录微信测试号页面,找到测试号二维码,然后用自己的微信号扫码,使自己的微信账号位于用户列表中。
https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index
打开上面的链接,按下图选择,然后填上 appid 和 secret ,点击检查问题,就能获取到 access_token 了。
按下图的提示选,然后 access_token 已经在上面查询到了,复制下来就好,body 则是填入对应的 json 串,下面已经提供了 demo ,直接复制就好。
{
"button": [{
"name": "我的",
"sub_button": [{
"type": "scancode_waitmsg",
"name": "扫码藏书",
"key": "rselfmenu_0_0",
"sub_button": []
},
{
"type": "view",
"name": "我的书房",
"url": "http://127.0.0.1/index.php"
}
]
},
{
"name": "关于",
"sub_button": [{
"type": "view",
"name": "关于我们",
"url": "http://127.0.0.1/index.php"
}]
}
]
}
点击 检查问题,往下拉查看返回结果。下图为成功的返回。
然后进入刚刚关注的微信测试号,就可以看到底部已经出现了对应的导航按钮了。
如果用户在微信客户端上访问第三方的网页,公众号可以通过微信网页授权机制,来获取用户信息,进而实现业务逻辑。
1)引导用户进入授权页面同意授权,获取 code
2)通过 code 换取网页授权 access_token
3)如果需要,开发者可以刷新网页授权 access_token ,避免过期
4)通过网页授权 access_token 和 openid 获取用户基本信息
NetUtil.java:实现 http 发送服务
Oauth2Token:存放 access_token 等信息的实体类
WxUserDO:存放用户信息的实体类
WxController:具体实现的控制层
下面的源码中都附带了导入的包名。
package com.controller.wechat;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NetUtil {
public static final Logger log = LoggerFactory.getLogger(NetUtil.class);
public static CloseableHttpClient httpClient = HttpClientBuilder.create().build();
/**
* get 请求获取String类型数据
* @param url
* @return
*/
public static String get(String url) {
log.info("get 请求开始 ...");
StringBuffer sb = new StringBuffer();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStreamReader reader = new InputStreamReader(entity.getContent(), "utf-8");
char [] charbuffer;
while(0 < reader.read(charbuffer=new char[10])) {
sb.append(charbuffer);
}
}catch(IOException e) {
e.printStackTrace();
}finally {
httpGet.releaseConnection();
}
log.info(sb.toString());
log.info("get 请求开始 ...");
return sb.toString();
}
/**
* post 请求获取数据
* @param url
* @param data
* @return
*/
@SuppressWarnings("unchecked")
public static String post(String url, Map data) {
log.info("post 请求开始 ...");
StringBuffer sb = new StringBuffer();
HttpPost httpPost = new HttpPost(url);
ArrayList valuePairs = new ArrayList();
if(null != data) {
for(String key : data.keySet()) {
valuePairs.addAll((Collection extends NameValuePair>) new BasicNameValuePair(key, data.get(key)));
}
}
try {
HttpResponse response = httpClient.execute(httpPost);
HttpEntity httpEntity = response.getEntity();
BufferedInputStream bis = new BufferedInputStream(httpEntity.getContent());
byte [] buffer;
while(0 < bis.read(buffer=new byte[128])) {
sb.append(new String(buffer,"utf-8"));
}
}catch(UnsupportedEncodingException e) {
//数据格式有误
e.printStackTrace();
}catch (IOException e) {
//请求出错
e.printStackTrace();
}finally {
httpPost.releaseConnection();
}
log.info(sb.toString());
log.info("post 请求开始 ...");
return sb.toString();
}
}
package com.controller.wechat;
public class Oauth2Token {
private String accessToken; //网页授权接口调用凭证
private int expiresIn; //凭证有效时长
private String refreshToken; //用于刷新凭证
private String openId; //用户标识
private String scope; //用户授权作用域
// get 和 set 方法
@Override
public String toString() {
return "Oauth2Token [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", refreshToken=" + refreshToken
+ ", openId=" + openId + ", scope=" + scope + "]";
}
}
package com.controller.wechat;
import java.io.Serializable;
import java.util.List;
public class WxUserDO implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id; //主键 id
private String openId; //用户主键
private String nickname; //用户昵称
private Integer sex; //性别(1:男,2:女,0:未知)
private String country; //国家
private String province; //省份
private String city; //城市
private String headimgurl; //用户头像链接
private String unionid; //unionid
private List privilegeList; //用户特权信息
//get 和 set 方法
@Override
public String toString() {
return "WxUserDO [id=" + id + ", openId=" + openId + ", nickname=" + nickname + ", sex=" + sex + ", country="
+ country + ", province=" + province + ", city=" + city + ", headimgurl=" + headimgurl + ", unionid="
+ unionid + ", privilegeList=" + privilegeList + "]";
}
}
package com.controller.wechat;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
@RestController
@RequestMapping("/wechat")
public class WxController {
private static Logger log = LoggerFactory.getLogger(WxController.class);
private static final String APP_ID = "自己的appid";
private static final String APP_SECRET = "自己的secret";
//回调地址,要跟下面的地址能调通(/wxLogin)
private static final String BACK_URL = "https://自己的域名/wechat/wechat/wxLogin";
//登录成功回调地址(返回你指定的地址)
private static final String URL_LOGIN = "https://自己的域名/wechat/hello";
/**
* 向指定 URL 发送 GET 方法的请求
* URL 所代表远程资源的响应结果
* @param request
* @param response
*
* 用户同意授权,获取 code
* @throws IOException
*/
@RequestMapping("/wxLoginInit")
public void loginInt(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("微信授权登录...");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
+ APP_ID
+ "&redirect_uri="
+ URLEncoder.encode(BACK_URL, "UTF-8")
+ "&response_type=code"
+ "&scope=snsapi_userinfo"
+ "&state=STATE#wechat_redirect" ;
//重定向到重定向地址
response.sendRedirect(url);
}
@RequestMapping("/wxLogin")
public void wxLogin(HttpServletRequest request, HttpServletResponse response) {
log.info("用户同意授权,重定向到重定向地址,获取 code");
String code = request.getParameter("code");
log.info("code:" + code);
String appId = APP_ID;
String appSecret = APP_SECRET;
try {
// 获取网页授权 access_token openid 等
Oauth2Token oauth2Token = getOauth2Token(appId, appSecret, code);
// 网页授权接口访问凭证
String accessToken = oauth2Token.getAccessToken();
// 用户标识
String openId = oauth2Token.getOpenId();
// 获取用户信息
WxUserDO wxUserInfo = getWxUserInfo(accessToken, openId);
// 具体业务 start
// 具体有什么业务需求自己实现,我这里只把 Oauth2Token 和 WxUserDO 的信息输出
// ...
log.info(oauth2Token.toString());
log.info(wxUserInfo.toString());
// ...
// 具体业务 end
// 授权登录成功后,跳转到指定的链接
response.sendRedirect(URL_LOGIN);
}catch(IOException e) {
e.printStackTrace();
log.error("网络异常");
}
}
/**
* 通过网页授权获取用户信息
*
* @param accessToken 网页授权接口调用凭证
* @param openId 用户标识
* @return
*/
private WxUserDO getWxUserInfo(String accessToken, String openId) {
log.info("获取用户信息 开始...");
log.info("网页授权接口访问凭证AccessToken:" + accessToken);
log.info("用户标识openId:" + openId);
WxUserDO wxUserInfo = null;
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
requestUrl = requestUrl.replace("OPENID", openId);
log.info("拼接请求地址:" + requestUrl);
// 通过网页授权获取用户信息
com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(NetUtil.get(requestUrl));
if (null != jsonObject) {
try {
wxUserInfo = new WxUserDO();
wxUserInfo.setOpenId(jsonObject.getString("openid"));
wxUserInfo.setNickname(jsonObject.getString("nickname"));
wxUserInfo.setSex(jsonObject.getInteger("sex"));
wxUserInfo.setCountry(jsonObject.getString("country"));
wxUserInfo.setProvince(jsonObject.getString("province"));
wxUserInfo.setCity(jsonObject.getString("city"));
wxUserInfo.setHeadimgurl(jsonObject.getString("headimgurl"));
//用户授权信息
List list = JSON.parseArray(jsonObject.getString("privilege"), String.class);
wxUserInfo.setPrivilegeList(list);
//与开放平台公用的唯一标识,只有在用户讲公众号绑定到微信开放平台账号后,才会出现该字段
wxUserInfo.setUnionid(jsonObject.getString("unionid"));
}catch (Exception e) {
wxUserInfo = null;
int errorCode = jsonObject.getInteger("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("获取用户信息失败 errcode:{} errmsg:{}",errorCode,errorMsg);
}
}
log.info("获取用户信息 结束...");
return wxUserInfo;
}
/**
* 获取网页授权凭证
* @param appId 公众账号的唯一标识
* @param appSecret 公众账号的密钥
* @param code
* @return
*/
private Oauth2Token getOauth2Token(String appId, String appSecret, String code) {
log.info("获取网页授权凭证 开始...");
Oauth2Token auth = null;
//拼接请求地址
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
requestUrl = requestUrl.replace("APPID", appId);
requestUrl = requestUrl.replace("SECRET", appSecret);
requestUrl = requestUrl.replace("CODE", code);
log.info("拼接后的请求地址为:" + requestUrl);
//获取网页授权凭证
com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject (NetUtil.get(requestUrl));
if(null != jsonObject) {
try {
auth = new Oauth2Token();
auth.setAccessToken(jsonObject.getString("access_token"));
auth.setExpiresIn(jsonObject.getInteger("expires_in"));
auth.setRefreshToken("refresh_token");
auth.setOpenId("openid");
auth.setScope("scope");
}catch(Exception e) {
auth = null;
int errorCode = jsonObject.getInteger("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("获取网页授权凭证失败 errcode:{} errmsg:{}",errorCode,errorMsg);
}
}
log.info("获取网页授权凭证 结束...");
return auth;
}
}
该功能的测试只能在微信上。例如:https://自己的域名/wechat/wxLoginInit。
把访问的链接发送到微信上。
在微信客户端上点击当前链接,跳转网页,就能出现如下提示是否收取登录的接口,点击同意即可。
注意:网页微信授权一般只需要授权一次,后面都会直接登入的。
到这里我们就学会了,在微信上实现网页授权登录。然后如何在公众号上实现呢???很简单,就是结合前面的 2.2 自定义菜单 把授权链接设置进去就可以了。
重要的事情说三遍 ↓↓↓
重要的事情说三遍 ↓↓↓
重要的事情说三遍 ↓↓↓
这只是一个简单的 demo ,具体要在那里实现授权登录,授权后要跳转到哪里或者要实现什么业务,请根据自己的实际情况编写!!!
需要以上公众号视频的,请关注博主的订阅号,在后台回复“ 公众号 ”即可获取百度元分享链接。