微信公众号开发--服务号
前言
因公司需要开发一款手机打卡程序,本人没有安卓APP开发经验,所以决定将写个服务号的公众号,集外出打卡,打卡查询等功能;
一,开发前测试帐号申请
以下是官方给出的建议,大家可以多参考参考
1)如果想简单的发送消息,达到宣传效果,建议可选择订阅号;
2)如果想用公众号获得更多的功能,例如开通微信支付,建议可以选择服务号;
3)如果想用来管理内部企业员工、团队,对内使用,可申请企业号;
4)订阅号可通过微信认证资质审核通过后有一次升级为服务号的入口,升级成功后类型不可再变;
5)服务号不可变更成订阅号。
申请地址:
http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
二,选择natapp进行内网外穿,为什么?这是因为自制程序可以连外网,但怎样让微信服务器与你的自制程序通信?那只能把自己的程序也设置为外网,但用传统的打包布署发布到LINUX?那将会对开发极为不便。natapp就是解决我们可以直接将tomcat设置为内网外穿,这样每次开发完,直接运行,外网就可以找到你这个内网外穿的外网。我个人喜好natapp,当然也有其它优秀的内网外穿工具,可自行选择。
(1). 下载
在以下地址:https://natapp.cn/,进行下载,打开链接之后,选择客户端下,如下图:
图1:客户端下载
我在这里下载的是windows64位。
(2). 注册并登录
同时还需要进行注册,(注册过程不详述)并进行登陆。登陆后的页面如下图:
图2:登录成功后的页面
(3). 购买隧道
此时我们需要进行购买隧道,如下图。
图3:购买隧道
如果是自己的项目可以使用免费隧道。不过我推荐大家使用VIP_2型,根据自己的需要进行选择。我使用的是付费隧道。(如下图),我购买是一起花了13元,建议购买前去网上找优惠码,可便宜2元。然后建议不要买太便宜的,哈哈。
图4:隧道购买成功
(4). 配置已购买隧道
下面是购买成功后,我的隧道,我之前申请了一个免费隧道,一个付费隧道,所以我的里面有两个隧道。如下图
选择第二个隧道中的配置按钮,进行隧道配置。打开如图所示:
图5:配置已购买隧道
此时为止,natapp的配置已完成。
(5). 启动natapp
新建config.ini文件,存储在下载的客户端同一个目录下。该文件中需要添加内容如下
[default]
authtoken= 6fdb788dce71d7e2
clienttoken= #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
log=none #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
loglevel=ERROR #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
http_proxy= #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空
双击natapp程序启动成功如下图所示:
至此,大功告成.
三.在微信平台进行配置.
完成上面第一步的注册后,即下面这个网址.
http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
说明一下.
appid:是公众号开发识别码,配合开发者密码可调用公众号的接口能力。
appsecret:是校验公众号开发者身份的密码,具有极高的安全性。
再往下看,我们会看到URL和Token这两个属性,和上面appid/appsecret不同的是,上面的是微信分配给我们的,但是下面这两个是需要我们填进去的。
我们先来了解一下,这两个属性有什么作用。
URL:就是指我们自己的服务器地址
该URL是开发者用来接收和响应微信消息和事件的接口URL
(必须以http://或https://开头,分别支持80端口和443端口,这就是为什么我刚刚第二步说要进行内网外穿,哈哈)
Token:可任意填写,用作生成签名(必须为英文或数字,长度为3-32字符)
该签名在后边会用到,这里暂时随便填个内容也可以
接下来我们需要了解的是微信与我们的服务器交互的过程:
当我们在微信app上,给公众号发送一条内容的时候,实际会发送到微信的服务器上,此时微信的服务器就会对内容进行封装成某种格式的数据比如xml格式,再转发到我们配置好的URL上,所以该URL实际就是我们处理数据的一个请求路径。所以该URL必须是能暴露给外界访问的一个公网地址,不能使用内网地址,生产环境可以申请腾讯云,阿里云服务器等,但是在开发环境中可以暂时利用一些软件来完成内网穿透,便于修改和测试,如NATAPP,花生壳等软件,使用起来也很方便,在本地安装对应的软件,配置运行后,直接使用软件分配的临时域名来访问本地应用即可,只是偶尔会存在网络不稳定的情况。这里不详细介绍如何使用了,具体教程可参考软件官网。
在开发的过程中,我们会经常使用到微信公众号提供给开发者的开发文档
具体地址:https://mp.weixin.qq.com/wiki
大家打开后可以选择”接入指南”,参考微信提供的一些帮助信息。
四.正式开发
(1),URL接入
我们需要先来了解一下接入的过程是怎么样的。下图是微信官方对接入过程的介绍。
由以上介绍可知,当我们填入url与token的值,并提交后,微信会发送一个get请求到我们填写的url上,并且携带4个参数,而signature参数结合了开发者填写的token参数和请求中的timestamp参数、nonce参数来做的加密签名,我们在后台需要对该签名进行校验,看是否合法。实际上,我们发现微信带过来的4个参数中并没有带token参数,仅有signature是和token有关的,所以我们应该在本地应用中也准备一个和填入的token相同的参数,再通过微信传入的timestamp与nonce做相同算法的加密操作,若结果与微信传入的signature相同,即为合法,则原样返回echostr参数,代表接入成功,否则不做处理,则接入失败。
我这里是使用的springboot+springmvc+mybaties
1.首先新建一个servlet,为什么是servlet而不是controller?因为servlet支持一个入口对应两个方法,即get post.开发到后面你就会明白这个意义.
package com.cosun.cosunp.weixin;import com.cosun.cosunp.service.IPersonServ;
import com.cosun.cosunp.tool.Constants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;/*** @author:homey Wong* @Date: 2019/9/11 上午 9:03* @Description:* @Modified By:* @Modified-date:*/
@WebServlet(urlPatterns = "/weixin/hello")
public class WeiXinServlet extends HttpServlet {private static Logger logger = LogManager.getLogger(WeiXinServlet.class);@AutowiredIPersonServ personServ;public static final String tooken = "homeyhomeyhomey";private static JedisPool pool;private static Jedis jedis;public WeiXinServlet() {//空构造函数}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String signature = request.getParameter("signature");String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String echostr = request.getParameter("echostr");PrintWriter outPW = null;try {outPW = response.getWriter();if (CheckUtil.checkSignature(signature, timestamp, nonce, tooken)) {System.out.println("签名成功!");outPW.write(echostr);} else {System.out.println("签名失败");}} catch (IOException e) {e.printStackTrace();} finally {outPW.close();}}
}
工具类CheckUtil
package com.cosun.cosunp.weixin;import java.security.MessageDigest;
import java.util.Arrays;/*** @author:homey Wong* @Date: 2019/9/11 0011 上午 9:10* @Description:* @Modified By:* @Modified-date:*/
public class CheckUtil {public static boolean checkSignature(String singnature, String timestamp, String nonce, String tooken) {String[] arr = {tooken, timestamp, nonce};Arrays.sort(arr);StringBuilder sb = new StringBuilder();for (String s : arr) {sb.append(s);}String temp = getSha1(sb.toString());return temp.equals(singnature);}public static String getSha1(String str) {if (str == null || str.length() == 0) {return null;}char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9','a', 'b', 'c', 'd', 'e', 'f'};try {MessageDigest mdTemp = MessageDigest.getInstance("SHA1");mdTemp.update(str.getBytes("UTF-8"));byte[] md = mdTemp.digest();int j = md.length;char buf[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];buf[k++] = hexDigits[byte0 >>> 4 & 0xf];buf[k++] = hexDigits[byte0 & 0xf];}return new String(buf);} catch (Exception e) {return null;}}}
可以拿你的手机测试一下.OK后,如下,可以互动了
@WebServlet(urlPatterns = "/weixin/hello")
public class WeiXinServlet extends HttpServlet {private static Logger logger = LogManager.getLogger(WeiXinServlet.class);@AutowiredIPersonServ personServ;public static final String tooken = "homeyhomeyhomey";private static JedisPool pool;private static Jedis jedis;@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");pool = new JedisPool(new JedisPoolConfig(), "127.0.0.1");jedis = pool.getResource();System.out.println(jedis.get(Constants.accessToken));System.out.println(jedis.get(Constants.jsapi_ticket));try {// https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd5109277d8902606&redirect_uri=http://homey.nat100.top/weixin/getMobileLocate&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirectPrintWriter out = response.getWriter();Map<String, String> map = WeiXinUtil.xmlToMap(request);String fromUserName = map.get("FromUserName");String toUserName = map.get("ToUserName");String msgType = map.get("MsgType");String content = map.get("Content");String key = map.get("EventKey");String message = null;StringBuilder returnMes = new StringBuilder();if ("event".equals(msgType)) {if (clickquery.equals(key)) {List<OutClockIn> allOutClockIn = personServ.findAllOutClockInByOpenId(fromUserName);if (allOutClockIn.size() > 0) {for (OutClockIn on : allOutClockIn) {returnMes.append(on.getClockInDateStr() + ":");returnMes.append(on.getClockInDateAMOnStr() + ",");returnMes.append(on.getClockInAddrAMOn() + ",");if (on.getAmOnUrl() != null && on.getAmOnUrl().trim().length() > 0) {returnMes.append("上午已摄像.");} else {returnMes.append("上午还未摄像.");}returnMes.append(on.getClockInDatePMOnStr() + ",");returnMes.append(on.getClockInAddrPMOn() + ".");if (on.getPmOnUrl() != null && on.getPmOnUrl().trim().length() > 0) {returnMes.append("下午已摄像.");} else {returnMes.append("下午还未摄像.");}returnMes.append(on.getClockInDateNMOnStr() + ",");returnMes.append(on.getClockInAddNMOn() + ".");if (on.getNmOnUrl() != null && on.getNmOnUrl().trim().length() > 0) {returnMes.append("晚上已摄像.");} else {returnMes.append("晚上还未摄像.");}}} else {returnMes.append("暂无考勤信息");}InMsgEntity text = new InMsgEntity();text.setFromUserName(toUserName); //原来的信息发送者,将变成信息接受者text.setToUserName(fromUserName); //原理的接受者,变成发送者text.setMsgType("text"); //表示消息的类型是text类型text.setCreateTime(new Date().getTime());text.setContent("您的考勤信息是:" + returnMes);message = WeiXinUtil.textMessageToXml(text); //装换成 xml 格式发送给微信解析}} else if ("text".equals(msgType)) {InMsgEntity text = new InMsgEntity();text.setFromUserName(toUserName); //原来的信息发送者,将变成信息接受者text.setToUserName(fromUserName); //原理的接受者,变成发送者text.setMsgType("text"); //表示消息的类型是text类型text.setCreateTime(new Date().getTime());text.setContent("您发送的信息是:" + content);message = WeiXinUtil.textMessageToXml(text); //装换成 xml 格式发送给微信解析}out.print(message);} catch (Exception e) {e.printStackTrace();}}
}
public void setRedisValue(AccessToken accessToken) {// 初始化Redis连接池pool = new JedisPool(new JedisPoolConfig(), "127.0.0.1");jedis = pool.getResource();jedis.set(Constants.accessToken, accessToken.getAccessToken());jedis.set(Constants.expiresin, accessToken.getExpiresin() + "");//jedis.set(Constants.jsapi_ticket, accessToken.getJsapi_ticket());}
至此微信公众号的接入就已经完成了,后继可以进行功能开发啦.
微信公众号开发--服务号相关推荐
- 微信公众平台的服务号和订阅号
微信公众平台 服务号 订阅号 作者:方倍工作室 地址:http://www.cnblogs.com/txw1958/p/ServiceNumber-subscriptionNumber.html ...
- c#实现微信公众号开发--服务号通过oauth2获取用户信息
2018年春节策划了一个"带现金红包的贺年卡"微信号推广活动,先说下效果:2个小时实现新增关注用户4万多户,活动页面PV达到16.8万,后因红包预算费用原因结束活动. 实现原理:每 ...
- 微信公众平台开发订阅号
忙活着搭建了ecplise和tomcat,申请了sae服务器,最后回过头来才发现微信订阅号的开发,如果仅仅只是每天发布一些文章,根本不需要去开通开发者帐号,只需要在注册成功后,就可以去群发里面编辑文章 ...
- 用Sunny_ngrok免费地址映射工具解决微信公众平台开发本地测试问题
问题: 1.微信公众平台开发如何进行本地测试? 2.微信公众平台目前只支持80和433端口如何解决? 3.如何解决外网访问内网? 案例场景: 在微信公众平台开发服务号,开发新功能,想本地起服务进行测试 ...
- 基于java的微信公众平台开发(一)--账号申请与服务器的搭建
2019独角兽企业重金招聘Python工程师标准>>> 微信公众号开发文档:https://mp.weixin.qq.com/wiki 微信公众平台接口调试工具:https://mp ...
- 微信公众平台开发中提示“该公众号提供的服务出现故障”问题解决
问题描述: 在处理室内数据推送的时候,服务器能正常接收并处理请求,,客户端也能正常接收消息 但是在每次收到消息后,微信界面会出现,"该公众号提供的服务出现故障"字样. 解决思路一: ...
- 用c#开发微信(1)服务号的服务器配置和企业号的回调模式 - url接入
2019独角兽企业重金招聘Python工程师标准>>> 阅读目录 一.用法 二.实现方法 最近研究了下服务号的服务器配置和企业号的回调模式.真正实现完后,觉得很简单,但一开始还是走了 ...
- 升讯威微信营销系统开发教程:(1)订阅号和服务号深入分析
微信开发系列教程,将以一个实际的微信平台项目为案例,深入浅出的讲解微信开发.应用各环节的实现方案和技术细节. 原创内容,欢迎转载,转载请注明出处. 首先在第1章节中,我们先理清什么是订阅号,什么又是服 ...
- 微信公众平台订阅号、服务号和企业号三者之间的区别与联系
现在很多人用微信营销,但是网上经常能看到有人问订阅号.服务号和企业号到底该选择哪个,下面我们会详细的讲解订阅号.服务号和企业号的区别与联系,需要的朋友可以参考下. 9月18日,微信正式开启了微信企业号 ...
最新文章
- select刷新后保存原先选择的信息
- boost::asio ssl
- 多个容器一起打包_程序员修神之路容器技术为什么会这么流行(记得去抽奖)
- 使用vagrant因用户权限导致文件不可写问题的解决
- Serv-U FTP Jail Break(越权遍历目录、下载任意文件)
- C++进阶教程之信号处理
- Linux系统编程 -- 信号及signal函数
- Nginx重启时丢失nginx.pid文件
- MAC编译OpenJDK8:error: invalid argument ‘-std=gnu++98‘ not allowed with ‘C‘
- matlab simulink 过程控制,[转载]MATLAB/Simulink与过程控制系统
- 使用tkinter+爬虫实现网易云音乐下载器
- 2017年节假日放假安排来了!
- 银河麒麟v10_备受瞩目的银河麒麟v10系统究竟好不好?开箱测评瞬间明了
- STM32F103_study66_The punctual atoms(STM32 Temperature sensor experiment)
- 系列笔记-USYD悉尼大学Data1001 RQuiz1——RQuiz6 做法讲解
- (iphone铃声制作)i39 for mac破解版永久激活方法
- VMware收购Wavefront增强云管理产品组合
- Connext DDSQoS参考
- Python的字符串方法join(插入间隔符)
- 磁盘在计算机没显示win10,win10机械硬盘检测不到怎么解决?
热门文章
- 2005年4月24日
- 毕业设计答辩ppt技巧
- 国产单片机MCU DSH550 ,可应用于中央空调温控器上
- Mac OS X上的不同字体位置及功能
- Unifier培训: 系列讲解26 : 项目级的业务流程--变更单(总承包商业务)
- 谷歌量子计算机和九章知乎,量子计算机《九章》问世 知乎微博消息: 北京时间 12 月 4 日凌晨 3 点,一篇重要文章以 First Releas... - 雪球...
- 基于jsp的中学班级信息管理系统
- 开题报告:基于java在线外卖点餐送餐系统 毕业设计论文开题报告模板
- 数据说Digg的兴衰史 从辉煌到没落
- java快照_网页快照 java 实现 | 学步园