从零接入微信公众号(Java实现 附源码)

目录

                                      从零接入微信公众号

一、微信测试号的申请与关注

1.申请

2.访问域名配置

3.关注

二、测试号快速生成底部导航栏

1.获取 access_token

2.自定义菜单

三、微信公众号网页授权

1.网页授权原理

2.代码实现

1)NetUtil.java

2)Oauth2Token.java

3)WxUserDO.java

4)WxController

3.测试

4.整合

四、公众号视频资源分享


                                      从零接入微信公众号


从零接入微信公众号(Java实现 附源码)_第1张图片


提前准备:

1.一台云服务器(配置好web项目环境)

2.一个域名(https 或者 http)

关于服务器的,如果你是小白可以看我的其他博客:

CentOS 服务器配置 jdk +Tomcat + mysql

基于腾讯云的域名绑定和 tomcat 部署

腾讯云申请免费 ssl 证书+tomcat配置https

本文是直接上代码,有些需要修改和解释都会说明。


一、微信测试号的申请与关注

1.申请

刚刚开始做微信公众号的时候,我们建议选择微信测试号就好,等熟悉了之后,微信公众号的配置什么的,跟测试号是一样的。

接下来就交大家怎么来申请测试号。

首先进入微信公众号的开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432

从零接入微信公众号(Java实现 附源码)_第2张图片

从零接入微信公众号(Java实现 附源码)_第3张图片

2.访问域名配置

找到  JS 接口安全域名修改 填写上自己的域名。然后考虑我们会在测好中里面进行网页的跳转操作,所以我们需要在网页账号功能这边填上授权的域名,如下图。

从零接入微信公众号(Java实现 附源码)_第4张图片

 

 

从零接入微信公众号(Java实现 附源码)_第5张图片

从零接入微信公众号(Java实现 附源码)_第6张图片

3.关注

登录微信测试号页面,找到测试号二维码,然后用自己的微信号扫码,使自己的微信账号位于用户列表中。

从零接入微信公众号(Java实现 附源码)_第7张图片

二、测试号快速生成底部导航栏

https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index

1.获取 access_token

打开上面的链接,按下图选择,然后填上 appid 和 secret ,点击检查问题,就能获取到 access_token 了。

从零接入微信公众号(Java实现 附源码)_第8张图片

从零接入微信公众号(Java实现 附源码)_第9张图片 

2.自定义菜单

按下图的提示选,然后 access_token 已经在上面查询到了,复制下来就好,body 则是填入对应的 json 串,下面已经提供了 demo ,直接复制就好。

从零接入微信公众号(Java实现 附源码)_第10张图片

{
	"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"
			}]
		}
	]
}

点击 检查问题,往下拉查看返回结果。下图为成功的返回。

从零接入微信公众号(Java实现 附源码)_第11张图片

然后进入刚刚关注的微信测试号,就可以看到底部已经出现了对应的导航按钮了。

从零接入微信公众号(Java实现 附源码)_第12张图片

三、微信公众号网页授权

如果用户在微信客户端上访问第三方的网页,公众号可以通过微信网页授权机制,来获取用户信息,进而实现业务逻辑。

1.网页授权原理

1)引导用户进入授权页面同意授权,获取 code

2)通过 code 换取网页授权 access_token 

3)如果需要,开发者可以刷新网页授权 access_token ,避免过期

4)通过网页授权 access_token 和 openid 获取用户基本信息

2.代码实现

NetUtil.java:实现 http 发送服务

Oauth2Token:存放 access_token 等信息的实体类

WxUserDO:存放用户信息的实体类

WxController:具体实现的控制层

下面的源码中都附带了导入的包名。

1)NetUtil.java

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

2)Oauth2Token.java

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 + "]";
	}
}

3)WxUserDO.java

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 + "]";
	}

}

4)WxController

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

3.测试

该功能的测试只能在微信上。例如:https://自己的域名/wechat/wxLoginInit。

从零接入微信公众号(Java实现 附源码)_第13张图片

把访问的链接发送到微信上。

在微信客户端上点击当前链接,跳转网页,就能出现如下提示是否收取登录的接口,点击同意即可。

从零接入微信公众号(Java实现 附源码)_第14张图片

注意:网页微信授权一般只需要授权一次,后面都会直接登入的。

4.整合

到这里我们就学会了,在微信上实现网页授权登录。然后如何在公众号上实现呢???很简单,就是结合前面的 2.2 自定义菜单 把授权链接设置进去就可以了。

重要的事情说三遍 ↓↓↓

重要的事情说三遍 ↓↓↓

重要的事情说三遍 ↓↓↓

这只是一个简单的 demo ,具体要在那里实现授权登录,授权后要跳转到哪里或者要实现什么业务,请根据自己的实际情况编写!!!

四、公众号视频资源分享

从零接入微信公众号(Java实现 附源码)_第15张图片

需要以上公众号视频的,请关注博主的订阅号,在后台回复“ 公众号 ”即可获取百度元分享链接。

小东 wechat

你可能感兴趣的:(微信公众号)