Wechat payment -java back-end implementation
Wechat payment -vue front-end implementation
Java demo: download address at the bottom of the article
technology stack
Leaf spring cover
Java language (a computer language, especially for creating websites)
XML (wechat is in. chi dori . wx pay;
Import core.com.wxpay.iwxpaydomain;
Import core.com.wxpay.wxpayconfig;
Import core.com.wxpay.wxpayconstants;
Import org.springframework.beans.factory.annotation.value;
Import org.springframework.stereotype.service;
Import java.io.bytearrayinputstream;
Import java.io.file;
Import java.io.fileinputstream;
Import java.io.inputstream;
@ Service
The public class iwxpayconfig extends WXPayConfig {// inherits sdk WXPayConfig to implement some abstract methods in sdk.
Private byte [] certdata;
@ Value(" $ { vendor . wx . config . app _ id } ")
Private string app _ id
@Value("${vendor.wx.pay.key} ")
Private string wx _ pay _ key
@ Value(" $ { vendor . wx . pay . mch _ id } ")
Private string wx _ pay _ mch _ id
The public iwxpayconfig () throwsexception {//constructor reads the certificate, and the sdk can get the certificate through getCertStream.
string cert path = "/data/config/chi dori/API client _ cert . p 12 ";
File file = new file (certpath);
InputStream certStream = new file InputStream(file);
this . certdata = new byte[(int)file . length()];
certstream . read(this . certdata);
certstream . close();
}
@ Overlay
Public string getAppID() {
Return app _ id
}
@ Overlay
Public string getMchID() {
Returns wx _ pay _ mch _ id.
}
@ Overlay
Public string getKey() {
Returns wx _ pay _ key.
}
@ Overlay
Common input stream getCertStream() {
Returns a new bytearray inputstream (this. certdata);
}
@ Overlay
Public iwxpaydomain getwxPaydomain () {//This method needs to be implemented, otherwise WXPay cannot be initialized normally.
IWXPayDomain IWXPayDomain = new IWXPayDomain(){
@ Overlay
Public void report (string field, long elapsedTimeMillis, Exception ex) {
}
@ Overlay
Public domain information getdomain (wxpayconfig) (
Returns a new IWXPayDomain. DomainInfo(WXPayConstants。 DOMAIN_API,true);
}
};
Return to iwxPayDomain
}
}
Initiate a unified order, and the front end will adjust the necessary parameters of WeChat payment.
//Initiate WeChat payment
WXPay wxpay = null
Map result = new HashMap & gt();
Try {
// ******************************************
//
//Unified sorting
//
// ******************************************
wx pay = new wx pay(iWxPayConfig); //* * * Inject the self-implemented WeChat configuration class to create the WXPay core class, including a unified ordering interface.
map data = new HashMap();
Data.put("body ","order details ");
data.put("out_trade_no ",trans order . getglobaloderid()); //Unique order number, which cannot be repeated.
data.put("total_fee ",string . value of(trans order . getorderamount()。 Multiplication (new BigDecimal( 100)). int value())); //Order amount, in minutes
data.put("spbill_create_ip "," 192. 168.3 1. 166 "); //place an order ip
data.put("openid ",openId); //WeChat official account unified logo openid
data.put("notify_url ","/pay callback "); //Order result notification, WeChat takes the initiative to call back this interface.
data.put("trade_type "," JSAPI "); //Fixed filling
Logger.info ("Initiate WeChat payment order interface, request={}", data);
Map response = wxpay.unifiedOrder (data); //WeChat sdk integration method, unifiedOrder interface, here we request MD5 encryption method.
Logger.info ("wechat payment order was placed successfully, and the return value is response={}", response);
string return code = response . get(" return _ code ");
If (! SUCCESS.equals(returnCode)) {
Returns null
}
string result code = response . get(" result _ code ");
If (! SUCCESS.equals(resultCode)) {
Returns null
}
string prepay _ id = response . get(" prepay _ id ");
if (prepay_id == null) {
Returns null
}
// ******************************************
//
//The front end calls out the necessary parameters for WeChat payment.
//
// ******************************************
string packages = " prepay _ id = "+prepay _ id;
map wx paymap = new HashMap();
wxPayMap.put("appId ",iwxpayconfig . getappid());
wxPayMap.put("timeStamp ",string . value of(utility . getcurrenttimestamp()));
wx pay map . put(" non centr ",utility . generate uid());
WxPayMap.put("package ",package);
wxPayMap.put("signType "," MD5 ");
//the encrypted string includes five parameters, appid timestamp nonce str package signtype, which is encrypted by sdk WXPayUtil class. Note that the MD5 encryption method is used here.
string sign = wxpayutil . generate signature(wxPayMap,iwxpayconfig . getkey());
// ******************************************
//
//Return the necessary parameters for calling WeChat payment to the front end.
//
// ******************************************
Result. put ("prepaid _ id", prepaid _ id);
Result.put("sign ",symbol);
result . putall(wx paymap);
Return the result;
Catch (exception e) {
}
Callback result processing
The core is to check whether the encryption signature matches when calling back the payment instruction to prevent the simulation success notice.
@ request mapping(value = "/pay callback ",method = RequestMethod。 Post)
Common string payCallback(HttpServletRequest, HttpServletResponse) (
Logger.info ("asynchronous notification of entering WeChat payment");
String resXml =
Try {
//
InputStream is = request . getinputstream();
//Convert InputStream into a string
buffered reader reader = new buffered reader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null
Try {
while ((line = reader.readLine())! = null) {
sb . append(line+" ");
}
} catch (IOException e) {
e . printstacktrace();
} Finally {
Try {
is . close();
} catch (IOException e) {
e . printstacktrace();
}
}
resXml = sb . tostring();
Logger.info ("WeChat payment asynchronous notification request package: {}", resxml);
Returns wxtticketservice. payback (resxml);
}catch (exception e){
Logger.error ("WeChat payment callback notification failed", e);
String result = "";
Return the result;
}
}
@ Overlay
String notify data (
logger.info("payBack() start,notifyData={} ",notify data);
String xmlBack =
Map notifyMap = null
Try {
wx pay wx pay = new wx pay(iWxPayConfig);
notify map = wxpayutil . XML tomap(notify data); //Convert to map
if(wx pay . ispayresultnotifysignaturevalid(notifyMap)){
//The signature is correct
//for processing.
//Pay attention to special circumstances: the order has been refunded, but the notice of successful payment has been received. You should not change the order status of the merchant from refund to successful payment.
string return _ code = notifymap . get(" return _ code "); //status
string out _ trade _ no = notifymap . get(" out _ trade _ no "); //Order number
if (out_trade_no == null) {
Logger.info ("WeChat payment callback failed order number: {}", notifymap);
xmlBack =
Return xmlBack
}
//Business logic processing * * * * * * * * * * * * * * * * * * * * * * *
Logger.info ("wechat payment callback successful order number: {0}", notifymap);
xmlBack =
Return xmlBack
} Otherwise {
Logger.error ("WeChat payment callback notification signature error");
xmlBack =
Return xmlBack
}
Catch (exception e) {
Logger.error ("WeChat payment callback notification failed", e);
xmlBack =
}
Return xmlBack
}
The signature of the unified order and the signature of the subsequent front-end pull WeChat payment need to be unified, that is, both of them are encrypted with MD5. If it is not the same, the front-end pull WeChat payment will fail, which is a huge pit. It has been debugged for a long time, and WeChat has not clearly stated in the file that the signature verification method of unified orders needs to be consistent with the signature verification of front-end pull WeChat payment.
The source code in WeChat sdk needs to be adjusted for this problem, and the adjustment is as follows:
The WXPay class needs to modify the encryption judgment. In the WXPay construction method, the adjustment is as follows.
The public WXPay (final WXPayConfig configuration, final string notifyUrl, final boolean autoReport, final boolean useSandbox) throws an exception {
this.config = config
this . notify URL = notify URL;
this.autoReport = autoReport
this . use sandbox = use sandbox;
if (useSandbox) {
this.signType = SignType。 MD5// Sandbox Environment
}
Otherwise {
this.signType = SignType。 MD5// Change the encryption method here to SignType. MD5, and keep consistent with the front-end WeChat encryption method.
}
this . WXPayRequest = new WXPayRequest(config);
}
Concluding remarks
After the completion, the back-end logic of WeChat payment is still very clear, but it is very difficult in the development process. It is not clear where each technical term is configured on WeChat, and the encryption method is very confusing.