目录

微信公众号开发

1、微信公众号简单介绍

2、微信公众号申请

3、开发模式启用以及接口配置

4、消息以及消息处理的工具

5、各种消息的接收与响应

6、图文消息

7、自定义菜单的创建以及菜单的相应

8、获取用户的网页授权

9、码云开源源码:


微信公众号开发

1、微信公众号简单介绍

微信公众号是开发者或商家在微信公众平台上申请的应用账号,该帐号与QQ账号互通,通过公众号,商家可在微信平台上实现和特定群体的文字、图片、语音、视频的全方位沟通、互动 。形成了一种主流的线上线下微信互动营销方式。

2、微信公众号申请

首先搜索进入微信公众平台,网址为:https://mp.weixin.qq.com/。

点击立即注册按钮,开始注册我们的微信公众号,可以申请订阅号,服务号,小程序,还有企业微信。

选择好要注册的微信平台之后,进行相关的信息填写就可以创建成功了。

我们作为开发者,在微信开发的时候有些功能是需要服务号等等功能的,而我们个人申请的微信公众号是不支持我们进行服务号的相关操作的,因此我们在这需要微信的测试号进行我们的一些相关功能的测试操作的。

微信测试公众号申请网址:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

这就是我们的测试公众号,我们进行相关的微信公众号测试,都要在这个基础上进行测试的。

3、开发模式启用以及接口配置

正式的微信公众号是需要启动开发者模式之后,我们开发者才能正式开发微信公众号呢,但在我们的测试微信公众号中,只需要进行相关的接口配置就可以了。

这里需要填写URL和Token两个值。URL指的是能够接收处理微信服务器发送GET/POST请求的地址,并且是已经存在的,现在就能够在浏览器访问到的地址,这就要求我们先把公众帐号后台处理程序开发好(至少应该完成了对GET请求的处理)并部署在公网服务器上。Token后面会详细说明。

以下是我的链接微信服务器的代码:

这样之后,我们的程序打包,发布到服务器上并运行,在微信公众号上填写url还有token进行链接测试即可。

4、消息以及消息处理的工具

最终我们写完的所有消息的封装结构为:

下面进行的操作我们首先要在自己的spring boot的配置文件——pom.xml文件中添加相关的依赖:

<!-- xstream 采用开源框架xstream来实现Java类到xml的转换-->

<dependency>

<groupId>com.thoughtworks.xstream</groupId>

<artifactId>xstream</artifactId>

<version>1.3.1</version>

</dependency>

<!--借助于开源框架dom4j去解析xml-->

<dependency>

<groupId>dom4j</groupId>

<artifactId>dom4j</artifactId>

<version>1.6.1</version><!--$NO-MVN-MAN-VER$-->

</dependency>

如何解析请求的消息:微信服务器会将用户的请求通过processRequest方法发送给我们,如下图所示:

doPost方法有两个参数,request中封装了请求相关的所有内容,可以从request中取出微信服务器发来的消息;而通过response我们可以对接收到的消息进行响应,即发送消息。

那么如何解析请求消息的问题也就转化为如何从request中得到微信服务器发送给我们的xml格式的消息了。这里我们借助于开源框架dom4j去解析xml(这里使用的是dom4j-1.6.1.jar),然后将解析得到的结果存入HashMap。

那么如何返回给微信服务器消息呢:这里我们将采用开源框架xstream来实现Java类到xml的转换。

下面是我的消息处理工具类:


