微信開發(4):微信第三方開放平臺的搭建(轉)

什麼是第三方開放平臺java

來波官方解釋: 
我纔是官方文檔node

簡單的說,就是讓公衆號受權給第三個開放平臺,根據受權不一樣,第三開放平臺能夠獲取到該公衆號的接口權限,從而直接調用微信api,進行公衆號開發;web

開通建立流程 spring

開發者資質審覈經過後,就能夠建立第三方開放平臺了,因爲咱們第三方開放平臺已經創建了。就不演示建立平臺的過程了,下面解釋下填寫的資料apache

  1. 第一步基本資料填寫,不作多餘說明,填寫基本資料便可
  2. 第二步選擇權限集,大概意思就是 選擇下 你這個第三方開放平臺 要代替公衆號實現那些業務 獲取公衆號的那些接口權限,須要注意的是首先要確保該公衆號已經有了這個權限 我是官方文檔
  3. 第三步是填寫開發資料,基本上就是域名,白名單一些的配置了 這裏官方文檔寫的也比較清楚 不懂看這裏

開始開發
首先要作的 是受權事件接收URL的處理,用於接收取消受權通知、受權成功通知、受權更新通知,也用於接收ticket,ticket是驗證平臺方的重要憑據,服務方在獲取component_access_token時須要提供最新推送的ticket以供驗證身份合法性。此ticket做爲驗證服務方的重要憑據,請妥善保存。api

