Java Micro-Scan code payment mode on-line payment function implementation and callback _java

Source: Internet
Author: User
Tags cdata flush key string md5 openid readline urlencode stringbuffer

First, preparatory work

First spit the micro-letter on the payment of this piece, the payment model itself to support several kinds, but the official documents are particularly fragmented, even a decent Java-related demo is not a few. I have not done before the micro-letter payment, at the beginning really was it dizzy, toss two days finally adjust pass, hereby write down, to enjoy posterity!

About the preparation, the "Micro-scan code Payment Mode II" Official document address in this https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1 can look first, actually need to prepare for the following things:

Which app_id and App_secret can be found in the public platform, mch_id and Api_key are found in the merchant platform, especially api_key to set up in the merchant platform, for "micro-scan Payment Mode II" (Payment and callback) actually only use app_id, Mch_ ID and Api_key, none of the others.

About the development environment, I will not wordy, whether you are SPRINGMVC, struts2 or direct serverlet, are almost, as long as you can ensure that the corresponding method can be called up on the line. With reference to a third party jar package, I only use an XML operation Jdom, remember is the 1.* version, not the official online the latest 2.*, both incompatible. Specifically Jdom-1.1.3.jar, relying on the package Jaxen-1.1.6.jar, on these two packages, I used some examples of the use of httpclient, feel unnecessary, and rely on the package is particularly complex, of course, you are maven when I did not say.

Second, the development of actual combat

1, the first is to access the micro-letter interface, to obtain micro-letter payment two-dimensional code.

public string Weixin_pay () throws Exception {//account information String AppID = payconfigutil.app_id;//AppID//stri ng Appsecret = Payconfigutil.app_secret; Appsecret String mch_id = payconfigutil.mch_id; Commercial number String key = Payconfigutil.api_key; 
    Key String currtime = Paycommonutil.getcurrtime (); 
    String strtime = currtime.substring (8, Currtime.length ()); 
    String strrandom = Paycommonutil.buildrandom (4) + ""; 
     
    String nonce_str = Strtime + strrandom; String order_price = 1;  Price Note: The unit of price is divided into String BODY = "goodssssss"; Product name String out_trade_no = "11338"; 
    Order number//Get the originating computer IP String spbill_create_ip = payconfigutil.create_ip; 
    Callback interface String Notify_url = Payconfigutil.notify_url; 
     
    String Trade_type = "NATIVE"; 
    sortedmap<object,object> packageparams = new treemap<object,object> (); 
    Packageparams.put ("AppID", AppID); 
    Packageparams.put ("mch_id", mch_id); PackaGeparams.put ("Nonce_str", nonce_str); 
    Packageparams.put ("Body", the body); 
    Packageparams.put ("Out_trade_no", out_trade_no); 
    Packageparams.put ("Total_fee", Order_price); 
    Packageparams.put ("Spbill_create_ip", spbill_create_ip); 
    Packageparams.put ("Notify_url", Notify_url); 
 
    Packageparams.put ("Trade_type", Trade_type); 
    String sign = paycommonutil.createsign ("UTF-8", Packageparams,key); 
     
    Packageparams.put ("sign", sign); 
    String RequestXML = Paycommonutil.getrequestxml (packageparams); 
  
    System.out.println (RequestXML); 
 
     
    String resxml = Httputil.postdata (Payconfigutil.ufdoder_url, RequestXML); 
    Map map = Xmlutil.doxmlparse (resxml); 
    String return_code = (string) map.get ("Return_code"); 
    String prepay_id = (string) map.get ("prepay_id"); 
     
    String urlcode = (string) map.get ("Code_url"); 
return urlcode; 
 }

If it's not an accident, we get a payment URL from the micro-trust server, which is like weixin://wxpay/bizpayurl?pr=pixxxxx, and then we need to generate a two-dimensional code for the URL, and then we can use our phone's micro-end sweep code to pay. There are a number of ways to generate two-dimensional code, you have to do it, I provide a Google's two-dimensional code generation interface:

public static string Qrfromgoogle (String chl) throws Exception { 
  int widhtheight =; 
  String ec_level = "L"; 
  int margin = 0; 
  CHL = UrlEncode (CHL); 
  String qrfromgoogle = "http://chart.apis.google.com/chart?chs=" + widhtheight + "x" + widhtheight 
      + "&CHT=QR &chld= "+ ec_level +" | "+ margin +" &chl= "+ CHL; 
 
  return qrfromgoogle; 
Special character handling public 
static string UrlEncode (String src) throws unsupportedencodingexception { 
  return Urlencoder.encode (SRC, "UTF-8"). Replace ("+", "%20"); 

The above code involves several tool classes: Payconfigutil, Paycommonutil, Httputil, and Xmlutil, where Payconfigutil puts some of the configuration and paths mentioned above. Paycommonutil involves getting the current event, generating a random string, getting the parameter signature, and stitching the XML in several ways, with the following code:

The public class Paycommonutil {/** * is signed correctly, and the rule is: Sort by parameter name-A-Z, parameters that encounter null values do not participate in the signature. * @return Boolean/public static Boolean istenpaysign (String characterencoding, Sortedmap<object, object> p 
    Ackageparams, String api_key) {stringbuffer sb = new StringBuffer (); 
    Set es = Packageparams.entryset (); 
    Iterator it = Es.iterator (); 
      while (It.hasnext ()) {Map.entry Entry = (map.entry) it.next (); 
      String k = (string) entry.getkey (); 
      String v = (string) entry.getvalue (); if (!) Sign ". Equals (k) && null!= v &&!" ". 
      Equals (v)) {sb.append (k + "=" + V + "&"); 
     
    } sb.append ("key=" + api_key); 
    Calculates the summary String mysign = Md5util.md5encode (sb.tostring (), characterencoding). toLowerCase (); 
     
    String tenpaysign = ((String) packageparams.get ("sign")). toLowerCase (); 
    System.out.println (Tenpaysign + "" + mysign); 
  Return Tenpaysign.equals (mysign); }/** * @autHor * @date 2016-4-22 * @Description: Sign Signature * @param characterencoding * Coding format * @param parameters * Request Parameters * @return/public static string Createsign (String characterencoding, Sortedmap<object, Ob 
    Ject> Packageparams, String api_key) {stringbuffer sb = new StringBuffer (); 
    Set es = Packageparams.entryset (); 
    Iterator it = Es.iterator (); 
      while (It.hasnext ()) {Map.entry Entry = (map.entry) it.next (); 
      String k = (string) entry.getkey (); 
      String v = (string) entry.getvalue (); if (null!= v &&! "". Equals (v) &&! " Sign ". Equals (k) &&!" 
      Key ". Equals (k)) {Sb.append (k +" = "+ V +" & "); 
    } sb.append ("key=" + api_key); 
    String sign = Md5util.md5encode (Sb.tostring (), characterencoding). toUpperCase (); 
  return sign;      /** * @author * @date 2016-4-22 * @Description: Converts request parameters to XML-formatted string * @param parameters * Request parameters
   * @return */public static String Getrequestxml (Sortedmap<object, object> parameters) {StringBuffer 
    SB = new StringBuffer (); 
    Sb.append ("<xml>"); 
    Set es = Parameters.entryset (); 
    Iterator it = Es.iterator (); 
      while (It.hasnext ()) {Map.entry Entry = (map.entry) it.next (); 
      String k = (string) entry.getkey (); 
      String v = (string) entry.getvalue (); if ("Attach". Equalsignorecase (k) | | "Body". Equalsignorecase (k) | | "Sign". Equalsignorecase (k)) {Sb.append ("< + K +" > "+" <![ 
      cdata["+ V +"]]></"+ K +" > "); 
      else {sb.append ("<" + K + ">" + V + "</" + K + ">"); 
    } sb.append ("</xml>"); 
  return sb.tostring (); 
   /** * takes out a random positive integer of the specified length size. * * @param length * int sets the lengths of the random number taken out. 
   Length less than one * @return int returns the generated random number. 
    */public static int buildrandom (int length) {int num = 1; Double random = Math.randoM (); 
    if (Random < 0.1) {random = random + 0.1; 
    for (int i = 0; i < length; i++) {num = num * 10; 
  return (int) ((random * num));  /** * Get Current time YYYYMMDDHHMMSS * * @return String */public static string Getcurrtime () {Date 
    now = new Date (); 
    SimpleDateFormat Outformat = new SimpleDateFormat ("Yyyymmddhhmmss"); 
    String s = Outformat.format (now); 
  return s; 
 } 
 
}

The

Httputil and Xmlutil are as follows:

public class Httputil {private static final Log logger = Logs.get (); Private final static int connect_timeout = 5000; 
   
  In milliseconds private final static String default_encoding = "UTF-8"; 
  public static string PostData (string urlstr, string data) {return PostData (URLSTR, data, NULL);  
    public static string PostData (string urlstr, String data, String contentType) {BufferedReader reader = null; 
      try {URL url = new URL (urlstr); 
      URLConnection conn = Url.openconnection (); 
      Conn.setdooutput (TRUE); 
      Conn.setconnecttimeout (connect_timeout); 
      Conn.setreadtimeout (connect_timeout); 
      if (contentType!= null) conn.setrequestproperty ("Content-type", ContentType); 
      OutputStreamWriter writer = new OutputStreamWriter (Conn.getoutputstream (), default_encoding); 
      if (data = = NULL) data = "";  
      Writer.write (data); 
      Writer.flush ();  
 
      Writer.close (); reader = new BuffeRedreader (New InputStreamReader (Conn.getinputstream (), default_encoding)); 
      StringBuilder sb = new StringBuilder (); 
      String line = null; 
        while (line = Reader.readline ())!= null) {sb.append (line); 
      Sb.append ("\ r \ n"); 
    return sb.tostring (); 
    catch (IOException e) {logger.error ("Error connecting to" + Urlstr + ":" + e.getmessage ()); 
      Finally {try {if (reader!= null) reader.close (); 
  The catch (IOException e) {}} return null; 
 } 
}
The public class Xmlutil {/** * parses the XML and returns the first-level element key-value pairs. 
   If the first level element has child nodes, the value of this node is the XML data for the child node. * @param strxml * @return * @throws jdomexception * @throws ioexception/public static Map Doxmlparse (String strxml) throws Jdomexception, IOException {strxml = Strxml.replacefirst ("encoding=\". *\ "", "encoding=\" UTF-8 
 
    \""); if (null = = Strxml | | 
    "". Equals (Strxml)) {return null; 
     
    } Map m = new HashMap (); 
    InputStream in = new Bytearrayinputstream (strxml.getbytes ("UTF-8")); 
    Saxbuilder builder = new Saxbuilder (); 
    Document doc = Builder.build (in); 
    Element root = Doc.getrootelement (); 
    List List = Root.getchildren (); 
    Iterator it = List.iterator (); 
      while (It.hasnext ()) {Element E = (Element) it.next (); 
      String k = E.getname (); 
      String v = ""; 
      List children = E.getchildren (); 
      if (Children.isempty ()) {v = e.gettextnormalize (); else {v = xmlutil.getchildreNText (children); 
    } m.put (k, v); 
     
    }//Close stream in.close (); 
  return m; /** * Gets the XML * @param children * @return string/public static string Getchildrentext (Lis 
    T children) {StringBuffer sb = new StringBuffer (); 
      if (!children.isempty ()) {Iterator it = children.iterator (); 
        while (It.hasnext ()) {Element E = (Element) it.next (); 
        String name = E.getname (); 
        String value = E.gettextnormalize (); 
        List List = E.getchildren (); 
        Sb.append ("<" + name + ">"); 
        if (!list.isempty ()) {Sb.append (Xmlutil.getchildrentext (list)); 
        } sb.append (value); 
      Sb.append ("</" + name + ">"); 
  } return sb.tostring (); 

 } 
   
}

Of course there is also a MD5 computing tool class

public class Md5util {private static String bytearraytohexstring (byte b[]) {StringBuffer RESULTSB = new Strin 
    Gbuffer (); 
 
    for (int i = 0; i < b.length i++) resultsb.append (bytetohexstring (b[i)); 
  return resultsb.tostring (); 
    private static String bytetohexstring (byte b) {int n = b; 
    if (n < 0) n = 256; 
    int D1 = N/16; 
    int d2 = n% 16; 
  return HEXDIGITS[D1] + HEXDIGITS[D2]; 
    public static string Md5encode (string origin, String charsetname) {string resultstring = null; 
      try {resultstring = new String (origin); 
      MessageDigest MD = messagedigest.getinstance ("MD5"); if (CharsetName = null | | 
      "". Equals (CharsetName)) resultstring = Bytearraytohexstring (Md.digest (resultstring. GetBytes ())); 
    else resultstring = bytearraytohexstring (Md.digest (resultstring. GetBytes (CharsetName))); 
   catch (Exception Exception) {} return resultstring;  private static final String hexdigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "B", "C", 
 
"D", "E", "F"}; 
 }

2. Payment Callback

Upon completion of the payment, the micro-trust sends the relevant payment results and user information to the callback address specified above, and we need to receive processing and return the response. When interacting with a background notification, if the micro-letter received the merchant's answer is not a success or timeout, the micro-letter said that the notification failed, the micro-letter through a certain strategy to periodically restart the notification, as far as possible to improve the success rate of notification, but the micro-letter does not guarantee that the (Notification frequency is 15/15/30/180/1800/1800/1800/1800/3600, unit: seconds)

On the payment callback interface, we first need to verify the content of the payment result notification, then the corresponding processing flow according to the payment result.

public void Weixin_notify (HttpServletRequest request,httpservletresponse response) throws exception{//Read parameters 
    InputStream InputStream; 
    StringBuffer sb = new StringBuffer (); 
    InputStream = Request.getinputstream (); 
    String s; 
    BufferedReader in = new BufferedReader (new InputStreamReader (InputStream, "UTF-8")); 
    while ((s = in.readline ())!= null) {sb.append (s); 
    } in.close (); 
 
    Inputstream.close (); 
    Parse XML into Map map<string, string> m = new hashmap<string, string> (); 
     
    m = Xmlutil.doxmlparse (Sb.tostring ());    
    Filter empty settings TreeMap sortedmap<object,object> packageparams = new treemap<object,object> (); 
    Iterator it = M.keyset (). iterator (); 
      while (It.hasnext ()) {String parameter = (string) it.next (); 
       
      String ParameterValue = m.get (parameter); 
      String v = ""; 
      if (null!= parametervalue) {v = Parametervalue.trim (); } packaGeparams.put (parameter, v); }//account information String key = Payconfigutil.api_key; 
    Key Logger.info (Packageparams); 
      Determine if the signature is correct if (paycommonutil.istenpaysign ("UTF-8", Packageparams,key)) {//------------------------------ 
      Processing business start//------------------------------String resxml = ""; if ("SUCCESS". Equals ((String) packageparams.get ("Result_code")) {//Here is paid successfully//////////execute own business logic////////// 
        String mch_id = (string) packageparams.get ("mch_id"); 
        String OpenID = (string) packageparams.get ("OpenID"); 
        String is_subscribe = (string) packageparams.get ("Is_subscribe"); 
         
        String out_trade_no = (string) packageparams.get ("Out_trade_no"); 
         
        String total_fee = (string) packageparams.get ("Total_fee"); 
        Logger.info ("mch_id:" +mch_id); 
        Logger.info ("OpenID:" +openid); 
        Logger.info ("Is_subscribe:" +is_subscribe); Logger.info ("Out_tradE_no: "+out_trade_no); 
         
        Logger.info ("Total_fee:" +total_fee); 
        Execute own business logic////////////////Logger.info ("pay success"); 
        Notify the micro-letter. Successful asynchronous acknowledgement. Otherwise it will always be notified backstage. After eight times, the deal failed. Resxml = "<xml>" + "<return_code><! [cdata[success]]></return_code> "+" <return_msg><! 
         
      [cdata[ok]]></return_msg> "+" </xml> "; 
        else {logger.info ("Payment failed, error message:" + packageparams.get ("Err_code")); Resxml = "<xml>" + "<return_code><! [cdata[fail]]></return_code> "+" <return_msg><! 
      [cdata[message is empty]]></return_msg> "+" </xml> "; }//------------------------------//processing business completed//------------------------------Bufferedoutputstr 
      EAM out = new Bufferedoutputstream (Response.getoutputstream ()); 
      Out.write (Resxml.getbytes ()); 
      Out.flush (); 
    Out.close (); } else{LoGger.info ("Notify Signature verification failure"); 
 } 
     
  }

The signature verification algorithm is similar to the algorithm generated by the signature and is provided in the Paycommonutil tool class above.
Third, something

Feel the micro-letter scanning payment experience is very good, the only drawback is that the relevant documents scattered, the official demo actually did not write Java, hope that after the micro-letter official can gradually improve it!

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.