/*** 消息工具类** @author yulin* @Creat date 2018-7-17 14:39*/
public class MessageUtil {/*** 返回消息类型:文本*/public static final String RESP_MESSAGE_TYPE_TEXT = "text";/*** 返回消息类型:音乐*/public static final String RESP_MESSAGE_TYPE_MUSIC = "music";/*** 返回消息类型:图文*/public static final String RESP_MESSAGE_TYPE_NEWS = "news";/*** 请求消息类型:文本*/public static final String REQ_MESSAGE_TYPE_TEXT = "text";/*** 请求消息类型:图片*/public static final String REQ_MESSAGE_TYPE_IMAGE = "image";/*** 请求消息类型:链接*/public static final String REQ_MESSAGE_TYPE_LINK = "link";/*** 请求消息类型:地理位置*/public static final String REQ_MESSAGE_TYPE_LOCATION = "location";/*** 请求消息类型:音频*/public static final String REQ_MESSAGE_TYPE_VOICE = "voice";/*** 请求消息类型:推送*/public static final String REQ_MESSAGE_TYPE_EVENT = "event";/*** 事件类型:subscribe(订阅)*/public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";/*** 事件类型:unsubscribe(取消订阅)*/public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";/*** 事件类型:CLICK(自定义菜单点击事件)*/public static final String EVENT_TYPE_CLICK = "CLICK";/*** 解析微信发来的请求(XML)** @param request* @return* @throws Exception*/@SuppressWarnings("unchecked")public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {// 将解析结果存储在HashMap中Map<String, String> map = new HashMap<String, String>();// 从request中取得输入流InputStream inputStream = request.getInputStream();// 读取输入流SAXReader reader = new SAXReader();Document document = reader.read(inputStream);// 得到xml根元素Element root = document.getRootElement();// 得到根元素的所有子节点List<Element> elementList = root.elements();// 遍历所有子节点for (Element e : elementList)map.put(e.getName(), e.getText());// 释放资源inputStream.close();inputStream = null;return map;}/*** 文本消息对象转换成xml** @param textMessage 文本消息对象* @return xml*/public static String textMessageToXml(TextMessage textMessage) {xstream.alias("xml", textMessage.getClass());return xstream.toXML(textMessage);}/*** 音乐消息对象转换成xml** @param musicMessage 音乐消息对象* @return xml*/public static String musicMessageToXml(MusicMessage musicMessage) {xstream.alias("xml", musicMessage.getClass());return xstream.toXML(musicMessage);}/*** 图文消息对象转换成xml** @param newsMessage 图文消息对象* @return xml*/public static String newsMessageToXml(NewsMessage newsMessage) {xstream.alias("xml", newsMessage.getClass());xstream.alias("item", new Article().getClass());return xstream.toXML(newsMessage);}/*** 扩展xstream,使其支持CDATA块**/private static XStream xstream = new XStream(new XppDriver() {public HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 对所有xml节点的转换都增加CDATA标记boolean cdata = true;@SuppressWarnings("unchecked")public void startNode(String name, Class clazz) {super.startNode(name, clazz);}protected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}});public static String initText(String toUserName, String fromUserName, String content){TextMessage text = new TextMessage();text.setFromUserName(toUserName);text.setToUserName(fromUserName);text.setMsgType(REQ_MESSAGE_TYPE_TEXT);text.setCreateTime(new Date().getTime());text.setContent(content);return textMessageToXml(text);}}

5、各种消息的接收与响应

在前面第四点中已经说明到接收到微信服务器发给我们的消息的,这里面说一下关于微信公众平台的核心处理类:

package com.b505.weixin.service;import com.b505.weixin.message.req.TextMessage;
import com.b505.weixin.util.MessageUtil;import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;/*** 描述:核心服务类* authro:yulin* Create date 2020-2-7 20:21*/
public class CoreService {/*** 处理微信发来的请求* @param request* @return*/public static String processRequest(HttpServletRequest request) {String respMessage = null;try {// 默认返回的文本消息内容String respContent = "请求处理异常,请稍候尝试!";// xml请求解析Map<String, String> requestMap = MessageUtil.parseXml(request);// 发送方帐号(open_id)String fromUserName = requestMap.get("FromUserName");// 公众帐号String toUserName = requestMap.get("ToUserName");// 消息类型String msgType = requestMap.get("MsgType");// 回复文本消息TextMessage textMessage = new TextMessage();textMessage.setToUserName(fromUserName);textMessage.setFromUserName(toUserName);textMessage.setCreateTime(new Date().getTime());textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);textMessage.setFuncFlag(0);// 文本消息if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {//发送图文消息respContent = "您发送的是文本消息!";}// 图片消息else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {respContent = "您发送的是图片消息!";}// 地理位置消息else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {respContent = "您发送的是地理位置消息!";}// 链接消息else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {respContent = "您发送的是链接消息!";}// 音频消息else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {respContent = "您发送的是音频消息!";}// 事件推送else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// 事件类型String eventType = requestMap.get("Event");// 订阅if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {respContent = "谢谢您的关注!";}// 取消订阅else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {// TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息}// 自定义菜单点击事件else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {// TODO 自定义菜单权没有开放,暂不处理该类消息}}textMessage.setContent(respContent);respMessage = MessageUtil.textMessageToXml(textMessage);} catch (Exception e) {e.printStackTrace();}return respMessage;}
}

6、图文消息

图文消息相关总结:

1)一定要给图文消息的Url属性赋值。不管是单图文,还是多图文,或者是不含图片的图文,都有可能会被用户点击。如果Url为空,用户点击后将会打开一个空白页面,这给用户的体验是非常差的;

2)只有单图文的描述才会显示,多图文的描述不会被显示;

3)图文消息的标题、描述中可以使用QQ表情和符号表情。合理地运用表情符号,会使得消息更加生动;

4)图文消息的标题、描述中可以使用换行符。合理地使用换行符,会使得内容结构更加清晰;

