微信開放平臺的第三方平臺、全網發佈流程、組件API、返回普通文本消息

        微信開放平臺的第三方平臺全網發佈流程

1、在這裏先吐槽一下微信的開放平臺的全網發佈流程文檔。說實話:這個文檔寫的是真的不咋地!

 (1)公衆號消息校驗Token公衆號消息加解密Key、公衆號消息與事件接收URL、網頁開發域名. 這些信息都需要在微信開放平臺設置

     (2) 、 加密、解密的 代碼在微信開放平臺文檔裏面都有,自己下載即可.

2、啥也不說了,直接上代碼:

 

import java.io.BufferedReader;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.rubyeye.xmemcached.MemcachedClient;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.map.ObjectMapper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.weixin.core.aes.AesException;
import com.weixin.core.aes.WXBizMsgCrypt;
import com.weixin.scm.auth.model.PlatformParam;
import com.weixin.scm.auth.service.PlatformParamService;
import com.weixin.support.api.ProxyInterfaceApi;
import com.weixin.support.model.component.AuthorizationInfo;
import com.weixin.support.model.component.MpAuthorization;
import com.weixin.support.service.WxConfigStorageService;
import com.weixin.util.HttpClientCommonSSL;

/**
 * <p>ClassName: 測試微信 全網檢測 </p> 
 * <p>Description: 檢測通過後 才能進行全網發佈 </p>
 * @author Andy  2015年8月31日
 */
@Controller
@RequestMapping(value = "/weixinOpenCheck")
public class WeixinOpenCheckController {
	
	private static final Log log = LogFactory.getLog(WeixinOpenCheckController.class);
	
	@Autowired
	private WxConfigStorageService wxConfigStorageService;
	
	@Autowired
	private PlatformParamService platformParamService;
	
