精华内容
下载资源
问答
  • thinkphp 5.0微信公众号插件,实现公众号自动回复设置、菜单设置、网站数据与公众号同时推送。
  • 微信公众号 微信公众号,是微信公众平台的一种账户类型,旨在为特定或公开用户群体提供信息、营销等服务。用户可通过关注公众号来使用特定服务,进行不同活动。 微信公众号主要包括三类:订阅号、服务号、企业号...

    微信公众号

    微信公众号,是微信公众平台的一种账户类型,旨在为特定或公开用户群体提供信息、营销等服务。用户可通过关注公众号来使用特定服务,进行不同活动。

    微信公众号主要包括三类:订阅号、服务号、企业号(现已改为企业微信。三者主要区别如下:

     订阅号服务号企业微信(原企业号)
    用途为媒体和个人提供信息资讯,功能类似报纸杂志,提供新闻信息或娱乐趣事。为企业和组织提供更强大的业务服务与用户管理能力,主要偏向服务类交互(功能类似12315,114,银行,提供绑定信息,服务交互的)企业的专业办公管理工具。提供丰富的办公应用,如打卡、审批等,还可与微信互通。
    适用对象个人、媒体、企业、政府或其他组织。媒体、企业、政府或其他组织企业、政府或其他组织
    群发次数1天内可群发1条消息1个月(按自然月)内可发送4条群发消息每分钟可发200次
    身份验证任何微信用户都可关注任何微信用户都可关注通讯录成员可关注
    消息保密消息可转发、分享消息可转发、分享消息可转发、分享。支持保密消息,防成员转发。
    高级接口权限不支持支持支持
    定制应用不支持,新增服务号需要重新关注。不支持,新增服务号需要重新关注。支持。一个企业号可聚合多个应用。
    应用场景简单发发消息,做宣传推广服务,可选择订阅号开通微信支付、进行商品销售等企业管理、办公、营销。

    公众号申请

    1. 登录微信公众平台注册,地址:https://mp.weixin.qq.com/

    2.邮件确认

    3.选择公众号类型,登记信息(包括实名认证)

    4.设置帐号名称(昵称,不是微信号)和功能介绍

    5.审核通过后使用。

    说明:

    由于个人订阅号权限受限,不能使用高级接口,如果要进行二次开发的话,需申请公众平台测试号。在测试号中,各类高级接口权限都是开放的。

    公众号管理维护

    登录微信公众平台,对你开通的公众号进行管理,包括自动回复(被添加自动回复,消息自动回复,关键词自动回复)、消息管理、用户管理、添加功能插件、自定义菜单设置等,类似网站后台。

    编辑模式

    在微信公众平台管理页面,使用官方提供的编辑功能,可实现自己公众号的消息回复、素材管理、自定义菜单设置等。编辑模式使用简便,无需编码即可实现公众号的服务功能。

    编辑模式支持公众号最基本、最典型的功能,但无法满足用户更高级、更复杂的需求。这时候便需要我们进行二次开发了。

    开发者模式

    该模式适用于基于微信公众平台进行二次开发,开发者可使用各类微信接口实现更加灵活、复杂的功能,以满足不同需求。开发模式与编辑模式是互斥的,“自动回复”与“自定义菜单”等只能在一种模式下使用。

    展开全文
  • JAVA微信公众号开发入门(详细) 有很多在学习公众号开发的小伙伴向我反映了,说在学习的过程中很矛盾,很多的公众号开发教程不够详细,亦或者是完全看不懂,况且官网给的文档也只是PHP的实例教程,而这时候学其他...

    JAVA微信公众号开发入门(详细)

    有在学习公众号开发的小伙伴向我反映了,说在学习的过程中很矛盾,很多的公众号开发教程不够详细,亦或者是完全看不懂,况且官网给的文档也只是PHP的实例教程,而这时候学其他编程语言的学者们往往就容易陷入苦海。小编认为这肯是初次接触新技术的迷茫,因为不知道从哪里下手就盲目的寻找各式各样的教程,不仅没学到,反倒乱了套,又或是一知半解。在这里小编将带带领大家一步一步的学习微信公众号开发。

    1.注册微信公众平台
    首先我们打开https://mp.weixin.qq.com进入微信公众平台的登录页面,如果还没有注册的同学点击右上角的注册按钮
    在这里插入图片描述
    如果有企业提供信息的话可以选择服务号,如果只是个人学习公众号开发的话,建议选择订阅号(除了功能少了点,其他效果跟服务号也差不多),本次教程,小编采用订阅号作为测试
    在这里插入图片描述
    我们可以在这里看到订阅号与服务号的大致区别,这里同样选择订阅号
    在这里插入图片描述
    这里我们选择个人,填写完信息后注册完成
    在这里插入图片描述
    2.后台与微信公众号对接
    登录微信公众号平台成功以后,我们看到左侧的功能栏,找到开发项点击 基本配置
    在这里插入图片描述
    在这里插入图片描述
    这里就是后台与公众号对接的地方了,下图输入框的内容暂时忽略
    在这里插入图片描述
    这时候我们可以打开我们的开发工具了,这里的小编使用的是IntelliJ IDEA开发工具,首先呢为了方便我们创建一个SpringBoot项目(主要是懒得写太多配置文件)
    在这里插入图片描述
    目前使用spring boot版本为2.1.4,导入一下依赖:

    		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
                    <!-- jackson依赖 -->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>2.9.6</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>2.9.6</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.9.6</version>
            </dependency>
            
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
    
            <dependency>
                <groupId>com.thoughtworks.xstream</groupId>
                <artifactId>xstream</artifactId>
                <version>1.3.1</version>
            </dependency>
    
            <!-- JSONObject对象依赖的jar包 -->
            <dependency>
                <groupId>net.sf.json-lib</groupId>
                <artifactId>json-lib</artifactId>
                <version>2.2.3</version>
                <classifier>jdk15</classifier><!-- 指定jdk版本 -->
            </dependency>
            
            <!-- 微信httpclient 获取用户 openId-->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.3.1</version>
            </dependency>
    

    我们首先需要三个工具类:
    1.MyX509TrustManager.java 用于检查证书

    
    import javax.net.ssl.X509TrustManager;
    import java.security.cert.CertificateEncodingException;
    import java.security.cert.X509Certificate;
    
    public class MyX509TrustManager implements X509TrustManager {
        /**
         * 该方法用于检查客户端的证书,若不信则抛出异常
         * 由于我们不需要对客户端进行认证,可以不做任何处理
         */
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateEncodingException {
    
        }
    
        /**
         * 该方法用于检验服务器端的证书,若不信任则抛出异常
         * 通过自己实现该方法,可以使之信任我们指定的任何证书
         * 在实现该方法时,也可以不做任何处理,即一个空的方法实现
         * 由于不会抛出异常,它就会信任任何证书
         */
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateEncodingException {
    
        }
    
        /**
         * 返回收信任的X509证书数组
         */
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
    
    

    2.WeixinUtil.java 发起https请求工具类

    import net.sf.json.JSONObject;
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ConnectException;
    import java.net.URL;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    
    /**
     * Created by Administrator on 2016/11/7.
     */
    public class WeixinUtil {
        private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
    
        /**
         * 发起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 MyX509TrustManager() };
                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;
        }
    }
    

    3.SignUtil.java 请求校验工具类

    
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    
    /**
     * 请求校验工具类
     */
    public class SignUtil {
    	// 与接口配置信息中的Token要一致
    	private static String token = "weixinCourse";
     
    	/**
    	 * 验证签名
    	 * 
    	 * @param signature
    	 * @param timestamp
    	 * @param nonce
    	 * @return
    	 */
    	public static boolean checkSignature(String signature, String timestamp, String nonce) {
    		String[] arr = new String[] { token, timestamp, nonce };
    		// 将token、timestamp、nonce三个参数进行字典序排序
    		Arrays.sort(arr);
    		StringBuilder content = new StringBuilder();
    		for (int i = 0; i < arr.length; i++) {
    			content.append(arr[i]);
    		}
    		MessageDigest md = null;
    		String tmpStr = null;
     
    		try {
    			md = MessageDigest.getInstance("SHA-1");
    			// 将三个参数字符串拼接成一个字符串进行sha1加密
    			byte[] digest = md.digest(content.toString().getBytes());
    			tmpStr = byteToStr(digest);
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    		}
     
    		content = null;
    		// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
    		return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    	}
     
    	/**
    	 * 将字节数组转换为十六进制字符串
    	 * 
    	 * @param byteArray
    	 * @return
    	 */
    	private static String byteToStr(byte[] byteArray) {
    		String strDigest = "";
    		for (int i = 0; i < byteArray.length; i++) {
    			strDigest += byteToHexStr(byteArray[i]);
    		}
    		return strDigest;
    	}
     
    	/**
    	 * 将字节转换为十六进制字符串
    	 * 
    	 * @param mByte
    	 * @return
    	 */
    	private static String byteToHexStr(byte mByte) {
    		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    		char[] tempArr = new char[2];
    		tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
    		tempArr[1] = Digit[mByte & 0X0F];
     
    		String s = new String(tempArr);
    		return s;
    	}
    }
    
    

    我们打开微信公众号开发文档接入指南https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319,不难看出,这是微信服务器在接入时给我们发送的四个参数,并且需要我们再将echostr随机字符串返回给微信服务器
    在这里插入图片描述
    创建package-》controller,创建类WxController:

    /**
     * 微信公众号对接
     */
    @Controller
    @RequestMapping("/wxDemo")
    public class WxController {
    
        @RequestMapping(value = "/coreController",method= RequestMethod.GET)
        public void login(HttpServletRequest request, HttpServletResponse response){
            // 微信加密签名
            String signature = request.getParameter("signature");
            // 时间戳
            String timestamp = request.getParameter("timestamp");
            // 随机数
            String nonce = request.getParameter("nonce");
            // 随机字符串
            String echostr = request.getParameter("echostr");
            PrintWriter out = null;
            try {
                out = response.getWriter();
                // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
                if(SignUtil.checkSignature(signature, timestamp, nonce)){
                    out.write(echostr);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                out.close();
            }
    
        }
      }
    

    ok,代码准备完毕,这时候我们发现公众号对接所使用的必须是有效域名,所以不能使用http://localhost:8080这样的域名了,没有服务器的小伙伴可以试试这个natapp外网穿透,官网:https://natapp.cn/,注册成功以后购买免费隧道即可,下载客户端后直接打开输入natapp -authtoken=你购买的隧道authtoken 回车 成功效果图为:
    在这里插入图片描述
    这样就生成了一个随机的临时域名,同时我们启动刚刚编写的项目,这时候我们回到公众号基本配置这里,将域名与请求的路径拼接填入URL输入框,将SignUtil.java的变量token填入Token输入框,EncodingAESKey随机生成即可。
    在这里插入图片描述
    配置完成以后我们点击提交,提交成功证明我们的项目与微信公众号已经对接完成
    在这里插入图片描述
    本章结束,有疑问或者有建议的小伙伴可以在下方评论区留言。
    git源码分享:------》》》》戳这里
    下一篇:java微信公众开发(原始篇-获取access_token)—》》》戳这里

    展开全文
  • 10万+IT人都在关注,史上最全面的微信开发实战教程:包含公众号,小程序,微信支付等开发案例 欢迎关注笔者个人博客:http://blogs.chenyunkeji.com/ 首先,直接上图,看效果,如下,有三个根菜单,每个菜单上有...

    10万+IT人都在关注,史上最全面的微信开发实战教程:包含公众号,小程序,微信支付等开发案例

    欢迎关注笔者个人博客:http://blogs.chenyunkeji.com/

    首先,直接上图,看效果,如下,有三个根菜单,每个菜单上有不同类型的子菜单,点击子菜单可以实现用户和公众号实时交互

    http://blogs.chenyunkeji.com

    本案例技术栈:springboot,mysql,logback,mybatis

    菜单创建请求接口:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

    首先是菜单项(按钮)的基类,所有一级菜单、二级菜单都有一个相同的属性,那就是name。菜单项基类的封装代码如下:

    public class Button {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    接着是子菜单项的封装。这里对子菜单是这样定义的:底部根菜单的二级菜单。这类子菜单项一定会包含三个属性:type、name和key,封装的代码如下

    public class CommandButton extends Button{
    
        private String type;
        private String key;
        
        public String getType() {
    	  return type;
        }
        public void setType(String type) {
    	  this.type = type;
        }
        public String getKey() {
    	  return key;
        }
        public void setKey(String key) {
    	  this.key = key;
        }
    }

     接着封装父菜单项。对父菜单项的定义:包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button是一个子菜单项数组。父菜单项的封装代码如下:

    public class ComplexButton extends Button{
    
        private Button[] sub_button;
    
        public Button[] getSub_button() {
            return sub_button;
        }
    
        public void setSub_button(Button[] sub_button) {
            this.sub_button = sub_button;
        }
    }

    最后是整个菜单对象的封装,菜单对象包含多个根菜单项(最多只能有3个),这些菜单项即可以是子菜单项(不含二级菜单的一级菜单),也可以是父菜单项(包含二级菜单的菜单项),如果能明白上面所讲的,再来看封装后的代码就很容易理解了:

    public class Menu {
        private Button[] button;
        public Button[] getButton() {
            return button;
        }
    
        public void setButton(Button[] button) {
            this.button = button;
        }
    }

     最后再封装一个链接类型的菜单,根据此处的名字也很好理解,不再赘述

    public class ViewButton extends Button{
    
        private String type;
        private String url;
        
        public String getType() {
            return type;
        }
        public void setType(String type) {
            this.type = type;
        }
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
    }

    关于菜单实体类以及菜单对象的封装就介绍完了,下面根据微信接口创建自定义菜单。

    一、封装菜单创建工具类

    public class WeiXinMenuUtil {
    
        private static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";        private static Logger log = LoggerFactory.getLogger(WeiXinMenuUtil.class);
        public static int createMenu(Menu menu, String accessToken) {
            int result = 0;
            // 拼接创建菜单的url
            String url = menu_create_url .replace("ACCESS_TOKEN", accessToken);
            // 将菜单对象转换成json字符串
            String jsonMenu = JSON.toJSONString(menu);
            // 调用接口创建菜单
            JSONObject jsonObject = WeiXinUtil.httpPost(url, "POST", jsonMenu);
            if (null != jsonObject) {
                if (0 != (Integer)jsonObject.get("errcode")) {
                    result = (Integer)jsonObject.get("errcode");
                    log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.get("errcode"), jsonObject.getString("errmsg"));
                }
            }
            return result;
        }
        
        public static Menu initMenu(){
            //1.创建菜单
            Menu menu = new Menu();
            // 主菜单1
            ComplexButton cb1 = new ComplexButton();
            cb1.setName("技术干货");
            
            // 主菜单2
            ComplexButton cb2 = new ComplexButton();
            cb2.setName("交流合作");
            
            // 主菜单3
            ComplexButton cb3 = new ComplexButton();
            cb3.setName("演示功能");
            
            // 主菜单1下面的子菜单1
            ViewButton cb01 = new ViewButton();
            cb01.setName("微服务教程连载");
            cb01.setType("view");
            cb01.setUrl("https://blog.csdn.net/guobinhui/article/category/8739270");
            
            // 主菜单1下面的子菜单2
            ViewButton cb02 = new ViewButton();
            cb02.setName("公众号开发教程");
            cb02.setType("view");
            cb02.setUrl("https://blog.csdn.net/guobinhui/article/category/8534361");
            
            ViewButton cb03 = new ViewButton();
            cb03.setName("小程序开发教程");
            cb03.setType("view");
            cb03.setUrl("https://blog.csdn.net/guobinhui/article/category/7763266");
            
            ViewButton cb04 = new ViewButton();
            cb04.setName("JavaEE基础");
            cb04.setType("view");
            cb04.setUrl("https://blog.csdn.net/guobinhui");
            
            ViewButton cb05 = new ViewButton();
            cb05.setName("笔者博客");
            cb05.setType("view");
            cb05.setUrl("http://blogs.chenyunkeji.com/");
            cb1.setSub_button(new ViewButton[]{cb01,cb02,cb03,cb04,cb05});
            
            // 主菜单2下面的子菜单1
            CommandButton cb11 = new CommandButton();
            cb11.setType("click");
            cb11.setKey("联系我");
            cb11.setName("联系笔者");
            
            CommandButton cb12 = new CommandButton();
            cb12.setName("技术交流");
            cb12.setType("click");
            cb12.setKey("18629374628");
            cb2.setSub_button(new CommandButton[]{cb11,cb12});
            
            CommandButton cb21 = new CommandButton();
            cb21.setType("scancode_waitmsg");
            cb21.setKey("rselfmenu_0_0");
            cb21.setName("扫码带提示");
            
            CommandButton cb22 = new CommandButton();
            cb22.setType("pic_sysphoto");
            cb22.setKey("rselfmenu_1_0");
            cb22.setName("系统拍照发图");
            
            CommandButton cb23 = new CommandButton();
            cb23.setType("pic_photo_or_album");
            cb23.setKey("rselfmenu_1_1");
            cb23.setName("拍照或者相册发图");
            
            CommandButton cb24 = new CommandButton();
            cb24.setType("pic_weixin");
            cb24.setKey("rselfmenu_1_2");
            cb24.setName("微信相册发图");
            
            CommandButton cb25 = new CommandButton();
            cb25.setType("location_select");
            cb25.setKey("rselfmenu_2_0");
            cb25.setName("发送地理位置");
            cb3.setSub_button(new CommandButton[]{cb21, cb22,cb23, cb24,cb25});
            menu.setButton(new Button[] { cb1,cb2, cb3});
            return menu;        
        }
    }

    二、微信接口凭证access_token的获取以及缓存实现

    access_token可以用各种缓存插件或者线程,定时任务,写入数据库等多种方式对access_token进行缓存7200秒,开发者可以依据自己的喜好选择其一,本案例策略采用IO流定时写入文件的方法缓存。首先获取access_token:

    public static JSONObject getToken()throws IOException{
    
     private String GET_ACCESS_TOKEN= "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
     String url = GET_ACCESS_TOKEN.replace("APPID",WeixinConstant.APPID).replace("APPSECRET",WeixinConstant.APPSECRET);
       JSONObject tokenObj = HttpGet(url);
       return tokenObj;
    }

    接着缓存access_token,也就是每隔7200秒生成一次access_token,生成的缓存7200秒,这样其余用到access_token的从文件中读取的就是最新的,不会过期。

    public static  Map <String,Object> cacheToken() throws IOException {
          Gson gson = new Gson();
          Map <String,Object> map = new HashMap <String,Object> ();
          String token = null;
          JSONObject tokenObj = null; //需要获取的access_token对象;
          String filePath = System.getProperty("user.dir")+"/src/main/resources/static/token.txt";
          File file = new File(filePath);//Access_token保存的位置
          if (!file.exists())
            file.createNewFile();
          // 如果文件大小等于0,说明第一次使用,存入Access_token
          if (file.length() == 0) {
            tokenObj = WeiXinUtil.getToken();
            token = (String)tokenObj.get("access_token");
            FileOutputStream fos = new FileOutputStream(filePath, false);// 不允许追加
            tokenObj.put("expires_in",System.currentTimeMillis()/1000+"");
            String json = gson.toJson(tokenObj);
            fos.write(json.getBytes());
            fos.close();
          }else {
            //读取文件内容
            @SuppressWarnings("resource")
            FileInputStream fis = new FileInputStream(file);
            byte[] b = new byte[2048];
            int len = fis.read(b);
            String jsonAccess_token = new String(b, 0, len);// 读取到的文件内容
            JSONObject access_token = gson.fromJson(jsonAccess_token,JSONObject.class);
            if (access_token.get("expires_in") != null) {
              String lastSaveTime = (String)access_token.get("expires_in");
              long nowTime = System.currentTimeMillis()/1000;
              long remianTime = nowTime - Long.valueOf(lastSaveTime);
              if (remianTime < WeixinConstant.EXPIRESIN_TIME) {
                  JSONObject access = gson.fromJson(jsonAccess_token,JSONObject.class);
                  token = (String)access.get("access_token");
              } else {
                  tokenObj = WeiXinUtil.getToken();
                  FileOutputStream fos = new FileOutputStream(file, false);// 不允许追加
                  tokenObj.put("expires_in",System.currentTimeMillis()/1000+"");
                  String json = gson.toJson(tokenObj);
                  fos.write((json).getBytes());
                  fos.close();
              }
          }
          }
          map.put("access_token",token);
          return map;
        }

    最后在项目的启动入口文件的main方法调用菜单创建方法进行初始化,那么项目在启动的时候,公众号的菜单就进行了初始化,用户就能看到公众号的菜单。

    @SpringBootApplication
    @MapperScan(basePackages = "com.chenyun.cloud.dao")
    public class HelloServiceApplication {
        private final static Logger logger= LoggerFactory.getLogger(HelloServiceApplication.class);
        
        public static void main(String[] args) {
             SpringApplication.run(HelloServiceApplication.class, args);
             Map<String, Object> map;
            try {
                map = WeiXinUtil.cacheToken();
                 String accessToken = (String)map.get("access_token");
                 logger.info("accessToken:"+accessToken);
                 Menu menu = WeiXinMenuUtil.initMenu();
                 System.out.println(JSON.toJSONString(menu));
                 int result  = WeiXinMenuUtil.createMenu(menu,accessToken);
                 if (0 == result){
                      logger.info("菜单创建成功!");
                  }else{
                      logger.info("菜单创建失败,错误码:" + result);
                  }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }    
    }

    启动项目后,打印的JSON格式的日志打就显示了创建的菜单结构。

    下节内容为大家分享公众号菜单栏的各种点击事件开发案例,更多JavaEE资料请关注下面公众号,欢迎广大开发者朋友一起交流。更多微信公众号功能演示请扫码体验,笔者电话(微信):18629374628

    展开全文
  • 最近在学node开发,于是想自己写一个node版的微信公众号开发开发期间踩了挺多的坑,也学到了挺多东西。这里分几个部分给大家分享一下node开发微信公众号的过程,以及哪些容易遇见的坑。(欢迎批评指正,源码在文章...

    最近在学node开发,于是想自己写一个node版的微信公众号开发。开发期间踩了挺多的坑,也学到了挺多东西。这里分几个部分给大家分享一下node开发微信公众号的过程,以及哪些容易遇见的坑。(欢迎批评指正,源码在文章末尾)


    微信公众号的接入可以分为三个部分。1.node服务器;2.将本地的node服务暴露到外网,3.微信公众号信息验证。我们依次来看一下。

    1.node服务器启动

    我们先创建一个文件夹,并引入相应的模块,我这里用的是express模块。端口随便选择这个没有被占用的就行,我这用的是1234端口。

    // 引入express模块
    var express = require("express");
    var app = express();
    
    app.get("/", (req, res, next)=> {
        res.send("这是1234端口页面");
    })
    
    // 监听1234端口
    app.listen(1234);

    我们到浏览器看一下,服务成功启动。

    2.将本地服务暴露到外网

    推荐一个工具——花生壳(个人感觉还挺好),去官网注册一下,花6块钱就可以获得免费版的内网穿透服务,另外注册还可以获得一个免费的域名。

    点击添加映射,名称随便写,域名选择免费送的就行,内网主机Ip可以在命令行下输入ipconfig查看。

    设置完之后,可以诊断一下是否成功。

    ps:如果不想用花生壳,也可以用其他一些免费的插件,比如node有个插件叫做Localtunnel,使用方法也特别简单,一个命令就行,缺点就是不太稳定,每次重启一下服务,就要重新暴露,而且每次的网址会发生变化。

    3.微信公众号信息验证

    进入微信公众号的开发文档,选择开始开发,接口测试号申请(当然有自己公众号的可以用自己的公众号),然后用微信扫码登录就可以看到这样的页面。

    Token可以随便填,URL就是我们刚才用花生壳暴露出来的外网服务。(但是现在直接填写保存是会出错的,因为我们还没有验证)

    当我们点提交的时候,微信服务器会给我们填写的URL地址发送一个get请求,并传回一些特定的字段。就是下图这些参数,我们需要把这些参数跟微信服务去验证。

    所以,我们要修改一下app.js,接受一下这几个参数,并把验证结果返回给微信服务器。

    // 引入express模块
    var express = require("express");
    var app = express();
    var sha1 = require("sha1");
    
    var config = {
        "appID": "wxd27649727105b6d2",
        "appsecret": "a3f2eb9f5819b0bf4b2a92a81f99baf4",
        "token": "wechat"   
    }
    
    app.get("/", (req, res, next)=> {
    
        // 获取微信服务器发送的数据
        var signature = req.query.signature,
        timestamp = req.query.timestamp,
            nonce = req.query.nonce,
        echostr = req.query.echostr;
    
        // token、timestamp、nonce三个参数进行字典序排序
        var arr = [config.token, timestamp, nonce].sort().join('');
        // sha1加密    
        var result = sha1(arr);
    
        if(result === signature){
            res.send(echostr);
        }else{
            res.send('mismatch');
        }
    })
    
    // 监听1234端口
    app.listen(1234);

    这里引入了一个新的模块sha1,主要是对结果进行加密的。现在,我们再到微信测试号配置设置就可以成功保存了,这就表示,我们的验证成功可以开始正式的开发了。

    到这一步,微信验证就已经成功了,但是为了后续代码的编写,我们可以把代码进行一些优化。比如把配置文件单独提取出来,把微信授权方法封装到一个模块中,优化完之后再到微信测试号上去重新配置保存一下,看是否出错。


    以下是优化部分:
    1.配置文件单独提取出来,写在config.json文件中;
    2.授权验证方法提取出来,写在wechat.js文件中
    wechat.js代码:

      var sha1 = require("sha1"); //引入加密模块
    
    // 构造函数
    function WeChat(config) {
        // 传入配置文件
        this.config = config;
        this.token = config.token;
        this.appID = config.appID;
        this.appScrect = config.appScrect;
    }
    
    // 微信授权验证方法
    WeChat.prototype.auth = function(req, res, next) {
    
        // 获取微信服务器发送的数据
        var signature = req.query.signature,
        timestamp = req.query.timestamp,
            nonce = req.query.nonce,
        echostr = req.query.echostr;
    
        // token、timestamp、nonce三个参数进行字典序排序
        var arr = [this.token, timestamp, nonce].sort().join('');
        // sha1加密    
        var result = sha1(arr);
    
        if(result === signature){
            res.send(echostr);
        }else{
            res.send('mismatch');
        }
    }
    
    // 暴露WeChat对象
    module.exports = WeChat;

    app.js

    // 引入express模块
    var express = require("express");
    var app = express();
    var config = require("./config"); //引入配置文件
    var WeChat = require("./wechat/wechat"); 
    
    var wechat = new WeChat(config); //实例化一个WeChat对象
    
    app.get("/", (req, res, next)=> {
        wechat.auth(req, res, next);
    })
    
    // 监听1234端口
    app.listen(1234);

    源码地址:https://github.com/yeshaojun/wechatBase
    如果喜欢就给我点个小星星吧!

    展开全文
  • vue微信公众号授权插件
  • 用于微信公众号网页开发Nodejs端的微信SDK,满足基础的微信开发调用
  • 基本配置1.设置—公众号设置—功能设置—配置JS接口安全域名安全域名配置规则如下2.开发—基本配置开发者密码第一次使用需要重新设置记录 开发者ID(AppID) 开发者密码(AppSecret)后面会用到3....微信公众号-开发-接...
  • 今天来说说所谓的微信公众号开发和填坑记录; 微信公众号:运行在微信终端的应用 (对于开发者来说比较爽的你只需考虑兼容微信浏览器,因为它是在微信内置浏览器环境下运行的) 微信公众号开发分为两部分:  一...
  • 微信机器人 5.0 版本对服务器要求非常高,只支持 Linux 服务器,PHP 要求 7.2 及以上版本,以及服务器要支持 Memcached。
  • 如何在本地进行微信公众号开发和调试
  • 使用该插件公众号,建议是认证订阅号、认证服务号,非认证的会受到功能限制,无法正常使用。 【前期准备】 1、获取微信号 2、获取公众号原始ID 3、获取开发者ID(AppID) 4、获取开发者密码(AppSecret) 登录...
  • 微信公众号开发

    2018-06-05 16:57:00
    1.微信公众号的区别  微信 公众号 社交圈 大多都是认识的人,可以进行一对一,一对多的交流 包括个人在内的更大的社交圈,大多的不认识的人 定位 主要用于聊天,朋友圈娱乐等活动 更加...
  • 这是php使用微信支付、小程序、公众号等功能的插件,代码简单实用,可直接下载导入,已封装好,下载解压后可以直接引入使用,里面包含说明文档资料!
  • 微信公众号接口准备这里我们要用前面搭建的aws服务器上部署的flask web应用来为微信公众号提供接口.修改flaskserver.pynano /var/www/flaskserver/flaskserver.py把代码截个图, 大家看下代码层次.以上代码包含了微....
  • 微信公众号网页开发(一)验证服务器前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 微信公众号网页开发第一步是验证服务器这一步是必不可少的。我是用的是liunx系统搭配宝塔面板,基于node.js+...
  • 在设置好微信公众号自定义菜单中,某一个菜单点击动作为发送消息后,想将这个点击动作换成跳转到网页,在原来的基础上修改,是不成功的。以下是小编为您带来的关于微信公众号自定义菜单将点击动作换成跳转到网页,...
  • 有同学问道微信公众号后台开发的自定义菜单怎么实现? 这个问题本来想放到后面的,因为的确对公众号的影响挺明显的, 因为开启后台服务,公众号的自定义菜单就不见了,很影响使用, 也有同学问这个问题,就提前...
  • 微信公众号网页开发

    2020-10-17 17:43:08
    1.设置—公众号设置—功能设置—配置JS接口安全域名 2.开发—基本配置 发者ID(AppID) 开发者密码(AppSecret) 3.IP白名单配置 填写当前本地开发IP地址和服务器IP地址 开发 jQuery + rem + flex或WeUi、SUI...
  • ios系统web开发 ios系统微信公众号开发 微信 fastclick
  • 有没有小伙伴还不知道微信公众号怎么做页面模板?针对这一类问题,小编马上要来为大家进行全面的分析,详细的解说。如果你正有这方面的困扰,也可以来阅读下面的内容!希望对你有帮助!1、微信公众号怎么做页面模板?1)...
  • 微信公众号开发

    2019-04-30 15:20:00
    1.方便微信公众号等手机网页调试插件eruda和vConsole 2. 转载于:https://www.cnblogs.com/kongge/p/10796194.html
  • 本篇文章将利用express框架进行微信公众号开发
  • 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解。 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发、微信公众平台定制开发,都不知道这些能给企业带来什么...
  • 今天使用微擎开发微信公众号运用确怎么都不能使用VueJs 老是报这个错误提示: “Uncaught ReferenceError: Vue is not defined” 明明把Vue引用进来了,却还是报错 最后把 页面 ‘{template ‘common/header’}’ ...
  • 微信公众号开发之自定义菜单

    万次阅读 2017-03-11 12:29:32
    微信开发交流群:148540125系列文章参考地址 极速开发微信公众号欢迎留言、转发 项目源码参考地址 点我点我–欢迎Start 前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者,重源码分析消息是如何...
  • 微信公众号java开发沉淀(六)发送模板消息 拿测试号举哥简单例子吧。 文档也说的比较清楚了 https://mp.weixin.qq.com/wiki?t=resource/res_main&amp;id=mp1433751277 测试号可以直接添加模板。 模板中参数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,485
精华内容 7,794
关键字:

微信公众号插件开发