5)图文消息的标题、描述中不支持超文本链接(html的<a>标签)。

6)图文消息的链接、图片链接可以使用外部域名下的资源。

7)使用指定大小的图片。第一条图文的图片大小建议为640*320,其他图文的图片大小建议为80*80。如果使用的图片太大,加载慢,而且耗流量;如果使用的图片太小,显示后会被拉伸,容易失真。

8)每条图文消息的图文建议控制在1-4条。这样在绝大多数终端上一屏能够显示完,用户扫一眼就能大概了解消息的主要内容,这样最有可能促使用户去点击并阅读。

借鉴https://blog.csdn.net/lyq8479/article/details/9393195

7、自定义菜单的创建以及菜单的相应

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

公众平台的API调用所需的access_token的使用及生成方式说明:

1、建议公众号开发者使用中控服务器统一获取和刷新access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;

2、目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;

3、access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。

公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。**调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。**小程序无需配置IP白名单。

下面是如何获取access_token的方法:

package com.b505.weixin.util;import com.b505.weixin.pojo.AccessToken;
import com.b505.weixin.pojo.Menu;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;/**** <p>b505信息科学研究所</p>* @Description 获取jsapi的凭证票(网上这代码可真坑人)* @author yulin* @Creat date 2018-11-30 13:23*/
public class JsapiTicketUtil {private static Logger log = LoggerFactory.getLogger(JsapiTicketUtil.class);// 获取access_token的接口地址(GET) 限2000(次/天)public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";// 菜单创建(POST) 限100(次/天)public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";/*** 创建菜单** @param menu        菜单实例* @param accessToken 有效的access_token* @return 0表示成功,其他值表示失败*/public static int createMenu(Menu menu, String accessToken) {int result = 0;// 拼装创建菜单的urlString url = menu_create_url.replace("ACCESS_TOKEN", accessToken);// 将菜单对象转换成json字符串String jsonMenu = JSONObject.fromObject(menu).toString();// 调用接口创建菜单JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);if (null != jsonObject) {if (0 != jsonObject.getInt("errcode")) {result = jsonObject.getInt("errcode");log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return result;}/**** 描述:创建按钮专用!获取accessToken* auhtor:yulin* Create date 2019-9-16 12:42* @return*/public static String getAccessToken(){String appid="wx41c9f671d9c6355f";//应用IDString appSecret="bad1b7703b0195a7ba94001cc455d1e7";//(应用密钥)String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+appSecret+"";String backData=JsapiTicketUtil.sendGet(url, "utf-8", 10000);String accessToken = (String) JSONObject.fromObject(backData).get("access_token");return accessToken;}/**** 模拟get请求* @param url* @param charset* @param timeout* @return*/public static String sendGet(String url, String charset, int timeout){String result = "";try{URL u = new URL(url);try{URLConnection conn = u.openConnection();conn.connect();conn.setConnectTimeout(timeout);BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));String line="";while ((line = in.readLine()) != null){result = result + line;}in.close();} catch (IOException e) {return result;}}catch (MalformedURLException e){return result;}return result;}/*** 发起https请求并获取结果** @param requestUrl    请求地址* @param requestMethod 请求方式(GET、POST)* @param outputStr     提交的数据* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)*/public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {JSONObject jsonObject = null;StringBuffer buffer = new StringBuffer();try {// 创建SSLContext对象,并使用我们指定的信任管理器初始化TrustManager[] tm = { new My509TrustManager() };SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");sslContext.init(null, tm, new java.security.SecureRandom());// 从上述SSLContext对象中得到SSLSocketFactory对象SSLSocketFactory ssf = sslContext.getSocketFactory();URL url = new URL(requestUrl);HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();httpUrlConn.setSSLSocketFactory(ssf);httpUrlConn.setDoOutput(true);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);// 设置请求方式(GET/POST)httpUrlConn.setRequestMethod(requestMethod);if ("GET".equalsIgnoreCase(requestMethod))httpUrlConn.connect();// 当有数据需要提交时if (null != outputStr) {OutputStream outputStream = httpUrlConn.getOutputStream();// 注意编码格式,防止中文乱码outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 将返回的输入流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();// 释放资源inputStream.close();inputStream = null;httpUrlConn.disconnect();jsonObject = JSONObject.fromObject(buffer.toString());} catch (ConnectException ce) {log.error("Weixin server connection timed out.");} catch (Exception e) {log.error("https request error:{}", e);}return jsonObject;}/*** 获取access_token** @param appid 凭证* @param appsecret 密钥* @return*/public static AccessToken getAccessToken(String appid, String appsecret) {AccessToken accessToken = null;String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);JSONObject jsonObject = httpRequest(requestUrl, "GET", null);// 如果请求成功if (null != jsonObject) {try {accessToken = new AccessToken();accessToken.setToken(jsonObject.getString("access_token"));accessToken.setExpiresIn(jsonObject.getInt("expires_in"));} catch (JSONException e) {accessToken = null;// 获取token失败log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));}}return accessToken;}}
public static Menu getMenu() {CommonButton btn11 = new CommonButton();btn11.setName("主页");btn11.setType("click");btn11.setKey("11");CommonButton btn21=new CommonButton();btn21.setName("会员通道");btn21.setType("click");btn21.setKey("21");CommonButton btn31=new CommonButton();btn31.setName("工作平台");btn31.setType("view");btn31.setUrl("http://hyxw.work/servicefunctiontwo");/* CommonButton btn32=new CommonButton();btn32.setName("收费测试");btn32.setType("view");btn32.setUrl("https://mp.weixin.qq.com/s?__biz=MzIyNjIyNzk4OQ==&mid=2247483660&idx=1&sn=57914686073b68cf156fe647321b87bf&chksm=e872e376df056a6090791b63ace6e065a8681a7976e5e68289bf37aa5f09cb53507bb074bd6f&token=1850092517&lang=zh_CN#rd");
*/
/*     CommonButton btn32=new CommonButton();btn32.setName("用户咨询");btn32.setType("click");btn32.setKey( "32" );*//*CommonButton btn33=new CommonButton();btn33.setName("联系方式");btn33.setType("click");btn33.setKey( "33" );*/ComplexButton mainBtn2=new ComplexButton();mainBtn2.setName("工作平台");mainBtn2.setSub_button(new CommonButton[]{btn31});Menu menu = new Menu();menu.setButton(new Button[] {btn11, btn21,mainBtn2 });return menu;}

8、获取用户的网页授权

/*** 描述:获取微信用户的网页授权* 接口地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx41c9f671d9c6355f&redirect_uri=http%3a%2f%2f39.105.65.69%2ftext1&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect* author:yulin* Create date 2020-2-21 12:22*/
@RequestMapping("/text1")
public String text1(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {request.setCharacterEncoding("gb2312");response.setCharacterEncoding("gb2312");//用户同意授权String code =request.getParameter("code");if(!"authdeny".equals(code)){WeixinOauth2Token weixinOauth2Token= AdvancedUtil.getOauth2AccessToken("","",code);//网页授权接口访问凭证String accessToken=weixinOauth2Token.getAccessToken();//用户标识String openId=weixinOauth2Token.getOpenId();//获取用户信息SNSUserInfo snsUserInfo=AdvancedUtil.getSNSUserInfo(accessToken,openId);System.out.println("--------------------------------------------用户的城市在"+snsUserInfo.getCity());return "text";}return "error1";}
package com.b505.weixin.util;import com.b505.weixin.pojo.SNSUserInfo;
import com.b505.weixin.pojo.WeixinOauth2Token;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.awt.*;public class AdvancedUtil {public static Logger logger = LoggerFactory.getLogger(AdvancedUtil.class);/*** 获取网页授权凭证* @param appId 公众号的唯一标识* @param appSecret 公众号的密匙* @param code* @return WeixinAouth2Token**/public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code){WeixinOauth2Token wat=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);//获取网页授权的凭证JSONObject jsonObject =JsapiTicketUtil.httpRequest(requestUrl,"GET",null);if(null!=jsonObject){try {wat=new WeixinOauth2Token();wat.setAccessToken(jsonObject.getString("access_token"));wat.setExpiresIn(jsonObject.getInt("expires_in"));wat.setRefreshToken(jsonObject.getString("refresh_token"));wat.setOpenId(jsonObject.getString("openid"));wat.setScope(jsonObject.getString("scope"));} catch (Exception e) {// TODO: handle exceptionwat=null;int errorCode=jsonObject.getInt("errcode");String errorMsg=jsonObject.getString("errmsg");logger.error("获取网络授权失败  errcode:{} errmsg:{}",errorCode,errorMsg);}}return wat;}/*** 通过网页授权获取用户的信息** @param accessToken 网页授权接口调用凭证* @param openId 用户标识**/@SuppressWarnings({"deprecation","unchecked"})public static SNSUserInfo getSNSUserInfo(String accessToken, String openId){SNSUserInfo snsuserInfo=null;//拼接请求地址String requestUrl="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";requestUrl =requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);//通过网页授权获取用户的信息JSONObject jsonObject=JsapiTicketUtil.httpRequest(requestUrl, "GET", null);if(null!=jsonObject){try {snsuserInfo=new SNSUserInfo();//用户标识snsuserInfo.setOpenId(jsonObject.getString("openid"));//昵称snsuserInfo.setNickname(jsonObject.getString("nickname"));//性别(1是男性 2是女性 0是未知)snsuserInfo.setSex(jsonObject.getInt("sex"));//用户所在的国家snsuserInfo.setCountry(jsonObject.getString("country"));//用户所在的省份snsuserInfo.setProvince(jsonObject.getString("province"));//用户所在的城市snsuserInfo.setCity(jsonObject.getString("city"));//用户头像snsuserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));//用户特权信息snsuserInfo.setPrivilegeList(JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class) );System.out.println("-----------------------------------------openid="+snsuserInfo.getOpenId());} catch (Exception e) {// TODO: handle exceptionsnsuserInfo=null;int errorCode=jsonObject.getInt("errcode");String errorMsg=jsonObject.getString("errmsg");logger.error("获取用户信息失败  errcode:{} errmsg:{}",errorCode,errorMsg);}}return snsuserInfo;}}

9、码云开源源码:

https://gitee.com/hyxw/wechat_learning/

Spring Boot+微信公众号开发Demo(源码见文章最低端)相关推荐

  1. java微信公众号开发及源码分享

    java微信公众号开发源码下载 刚做完微信公众号项目,分享一下代码,经验!初写博客,格式写得不好,还请见谅.有不懂的可以留言或加qq 505281494交流下. 一. 第一步进行服务器接口配置,提交信 ...

  2. 微信公众号引流源码?基本上没啥用!

    简介: 微信公众号引流源码?基本上没啥用! 这套源码可以对接微信公众号,给公众号引流也是个不错的选择 源码的bug基本上我都已经修复了,可以正常使用. 附带网盘下载地址: http://www.rry ...

  3. 分享一套微信门户应用管理系统源码 微信公众号平台开发框架源码

    微信门户开发框架源码 微信公众号平台开发框架源码 源码分享,需要源码学习可私信我获取. 微信门户应用管理系统,采用基于 MVC + Bootstrap + Ajax + Enterprise Libr ...

  4. 微信公众号开发 如何发布图文并茂的文章?

    本人刚刚开始学习微信公众号开发,想要实现点击按钮后群发一段图文并茂的文本,可是实现了之后才发现: {"articles":[ {"author":"& ...

  5. 微信公众号 餐饮 前端源码_成都餐饮茶楼微信公众号开发方案

    在很多人的印象中,传统的餐饮茶楼就应该做好自己的生意,和互联网是拉不上关系的,甚至格格不入.但是就用独立思考的餐饮茶楼客户提出了新的思路,能不能用微信公众号来吸引用户,让微信公众号成为用户的入口,而不 ...

  6. JS_微信公众号开发调用扫码支付功能

    需要在公众号里面切入扫码功能 前端代码: <!DOCTYPE html> <html> <head lang="en"><meta cha ...

  7. java spring boot 微信公众号 分享功能

    /*** 方法名:getWxConfig</br>* 详述:获取微信的配置信息 </br>* @param* @return 说明返回值含义* @throws*/public ...

  8. Spring Boot + 微信公众号授权登录获取用户信息

    通过微信公众平台的官方文档,总结出网页授权流程分为: 1.引导用户进入授权页面同意授权,获取code 2.通过code换取网页授权access_token(与基础支持中的access_token不同) ...

  9. 关于微信公众号开发中扫码关注和关注之后继续扫码的不同点

    2019独角兽企业重金招聘Python工程师标准>>> 开发微信商城,当遇到需要绑定上下级关系的时候,会通过扫码的方式关注公众号,但是如果不想做这个人的下级,后台添加解绑功能,继续扫 ...

最新文章

  1. linux var目录满了,Linux入门教程:/var/spool/clientmqueue 占满根目录
  2. php动态成本管理,网上审批系统环境下的动态目标成本管理
  3. mysql 如何磁阵_Raid教程 全程图解手把手教你做RAID
  4. 3.15 晚会—「饿了么」之殇
  5. shell 启动java程序_Shell 脚本启动java程序
  6. 惊喜:vs2005 和 msdn 中文版 已经提供Subscriber 下载,MSDN全球订户可以下中文版爽了...
  7. Intouch | 报警延时设定
  8. word页眉前后不一致怎么设置_如何设置页眉部分内容前后不同,页脚部分内容也前后不同的WORD文档?...
  9. 勒索病毒的发展史及解密办法
  10. 隐私计算 — 联邦学习 — Overview
  11. 【java】微信文章抓取
  12. 【Chrome】解决浏览器萤幕画面模糊字体不清楚方法
  13. 学生信息管理系统 C++实现
  14. Word插入的表格怎么合并单元格
  15. 鸿蒙需要多少技能命中,【攻略团】鸿蒙困难(天音视角)
  16. ubuntu和windows双系统默认启动顺序
  17. 使用MMA解决拓扑优化问题的并行框架
  18. 韩创变色镜片和普通镜片哪个更好用
  19. 发布Windows应用程序!试试英伟达“神笔马良”GauGAN
  20. WEBGL 2D游戏引擎研发系列 第三章 正交视口

热门文章

  1. Haskell初学指南(一)
  2. 多云和混合云场景下的 API 管理:挑战与选择
  3. nginx 1.14 php,安装php7.2+nginx1.14.2常见报错解决方法_2018_lcf
  4. hp dl160 gen8 b120i驱动与win2008r2忘记密码
  5. 工作周报2016.08.01-2016.08.07
  6. 当我让AI描绘古代男子谪仙外貌。。。
  7. 郭金东旗下江苏钟山化工参加2019聚氨酯行业大会并受到表彰
  8. IO口未初始化差点烧板子
  9. 市场调研报告-全球与中国皮肤护理服务市场现状及未来发展趋势
  10. 商业地产噱头多 贸然投资有风险