	@Autowired
	private MemcachedClient memcachedClient;
	
	
	@ResponseBody
	@RequestMapping(value = "{appid}/callback", method = RequestMethod.POST)
    public void acceptMessageAndEvent(HttpServletRequest request, HttpServletResponse response
    		,@PathVariable(value = "appid") String appId)//springMVC 獲取地址裏面的參數信息
    				throws IOException, AesException, DocumentException {
		
        log.info("進入全網發佈流程=================================================================================");
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        String msgSignature = request.getParameter("msg_signature");
        
        log.info("讀取數據爲:"+"msg_signature="+msgSignature+",  timestamp="+timestamp+",  nonce="+nonce+",  appid="+appId);
        
        if (!StringUtils.isNotBlank(msgSignature))
            return;// 微信推送給第三方開放平臺的消息一定是加過密的,無消息加密無法解密消息
 
        StringBuilder sb = new StringBuilder();
        BufferedReader in = request.getReader();
        String line;
        while ((line = in.readLine()) != null) {
            sb.append(line);
        }
        in.close();
        String xml = sb.toString(); //將xml變成字符串
        
        log.info("讀取的XML爲:"+xml);
 
        if (appId.equals("wx570bc396a51b8ff8")){// 微信自動化測試的專用測試公衆賬號
        	
        	PlatformParam component = platformParamService.selectPlatformParam();//獲取 平臺ID
        	
            WXBizMsgCrypt pc = new WXBizMsgCrypt(component.getToken(),component.getSymmetricKey(),
            												component.getComponentAppId());
            log.info("加解密======================================");
            try {
            	xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);//將xml進行加密後,和sign簽名碼進行對比,如果正確則返回xml
            	log.info("解密後:"+xml);
            	Document doc = DocumentHelper.parseText(xml);
                Element rootElt = doc.getRootElement();
                String msgType = rootElt.elementText("MsgType");
                String toUserName = rootElt.elementText("ToUserName");
                String fromUserName = rootElt.elementText("FromUserName");
                
                if(msgType.equals("event")){// 返回類型值,做一下區分
                	String event = rootElt.elementText("Event");
                	//返回時, 將發送人和接收人 調換一下即可 
                	replyEventMessage(request,response,event,fromUserName,toUserName);
                }
                
                if(msgType.equals("text")){ //標示文本消息,
                	String content = rootElt.elementText("Content");
                	//返回時, 將發送人和接收人 調換一下即可 
                	processTextMessage(request,response,content,fromUserName,toUserName);//用文本消息去拼接字符串。微信規定
                }
			} catch (AesException e) {
				log.error("錯誤碼爲: "+e.getCode());
				log.error("錯誤信息爲: "+e.getMessage());
				//應該做容錯處理
			}
        }else{
        	log.info("appid="+appId+",正確的值爲:wx570bc396a51b8ff8");
        	log.info("檢測不是微信開放平臺測試賬號,發佈程序終止.");
        }
        
    }
	
	/**
	 * 方法描述: 類型爲enevt的時候,拼接
	 * @param request
	 * @param response
	 * @param event
	 * @param toUserName  發送接收人
	 * @param fromUserName  發送人
	 * @author Andy 2015年9月1日  下午2:16:26
	 */
	public void replyEventMessage(HttpServletRequest request, HttpServletResponse response, 
					String event, String toUserName, String fromUserName) 
							throws DocumentException, IOException {
        String content = event + "from_callback";
        replyTextMessage(request,response,content,toUserName,fromUserName);
    }
	
	
	/**
	 * 方法描述: 立馬迴應文本消息並最終觸達粉絲
	 * @param content  文本
	 * @param toUserName  發送接收人
	 * @param fromUserName  發送人
	 * @author Andy 2015年8月31日  下午6:24:38
	 */
	public void processTextMessage(HttpServletRequest request, HttpServletResponse response,
					String content,String toUserName, String fromUserName) 
							throws IOException, DocumentException{
        if("TESTCOMPONENT_MSG_TYPE_TEXT".equals(content)){
            String returnContent = content+"_callback";
            replyTextMessage(request,response,returnContent,toUserName,fromUserName);
        }else if(StringUtils.startsWithIgnoreCase(content, "QUERY_AUTH_CODE")){
        	response.getWriter().print("");//需在5秒內返回空串表明暫時不回覆,然後再立即使用客服消息接口發送消息回覆粉絲
        	log.info("content:"+content+" content[1]:"+content.split(":")[1]+" fromUserName:"+fromUserName+" toUserName:"+toUserName);
            //接下來客服API再回復一次消息
        	//此時 content字符的內容爲是 QUERY_AUTH_CODE:adsg5qe4q35
            replyApiTextMessage(content.split(":")[1],toUserName);
        }
    }
	
	
	
	/**
	 * 方法描述: 直接返回給微信開放平臺
	 * @param request
	 * @param response
	 * @param content  文本
	 * @param toUserName  發送接收人
	 * @param fromUserName  發送人
	 * @author Andy 2015年9月1日  下午2:15:40
	 */
	public void replyTextMessage(HttpServletRequest request, HttpServletResponse response, 
							String content,String toUserName, String fromUserName) 
												throws DocumentException, IOException {
        Long createTime = System.currentTimeMillis() / 1000;
        StringBuffer sb = new StringBuffer(512);
        sb.append("<xml>");
        sb.append("<ToUserName><![CDATA["+toUserName+"]]></ToUserName>");
        sb.append("<FromUserName><![CDATA["+fromUserName+"]]></FromUserName>");
        sb.append("<CreateTime>"+createTime.toString()+"</CreateTime>");
        sb.append("<MsgType><![CDATA[text]]></MsgType>");
        sb.append("<Content><![CDATA["+content+"]]></Content>");
        sb.append("</xml>");
        String replyMsg = sb.toString();
        log.info("確定發送的XML爲:"+replyMsg);//千萬別加密
        returnJSON(replyMsg,response);
    }
	
	/**
	 * 方法描述: 調用客服回覆消息給粉絲
	 * @param auth_code
	 * @param fromUserName
	 * @throws DocumentException
	 * @throws IOException
	 * @return void
	 * @author Andy 2015年9月7日  上午9:48:01
	 */
	public void replyApiTextMessage(String auth_code, String fromUserName) throws DocumentException, IOException {
	        // 得到微信授權成功的消息後,應該立刻進行處理!!相關信息只會在首次授權的時候推送過來
	        String componentAccessToken= wxConfigStorageService.getComponentAccessToken();//本人平臺緩存的token
	        PlatformParam component = platformParamService.selectPlatformParam();//獲取 平臺ID
	        //https://api.weixin.qq.com/cgi-bin/component/api_query_auth  到這個微信的接口去獲取數據
	        MpAuthorization m=ProxyInterfaceApi.getInstance().mpAuthorization(componentAccessToken, component.getComponentAppId(),auth_code);
	        AuthorizationInfo info=m.getAuthorization_info();
	        String authorizer_access_token = info.getAuthorizer_access_token();
	        
	        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+authorizer_access_token;
			JSONObject json = new JSONObject();
			json.put("touser",fromUserName);
			json.put("msgtype", "text");
			json.put("text", "{\"content\":\""+auth_code+"_from_api"+"\"}");
	        
			String result = HttpClientCommonSSL.commonPostStream(url, json.toString());
	        log.info("客服發送接口返回值:"+result);
    }   
	
	
	/**
	 * 方法描述: 返回數據到請求方
	 * @param data 數據
	 * @param response
	 * @author Andy 2015年9月1日  下午1:06:54
	 */
	public void returnJSON(Object data,HttpServletResponse response) {
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			JsonEncoding encoding = JsonEncoding.UTF8;
			response.setContentType("application/json");
			org.codehaus.jackson.JsonGenerator generator = objectMapper.getJsonFactory().
									createJsonGenerator(response.getOutputStream(), encoding);
			objectMapper.writeValue(generator, data);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 方法描述:
	 * @param args
	 * @return void
	 * @author Andy 2015年8月31日  下午5:31:07
	 */
	public static void main(String[] args) {
		JSONObject j=new JSONObject();
		j.put("content", "aaa"+"_from_api");
		System.out.println(j.toString());
		System.out.println("{\"content\":\"好的_from_api\"}");
	}
	
}

3、容易出錯的點:

      (1)、組件API: 記住這地方,要去重新獲取authorizer_access_token值,發送消息的人,必須是自己,別弄錯了,不然返回錯誤碼4***3

      (2)、返回普通文本消息的時候,千萬別加密那個XML的字符串,加密就報錯.

      (3)、還有一個就是,全網發佈的時候,要將自己的外網IP填寫在 白名單裏面,不然獲取token會失敗報錯 61004

      (4)、如果幾次的測試都通過的情況下,突然有一天或者一段時間  客服發送接口返回值 出現48001,提示api沒有權限,那估計就是騰訊的服務器八成掛了,耐心的等待吧!

4、本文檔截稿日期爲 2015-09-07, 請距此時間過久的朋友閱讀時,具體以微信開放平臺官方文檔爲主! 此處僅供參考


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章