微信公众号后台基础能力接口

  • 说明
    • 步骤
    • 后台代码
      • maven
      • 消息接收
      • 接口类
      • 帮助类
      • 实体类
    • 结尾

说明

本文主要是对接公众号的基础能接口
消息自动回复
用户信息事件
模板消息推送

步骤

1.申请公众号
2.进入公众号后台 获取 appid 和 secret
3.设置微信公众号后台接口地址,与关注用户的互动都会发到这个地址

后台代码

maven

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--devtools热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional><scope>true</scope></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.3</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.59</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency>

消息接收

将服务器地址设置为http:xxx/mainCall
将自己ip设为在白名单里面
将token 设置 与CheckUtil 一致
废话少说 上代码

//接收微信消息接口
@RestController
public class WxCallBackApi {@AutowiredWxSubscription wxSubscription;@RequestMapping("/mainCall")public void mainCall(HttpServletRequest request, HttpServletResponse response){try {Signature sg = new Signature(request.getParameter("signature"),request.getParameter("timestamp"),request.getParameter("nonce"),request.getParameter("echostr"));String method = request.getMethod();// 配置服务器域名 回调地址时 会发送一条验证消息 是GET请求if ("GET".equals(method)) {if (sg != null && CheckUtil.checkSignature(sg)) {wxSubscription.reply(response,sg.getEchostr());}}// 后续如果公众号收到用户消息 各种事件 是POST请求if ("POST".equals(method)) {if (CheckUtil.checkSignature(sg)) {wxSubscription.callWeChatMessage(request,response);}}} catch (Exception e) {e.printStackTrace();}}
}

接口类

@Slf4j
@EnableScheduling
@Component
public class WxSubscription {private  final String BASE_URL = "https://api.weixin.qq.com";private  final String URL_TOKEN = BASE_URL+"/cgi-bin/token";private  final String URL_MENU_CREATE = BASE_URL+"/cgi-bin/menu/create";private  final String URL_GET_CURRENT_SELFMENU_INFO = BASE_URL+"/cgi-bin/get_current_selfmenu_info";private  final String URL_MEDIA_UPLOAD = BASE_URL+"/cgi-bin/media/upload";private  final String URL_MEDIA_GET = BASE_URL+"/cgi-bin/media/get";private  final String URL_USER_GET = BASE_URL+"/cgi-bin/user/get";private  final String URL_USER_INFO = BASE_URL+"/cgi-bin/user/info";private  final String URL_TEMPLATE_GET_ALL_PRIVATE_TEMPLATE = BASE_URL+"/cgi-bin/template/get_all_private_template";private  final String URL_MESSAGE_TEMPLATE_SEND= BASE_URL+"/cgi-bin/message/template/send";//获取AccessTokenpublic  String getAccessToken(){HashMap<String,Object> param = new HashMap<String,Object>();param.put("grant_type","client_credential");param.put("appid",CheckUtil.appid);param.put("secret",CheckUtil.secret);String jsonstr = HttpUtil.get(URL_TOKEN,param);JSONObject result = JSONObject.parseObject(jsonstr);if(StrUtil.isBlank(result.getString("errcode"))){return  result.getString("access_token");}return "";}//每小时刷新access_token@Scheduled(cron = "0 0 1 * * ?")@PostConstruct//启动时执行一次public  void flushAccessToken(){CheckUtil.access_token = getAccessToken();log.info("========定期刷新token========{}",CheckUtil.access_token);}//创建公众号菜单//需开启后台配置地址//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.htmlpublic  boolean createMenu(JSONObject param){String validUrl = URL_MENU_CREATE +"?access_token="+CheckUtil.access_token;String jsonstr =  HttpUtil.post(validUrl,param.toJSONString());JSONObject result = JSONObject.parseObject(jsonstr);return returnBoolean(result);}//获取当前菜单信息//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Querying_Custom_Menus.htmlpublic  JSONObject getMenuInfo(){String validUrl = URL_GET_CURRENT_SELFMENU_INFO +"?access_token="+CheckUtil.access_token;String jsonstr =  HttpUtil.get(validUrl);JSONObject result = JSONObject.parseObject(jsonstr);if(StrUtil.isBlank(result.getString("errcode"))){return  result;}return null;}//删除菜单(不常用 懒得写)//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Deleting_Custom-Defined_Menu.html//创建个性化菜单(不常用 懒得写)//参数参考文档 https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Personalized_menu_interface.html//接收公众用户消息、事件public void callWeChatMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {try {//把微信返回的xml信息转成mapMap<String, String> map = XmlUtil.xmlToMap(request);//发送方用用户帐号(OpenID)String fromUserName = map.get("FromUserName");//开发者(公众号)String toUserName = map.get("ToUserName");//消息类型String msgType = map.get("MsgType");//消息内容String content = map.get("Content");String eventType = map.get("Event");if(CheckUtil.MSGTYPE_EVENT.equalsIgnoreCase(msgType)){//如果为事件类型if(CheckUtil.MESSAGE_SUBSCIBE.equalsIgnoreCase(eventType)){//处理关注事件if(StringUtils.isNotEmpty(fromUserName)){//用户信息入库 ybc}}else if(CheckUtil.MESSAGE_UNSUBSCIBE.equalsIgnoreCase(eventType)){//处理取消关注事件}else if(CheckUtil.MESSAGE_CLICK.equalsIgnoreCase(eventType)){//处理菜单点击事件String EventKey = map.get("EventKey");}}else if(CheckUtil.MESSAGE_TEXT.equalsIgnoreCase(msgType)){//用户发送文字//返回文字消息//测试HashMap<String,Object> param = new HashMap<String,Object>();param.put("ToUserName",fromUserName);param.put("FromUserName",toUserName);param.put("CreateTime","12345678");param.put("MsgType",CheckUtil.MESSAGE_TEXT);param.put("Content","你好");//返回图片消息
//                HashMap<String,Object> param = new HashMap<String,Object>();
//                param.put("ToUserName",fromUserName);
//                param.put("FromUserName",toUserName);
//                param.put("CreateTime","12345678");
//                param.put("MsgType",CheckUtil.MESSAGE_IMAGE);
//                HashMap<String,Object> Image = new HashMap<String,Object>();
//                Image.put("MediaId","2qvNch5UW27Q-6IdwchvMj7XEOihDGo2Myb1o3F1xrELcHEQE90Zjjv9zDQLSmob");//通过上传素材接口返回的id 或直接在微信公众号后台上传
//                param.put("Image",Image);//其他类型参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.htmlreply(response,param);return;}//...其他类型自己加} catch (Exception e) {e.printStackTrace();}reply(response,"success");}//无回复类型public void reply(HttpServletResponse response,String str) {try {response.setCharacterEncoding("UTF-8");PrintWriter writer = response.getWriter();writer.write(str);writer.close();}catch (Exception e){e.printStackTrace();}}//被动回复用户消息//参数参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html#%E5%9B%9E%E5%A4%8D%E6%96%87%E6%9C%AC%E6%B6%88%E6%81%AFpublic void reply(HttpServletResponse response,Map<String,Object> map)throws Exception{XmlUtil.mapToXmlResponse(response,map);}//新增临时素材//参考 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.htmlpublic boolean materialAddNews(String filepath){HashMap<String,Object> param = new HashMap<String,Object>();param.put("access_token",CheckUtil.access_token);param.put("type",CheckUtil.MESSAGE_IMAGE);param.put("media", FileUtil.file(filepath));String jsonstr = HttpUtil.post(URL_MEDIA_UPLOAD,param);JSONObject result = JSONObject.parseObject(jsonstr);log.info("请求地址{},返回值{}",URL_MEDIA_UPLOAD,jsonstr);return returnBoolean(result);}//获取临时素材//参考 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.htmlpublic void mediaDownload(String media_id,String filepath){String validUrl = URL_MEDIA_GET+"?access_token="+CheckUtil.access_token+"&media_id="+media_id;HttpUtil.downloadFile(validUrl,filepath);log.info("请求地址{}",validUrl);}//**********新增永久图文素材//实际上这一块直接在微信公众号平台管理操作会比较方便//项目中很少会将图文发布放在自己的项目中 浪费成本 还不一定好用//接下来我只写公众号平台无法完成 和 可能需要和自己的项目互动的接口//**********//获取用户列表 (关注者)//一次最多10000个 如果超过 则将返回值中的next_openid 传入再次获取//参考 https://developers.weixin.qq.com/doc/offiaccount/User_Management/Getting_a_User_List.htmlpublic JSONObject userGet(String next_openid){HashMap<String,Object> param = new HashMap<String,Object>();param.put("access_token",CheckUtil.access_token);param.put("next_openid",next_openid);String jsonstr =HttpUtil.get(URL_USER_GET,param);JSONObject result = JSONObject.parseObject(jsonstr);log.info("请求地址{},参数{},返回值{}",URL_USER_GET,param,jsonstr);return  result;}//获取用户基本信息//参考 https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonIdpublic JSONObject userInfo(String openid){HashMap<String,Object> param = new HashMap<String,Object>();param.put("access_token",CheckUtil.access_token);param.put("openid",openid);String jsonstr =HttpUtil.get(URL_USER_INFO,param);JSONObject result = JSONObject.parseObject(jsonstr);log.info("请求地址{},参数{},返回值{}",URL_USER_INFO,param,jsonstr);return  result;}//获取模板列表//模板须在微信公众号后台创建或添加//参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#%E8%8E%B7%E5%8F%96%E6%A8%A1%E6%9D%BF%E5%88%97%E8%A1%A8public JSONObject getAllPrivateTemplate(String openid){HashMap<String,Object> param = new HashMap<String,Object>();param.put("access_token",CheckUtil.access_token);String jsonstr =HttpUtil.get(URL_TEMPLATE_GET_ALL_PRIVATE_TEMPLATE,param);JSONObject result = JSONObject.parseObject(jsonstr);log.info("请求地址{},参数{},返回值{}",URL_TEMPLATE_GET_ALL_PRIVATE_TEMPLATE,param,jsonstr);return  result;}//发送模板消息//模板须在微信公众号后台创建或添加//参考 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#%E5%8F%91%E9%80%81%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AFpublic JSONObject messageTemplateSend(JSONObject param){String validUrl = URL_MESSAGE_TEMPLATE_SEND+"?access_token="+CheckUtil.access_token;String jsonstr =HttpUtil.post(validUrl,param);JSONObject result = JSONObject.parseObject(jsonstr);log.info("请求地址{},参数{},返回值{}",validUrl,param,jsonstr);return  result;}public boolean returnBoolean(JSONObject result){Integer errcode = result.getInteger("errcode");if(errcode!=null){if(errcode == 0){return true;}else{return false;}}else{return true;}}}

帮助类

CheckUtil

public class CheckUtil {//私钥 随便定义 但是要和公众号管理平台一致private  final static String token = "自己设置";//appid 申请微信公众号时获取public  final static String  appid = "自己获取";//secret 申请微信公众号时获取public  final static String secret = "自己获取";//通过appid 、secret 换取 调用接口凭证  2个小时失效 定期刷新public static  String access_token = "";//消息类型--事件public static final String MSGTYPE_EVENT = "event";//消息事件类型--订阅事件public static final String MESSAGE_SUBSCIBE = "subscribe";//消息事件类型--取消订阅事件public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";//菜单点击事件public static final String MESSAGE_CLICK = "CLICK";//消息类型--文本消息public static final String MESSAGE_TEXT = "text";//消息类型--图片消息public static final String MESSAGE_IMAGE = "image";//消息类型--语音消息public static final String MESSAGE_VOICE = "voice";//消息类型--视频消息public static final String MESSAGE_VIDEO = "video";//消息类型--小视频消息public static final String MESSAGE_SHORTVIDEO = "shortvideo";//消息类型--位置消息public static final String MESSAGE_LOCATION = "location";//消息类型--链接消息public static final String MESSAGE_LINK = "link";public static boolean checkSignature(Signature sg) {String[] arr = new String[] { token, sg.getTimestamp(), sg.getNonce() };// 排序Arrays.sort(arr);// 生成字符串StringBuffer content = new StringBuffer();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}// sha1加密String temp = getSha1(content.toString());// 比较return temp.equals(sg.getSignature());}// 加密算法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;}}}

XmlUtil

public class XmlUtil {/** xml转map*/public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {HashMap<String, String> map = new HashMap<String,String>();SAXReader reader = new SAXReader();InputStream ins = request.getInputStream();Document doc = reader.read(ins);Element root = doc.getRootElement();@SuppressWarnings("unchecked")List<Element> list = (List<Element>)root.elements();for(Element e:list){map.put(e.getName(), e.getText());}ins.close();return map;}/** map转xml 并响应*/public static void mapToXmlResponse(HttpServletResponse response, Map<String,Object> map) throws Exception {response.setContentType("text/xml");response.setCharacterEncoding("UTF-8");PrintWriter writer = response.getWriter();writer.write(mapToXml(map));writer.close();}/*** map 对象转换成 xml 字符串**/public static String mapToXml(Map map) throws Exception{if (null == map) return null;
//        System.out.println("转换前的Map对象数据:" + map.toString());StringBuffer sb = new StringBuffer();/** 添加xml 的公共头信息 */
//        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");sb.append("<xml>");mapToXmlHelp(map, sb);sb.append("</xml>");
//        System.out.println("将map转成xml后的数据:" + sb.toString());return sb.toString();}/*** 转换帮助方法**/private static void mapToXmlHelp(Map map, StringBuffer str) throws Exception{Set set = map.keySet();/** 遍历key */for (Iterator it = set.iterator(); it.hasNext();) {String key = (String) it.next();Object value = map.get(key);if (null == value)value = "";/** 如果对象是集合 */if (value.getClass().getName().equals("java.util.ArrayList")) {ArrayList list = (ArrayList) map.get(key);str.append("<" + key + ">");for (int i = 0; i < list.size(); i++) {HashMap hm = (HashMap) list.get(i);mapToXmlHelp(hm, str);}str.append("</" + key + ">");/** 如果该集合对象的长度只有1,那么默认重复添加集合下节点 */if (null !=list && !list.isEmpty() && list.size() <= 1) {str.append("<" + key + ">");for (int i = 0; i < list.size(); i++) {HashMap hm = (HashMap) list.get(i);mapToXmlHelp(hm, str);}str.append("</" + key + ">");}/** 对象非集合时 */} else {if (value instanceof HashMap) {str.append("<" + key + ">");mapToXmlHelp((HashMap) value, str);str.append("</" + key + ">");} else {str.append("<" + key + ">" + value + "</" + key + ">");}}}}}

实体类

Signature

@Data
@NoArgsConstructor                 //无参构造
@AllArgsConstructor
public class Signature {private String signature;private String timestamp;private String nonce;private String echostr;
}

结尾

实际上公众号不需要配置后台地址也可以用,如果想与自建系统互动,则可参照上述代码。
写了一下常用接口,代码有点乱,为了方便很多都没分开,如果能给到大佬们一点点帮助,请给我一点点动力,让我相信光
后续将完成更多接口,顺便将返回值JsonObject 用实体类代替哦,代码没什么技术含量,只想用劳动造福社会
gitee地址:https://gitee.com/yangbaocai/wxInterface

【微信公众号后台基础能力接口对接】相关推荐