權限變動這些能夠先不考慮,先考慮的是 接受這個ticket,只有擁有了ticket才能去換取第三方平臺的token
下面是主要代碼。實體類這些不提供了,根據需求能夠自行建立緩存

  1  package com.ysh.wxtest.controller;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.IOException;
  5 import java.io.PrintWriter;
  6 import java.security.MessageDigest;
  7 import java.security.NoSuchAlgorithmException;
  8 import java.util.Arrays;
  9 import java.util.Date;
 10 import java.util.List;
 11 
 12 import javax.servlet.http.HttpServletRequest;
 13 import javax.servlet.http.HttpServletResponse;
 14 import javax.servlet.http.HttpSession;
 15 import javax.websocket.Session;
 16 
 17 import org.apache.commons.lang.StringUtils;
 18 import org.dom4j.Document;
 19 import org.dom4j.DocumentException;
 20 import org.dom4j.DocumentHelper;
 21 import org.dom4j.Element;
 22 import org.springframework.beans.factory.annotation.Autowired;
 23 import org.springframework.stereotype.Controller;
 24 import org.springframework.web.bind.annotation.RequestMapping;
 25 import org.springframework.web.bind.annotation.ResponseBody;
 26 import org.springframework.web.servlet.ModelAndView;
 27 
 28 import com.qq.weixin.mp.aes.AesException;
 29 import com.qq.weixin.mp.aes.WXBizMsgCrypt;
 30 import com.ysh.wxtest.model.Users;
 31 import com.ysh.wxtest.model.Wxauthinfo;
 32 import com.ysh.wxtest.model.Wxauthorizerinfo;
 33 import com.ysh.wxtest.model.Wxcomtoken;
 34 import com.ysh.wxtest.model.Wxticket;
 35 import com.ysh.wxtest.service.WxauthinfoService;
 36 import com.ysh.wxtest.service.WxauthorizerinfoService;
 37 import com.ysh.wxtest.service.WxcomtokenService;
 38 import com.ysh.wxtest.service.WxticketService;
 39 import com.ysh.wxtest.util.AjaxMessage;
 40 
 41 import common.Logger;
 42 import weixin.popular.bean.component.*;
 43 import weixin.popular.util.XMLConverUtil;
 44 
 45 
 46 /**
 47  * 微信 第三方開放平臺  controller層
 48  * @author YaoShiHang
 49  *
 50  */
 51 @Controller
 52 public class WeixinAccreditController {
 53 
 54     @Autowired
 55     private WxticketService  wxticketService;   //微信推送 ticket服務,用於保存 ticket
 56     @Autowired
 57     private WxcomtokenService wxcomtokenService; //微信第三方平臺  token服務 ,有效期2小時。獲取次數有限 注意緩存
 58     @Autowired
 59     private WxauthinfoService wxauthinfoService; //微信受權信息 服務   
 60     @Autowired
 61     private WxauthorizerinfoService WxinfoService; 
 62 
 63     private final String APPID = "???";
 64 
 65     private Logger log= Logger.getLogger(getClass());
 66 
 67     /**
 68      * 微信全網測試帳號
 69      */
 70     private final static String COMPONENT_APPID = "XXXXXXXXXXXX"; //第三方平臺 APPID
 71     private final String COMPONENT_APPSECRET = "XXXXXXXXXXXX";    //第三方平臺 祕鑰
 72     private final static String COMPONENT_ENCODINGAESKEY = "XXXXXXXXXXXX";  //開發者 設置的 key
 73     private final static String COMPONENT_TOKEN = "XXXXXXXXXXXX";   //開發者 設置的 token 
 74 
 75     // 受權事件接受url 每隔10分鐘 獲取微信服務器推送ticket 接收後須要解密 接收到後 必須返回字符串success
 76     @RequestMapping("/openwx/getticket")
 77     public void getTicket(HttpServletRequest request, HttpServletResponse response)
 78             throws IOException, DocumentException, AesException {
 79         processAuthorizeEvent(request);
 80         output(response, "success"); // 輸出響應的內容。
 81     }
 82 
 83     /**
 84      *  受權事件處理 
 85      * @param request
 86      * @throws IOException
 87      * @throws DocumentException
 88      * @throws AesException
 89      */
 90     public void processAuthorizeEvent(HttpServletRequest request) throws IOException, DocumentException, AesException {
 91         String nonce = request.getParameter("nonce");
 92         String timestamp = request.getParameter("timestamp");
 93         String signature = request.getParameter("signature");
 94         String msgSignature = request.getParameter("msg_signature");
 95         HttpSession session  = request.getSession();
 96         if (!StringUtils.isNotBlank(msgSignature)){ //判斷消息是否空
 97             return;// 微信推送給第三方開放平臺的消息必定是加過密的,無消息加密沒法解密消息
 98         }
 99         boolean isValid = checkSignature(COMPONENT_TOKEN, signature, timestamp, nonce);
100         if (isValid) {
101             StringBuilder sb = new StringBuilder();
102             BufferedReader in = request.getReader();
103             String line;
104             while ((line = in.readLine()) != null) {
105                 sb.append(line);
106             }
107             String xml = sb.toString();
108               log.info("第三方平臺全網發佈-----------------------原始 Xml="+xml);
109             String encodingAesKey = COMPONENT_ENCODINGAESKEY;// 第三方平臺組件加密密鑰
110             String appId =  (xml);// 此時加密的xml數據中ToUserName是非加密的,解析xml獲取便可
111                log.info("第三方平臺全網發佈-------------appid----------getAuthorizerAppidFromXml(xml)-----------appId="+appId);
112             WXBizMsgCrypt pc = new WXBizMsgCrypt(COMPONENT_TOKEN, encodingAesKey, COMPONENT_APPID);
113             xml = pc.decryptMsg(msgSignature, timestamp, nonce, xml);
114                log.info("第三方平臺全網發佈-----------------------解密後 Xml="+xml);
115             ComponentReceiveXML com = XMLConverUtil.convertToObject(ComponentReceiveXML.class, xml);
116             session.setAttribute("com",com);
117             processAuthorizationEvent(xml);
118         }
119     }
120     /**
121      * 保存Ticket
122      * @param xml
123      */
124     void processAuthorizationEvent(String xml) {
125         Document doc;
126 
127         try {
128             doc = DocumentHelper.parseText(xml);
129             Element rootElt = doc.getRootElement();
130             String ticket = rootElt.elementText("ComponentVerifyTicket");
131             if(ticket!=null){
132                 Wxticket wxticket = new Wxticket();
133                 wxticket.setAppid(APPID);
134                 wxticket.setAddtime(new Date());;
135                 wxticket.setId(1l);
136                 wxticket.setTicket(ticket);
137                 wxticketService.updateNotNull(wxticket);
138             }
139         } catch (DocumentException e) {
140             e.printStackTrace();
141         }
142     }
143 
144     String getAuthorizerAppidFromXml(String xml) {
145         Document doc;
146         try {
147             doc = DocumentHelper.parseText(xml);
148             Element rootElt = doc.getRootElement();
149             String toUserName = rootElt.elementText("ToUserName");
150             return toUserName;
151         } catch (DocumentException e) {
152             // TODO Auto-generated catch block
153             e.printStackTrace();
154         }
155         return null;
156     }
157 
158     /**
159      * 判斷消息是否加密
160      * @param token
161      * @param signature
162      * @param timestamp
163      * @param nonce
164      * @return
165      */
166     public static boolean checkSignature(String token, String signature, String timestamp, String nonce) {
167         System.out.println(
168                 "###token:" + token + ";signature:" + signature + ";timestamp:" + timestamp + "nonce:" + nonce);
169         boolean flag = false;
170         if (signature != null && !signature.equals("") && timestamp != null && !timestamp.equals("") && nonce != null
171                 && !nonce.equals("")) {
172             String sha1 = "";
173             String[] ss = new String[] { token, timestamp, nonce };
174             Arrays.sort(ss);
175             for (String s : ss) {
176                 sha1 += s;
177             }
178             sha1 = AddSHA1.SHA1(sha1);
179             if (sha1.equals(signature)) {
180                 flag = true;
181             }
182         }
183         return flag;
184     }
185     /**
186      * 工具類:回覆微信服務器"文本消息"
187      * @param response
188      * @param returnvaleue
189      */
190     public void output(HttpServletResponse response, String returnvaleue) {
191         try {
192             PrintWriter pw = response.getWriter();
193             pw.write(returnvaleue);
194             System.out.println("****************returnvaleue***************="+returnvaleue);
195             pw.flush();
196         } catch (IOException e) {
197             e.printStackTrace();
198         }
199     }
200 
201 }
202 
203 class AddSHA1 {
204     public static String SHA1(String inStr) {
205         MessageDigest md = null;
206         String outStr = null;
207         try {
208             md = MessageDigest.getInstance("SHA-1"); // 選擇SHA-1,也能夠選擇MD5
209             byte[] digest = md.digest(inStr.getBytes()); // 返回的是byet[],要轉化爲String存儲比較方便
210             outStr = bytetoString(digest);
211         } catch (NoSuchAlgorithmException nsae) {
212             nsae.printStackTrace();
213         }
214         return outStr;
215     }
216     public static String bytetoString(byte[] digest) {
217         String str = "";
218         String tempStr = "";
219         for (int i = 0; i < digest.length; i++) {
220             tempStr = (Integer.toHexString(digest[i] & 0xff));
221             if (tempStr.length() == 1) {
222                 str = str + "0" + tempStr;
223             } else {
224                 str = str + tempStr;
225             }
226         }
227         return str.toLowerCase();
228     }
229 }

