微信开放平台全网发布

最近刚做了微信开放平台全网发布的开发,整理一下贴出来


前置条件 已经做好了相关的开发工作(比如扫码授权之类的),项目导入了微信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")
	@ResponseBody
	public 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:你要全网发布的开放平台的appId
				WXBizMsgCrypt 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}")
	@ResponseBody
	public 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是固定的微信全网发布测试公众号appid
					publishThirdPlatform(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:你要全网发布的开放平台的appId
				pc = 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:你要全网发布的开放平台的appId
			pc = 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:你要全网发布的开放平台的appId
		String verifyTicket = this.verifyticketDao.getRecentTicket(platformAppId);
		if(verifyTicket == null){
			logger.error("================>publishGetToken,verifyTicket is null");
			return null;
		}
		//获取开放平台access_token,appSecret:你要全网发布的开放平台的appsecret,  appId:你要全网发布的开放平台的appId
		ComponentAccessToken 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.已经发布的开放平台内容可以更改,更改完了还需要进行一次全网发布,会有一个覆盖现有发布,需要审核,审核完成之前将继续使用上次发布的内容


转载自:https://blog.csdn.net/li_yan_fei/article/details/78111996





猜你喜欢

转载自blog.csdn.net/qq736150416/article/details/80965945
今日推荐