최근에 나는 내 작업에서 WeChat 지불에 관한 몇 가지에 노출되었습니다. 나는 내가 준 데모가 모든 PHP 버전이라는 것을 보았고, WeChat 지불 문서에 만족하지 못했습니다. 많은 함정을 겪은 후, 나는 요약을하는 것을 유휴 상태였습니다.
1. 준비
WeChat을 개발하려면 먼저 공개 계정을 신청해야합니다. 신청서가 성공하면 이메일로 귀하에게 보내집니다. 공개 계정에는 개발 문서, 개발 중 필요한 정보 및 테스트를위한 데이터 쿼리가 포함되어 있습니다.
2. 도구
1.MD5 암호화 도구 클래스
package com.pay.utils.weixin; import java.security.messagegegest; public class md5util {public final static string md5 (String s) {char HexDigits [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; try {byte [] btinput = s.getBytes (); // md5 다이제스트 알고리즘의 MessageAdigest 객체를 가져옵니다 messageDigest mdinst = messageDigest.getInstance ( "md5"); // 다이제스트 mdinst.update (btinput)를 업데이트합니다. // ciphertext byte [] md = mdinst.digest ()를 가져옵니다. // ciphertext를 육각 문자열로 변환 int j = md.length; char str [] = 새로운 char [j * 2]; int k = 0; for (int i = 0; i <j; i ++) {byte byte0 = md [i]; str [k ++] = hexDigits [byte0 >>> 4 & 0xf]; str [k ++] = hexDigits [byte0 & 0xf]; } 새 문자열 (str)을 반환합니다. } catch (예외 e) {e.printstacktrace (); 널 리턴; }}}2. WeChat에 필요한 XML을 대체하는 데 사용되는 Commonutil Tool Class . 다음은 새 문자열 (xml.toString (). getBytes (), "iso8859-1"); 도구 클래스의 UTF-8을 ISO8859-1로 변경하십시오. 그렇지 않으면 WeChat 순서의 중국어 텍스트가 표시되며 변경 후 올바르게 표시 될 수 있습니다.
package com.pay.utils.weixin; import java.io.unsupportedencodingException; import java.net.urlencoder; import java.util.*; import java.util.map.entry; public class commonutil {public static string createoncest (int length) {String chars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; 문자열 res = ""; for (int i = 0; i <길이; i ++) {random rd = new random (); res += chars.indexof (rd.nextint (chars.length () -1)); } return res; } public static String createNoncErst () {String chars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789"; 문자열 res = ""; for (int i = 0; i <16; i ++) {random rd = new random (); res += chars.charat (rd.nextint (chars.length () -1)); } return res; } public static string formatqueryparamap (Hashmap <String, String> Parameters)는 sdkruntimeexception {String buff = ""; try {list <map.entry <string, string >> infoids = new ArrayList <map.entry <String, String >> (parameters.entryset ()); collections.sort (Infoids, new Comparator <map.entry <string, String >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); if (item.getKey ()! = "") {buff + = item.getKey () + "=" + urlencoder.encode (item.getValue (), "utf-8") + "&"; }} if (buff.isempty () == false) {buff = buff.substring (0, buff.length () -1); }} catch (예외 e) {새로운 sdkruntimeexception (e.getMessage ()); } 반환 버프; } public static string formatbizqueryparamap (Hashmap <string, String> paramap, boolean urlencode) sdkruntimeexception {String buff = ""; try {list <map.entry <string, string >> infoids = new ArrayList <map.entry <String, String >> (paramap.entryset ()); collections.sort (Infoids, new Comparator <map.entry <string, String >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); //system.out.println (item.getKey ()); if (item.getKey ()! = "") {String key = item.getKey (); String val = item.getValue (); if (urlencode) {val = urlencoder.encode (val, "utf-8"); } buff + = key.tolowerCase () + "=" + val + "&"; }} if (buff.isempty () == false) {buff = buff.substring (0, buff.length () -1); }} catch (예외 e) {새로운 sdkruntimeexception (e.getMessage ()); } 반환 버프; } public static boolean isnumeric (string str) {if (str.matches ( "// d *")) {return true; } else {return false; }} public static string arraytoxml (hashmap <string, String> arr) {String xml = "<xml>"; iterator <enly <string, String >> iter = arr.entryset (). iterator (); while (iter.hasnext ()) {entry <string, string> entry = iter.next (); 문자열 key = Entry.getKey (); String val = entry.getValue (); if (isnumeric (val)) {xml + = "<" + key + ">" + val + "</" + key + ">"; } else xml + = "<" + key + "> <! [cdata [" + val + "]> </" + key + ">"; } xml += "</xml>"; try {return new String (xml.toString (). getBytes (), "iso8859-1"); } catch (UnsupportedEncodingException e) {// todo 자동 생성 캐치 블록 e.printstacktrace (); } 반품 ""; }}3. ClientCustomsSL Tool Class , 표지판을 생성하고 WeChat 주문 패키지 com.pay.utils.weixin을 생성하는 데 사용됩니다.
import java.util.arraylist; import java.util.collection; import java.util.comparator; import java.util.hashmap; import java.util.list; import java.util.list; import org.spramework.util.stringutils; import org.spramework.util.stringutils; */public class clientCustomsSl {public static string getBizSign (Hashmap <String, String> bizobj) sdkruntimeexception {hashmap <string, string> bizparameters = new Hashmap <String, String> (); list <map.entry <string, string >> infoids = new ArrayList <map.Entry <String, String >> (bizobj.entryset ()); System.out.println (Infoids); collections.sort (Infoids, new Comparator <map.entry <string, string >> () {public int compare (map.entry <string, string> o1, map.entry <string, string> o2) {return (o1.getKey ()). System.out.println (Infoids); for (int i = 0; i <infoids.size (); i ++) {map.entry <string, string> item = infoids.get (i); if (item.getKey ()! = "") {bizparameters.put (item.getKey (). tolowercase (), item.getValue ()); }} //bizparameters.put("key ","1234567812345678123456781234567812345671 "); 문자열 bizstring = commonutil.formatbizqueryparamap (bizparameters, false); 비즈 스트링 += "& key = 123456781234567812345671"; System.out.println ( "***************"); System.out.println (bizstring); // return sha1util.sha1 (bizstring); md5util.md5 (bizstring)를 반환합니다. } / ** * wechat 주문 작성 * @param noncest * @param orderdescribe * @param orderdescribe * @param orderdescribe * @param timestart * @param timeexpire * @return * @throws sdkruntimeexception * / public static string createativepackage (문자열 noncest, string), 문자열, string, string, string, string, string) sdkruntimeexception {hashmap <string, string> avatibj = new Hashmap <string, String> (); NativeObj.put ( "appid", "공개 계정 참조"); // public acc // Merchant Number NativeObj.put ( "nonce_str", noncestr); // random String avativeObj.put ( "body", orderdescribe); // 제품 설명 NativeObj.put ( "첨부", "tradeno"); // 첨부 된 데이터 avativeObj.put ( "out_trade_no", orderno); // 가맹점 주문 번호 (글로벌 고유) avatibj.put ( "total_fee", 가격); // 총 금액 (단위는 센트입니다. 소수점으로는 소수점으로 취할 수 없습니다) aviRobj.put ( "spbill_create_ip", "192.168.0.144"); // terminal ip avativeobj.put ( "time_start", timestart); // 트랜잭션 시작 시간 avativeObj.put ( "time_expire", timeexpire); // 트랜잭션 종료 시간 네이티브 로브 (avirettime) put ( "notify_url", customizedPropertyPlaceHolderConfigurer.GetContextProperty ( "wxurl")+"/weixin_callback/weixincallback/init.action"); // Callback 알림 주소 avativeObj.put ( "trade_type", "avire"); // 트랜잭션 유형 문자열 부호 = getBizSign (NativeObj); NativeObj.put ( "sign", sign.toupperCase ()); return commonutil.arraytoxml (aviretobj); } /*** wechat 주문 지불 쿼리* @param noncestr* @param orderdescribe* @param orderdescribe* @param orderdescribe* @param timestart* @param timeexpire* @return* @throws sdkruntimeexception* /public string searchnativepackage (문자열 transactId, string nontradeno) sdkruntimeexection. {hashmap <string, string> aviretobj = new Hashmap <string, String> (); avatibj.put ( "appid", "공개 계정 참조"); // 공개 계정 idnativeObj.put ( "mch_id", "이메일 참조"); // Merchant Number NativeObj.put ( "nonce_str", noncestr); // random string if (! stringUtils.isempty (transactionId)) {avatiorbj.put ( "transaction_id", transactionId); } if (! stringUtils.isempty (outtradeno)) {avatiorbj.put ( "out_trade_no", outtradeno); // random string} 문자열 부호 = getBizSign (NativeObj); NativeObj.put ( "sign", sign.toupperCase ()); return commonutil.arraytoxml (aviretobj); /*** wechat 환불* @param outtradeno* @param antRefundno* @param totalfee* @param totalfee* @param repundfee* @return* @throws sdkruntimeexception*/public string string string untradeno, string totalfee, String refundfee, string noncrestfee, string noncrest) sdkruntimeexception {hashmap <string, string> aviretobj = new Hashmap <string, string> (); avatibj.put ( "appid", "public account"참조 "; // public acc NativeObj.put ( "out_trade_no", outtradeno); // Merchant 주문 번호 (Global Order) NativeObj.put ( "out_refund_no", antRefundno); // Merchant 환불 주문 번호 (Global Cight) NativeObj.put ( "Total_fee", Totalfee); // repund _. 환불 피); // 환불 금액 (센트의 단위, 소수점을 가져갈 수 없음) aviRovj.put ( "op_user_id", "mail"); 문자열 부호 = getBizSign (NativeObj); NativeObj.put ( "sign", sign.touppercase ()); return commonutil.arraytoxml (avatibj);}/*** wechat를 지불하려면* @param noncest* @param orderdescribe* @param orderno* @param price* @param timexpire*/public static* @throws sdkruntimexection*/public static strows createJsapipackage (String noncest, String orderdescribe, String orderno, String Price, String Timestart, String TimeExpire, String OpenID) sdkruntImeexception {Hashmap <String, String> aviretobj = new Hashmap <string, String> (); aviatroBj.put ( "appubl", "see openId"); // OpenID); // 공개 계정 idnativeObj.put ( "MCH_ID", "이메일 참조") // Merchant Number NativeObj.put ( "nonce_str", noncest); // random String avatiorbj.put ( "body", orderdescribe); // 제품 설명 avatilebj.put ( "attach", "tradeno"); Orderno); // Merchant Order Number (Global Order Nought NativeObj.put ( "Total_fee", Price); // 총 금액 (단위는 Cent, 소수점을 가져갈 수 없음) NativeObj.put ( "Spbill_Create_ip", "192.168.0.144"); // terminal iPnativeObj.put ( "time_start", TimestArct "; NativeObj.put ( "time_expire", timeexpire) // 트랜잭션 종료 시간 Time avativeBj.put ( "notify_url", customizedPropertyPlaceHolderConfigurer.getContextProperty ( "wxurl")+"/weixin_callback/weixincallback/init. "jsapi"); // 트랜잭션 유형 문자열 부호 = getBizSign (avatiObj); avativeObj.put ( "부호", sign.toupperCase ()); return commenutil.arraytoxml (averabj);}/*** wechat* @param noncest* @param orderdescribe* @param orderno* @param price* @param timestart* @param timeexpire* @param openid* @return* @throws sdkruntimeexception*/public string createclose (strateclose) sdkruntimeexception {hashmap <string, string, String> avatilebj = new hashmap <string, string> (); NativeObj.put ( "appid", "공개 계정보기"); // public account idnativeObj.put ( "mch_id", "이메일보기"); // merchant Number NativeObj.put ( "out_trade_. // outtadeo", /// (전 세계적으로 고유 한) NativeObj.put ( "nonce_str", noncest); // random string sign = getBizSign (NativeObj); NativeObj.put ( "sign", sign.toupperCase ()); return commonutil.arraytoxml (avatiorbj);}}} 4. WeChat 결제 인터페이스에 전화하십시오
package com.pay.controller.weixin; import java.io.file; import java.io.fileinputStream; import java.security.keystore; import java.text.simpledateformat; import java.util.date; import java.util.list; import javax.net.ssl.sslcontext; javax.servlet.http.httpervletrequest; import javax.servlet.http.htttp.httpervletresponse; import net.sf.json.jsonarray; import net.sf.json.jsonobject; import org.apache.http.httpentity; import org.apache.http.client.methods.closeablehtttpresponse; import org.apache.http.client.methods.httppost; import org.apache.http.conn.ssl.sslconnectionsocketfactory; import org.apache.http.conn.ssl.slcontexts; org.apache.http.entity.stringentity; import org.apache.http.impl.client.closeablehttpclient; import org.apache.http.impl.client.httpclients; import org.apache.http.util.entityutils; import org.docum4j.document; org.dom4j.documenthelper; import org.dom4j.element; import org.dom4j.io.saxreader; import org.spramework.beans.beans.annotation.autowired; import org.springframework.http.httpstatus; import org org.springframwork.web.bind.ontation org.springframework.web.bind.annotation.requestmapping; import org.springframework.web.bind.annotation.requestmethod; import org.spramframework.web.bind.annotation.responsestatus; import org.springframework.bind.bind.restoration com.pay.bo.payhistants.import com.pay.constants.payhistorypaystatus; import com.pay.constants.payhistorypaytype; import com.pay.service.weixinpayservice; import com.pay.utils.weixin.clientcustomssl; import com.pay.utils.weixin.closeweixinorderutils; import com.pay.utils.weixin.customizedPropertyplaceholderConfigurer;@restcontroller@restontroller ( "/pay") public class weixinpayController {@autowired weixinpayservice weixinpayservice; 개인 정적 긴 표준 시간 = 1662652800000L; /** * QR 코드를 생성하는 URL을 반환 * @param request * @param response * @return */@requestmapping (value = "/geturl", method = requestmethod.post) @responsestatus (httpstatus.ok) public object geturl (httpservletresponse 응답, @requestible body) {jsonobject jsono = jsonobject jsono = jsonobject.fromobject (body); payhist ph = null; // list <map <string, object >> td = weixinpayservice.gettrade (OrderNo); 날짜 dt = 새 날짜 (); simpledateformat sdf = 새로운 simpledateformat ( "yyyymmddhhmmss"); 문자열 noncestr = sdf.format (dt) .toString (); 날짜 지금 = 새 날짜 (); String tradepayno = jsono.get ( "OrderNo"). toString ()+string.format ( "%10D", 표준 시간 - now.getTime ()). substring (0, 10); System.out.println ( "订单标号 orderno ======="+jsono.get ( "OrderNo"). toString ()); System.out.println ( "10 位随机数 ======="+string.format ( "%10d", 표준 시간 - now.gettime ()). substring (0, 10)); 문자열 price = math.round (float.valueof (jsono.get ( "price"). tostring ())*100)+""; Long TimeExpirestrold = dt.gettime (); long timenew = long.parselong (CustomizedPropertyPlaceHolderConfigurer.GetContextProperty ( "weixin.send2finish.overtime"). toString ()); Long TimeExpirenew = TimeExpirestrold+Timenew; 날짜 dttimeexpire = 새 날짜 (TimeExpirenew); simpledateformat dtsdf = 새로운 simpledateformat ( "yyyymmddhhmmss"); String TimeExpire = dtsdf.format (dttimeexpire) .toString (); System.out.println ( "noncest =="+noncestr); System.out.println ( "orderno =="+jsono.get ( "orderno"). toString ()); System.out.println ( "price =="+price); System.out.println ( "timestart =="+noncestr); System.out.println ( "TimeExpire =="+TimeExpire); jsonobject result = (jsonobject) seturl (비정부, "순서", tradepayno, 가격, 비정규, TimeExpire); if (result.get ( "status"). toString (). Equals ( "success")) {ph = new Payhist (); ph.settradepayurl (result.getstring ( "weixinpayurl")); //이 필드는 결제 링크입니다. ph.setpaytradeno (jsono.get ( "orderno"). tostring ())를 지불하기 위해 코드를 스캔하는 QR 코드를 생성 할 수 있습니다. Ph.SetTradepayno (TradePayno); ph.setpaystatus (payhistorypaystatus.wechat_pay_status_wait); ph.setpaytype (payhistorypaytype.wechat); ph.setappkey (jsono.getstring ( "appkey"). tostring ()); ph.setpayamount (가격); result.put ( "paytradeno", ph.getPayTradeno ()); result.put ( "tradepayno", ph.gettradepayno ()); result.put ( "paystatus", ph.getPayStatus ()); result.put ( "paytype", ph.getPayType ()); } 반환 결과; } catch (예외 e) {e.printstacktrace (); jsonobject result = new jsonobject (); result.put ( "상태", "오류"); result.put ( "msg", e.getMessage ()); // return result.toString (); } return null; } public Object SetUrl (문자열 비 시스트, 문자열 정서 도시, 문자열 orderno, 문자열 가격, 문자열 timestart, String TimeExpire) {try {keystore keystore = keystore.getInstance ( "pkcs12"); FileInputStream instream = 새 FileInputStream (새 파일 (WeChat 인증서의 절대 경로)); try {keystore.load (instream, "merchant id".tochararray ()); } 마침내 {enterstream.close (); } // 자신의 CA 및 모든 자체 서명 된 CERTS SSLCONTEXT SSLCONTEXT = SSLCONTEXTS.CUSTOM (). LOADKEYMATERIAL (keystore, <span style = "font-family : arial, helvetica, sans-serif;"> Merchant id </span> .tochararray ()); build (); // tlsv1 프로토콜 허용 SSLConnectionSocketFactory sslsf = new sslConnectionSocketFactory (sslcontext, new String [] { "tlsv1"}, null, sslconnectionsocketfactory.allow_all_all_hostname_verifier); Closeblehttpclient httpclient = httpclients.custom () .setsslsocketfactory (sslsf) .build (); // httpget httpget = new // httpget ( "https://api.mch.weixin.qq.com/secapi/pay/refund"); httppost httppost = new httppost ( "https://api.mch.weixin.qq.com/pay/unifeordorder"); 문자열 XML = ClientCustomsSl.CreatEnativePackage (비 CESTRED, ORDERDESCRIBE, ORDERNO, 가격, TIMESTART, TIMEEXPIRE); try {stramentity se = 새로운 엄격함 (xml); httppost.setentity (se); System.out.println ( "실행 요청" + httppost.getRequestline ()); closeblehtttpresponse responseentry = httpclient.execute (httppost); {httpentity entity = responsentry.getentity (); System.out.println ( "-------------------------------------------------------- System.out.println (ResponseEntry.getStatusline ()); if (entity! = null) {system.out.println ( "응답 내용 길이 :" + entity.getContentLength ()); /* bufferedReader bufferedReader = new bufferedReader (new inputStreamReader (entity.getContent ()); 문자열 텍스트; while ((text = bufferedReader.Readline ())! = null) {system.out.println ( "===================="+텍스트); }*/ saxReader saxReader = new SaxReader (); 문서 문서 = saxReader.Read (entity.getContent ()); 요소 rootelt = document.getRootElement (); System.out.println ( "루트 노드 :" + rootelt.getName ()); System.out.println ( "==="+rootelt.elementText ( "result_code")); System.out.println ( "==="+rootelt.elementText ( "return_msg")); 문자열 resultCode = rootelt.elementText ( "result_code"); jsonobject result = new jsonobject (); document documentxml = documentHelper.parsetext (XML); 요소 rooteltxml = documentxml.getRootElement (); if (resultCode.equals ( "success")) {System.out.println ( "====================================="+ rootelt.elementText ( "prepay_id")); System.out.println ( "================== 표시 ==================="+ rooteltxml.elementText ( "sign")); result.put ( "weixinpayurl", rootelt.elementtext ( "code_url")); result.put ( "prepayId", rootelt.elementText ( "propay_id")); result.put ( "상태", "성공"); result.put ( "msg", "success"); } else {result.put ( "status", "false"); result.put ( "msg", rootelt.elementtext ( "err_code_des")); } 반환 결과; } entityutils.consume (엔티티); } 마침내 {responseentry.close (); }} 마침내 {httpclient.close (); } return null; } catch (예외 e) {e.printstacktrace (); jsonobject result = new jsonobject (); result.put ( "상태", "오류"); result.put ( "msg", e.getMessage ()); 반환 결과; }}} httpclient jar 패키지 및 JSON JAR 패키지 : 다운로드 주소.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.