Java implementation SPRINGMVC mode of micro-letter access, implementation of message automatic reply instance _java

Source: Internet
Author: User
Tags sha1 sha1 encryption

A little busy a while ago, the development of micro-letter public number, from scratch to see the document, stepped on a lot of pits, is also a boil over, and recently consider doing some summary, convenient later development of the time to review, but also to do the relevant project students to make a reference.

1. Thinking

Micro-Credit Access: User messages and developers need the event to push through the micro-client server to initiate a request, forwarded to your public platform configuration of the server URL address, the micro-trust will be taken with signature,timestamp,nonce,echostr four parameters, Our own server through the Mosaic public platform configuration of the token, as well as the timestamp,nonce SHA1 encrypted after the match signature, return ture to explain the successful access.

Message reply: When the user sends a message to the public number, the micro-server will send the user message in XML format to the interface of our configured server, and what we do is to do the corresponding logical processing according to the message type, etc. The final return result is also returned to the micro-trust server through the XML format, which is communicated to the user by the micro-signaling process.

1. Public platform Configuration

2.Controller

@Controller @RequestMapping ("/wechat") Publicclass Wechatcontroller {@Value ("${dnbx_token}") Private String Dnbx_tok
  
  EN;
  
  private static final Logger Logger = Loggerfactory.getlogger (Wechatcontroller.class);
  
  @Resource Wechatservice Wechatservice; /** * Micro-letter Access * @param WC * @return * @throws IOException/@RequestMapping (value= "/connect", method = {Req Uestmethod.get, requestmethod.post}) @ResponseBody publicvoid connectweixin (httpservletrequest request, HttpServletResponse response) throws ioexception{//The encoding of the request and response is set to UTF-8 (prevent Chinese garbled) request.setcharacterencoding ("UTF -8 "); Micro-trust server post message with the UTF-8 code, in the receiver will also use the same code, otherwise Chinese will garbled; response.setcharacterencoding ("UTF-8"); 
   
    In response to a message (reply to the message to the user), the encoding is also set to UTF-8, the principle above, Boolean isget = Request.getmethod (). toLowerCase (). Equals ("get");
     
    PrintWriter out = Response.getwriter (); try {if (isget) {string signature = Request.getparameter ("signature");//micro-letter encrypted signature string timestamp = Request.getparameter ("timestamp");//timestamp string nonce = Request.getparameter ("nonce");//random number string E  Chostr = Request.getparameter ("Echostr");//random string//Check the request through the test signature, if the validation is successful then return to the original ECHOSTR, indicating the success of the access, or access failure  if (Signutil.checksignature (Dnbx_token, signature, timestamp, nonce)) {Logger.info ("Connect the" Weixin server
          is successful. "); 
        Response.getwriter (). write (ECHOSTR); 
        else {logger.error ("Failed to verify the signature!"); }}else{String respmessage = "Exception message!
        
        ";
          try {respmessage = wechatservice.weixinpost (request);
          Out.write (Respmessage);
          Logger.info ("The request completed successfully");
        Logger.info ("to Weixin server" +respmessage); 
        catch (Exception e) {logger.error ("Failed to convert"); The catch (Exception e) {logger.error (Connect the Weixin Server is error. ");}
    finally{Out.close ();
 }
  }
}

3. Signature Verification Checksignature

From the above controller we can see that I encapsulated a tool class Signutil, called Checksignature inside, and passed in four values, Dnbx_token, signature, timestamp, nonce. This process is very important, in fact, we can understand that the micro-letter passed the value of a process of encryption and decryption, many large projects all the interfaces to ensure that security will have such a validation process. Dnbx_token we have a token string configured in the micro-trust public platform, the idea is secret Oh! The other three are the parameters that the micro-mail server sends the GET request, and we do a layer of SHA1 encryption:

public class Signutil { 
 
  /** 
   * Authentication Signature 
   * 
   * @param token micro-server token, configured in the Env.properties file and configured in the developer center must be consistent 
   * @param signature Micro-trust Server SHA1 encrypted certificate signature
   * @param timestamp timestamp
   * @param nonce random number 
   * @return 
  * * public static Boolean checksignature (String token,string signature, string timestamp, string nonce) { 
    string[] arr = New string[] {token, timestamp, nonce}; 
    The token, timestamp, nonce three parameters are sorted in dictionary order 
    Arrays.sort (arr); 
    
    Concatenation of three parameter strings into a string for SHA1 encryption 
    string tmpstr = Sha1.encode (arr[0] + arr[1] + arr[2); 
    
    The SHA1 encrypted string can be compared with signature to identify the request from the micro-letter return 
    tmpstr!= null tmpstr.equals (Signature.touppercase ()): false;< c18/>} 
  
}

SHA1:

/** * Micro-trust platform (JAVA) SDK * * SHA1 algorithm * * @author helijun 2016/06/15 19:49 * * Public final class SHA1 {Priva Te static final char[] Hex_digits = {' 0 ', ' 1 ', ' 2 ', ' 3 ', ' 4 ', ' 5 ', ' 6 ', ' 7 ', ' 8 ', ' 9 ', ' A ', ' B ', ' C ', ' D ', 
 
  ' E ', ' F '}; 
   /** * takes the raw bytes from the digest and formats them. 
   * * @param bytes The raw bytes from the digest. 
   * @return the formatted bytes. 
    * * private static String getformattedtext (byte[] bytes) {int len = bytes.length; 
    StringBuilder buf = new StringBuilder (len * 2); Converts cipher text into a string form of 16 for (int j = 0; J < Len; J +) {Buf.append (hex_digits[(BYTES[J) >> 4) & 0x0f] 
      ); 
    Buf.append (Hex_digits[bytes[j] & 0x0f]); 
  return buf.tostring (); 
    public static string encode (String str) {if (str = null) {return null; 
      try {messagedigest messagedigest = messagedigest.getinstance ("SHA1"); Messagedigest.updatE (Str.getbytes ()); 
    Return Getformattedtext (Messagedigest.digest ()); 
    catch (Exception e) {throw new RuntimeException (e);
 } 
  } 
}

When you submit a save on the public platform and see the green hint "access successful", congratulations you have completed the micro-letter access. This process needs to be careful, pay attention to the case of encryption algorithm, if the access is unsuccessful, most cases are the problem of encryption algorithm, multiple checks.

4. Realize message Automatic reply service

/** * Processing of requests for micro-letters * * @param request * @return/Public String weixinpost (HttpServletRequest request) {
    String respmessage = null;

      try {//XML request parsing map<string, string> requestmap = messageutil.xmltomap (request);
      Sender account (open_id) String fromusername = Requestmap.get ("Fromusername");
      Public account String Tousername = Requestmap.get ("Tousername");
      Message type String Msgtype = Requestmap.get ("Msgtype");
      
      Message contents String content = Requestmap.get ("content");

      Logger.info ("Fromusername is:" + Fromusername + ", Tousername are:" + Tousername + ", Msgtype is:" + msgtype); Text message if (Msgtype.equals (Messageutil.req_message_type_text)) {///here according to the keyword to execute the corresponding logic, only you can not think of, do not have to do if (
        Content.equals ("xxx")) {}//automatically reply textmessage text = new TextMessage ();
        Text.setcontent ("The text is" + content);
 Text.settousername (Fromusername);       Text.setfromusername (Tousername);
        Text.setcreatetime (New Date (). GetTime () + "");
        
        Text.setmsgtype (Msgtype);
        
      Respmessage = Messageutil.textmessagetoxml (text); }/*else if (Msgtype.equals (messageutil.req_message_type_event)) {//event push String EventType = Requestmap.get ("Event ")//Event type if (Eventtype.equals (Messageutil.event_type_subscribe)) {//subscribe to Respcontent =" Welcome to XX X Public number!
          ";
        Return Messageresponse.gettextmessage (Fromusername, Tousername, respcontent); else if (eventtype.equals (Messageutil.event_type_click)) {//custom menu click event String eventkey = Requestmap.get ("Event
          Key ")//Event key value, corresponding to the key value specified when creating the custom menu Logger.info (" Eventkey is: "+eventkey);
        return xxx; 2015-3-30 Else if (msgtype.equals ("Voice")) {String recvmessage = Request
        Map.get ("recognition");
      Respcontent = "Received speech parsing result:" +recvmessage;  if (recvmessage!=null) {respcontent = Tulingapiprocess.gettulingresult (recvmessage); }else{respcontent = "You are too vague, can you say it again?"
        "; 
      Return Messageresponse.gettextmessage (Fromusername, Tousername, respcontent); }//Photo function else if (msgtype.equals ("Pic_sysphoto")) {} else {return Me 
      Ssageresponse.gettextmessage (Fromusername, Tousername, "Back to Empty"); }*///Event Push else if (msgtype.equals (messageutil.req_message_type_event)) {String EventType = requestm
          
          Ap.get ("event");//Event type//subscription if (Eventtype.equals (Messageutil.event_type_subscribe)) {
          TextMessage Text = new TextMessage ();
          Text.setcontent ("Welcome attention, XXX");
          Text.settousername (Fromusername);
          Text.setfromusername (Tousername);
          Text.setcreatetime (New Date (). GetTime () + "");
          
 Text.setmsgtype (Messageutil.resp_message_type_text);         Respmessage = Messageutil.textmessagetoxml (text); //TODO The Subscriber will not receive the message sent by the public number after canceling the subscription, so there is no need to reply to the message else if (Eventtype.equals (Messageutil.event_type_unsubscribe)) {/ /unsubscribe}//custom menu click event Else if (Eventtype.equals (messageutil.event_type_clic K)) {String Eventkey = requestmap.get ("Eventkey");//Event key value, corresponding to the key value specified when creating the custom menu if (Eventkey.equals ("C
            Ustomer_telephone ")) {textmessage text = new TextMessage ();
            Text.setcontent ("0755-86671980");
            Text.settousername (Fromusername);
            Text.setfromusername (Tousername);
            Text.setcreatetime (New Date (). GetTime () + "");
            
            Text.setmsgtype (Messageutil.resp_message_type_text);
          Respmessage = Messageutil.textmessagetoxml (text);
  catch (Exception e) {logger.error ("error ...")} return respmessage;

 }

