[Public account development] [2] registering and constructing your own public account, which belongs to your own public account
Preface:
1, the official public number needs to apply on the public platform (https://mp.weixin.qq.com /);
You can also apply for a test number for development, test account application (https://mp.weixin.qq.com/debug/cgi-bin/sandbox? T = sandbox/login)
There are limits on the number of API calls.
I applied for the test number first (the test number has all functions, but the interface is called a few times and cannot be searched. It will expire (but I have not expired yet ))
2. There are two modes for public accounts.
Editing mode: applicable to non-programmers and information publishing accounts. The public platform is equivalent to the management background of the public account.
Development Mode: used by developers. Related functions are implemented through called interfaces. The public platform is like an interface center responsible for authorization.
3. My development environment is: Eclipse + Java + Spring
Body:
1. Test number Management
Go to the above test code URL and get the test code information,
Among them, appID and appsecret are more important.
Among them, we need to handle the following:
(1) interface configuration information
URL: the address that can be accessed externally to process interaction
Token: You can specify it as needed to keep the program consistent with the page.
(2) JS interface Security Domain Name
Domain Name: JSJDK can be called only after verification is passed under this domain name
(3) OAuth2.0 webpage authorization
User Experience interface permission table-webpage service-webpage account-webpage authorization to obtain basic user information
Authorization callback page Domain Name: it must be the same as above (the parameters included when OAuth2.0 url is used must be the same as here)
2. Basic Elements
There is no limit to calling the public account interface! (The authenticated account can reset the number of real-time calls; the number of test accounts is much less)
Two parameters (access_token, jsapi_ticket) are required for an interface call (the validity period is 7200 seconds, and the new one will invalidate the old one)
Solution:
(1) store the parameters in the properties file and read them directly during use. Restart the service and update the file every two hours.
Update:
// Load @ PostConstruct public void init () {refreshProperties ();} // update access_token and jsapi_ticket @ Scheduled (cron = "0 0 0/2 **? ") // Every two hours public void refreshProperties () {try {writeProperties (Config. crcTokenFileName, Config. appId (), Config. appSecret ();} catch (Exception e) {logger.info ("failed to update access_token and jsapi_ticket:" + e );}}
Update Data in the properties File
public static void writeProperties(String fileName, String appId, String appSecret) throws Exception { String url = "https://api.weixin.qq.com/cgi-bin/token"; String ticketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket"; String jsonStrToken = HttpRequest.sendGet(url, "grant_type=client_credential&appid="+ appId + "&secret=" + appSecret); JSONObject json = JSONObject.fromObject(jsonStrToken); String access_token = (String) json.getString("access_token"); logger.info("access_token:"+access_token); String jsonStrTicket = HttpRequest.sendGet(ticketUrl, "access_token=" + access_token + "&type=jsapi"); JSONObject ticketJson = JSONObject.fromObject(jsonStrTicket); String ticket = (String) ticketJson.get("ticket"); logger.info("ticket:"+ticket); PropertiesUtil.writeData(fileName, ACCESS_TOKEN, access_token); PropertiesUtil.writeData(fileName, JSAPI_TICKET, ticket); }
The HttpRequest. sendGet method in the preceding section (the httpRequest method is more optimized in Chapter 3, but this method can meet your needs)
// Send the public static String sendGet (String URL, String param) request for the GET Method to the specified url)
{String result = ""; BufferedReader in = null; try {String urlNameString = url + "? "+ Param; URL realUrl = new URL (urlNameString); // enable the URL connection URLConnection connection = realUrl. openConnection (); // set the common request attribute connection. setRequestProperty ("accept", "*/*"); connection. setRequestProperty ("connection", "Keep-Alive"); // create an actual connection. connect (); // obtain all response header fields Map <String, List <String> map = connection. getHeaderFields (); // traverses all response header fields for (String key: map. keySet () {logger. I Nfo (key + "--->" + map. get (key);} // defines the BufferedReader input stream to read the URL response in = new BufferedReader (new InputStreamReader (connection. getInputStream (); String line; while (line = in. readLine ())! = Null) {result + = line;} catch (Exception e) {logger.info ("an Exception occurred when sending a GET request! "+ E); e. printStackTrace () ;}// use the finally block to close the input stream finally {try {if (in! = Null) {in. close () ;}catch (Exception e2) {e2.printStackTrace () ;}} return result ;}
Read: fileName is the name of the properties file (for example, tt. properties)
public static String getAccessToken(String fileName, String appId, String appSecret) { String access_token = PropertiesUtil.readData(fileName, ACCESS_TOKEN); return access_token; } public static String getWeiXinTicket(String fileName, String appId,String appSecret) { String ticket = PropertiesUtil.readData(fileName, JSAPI_TICKET); return ticket; }
Read data from the properties File
Public static String readData (String fileName, String key) {filePath = PropertiesUtil. class. getResource ("/" + fileName ). toString (); // obtain the absolute path filePath = filePath. substring (6); // cut off the path's "file:" prefix Properties props = new Properties (); try {InputStream in = new BufferedInputStream (new FileInputStream (fileName); props. load (in); in. close (); String value = props. getProperty (key); return value;} catch (Exception e) {e. printStackTrace (); return null ;}
}
3. Code (Java)
(1) URL of interface configuration information must be verified
@ ResponseBody @ RequestMapping (value = "coreServlet", method = RequestMethod. GET) public void coreServletGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// verification address String signature = request. getParameter ("signature"); // encrypted signature String timestamp = request. getParameter ("timestamp"); // timestamp String nonce = request. getParameter ("nonce"); // random number String echostr = request. getParameter ("echostr"); // random string PrintWriter out = response. getWriter (); // verify the request by verifying signature. if the request is verified successfully, echostr is returned as is, indicating that the access is successful. Otherwise, the access fails if (Sign. checkSignature (Config. token (), signature, timestamp, nonce) {out. print (echostr);} out. close (); out = null;
}
Verify Sign. checkSignature
Public static boolean checkSignature (String token, String signature, String timestamp, String nonce) {String [] arr = new String [] {token, timestamp, nonce }; // sort the tokens, timestamp, and nonce in Lexicographic Order. sort (arr); StringBuilder content = new StringBuilder (); for (int I = 0; I <arr. length; I ++) {content. append (arr [I]);} MessageDigest md = null; String tmpStr = null; try {md = MessageDigest. getI Nstance ("SHA-1"); // concatenates three parameter strings into one string for sha1 encryption byte [] digest = md. digest (content. toString (). getBytes (); tmpStr = byteToStr (digest);} catch (NoSuchAlgorithmException e) {e. printStackTrace ();} content = null; // compares the sha1 encrypted string with signature to identify the request from return tmpStr! = Null? TmpStr. equals (signature. toUpperCase (): false;
}
// Convert the byte array to a hexadecimal String private static String byteToStr (byte [] byteArray) {String strDigest = ""; for (int I = 0; I <byteArray. length; I ++) {strDigest + = byteToHexStr (byteArray [I]);} return strDigest;} private static String byteToHexStr (byte mByte) {char [] Digit = {'0', '1', '2', '3', '4', '5', '6', '7 ', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F '}; char [] tempArr = new char [2]; tempArr [0] = Digit [(mByte >>> 4) & 0X0F]; tempArr [1] = Digit [mByte & 0X0F]; String s = new String (tempArr); return s ;}
Access CoreServlet in the browser after release. If 500 is reported
(2) JS interface Security Domain Name JS sends a request to the background for verification
Front-end JS:
$. Ajax ({type: "post", url: "/getTicket", data: {"url": wxUrl}, dataType: "json", success: function (data) {var obj = data; wx. config ({debug: false, // enable the debugging mode. The returned values of all called APIs are displayed in the client alert. To view the input parameters, you can open them on the pc, the parameter information is output through log and printed only on the pc end. AppId: obj. appId, // required. timestamp is the unique identifier of the public number. timestamp, // required. The signature timestamp nonceStr: obj. nonceStr, // required. The random string signature: obj. signature, // required, and signature. For details, see Appendix 1 jsApiList of the Development Documentation: ['selectesimage', 'previewimag', 'uploadimag', 'downloadimage'] // required, list of JS interfaces to be used. For the list of all JS interfaces, see appendix 2 });}});
Background Verification:
// Call the verification before JSJDK @ ResponseBody @ RequestMapping (value = "getTicket", method = RequestMethod. POST) public Map <String, String> getTicket (String url) throws Exception {// get jsapi_ticket, which is a temporary ticket used by the public account to call the JS interface. Under normal circumstances, jsapi_ticket is valid for 7200 seconds and obtained through access_token. String jsapi_ticket = WeixinUtil. getWeiXinTicket (Config. jow.kenfilename, Config. appId (), Config. appSecret (); // The URL is the page path Map <String, String> ret = Sign. sign (Config. appId (), jsapi_ticket, url); return ret ;}
WeixinUtil. getWeiXinTicket is the jsapi_ticket method in 2.
Sign. sign
Public static Map <String, String> sign (String appId, String jsapi_ticket, String url) {Map <String, String> ret = new HashMap <String, String> (); string nonce_str = create_nonce_str (); // random String timestamp = create_timestamp (); // The timestamp String string1; String signature = ""; // signature // note that all parameter names must be in lowercase, the string1 = "jsapi_ticket =" + jsapi_ticket + "& noncestr =" + nonce_str + "× tamp =" + timestamp + "& url =" + url; try {MessageDigest crypt = MessageDigest. getInstance ("SHA-1"); crypt. reset (); crypt. update (string1.getBytes ("UTF-8"); signature = byteToHex (crypt. digest ();} catch (NoSuchAlgorithmException e) {e. printStackTrace ();} catch (UnsupportedEncodingException e) {e. printStackTrace ();} ret. put ("url", url); ret. put ("jsapi_ticket", jsapi_ticket); ret. put ("nonceStr", nonce_str); ret. put ("timestamp", timestamp); ret. put ("signature", signature); ret. put ("appId", appId); return ret;} private static String byteToHex (final byte [] hash) {Formatter formatter = new Formatter (); for (byte B: hash) {formatter. format ("% 02x", B);} String result = formatter. toString (); formatter. close (); return result;} private static String create_nonce_str () {return UUID. randomUUID (). toString ();} private static String create_timestamp () {return Long. toString (System. currentTimeMillis ()/1000 );}