  1. SpringBoot搭建微信公众号后台(零):服务搭建与接口验证

    关注作者,更多动态实时掌握,微信公众号:隔壁的程序员 前言:从这篇开始小王子将开始一个新的系列内容,从零开始搭建自己的微信公众号后台.内容大致规划为:环境篇,包括用到的工具安装,破解,配置:基础篇,主 ...

  2. Python微信公众号后台开发003:自定义菜单

    有同学问道微信公众号后台开发的自定义菜单怎么实现? 这个问题本来想放到后面的,因为的确对公众号的影响挺明显的, 因为开启后台服务,公众号的自定义菜单就不见了,很影响使用, 也有同学问这个问题,就提前了 ...

  3. python开发微信公众号开发教程百度云_Python开发微信公众号后台(系列一)

    Python 开发微信公众号后台(系列一) 專 欄段晓晨,写过一点爬虫,写过几篇文章.能力虽 有限,会尽量把想说的东西讲清楚. 知乎 ID :段小草 知乎专栏:小段同学的杂记, https://zhu ...

  4. Yii2.0实现微信公众号后台开发

    2019独角兽企业重金招聘Python工程师标准>>> 研读 微信公众平台开发者文档 ,然后再阅读本文,效果更佳! 接入微信 Yii2后台配置 1.在app/config/param ...

