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

目录

 

微信公众号开发

1、微信公众号简单介绍

2、微信公众号申请

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

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

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

6、图文消息

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

8、获取用户的网页授权

9、码云开源源码:


微信公众号开发

1、微信公众号简单介绍

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

2、微信公众号申请

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

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第1张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第2张图片

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第3张图片

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

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第4张图片

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

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

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第5张图片

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第6张图片

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第7张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第8张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第9张图片

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

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第10张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第11张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第12张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第13张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第14张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第15张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第16张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第17张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第18张图片

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第19张图片

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第20张图片

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

com.thoughtworks.xstream

xstream

1.3.1

dom4j

dom4j

1.6.1

 

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

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第21张图片

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 parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map map = new HashMap();

        // 从request中取得输入流
        InputStream inputStream = request.getInputStream();
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        List 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("");
                    } 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 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;
    }
}

 

Spring Boot+微信公众号开发Demo(源码见文章最低端)_第22张图片

6、图文消息

图文消息相关总结:

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

 

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

 

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

 

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

 

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

 

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;


/***
 * 

b505信息科学研究所

* @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; // 拼装创建菜单的url String 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";//应用ID String 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 exception
                wat=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 exception
                snsuserInfo=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,spring)