微信开放平台全网发布
最近刚做了微信开放平台全网发布的开发,整理一下贴出来
前置条件 已经做好了相关的开发工作(比如扫码授权之类的),项目导入了微信SDK(最后会附上我自己用的SDK jar包)
sdk jar 地址: https://github.com/liyiorg/weixin-popular
BUG :weixin.popular.bean.message.EventMessage 内的@XmlElement(name = "MsgID") private String msgId; // 消息ID号 红色处原来D是小写,应该是大写,不知道现在改了没有,自己注意
platformToken:你要全网发布的开放平台填写的token, platformAESKey:你要全网发布的开放平台填写的加密秘钥, platformAppId:你要全网发布的开放平台的appId
/*** 功能描述:扫码授权,第三方开放平台每10分钟推送一次component_verify_ticket接受处理方法,这是controller* @author yanfei.li* @date 2017年9月26日 下午3:42:24 * @param request* @param response* @return "success"* @throws BusinessException*/@RequestMapping(value = "/platform/event/receive")@ResponseBodypublic String receiver(HttpServletRequest request, HttpServletResponse response) throws BusinessException{ try {ServletInputStream inputStream = request.getInputStream();if (inputStream != null) {String xmlData = StreamUtils.copyToString(inputStream,Charset.forName("utf-8"));String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String msgSignature = request.getParameter("msg_signature");//解密,platformToken:你要全网发布的开放平台填写的token, platformAESKey:你要全网发布的开放平台填写的加密秘钥, platformAppId:你要全网发布的开放平台的appIdWXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(platformToken, platformAESKey, platformAppId);xmlData = wxBizMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, xmlData);//下面是将component_verify_ticket 信息保存到自己的数据库,这一块应该是调用service再调用dao的,为了方便整合到一起了,自己拆分。//转换成map,XMLConverUtil是微信SDK的工具Map<String,String> xmlMap=XMLConverUtil.convertToMap(xmlData);String appId = xmlMap.get("AppId");String componentVerifyTicket = xmlMap.get("ComponentVerifyTicket");Date createTime = new Date(Long.parseLong(xmlMap.get("CreateTime"))*1000);String infoType = xmlMap.get("InfoType");String authorizerAppid = xmlMap.get("AuthorizerAppid");String authCode = xmlMap.get("AuthorizationCode");String authCodeExpiredTime = xmlMap.get("AuthorizationCodeExpiredTime");//数据库表实体初始化WechatVerifyTicketEntity verifyticket = null;verifyticket = verifyticketDao.findOne(appId, infoType);if(verifyticket == null ) {verifyticket = new WechatVerifyTicketEntity();}verifyticket.setAppId(appId);verifyticket.setCreateTime(createTime);verifyticket.setInfoType(infoType);verifyticket.setAuthorizerAppid(authorizerAppid);verifyticket.setAuthCode(authCode);verifyticket.setAuthCodeExpiredTime(authCodeExpiredTime);verifyticket.setVerifyTicket(componentVerifyTicket);//保存到数据库this.verifyticketDao.saveOrUpdate(verifyticket);}} catch (IOException | AesException e) {logger.error("/wxopen/platform/event/receive error: ", e);} //不管出没出错,都返回了success,出错信息自己查自己的日志return "success";}
消息与事件推送受理入口
/*** 功能描述:微信消息与事件推送 接受处理方法入口* @author yanfei.li* @date 2017年9月26日 下午3:44:29 * @param appid 公众号appid* @param request* @param response* @throws BusinessException*/@RequestMapping(value = "/platform/callback/{appid}")@ResponseBodypublic void callback(@PathVariable("appid") String appid, HttpServletRequest request, HttpServletResponse response) throws BusinessException{ try{ServletInputStream inputStream = request.getInputStream();if (inputStream != null) {//StreamUtils 微信SDK的工具类String xmlData = StreamUtils.copyToString(inputStream,Charset.forName("utf-8"));inputStream.close();String timestamp = request.getParameter("timestamp");String nonce = request.getParameter("nonce");String msgSignature = request.getParameter("msg_signature");//解密WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(platformToken, platformAESKey, platformAppId);xmlData = wxBizMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, xmlData);logger.info("==>receiveData=" + xmlData );EventMessage eventMessage = null;eventMessage = XMLConverUtil.convertToObject(EventMessage.class, xmlData);if("wx570bc396a51b8ff8".equals(appid)){//全网发布,wx570bc396a51b8ff8是固定的微信全网发布测试公众号appidpublishThirdPlatform(eventMessage, request, response);}else {//正常业务处理normalBusiness(appid, eventMessage, request, response);}}else {responseReplyMessage(response,"success");}}catch(Exception e){logger.error("/wxopen/platform/callback/" + appid + " error: ", e);if(!(e instanceof IOException)){try {responseReplyMessage(response,"success");} catch (IOException e1) {logger.error("/wxopen/platform/callback/" + appid + " return error: ", e1);}}else {logger.error("IOException");}}}
全网发布相关处理函数
/*** 功能描述:全网发布主函数处理入口* @author yanfei.li* @date 2017年9月26日 下午3:41:22 * @param eventMessage* @param request* @param response* @throws IOException* @throws AesException */private void publishThirdPlatform(EventMessage eventMessage,HttpServletRequest request, HttpServletResponse response) throws IOException, AesException{String event = eventMessage.getMsgType();if("event".equals(event)){replyEventMessage(request, response,eventMessage);}else if ("text".equals(eventMessage.getMsgType())) {replyTextMessage(request, response, eventMessage);}}/*** 功能描述:全网发布,步骤二、三 回复文本消息* @author yanfei.li* @date 2017年9月26日 下午4:10:56 * @param request* @param response* @param eventMessage* @throws BusinessException * @throws IOException */private void replyTextMessage(HttpServletRequest request, HttpServletResponse response, EventMessage eventMessage) throws BusinessException, IOException{if(eventMessage == null){throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "==>replyTextMessage,eventMessage is null");}String content = eventMessage.getContent();if("TESTCOMPONENT_MSG_TYPE_TEXT".equals(content)){//步骤二,回复文本消息content = content + "_callback";StringBuffer sb = new StringBuffer(); sb.append("<xml>"); sb.append("<ToUserName><![CDATA["+eventMessage.getFromUserName()+"]]></ToUserName>"); sb.append("<FromUserName><![CDATA["+eventMessage.getToUserName()+"]]></FromUserName>"); sb.append("<CreateTime>"+eventMessage.getCreateTime()+"</CreateTime>"); sb.append("<MsgType><![CDATA[text]]></MsgType>"); sb.append("<Content><![CDATA["+content+"]]></Content>");sb.append("</xml>"); String replyMsg = sb.toString();String returnValue = "";WXBizMsgCrypt pc;try {//platformToken:你要全网发布的开放平台填写的token, platformAESKey:你要全网发布的开放平台填写的加密秘钥, platformAppId:你要全网发布的开放平台的appIdpc = new WXBizMsgCrypt(platformToken, platformAESKey, platformAppId);returnValue = pc.encryptMsg(replyMsg, eventMessage.getCreateTime().toString(), request.getParameter("nonce"));responseReplyMessage(response,returnValue);} catch (AesException e) {throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "replyTextMessage",e);}}else {//步骤三,回复空字符串,然后调用客服接口发送消息String touser = eventMessage.getFromUserName();//因为是往回发,所有接收人是消息发送人,容易写错String authCode = content.replaceAll("QUERY_AUTH_CODE:", "");//authcode 用于“使用授权码换取公众号的授权信息”API,将$query_auth_code$的值赋值给API所需的参数authorization_code获取接口调用凭证。try {//直接回复""字符串responseReplyMessage(response,"");} catch (IOException e) {throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "replyTextMessage",e);}//调用客服接口发送消息//获取测试公众号接口调用凭证,接口方法实现 见最后同名方法String authorizerAccessToken = this.wechatTokenService.publishGetToken(authCode);if(authorizerAccessToken == null){throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "==>get authorizer access token failure,value is null");}//Message TextMessage是微信SDK的Message message = new TextMessage(touser,authCode+"_from_api");//发送客服消息weixin.popular.api.MessageAPI.messageCustomSend(token,JSON.toJSONString(message));}}/*** 功能描述:全网发布,步骤一回复事件消息* @author yanfei.li* @date 2017年9月26日 下午4:34:14 * @param request* @param response* @param eventMessage* @throws IOException* @throws AesException */private void replyEventMessage(HttpServletRequest request, HttpServletResponse response, EventMessage eventMessage) throws BusinessException, IOException{if(eventMessage == null){throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "==>replyEvetMessage,eventMessage is null");}String content = eventMessage.getEvent() + "from_callback";StringBuffer sb = new StringBuffer();sb.append("<xml>"); sb.append("<ToUserName><![CDATA["+eventMessage.getFromUserName()+"]]></ToUserName>"); sb.append("<FromUserName><![CDATA["+eventMessage.getToUserName()+"]]></FromUserName>"); sb.append("<CreateTime>"+eventMessage.getCreateTime()+"</CreateTime>"); sb.append("<MsgType><![CDATA[text]]></MsgType>"); sb.append("<Content><![CDATA["+content+"]]></Content>"); sb.append("</xml>"); String replyMsg = sb.toString(); String returnValue = "";WXBizMsgCrypt pc;try {//platformToken:你要全网发布的开放平台填写的token, platformAESKey:你要全网发布的开放平台填写的加密秘钥, platformAppId:你要全网发布的开放平台的appIdpc = new WXBizMsgCrypt(platformToken, platformAESKey, platformAppId);returnValue = pc.encryptMsg(replyMsg, eventMessage.getCreateTime().toString(), request.getParameter("nonce"));responseReplyMessage(response,returnValue);} catch (AesException e) {throw new BusinessException(BusinessException.ERROR_INTERNAL_SERVER_ERROR, "replyEventMessage",e);}}/*** 统一回复微信服务器 * @param response* @param content* @throws IOException*/public void responseReplyMessage(HttpServletResponse response,String content) throws IOException{PrintWriter pw = response.getWriter();pw.write(content);pw.flush();pw.close();} /*** 功能描述:获取access_token* @author yanfei.li* @date 2017年9月27日 下午2:18:24 * @param authCode* @return*/public String publishGetToken(String authCode) {if(authCode == null){logger.error("================>publishGetToken,authCode is null");return null;}//获取每十分钟推送一次的那个ticket, platformAppId:你要全网发布的开放平台的appIdString verifyTicket = this.verifyticketDao.getRecentTicket(platformAppId);if(verifyTicket == null){logger.error("================>publishGetToken,verifyTicket is null");return null;}//获取开放平台access_token,appSecret:你要全网发布的开放平台的appsecret, appId:你要全网发布的开放平台的appIdComponentAccessToken accessToken = weixin.popular.api.ComponentAPI.api_component_token(appId, appSecret, verifyTicket);if(accessToken == null){logger.error("================>publishGetToken,accessToken is null");return null;}String accessTokenStr = accessToken.getComponent_access_token();ApiQueryAuthResult queryAuth = weixin.popular.api.ComponentAPI.api_query_auth(accessToken, appId, authCode);if(queryAuth == null){logger.error("================>publishGetToken,queryAuth is null");return null;}return queryAuth.getAuthorization_info().getAuthorizer_access_token();}
结合微信SDK工具包 实现的。请忽略日志打印,不能直接复制使用,另外正常的业务处理分支没有贴出来,只贴了全网发布的。消息推送入口对全网发布和正常业务处理做了分流处理,不影响原本的项目
全网发布,开放平台注意事项
1.公众号的IP白名单只针对通过公众号的appid和secret获取access_token时有效(直接通过api接口调用https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxx&secret=xxx),如果是通过扫码授权即微信开放平台则IP白名单无效(个人推测微信开放平台在所有微信公众号的默认白名单内),最好配置IP白名单,这样在appid和secret泄露后还有一层保护,因为IP白名单的修改需要管理员扫码确认,不能直接通过这俩值获取token
2.微信开放平台全网发布前,只接受授权测试公众号列表内的授权,一旦全网发布后会支持所有微信公众的授权。IP白名单配置的是访问开放平台的服务器的IP地址,发布不发布都需要,否则会报错
3.开放平台IP白名单的修改没有在发布的范畴内,可随时更改
4.调用开放平台接口所需要的appId和secret是对应开放平台应用的,跟公众号没有关系
5.授权事件接受URL主要是每十分钟推送一次component_verify_ticket,该值用户获取开放平台的接口调用凭证的参数之一
6.开放平台的公众号消息校验Token和加解密Key可以自己定义,但一定要和我们开发配置中保持对应一致
7.公众号消息与事件接受URL会将粉丝跟公众号的互动推送到该URL,%APPID%是当前公众号的APPID
8.已经发布的开放平台内容可以更改,更改完了还需要进行一次全网发布,会有一个覆盖现有发布,需要审核,审核完成之前将继续使用上次发布的内容
微信开放平台全网发布相关推荐
- 微信开放平台全网发布时,检测失败 —— C#
主要就是三个:返回API文本消息,返回普通文本消息,发送事件消息 --会出现失败的情况 (后续补充说明:出现检测出错,不一定是代码出现了问题,也有可能是1.微信方面检测时出现服务器请求失败,2.我 ...
- 开放平台全网发布php,微信开放平台 全网发布 组件ticket检测失败
api接口文本错误的 之前我也是遇到问题 困扰几天了终于搞好了 问题是这样解决的 发现有点坑爹 他这两个接口要求的code取值不一样 第三方平台方拿到$query_auth_code$的值后,通过接口 ...
- 微信三方平台全网发布总结
相信很多第一次玩三方平台全网发布的童鞋同会遇到很多问题.这里将这两天我们在全网发布测试中遇到的问题做个总结,希望对大家有用: 在这里首先感慨一下微信有点店大欺客的感觉,文档写的确实不咋地,包括微信支付 ...
- 开放平台全网发布php,微信开放平台开发-受权、全网发布(PHP)
接着看看全网发布的测试用例怎么作: 一.模拟粉丝触发专用测试公众号的事件,并推送事件消息到专用测试公众号,第三方平台方开发者须要提取推送XML信息中的event值,并在5秒内当即返回按照下述要求组装的 ...
- java微信第三方平台全网发布(三)
在java微信第三方平台开发(二)中写了授权事件的处理,并且第三方平台代公众号发起网页授权,获取用户信息和发红包等基本业务.接下来代公众号处理消息和事件.这时候就需要用到在开发者资料中填写的公众号消息 ...
- 微信开放平台(公众号第三方平台) -- 全网发布
一.微信开放平台,第三方平台,全网发布怎么通 过? 二. 微信开放平台 全网发布 组件ticket检测失败? 解决步骤 1.将附件中的代码发布到你配置的域名下: 2.直接点全网发布: 3. ...
- 微信开放平台-第三方平台-全网发布接入【java版本】
微信给出的文档 概述 在第三方平台方创建成功并最终开发测试完毕,提交全网发布申请时,微信服务器会通过自动化测试的方式,检测服务的基础逻辑是否可用,在确保基础可用的情况下,才会允许公众号第三方平台提交全 ...
- 微信开放平台之公众号第三方平台开发及全网发布验证
技术交流请加QQ群:Jeewx微信开发④[289709451] 微信公众号第三方平台的开放,让公众号运营者在面向垂直行业需求时,可以通过一键登录授权给第三方开发者,来完成相关的处理能力,方便快捷,那如 ...
- mysql 推送微信公众号_10分钟完成微信公众号第三方平台全网发布
背景:在微信公众平台配置服务器URL时,使用了新浪云SAE自带的二级域名,提交时出现一个安全风险的警告,网上查了下,许多服务平台和团队也遇到同样的问题. 经过一番研究 - 为什么会有安全风险的警告? ...
最新文章
- 解决 PermGen space Tomcat内存设置
- scanf 接收 空格 输入_【C/C++】【输入】关于scanf:输入空格,多次使用
- Unity编译Mono
- java ftp 中文上传_java实现ftp文件上传下载,解决慢,中文乱码,多个文件下载等问题...
- 疑问:关于Microsoft Office InfoPath 2003 Toolkit for Visual Studio 2005 Beta 2
- ASP.NET Core 认证与授权[5]:初识授权
- 已知有几个数据存放在BUF为首址的字节存储区中,试统计其中正数的个数,并将结果存入ZNUM单元中。
- java int相除向上取整_java实战项目常用类,Date、Calendar、BigDecimal、Math、UUID
- 用python重构策略模式
- 工业物联网卡未来发展的优势和特点
- iOS开发,自定义字体,字体名称查询
- Android筑基——深入理解 LayoutInflater.inflate() 方法
- Windows的hosts文件在哪里?
- 怎么进行PDF合并?PDF合并方法
- 科目二经验之谈 10小时必过秘笈
- Win 10 任务栏中Google开启时出现两个Google图标
- gpasswd命令简介
- 京东科技风格 NutUI 发布了
- 对象数据如何转化成数组
- JavaScript 发明者布兰登·艾克成为 Mozilla CEO
热门文章
- 春晚的科技梦,与科技企业的春晚梦
- oracle怎么deadlock,APPARENT DEADLOCK!!! 错误解决过程
- [解决办法] Caused by: java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0
- IDEA 运行Java swing项目报错误: # Problematic frame: # C [rxtxSerial.dll+0x4465]
- pmsm simulink foc 仿真_汽车雷达场景仿真方法的研究
- java打印各种三角形
- 【论文阅读--WSOL】Spatial-Aware Token for Weakly Supervised Object Localization
- 算法刷题【一本通YbtOJ1488】新的开始
- 禅道CMS文件上传漏洞(CNVD-C-2020-121325)
- 每日学术速递5.26