  5. 微信公众号后台服务开发(一):自动消息回复

    微信公众号后台服务开发 简述 微信平台提供的自动回复机制 后台服务开发 配置指定服务器 消息自动回复功能开发 简述 使用Java SpringBoot框架搭建微信工作号后台实现自定义逻辑自动回复 先注 ...

  6. php 公众号 模板消息id如何获取_微信公众号后台模板消息如何实现发送的功能...

    在公众平台实现发送模板消息功能,只能通过公众平台的接口开发实现,或者通过第三方平台微号帮功能模板消息群发实现,均能为微信公众号发送模板消息功能,模板消息发送不占用公众号每月的群发次数,模板消息仅用于公 ...

  7. SpringBoot搭建微信公众号后台(一):消息接收与响应

    关注作者,更多动态实时掌握,微信公众号:隔壁的程序员 上一篇我们经过接口验证,已经可以与微信的服务器进行通信,错过的可以通过下面链接来进行回顾,这一篇就来实现一个基本的消息接收与响应. SpringB ...

  8. python 公众号菜单_Python微信公众号后台开发003:自定义菜单

    有同学问道微信公众号后台开发的自定义菜单怎么实现? 这个问题本来想放到后面的,因为的确对公众号的影响挺明显的, 因为开启后台服务,公众号的自定义菜单就不见了,很影响使用, 也有同学问这个问题,就提前了 ...

