In the previous article "development learning summary (1) -- Development environment setup", we have completed the development preparations. after the preparation is complete, we will begin to get started. In the previous article "development-development environment setup", we have completed the development preparations. after the preparation is complete, we will begin to step into the topic.
I. basic principles of the public platform
Before proceeding, I briefly introduced the basic principles of the public platform.
A server is equivalent to a forwarding server. a terminal (such as a mobile phone or tablet) initiates a request to the server, which then forwards the request to our application server. After the application server completes processing, it sends the response data back to the server, and then the server replies the specific response information to the App terminal.
The communication protocol is HTTP.
The data transmission format is XML.
The specific process is shown in:
Compile a servlevt and define the verification method in the doGet method. the specific code is as follows:
Package me. gacl. wx. web. servlet; import javax. servlet. servletException; import javax. servlet. annotation. webServlet; import javax. servlet. http. httpServlet; import javax. servlet. http. httpServletRequest; import javax. servlet. http. httpServletResponse; import java. io. IOException; import java. security. messageDigest; import java. security. noSuchAlgorithmException; import java. util. arrays;/*** Created by xdp on 2016 /1/25. * use the @ WebServlet annotation to configure WxServlet. the urlPatterns attribute specifies the access path of WxServlet */@ WebServlet (urlPatterns = "/WxServlet ") public class WxServlet extends HttpServlet {/*** Token can be filled by the developer at will to generate a signature (this Token will be compared with the Token contained in the interface URL to verify security) * for example, here I set Token to gacl */private final String TOKEN = "gacl"; protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {} p Rotected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System. out. println ("start verifying the signature");/*** four parameters passed when receiving a request from the server */String signature = request. getParameter ("signature"); // The encrypted signature combines the token parameter entered by the developer with the timestamp parameter and nonce parameter in the request. String timestamp = request. getParameter ("timestamp"); // timestamp String nonce = request. getParameter ("nonce"); // random number String echostr = request. getParameter ("echostr"); // random String // sort String sortString = sort (TOKEN, timestamp, nonce); // encrypted String mySignature = sha1 (sortString ); // verify the signature if (mySignature! = Null & mySignature! = "" & MySignature. equals (signature) {System. out. println ("signature verification passed. "); // If the echostr output is successful, the server receives the output to confirm that the verification is complete. // Response. getWriter (). println (echostr); response. getWriter (). write (echostr);} else {System. out. println ("signature verification failed. ") ;}}/*** sorting method ** @ param token * @ param timestamp * @ param nonce * @ return */public String sort (String token, String timestamp, string nonce) {String [] strArray = {token, timestamp, nonce}; Arrays. sort (strArray); StringBuilder sb = new StringBuilder (); for (String str: strArray) {sb. append (str);} return sb. toString ();}/*** encrypt the String with sha1 ** @ param str the String to be encrypted * @ return the encrypted content */public String sha1 (String str) {try {MessageDigest digest = MessageDigest. getInstance ("SHA-1"); digest. update (str. getBytes (); byte messageDigest [] = digest. digest (); // Create Hex String StringBuffer hexString = new StringBuffer (); // converts a byte array to a hexadecimal number for (int I = 0; I <messageDigest. length; I ++) {String shaHex = Integer. toHexString (messageDigest [I] & 0xFF); if (shaHex. length () <2) {hexString. append (0);} hexString. append (shaHex);} return hexString. toString ();} catch (NoSuchAlgorithmException e) {e. printStackTrace ();} return "";}}
I use Servlet3.0 here. the advantage of using Servlet3.0 is that the @ WebServlet annotation can be directly used to map the Servlet access path and no longer need to be configured in the web. xml file.
Deploy the WxStudy project to the Tomcat server to run it. start the project directly and use ngrok to map the local port 8080 to the Internet. (for how to use ngrok, see the development-development environment building blog.) As shown in:
The following describes how to implement the above ideas in the project. because the returned data is in json format, Alibaba's fastjson library is used here, it provides support for data serialization and deserialization after request construction and processing.
1. define an AccessToken object class
Package me. gacl. wx. entry;/*** AccessToken data model * Created by xdp on. */public class AccessToken {// The obtained credential private String accesresien; // The validity period of the credential. unit: Second private int expiresin; public String getAccessToken () {return accesresien ;} public void setAccessToken (String accessToken) {this. accessToken = accessToken;} public int getExpiresin () {return expiresin;} public void setExpiresin (int expiresin) {this. expiresin = expiresin ;}}
2. define an AccessTokenInfo class to store the obtained AccessToken. the code is as follows:
Package me. gacl. wx. common; import me. gacl. wx. entry. accessToken;/*** Created by xdp on 2016/1/25. */public class AccessTokenInfo {// note that the static public static AccessToken accessToken = null ;}
3. compile a tool class NetWorkHelper for initiating https requests. the code is as follows:
Package me. gacl. wx. util; import javax.net. ssl. *; import java. io. bufferedReader; import java. io. inputStream; import java. io. inputStreamReader; import java.net. URL; import java. security. cert. certificateException; import java. security. cert. x509Certificate; /*** tool class used to access the network */public class NetWorkHelper {/*** initiate an Https request * @ param reqUrl the URL of the request * @ param requestMethod * @ return string */public String getHttps Response (String reqUrl, String requestMethod) {URL url; InputStream is; String resultData = ""; try {url = new URL (reqUrl); HttpsURLConnection con = (HttpsURLConnection) url. openConnection (); TrustManager [] tm = {xtm}; SSLContext ctx = SSLContext. getInstance ("TLS"); ctx. init (null, tm, null); con. setSSLSocketFactory (ctx. getSocketFactory (); con. setHostnameVerifier (new HostnameVerifier () {@ Overri De public boolean verify (String arg0, SSLSession arg1) {return true ;}}); con. setDoInput (true); // allow input stream, that is, allow download // this item must be set to false con in android. setDoOutput (false); // allows the output stream, that is, allows the upload of con. setUseCaches (false); // if (null! = RequestMethod &&! RequestMethod. equals ("") {con. setRequestMethod (requestMethod); // use the specified method} else {con. setRequestMethod ("GET"); // use get request} is = con. getInputStream (); // get the input stream. in this case, the link InputStreamReader isr = new InputStreamReader (is); BufferedReader bufferReader = new BufferedReader (isr); String inputLine; while (inputLine = bufferReader. readLine ())! = Null) {resultData + = inputLine + "\ n";} System. out. println (resultData);} catch (Exception e) {e. printStackTrace ();} return resultData;} X509TrustManager xtm = new X509TrustManager () {@ Override public X509Certificate [] getAcceptedIssuers () {return null ;} @ Override public void checkServerTrusted (writable [] arg0, String arg1) throws CertificateException {}@ Override public void checkClientTrusted (writable [] arg0, String arg1) throws CertificateException {}};}
The getHttpsResponse method is used to request an https address. the requestMethod parameter is the string "GET" or "POST". The default value of null or "" is get.
4. define a default started servlet and start a new thread in the init method to obtain the accessToken.
Package me. gacl. wx. web. servlet; import com. alibaba. fastjson. JSON; import com. alibaba. fastjson. JSONObject; import me. gacl. wx. common. accessTokenInfo; import me. gacl. wx. entry. accessToken; import me. gacl. wx. util. netWorkHelper; import javax. servlet. servletException; import javax. servlet. annotation. webInitParam; import javax. servlet. annotation. webServlet; import javax. servlet. http. httpServlet;/*** used to obtain the accessToke N Servlet * Created by xdp on 2016/1/25. * // @ WebServlet (name = "AccessTokenServlet", urlPatterns = {"/AccessTokenServlet"}, loadOnStartup = 1, initParams = {@ WebInitParam (name = "appId ", value = "secret"), @ WebInitParam (name = "appSecret", value = "secret")}) public class AccessTokenServlet extends HttpServlet {@ Override public void init () throws ServletExce Ption {System. out. println ("start WebServlet"); super. init (); final String appId = getInitParameter ("appId"); final String appSecret = getInitParameter ("appSecret"); // start a new Thread (new Runnable () {@ Override public void run () {while (true) {try {// Obtain accesen en AccessTokenInfo. accessToken = getAccessToken (appId, appSecret); // if (AccessTokenInfo. accessToken! = Null) {// Get the access_token to sleep for 7000 seconds, about 2 hours. sleep (7000*1000); // Thread. sleep (10*1000); // get once in 10 seconds} else {// Get failed Thread. sleep (1000*3); // The obtained access_token is null and sleep for 3 seconds} catch (Exception e) {System. out. println ("exception:" + e. getMessage (); e. printStackTrace (); try {Thread. sleep (1000*10); // 1 second when an Exception occurs} catch (Exception e1 ){}}}}}). start ();}/*** get access_token ** @ return AccessToken */private accesen en getAccessToken (String appId, String appSecret) {NetWorkHelper netHelper = new NetWorkHelper (); /*** the interface address is https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET , Where grant_type is fixed to client_credential. */String Url = String. format (" https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s ", AppId, appSecret); // This request is an https get request. the returned data format is {" access_token ":" ACCESS_TOKEN "," expires_in ": 7200} String result = netHelper. getHttpsResponse (Url, ""); System. out. println ("obtained access_token =" + result); // use FastJson to parse the Json string into a Json object JSONObject json = JSON. parseObject (result); AccessToken token = new AccessToken (); token. setAccessToken (json. getString ("access_token"); token. setExpiresin (json. getInteger ("expires_in"); return token ;}}
The AccessTokenServlet is configured with annotations.
After the code implementation is complete, deploy the project. the console output is as follows:
To make it easier to see the effect, you can set the sleep time to a little shorter, for example, once every 10 seconds, and then output the access_token.
The following is a test jsp page and sets the sleep time to 10 seconds. after 10 seconds, refresh the page and you will see the changes.
<% -- Created by IntelliJ IDEA. -- %> <% @ page contentType = "text/html; charset = UTF-8" language = "java" %> <% @ page import = "me. gacl. wx. common. accessTokenInfo "%> Learning
Access_token: <% = AccessTokenInfo. accessToken. getAccessToken () %>
4. receive and respond to messages sent by the server
After the above three steps, we have completed the preparations before the development. The next step is to receive and respond to the messages sent by the server.
You can see from the public platform interface message guide that when a user sends a message to a public account, the server will submit the message to the URL we entered in the interface configuration information through the POST method, however, we need to receive, process, and respond to messages in the doPost method of the WxServlet request processing class pointed to by the URL.
. Compile a tool class for processing messages
Compile the toolbar for message processing. the tool code is as follows:
Package me. gacl. wx. util; import org. dom4j. document; import org. dom4j. element; import org. dom4j. io. SAXReader; import javax. servlet. http. httpServletRequest; import java. io. inputStream; import java. text. dateFormat; import java. text. simpleDateFormat; import java. util. date; import java. util. hashMap; import java. util. list; import java. util. map;/*** message processing tool class * Created by xdp on 2016/1/26. */public class MessageHandlerUtil {/*** parse the request (XML) * @ param request * @ return map * @ throws Exception */public static Map
ParseXml (HttpServletRequest request) throws Exception {// store the parsing result in the HashMap Map
Map = new HashMap (); // Obtain the input stream InputStream inputStream = request from the request. getInputStream (); System. out. println ("Get input stream"); // read the input stream SAXReader reader = new SAXReader (); Document document = reader. read (inputStream); // Get the xml root Element root = document. getRootElement (); // obtain the List of all child nodes of the root element.
ElementList = root. elements (); // traverse all subnodes for (Element e: elementList) {System. out. println (e. getName () + "|" + e. getText (); map. put (e. getName (), e. getText ();} // release the resource inputStream. close (); inputStream = null; return map;} // Construct the public static String buildXml (Map
Map) {String result; String msgType = map. get ("MsgType "). toString (); System. out. println ("MsgType:" + msgType); if (msgType. toUpperCase (). equals ("TEXT") {result = buildTextMessage (map, "lone wolf was developed in learning and summarizing to build a TEXT message: Hello World! ");} Else {String fromUserName = map. get ("FromUserName"); // developer id String toUserName = map. get ("ToUserName"); result = String. format ("
"+"
%s
"+"
%s
"+"
% S
"+"
text
"+"
%s
"+"
", FromUserName, toUserName, getUtcTime ()," Please reply the following keywords: \ n text \ n Image \ n voice \ n Video \ n music \ n Image ");} return result;}/*** construct a text message ** @ param map * @ param content * @ return */private static String buildTextMessage (Map
Map, String content) {// sender account String fromUserName = map. get ("FromUserName"); // developer id String toUserName = map. get ("ToUserName");/*** text message XML data format *
toUser
fromUser
1348831860
text
this is a test
1234567890123456
*/Return String. format ("
"+"
%s
"+"
%s
"+"
% S
"+"
text
"+"
%s
"+"
", FromUserName, toUserName, getUtcTime (), content);} private static String getUtcTime () {Date dt = new Date (); // if the format is not required, dt can be used directly. dt is the current system time DateFormat df = new SimpleDateFormat ("yyyyMMddhhmm"); // you can set the display format String nowTime = df. format (dt); long dd = (long) 0; try {dd = df. parse (nowTime ). getTime ();} catch (Exception e) {} return String. valueOf (dd );}}
To facilitate parsing the xml format data that the server sends to us, here we use the open source framework dom4j to parse xml (the dom4j-2.0.0-RC1.jar is used here)
. Process the request in the doPost method of WxServlet
The doPost method code of WxServlet is as follows:
/*** Process the message sent from the server */protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO receive, process, and respond to messages sent to a public account by the server-forwarded user // the request and response encoding is set to UTF-8 (to prevent Chinese garbled characters) request. setCharacterEncoding ("UTF-8"); response. setCharacterEncoding ("UTF-8"); System. out. println ("request to enter"); String result = ""; try {Map
Map = MessageHandlerUtil. parseXml (request); System. out. println ("start to construct a message"); result = MessageHandlerUtil. buildXml (map); System. out. println (result); if (result. equals ("") {result = "incorrect response" ;}} catch (Exception e) {e. printStackTrace (); System. out. println ("exception:" + e. getMessage ();} response. getWriter (). println (result );}
At this point, our WxServlet can normally process user requests and respond to them. Next, let's test whether the developed public account application can interact with users normally.
Deploy WxStudy on the Tomcat server and start the server. remember to use ngrok to map port 8080 of the local Tomcat server to the Internet to ensure the URL of interface configuration information: http://xdp.ngrok.natapp.cn/wxservletcan communicate with the server normally
Log on to the management background of our test public account, and scan the QR code of the test number, as shown in:
The XML data of the text message that our public account app responds to users is as follows:
ojADgs0eDaqh7XkTM9GvDmdYPoDw
gh_43df3882c452
1453755900000
text
孤傲苍狼在学习和总结开发了,构建一条文本消息:Hello World!
You can also see the list of users who follow the Test number in the management background of the test public number, as shown in:
Through this simple Getting Started program, we unveil the secret of development.
For more articles on getting started with development, refer to the Chinese PHP website!