微信开放平台全网发布
来源:互联网 发布:重装系统无法安装软件 编辑:程序博客网 时间:2024/05/15 07:15
最近刚做了微信开放平台全网发布的开发,整理一下贴出来
前置条件 已经做好了相关的开发工作(比如扫码授权之类的),项目导入了微信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.已经发布的开放平台内容可以更改,更改完了还需要进行一次全网发布,会有一个覆盖现有发布,需要审核,审核完成之前将继续使用上次发布的内容
- 微信开放平台全网发布
- 微信开放平台—全网发布
- 微信开放平台全网发布61009错误处理
- [php] 微信开放平台受权和全网发布
- 微信开放平台(公众号第三方平台) -- 全网发布
- 微信开放平台之公众号第三方平台开发及全网发布验证
- 微信开放平台之公众号第三方平台开发及全网发布验证
- 微信开放平台之公众号第三方平台开发及全网发布验证
- 微信开放平台之公众号第三方平台开发及全网发布验证
- 微信开放平台之公众号第三方平台开发及全网发布验证
- 微信开放平台开发-授权、全网发布(PHP)
- 微信开放平台的流程以及最终的全网发布
- 微信开放平台的第三方平台、全网发布流程、组件API、返回普通文本消息
- 微信第三方平台全网发布流程
- 微信第三平台全网发布小结
- 微信公众号三方平台开发【全网发布及全网发布接入检测】
- 微信公众号三方平台开发【全网发布及全网发布接入检测】
- 微信开放平台
- iOS Runloop
- python 常用方法-路径处理
- WinSock2.h和windows.h发送冲突的解决方法
- C#之高级参数 ref,out,params的使用
- go语言学习-iota和<<左移>>右移的用法
- 微信开放平台全网发布
- 排查在 Azure 中创建、重启 Linux VM 或调整其大小时发生的分配故障
- Locust分布式进行性能测试
- SQL Server局域网之内远程备份数据库
- 继承
- Android Studio 插件开发详解一:入门练手
- MATLAB对三阶魔方建模并进行旋转操作
- 一条指令分条件向多个表插入数据
- html input文本输入框的一些总结