  9. 开启微信公众号服务器后面的开发,微信公众号开发者权限 开通接口与配置服务器...

    微信公众号开发者权限 开通接口与配置服务器 作为微信公众平台的开发者,是可以修改自定义菜单的.每个公众号下端都会有三个或者是四个菜单.关于菜单的内容以及显示的方式都是可以通过后台的开发者权限更改的.如 ...

  10. 微信公众号后台java开发实现自动回复机器人

    1.注册微信公众号.(简单) 2.注册图灵机器人.(自己百度) 1)注册后可以拿到key  (注意  api接入里的钥匙不要打开,否则要加解密,麻烦) 3.配置微信公众号服务器验证. 1)在开发的基本 ...

最新文章

  1. springboot配置国际化资源文件 使用themself模板进行解析
  2. 二叉树的遍历:前序、中序、后序遍历
  3. Google Maps API 调用实例
  4. php7.4 微信小程序获取手机号
  5. input单选框多选框时可用的事件
  6. 【PAT甲】1007 Maximum Subsequence Sum (25分),求最大字段和及区间
  7. Linux操作系统配置基础详解:GRUB入门 (转)
  8. 南京电子地图下载 离线电子地图
  9. matlab传递闭包算法,传递闭包(用关系矩阵求传递闭包怎么求)
  10. iis 程序池设置及详解
  11. 用计算机查看终身伴侣,爱情是男女之间基于共同的生活理想,在各自内心形成的相互倾慕,并渴望对方成为自己终身伴侣的一种强烈、纯真、专一的感情。...
  12. charles——教程——转载
  13. python实现Content-Type:application/octet-stream
  14. iOS .tdb代替.dylib
  15. 正弦稳态电路的阻抗和功率
  16. 设置app icon角标
  17. 争议不断的AI绘画,靠啥成为了顶流?
  18. 深度测试oppo软件,OPPO手机推深度测试:可解锁Bootloader,已支持Find X正式版
  19. CTF常见加密方式汇总
  20. ERROR: Command errored

热门文章

  1. 安装VMware15.5+安装win10虚拟机操作系统
  2. QTDesigner简介
  3. 【虚拟机】VMWare虚拟机中大小写切换失效的解决方法
  4. 三个三维矢量叉乘公式(拉格朗日矢量公式)推导(非坐标法)
  5. 自动化测试工程师简历模板
  6. 微信聊天记录做成词云~
  7. 飞行堡垒fx80g拆卸电源_集成度较高 华硕飞行堡垒FX50拆机解析
  8. 本科计算机课程学习路线建议
  9. 安科瑞综合能效管理系统在数据中心的应用
  10. 软件开发项目各阶段交付物列表