提供一個xml 解析工具類服務器

  1 import java.io.IOException;
  2 import java.io.InputStream;
  3 import java.io.InputStreamReader;
  4 import java.io.Reader;
  5 import java.io.StringReader;
  6 import java.io.StringWriter;
  7 import java.io.Writer;
  8 import java.util.HashMap;
  9 import java.util.LinkedHashMap;
 10 import java.util.Map;
 11 
 12 import javax.xml.bind.JAXBContext;
 13 import javax.xml.bind.JAXBException;
 14 import javax.xml.bind.Marshaller;
 15 import javax.xml.bind.Unmarshaller;
 16 import javax.xml.parsers.DocumentBuilder;
 17 import javax.xml.parsers.DocumentBuilderFactory;
 18 import javax.xml.parsers.ParserConfigurationException;
 19 
 20 import org.w3c.dom.DOMException;
 21 import org.w3c.dom.Document;
 22 import org.w3c.dom.Element;
 23 import org.w3c.dom.Node;
 24 import org.w3c.dom.NodeList;
 25 import org.xml.sax.InputSource;
 26 import org.xml.sax.SAXException;
 27 
 28 import com.sun.xml.bind.marshaller.CharacterEscapeHandler;
 29 
 30 /**
 31  * XML 數據接收對象轉換工具類
 32  * @author LiYi
 33  *
 34  */
 35 public class XMLConverUtil{
 36 
 37     private static final ThreadLocal<Map<Class<?>,Marshaller>> mMapLocal = new ThreadLocal<Map<Class<?>,Marshaller>>() {
 38         @Override
 39         protected Map<Class<?>, Marshaller> initialValue() {
 40             return new HashMap<Class<?>, Marshaller>();
 41         }
 42     };
 43 
 44     private static final ThreadLocal<Map<Class<?>,Unmarshaller>> uMapLocal = new ThreadLocal<Map<Class<?>,Unmarshaller>>(){
 45         @Override
 46         protected Map<Class<?>, Unmarshaller> initialValue() {
 47             return new HashMap<Class<?>, Unmarshaller>();
 48         }
 49     };
 50 
 51     /**
 52      * XML to Object
 53      * @param <T> T
 54      * @param clazz clazz
 55      * @param xml xml
 56      * @return T
 57      */
 58     public static <T> T convertToObject(Class<T> clazz,String xml){
 59         return convertToObject(clazz,new StringReader(xml));
 60     }
 61 
 62     /**
 63      * XML to Object
 64      * @param <T> T
 65      * @param clazz clazz
 66      * @param inputStream  inputStream
 67      * @return T
 68      */
 69     public static <T> T convertToObject(Class<T> clazz,InputStream inputStream){
 70         return convertToObject(clazz,new InputStreamReader(inputStream));
 71     }
 72 
 73     /**
 74      * XML to Object
 75      * @param <T> T
 76      * @param clazz clazz
 77      * @param reader reader
 78      * @return T
 79      */
 80     @SuppressWarnings("unchecked")
 81     public static <T> T convertToObject(Class<T> clazz,Reader reader){
 82         try {
 83             Map<Class<?>, Unmarshaller> uMap = uMapLocal.get();
 84             if(!uMap.containsKey(clazz)){
 85                 JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
 86                 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
 87                 uMap.put(clazz, unmarshaller);
 88             }
 89             return (T) uMap.get(clazz).unmarshal(reader);
 90         } catch (JAXBException e) {
 91             e.printStackTrace();
 92         }
 93         return null;
 94     }
 95 
 96     /**
 97      * Object to XML
 98      * @param object object
 99      * @return xml
100      */
101     public static String convertToXML(Object object){
102         try {
103             Map<Class<?>, Marshaller> mMap = mMapLocal.get();
104             if(!mMap.containsKey(object.getClass())){
105                 JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
106                 Marshaller marshaller = jaxbContext.createMarshaller();
107                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
108                 //設置CDATA輸出字符
109                 marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() {
110                     public void escape(char[] ac, int i, int j, boolean flag, Writer writer) throws IOException {
111                         writer.write(ac, i, j);
112                     }
113                 });
114                 mMap.put(object.getClass(), marshaller);
115             }
116             StringWriter stringWriter = new StringWriter();
117             mMap.get(object.getClass()).marshal(object,stringWriter);
118             return stringWriter.getBuffer().toString();
119         } catch (JAXBException e) {
120             e.printStackTrace();
121         }
122         return null;
123     }
124 
125     /**
126      * 轉換簡單的xml to map
127      * @param xml xml
128      * @return map
129      */
130     public static Map<String,String> convertToMap(String xml){
131         Map<String, String> map = new LinkedHashMap<String,String>();
132         try {
133             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
134             DocumentBuilder db = dbf.newDocumentBuilder();
135             StringReader sr = new StringReader(xml);
136             InputSource is = new InputSource(sr);
137             Document document = db.parse(is);
138 
139             Element root = document.getDocumentElement();
140             if(root != null){
141                 NodeList childNodes = root.getChildNodes();
142                 if(childNodes != null && childNodes.getLength()>0){
143                     for(int i = 0;i < childNodes.getLength();i++){
144                         Node node = childNodes.item(i); 
145                         if( node != null && node.getNodeType() == Node.ELEMENT_NODE){
146                             map.put(node.getNodeName(), node.getTextContent());
147                         }
148                     }
149                 }
150             }
151         } catch (DOMException e) {
152             e.printStackTrace();
153         } catch (ParserConfigurationException e) {
154             e.printStackTrace();
155         } catch (SAXException e) {
156             e.printStackTrace();
157         } catch (IOException e) {
158             e.printStackTrace();
159         }
160         return map;
161     }
162 }

這一步結束後 第三方開放平臺就能夠審覈經過了。而後就是進行代公衆號實現業務了,相對來講簡單了不少,微信提供的都有相關文檔。直接調用接口就好了。須要注意的是在首先要確保公衆號獲取了這個權限,其次確保公衆號把這個權限受權給了第三方平臺。在開發中代公衆號實現網頁受權的接口 假如使用第三方開放平臺的話,接口地址是有所改變的,參考第三方開放平臺開發文檔,其餘的接口 只需將原來公衆號的token 改變爲 經過第三方開放平臺token 獲取的公衆號受權給第三方開放平臺的token 兩個token是不同的。有效期都是2小時 須要緩存。最後上一波成功圖片
微信

 

 

相關文章
相關標籤/搜索