First paste code as above, most have comments, read the basic semantics also understand that do not need more explanation.

There is one place that needs to be noted in particular:

The above marked red fromusername and Tousername just the opposite , this is also one of the pits, remember I was adjusted for a long time, obviously there is no problem is not pass, and finally put the two a change of message received! In fact, back to think also right, back to the micro-trust server at this time the role of the change, so the sending and receiving side is also certainly the opposite.

5.MessageUtil

public class Messageutil {/** * return message type: text/public static final String resp_message_type_text = "text"; 
 
  /** * Return message type: Music/public static final String resp_message_type_music = "musical"; 
 
  /** * Return Message type: text/* public static final String resp_message_type_news = "News"; 
 
  /** * Request Message Type: Text */public static final String req_message_type_text = "text"; 
 
  /** * Request Message type: Picture */public static final String req_message_type_image = "image"; 
 
  /** * Request Message Type: Link/public static final String Req_message_type_link = "link"; 
 
  /** * Request Message Type: GEO/public static final String req_message_type_location = "LOCATION"; 
 
  /** * Request Message Type: Audio/public static final String Req_message_type_voice = "VOICE"; 
 
  /** * Request Message Type: Push/public static final String req_message_type_event = "EVENT"; /** * Event Type: Subscribe (subscribe)/public static final String event_type_subscribe = "Subscribe"; 
 
  /** * Event Type: Unsubscribe (UNSUBSCRIBE)/public static final String event_type_unsubscribe = "unsubscribe"; 
/** * Event Type: Click (custom Menu click event) * * public static final String Event_type_click = "click";
 }

Here for the readability and extensibility of the program, I did some encapsulation, defined a few constants, and encapsulated some of the micro-letter parameters into Java Bean Persistence objects, as the core code above. Focus on the transformation between XML and map

In fact, the problem is that the micro-letter is used in XML communication, and we usually use JSON, so it may be a little bit inappropriate in a short time

1. Introducing Jar Packs

<!--parsing xml-->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactid>dom4j </artifactId>
      <version>1.6.1</version>
    </dependency>
    
    <dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.4.9</version>
    </dependency>

2.xml Turn Map Collection Object

/**
   * XML converted to map
   * @param request
   * @return
   * @throws ioexception
  /@SuppressWarnings (" Unchecked ") public
  static map<string, string> Xmltomap (HttpServletRequest request) throws ioexception{
    map<string, string> map = new hashmap<string, string> ();
    Saxreader reader = new Saxreader ();
    
    InputStream ins = null;
    try {
      ins = Request.getinputstream ();
    } catch (IOException E1) {
      e1.printstacktrace ();
    }
    Document doc = null;
    try {
      doc = reader.read (ins);
      Element root = Doc.getrootelement ();
      
      list<element> list = Root.elements ();
      
      for (Element e:list) {
        map.put (E.getname (), E.gettext ());
      }
      
      return map;
    } catch (Documentexception E1) {
      e1.printstacktrace ();
    } finally{
      ins.close ();
    }
    
    return null;
  }

3. Convert text message objects to XML

/** 
   * Text message object converted to XML 
   * 
   * @param textmessage Text Message Object 
   * @return XML/Public 
  static String Textmessagetoxml (TextMessage textmessage) {
    XStream XStream = new XStream ();
    Xstream.alias ("xml", Textmessage.getclass ());
    Return Xstream.toxml (TextMessage);
  }

So far it's done, and it's time to try to send a "test" in the public number, you will receive the micro-letter reply "The text is Test", which is also done in the code of the reply processing, of course, you can also play your imagination with him to do all you want to do, such as reply to 1 weather, 2 check violations and so on ....

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.