公眾號微信支付java開發,微信支付簽名錯誤,或者一直請求回撥方法問題
阿新 • • 發佈:2018-12-17
本編為原創,如需轉載,請註明出處。
微信支付開發過程中,如果沒有遇到簽名錯誤這個問題或者一直請求回撥方法問題,那麼感覺你開發了一個假對接,網上也有許多列子,以及官網也有微信團隊demo,但是還是有解決不了的各種簽名問題,demo需要手動修改因為他的加密方式會不盡如人意,還有排序問題。好了,話不多說,直接進入步驟中。
注意:如果遇到簽名錯誤,一定要檢視引數順序
比較坑的是,
1:官網商戶key填寫的時候提示你8位數還是6位數以上的數字加字母組成就可以,但是你必須在設定完之後,再次修改成32位加密字串!!!
2:回撥地址,如果你是http://www.xxx.cn/txxxr/wxpay/wxpay.do的方式,你的地址需要寫成http://www.xxx.cn/txxxr/wxpay/ !!!
好了,以上兩個問題如果都沒問題了,那麼我們進入正式程式碼開發。(具體工具類以及全部程式碼,會在本文的末尾中。)
在此只介紹重點步驟,開發可以在demo中修改我的路徑以及自己的邏輯就可以。
controller方法:
package cn.teacher.wxpay.controller;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.teacher.weiXin.dao.BasWxUserForStuDao;
import cn.teacher.wxpay.sdk.WXPay;
import cn.teacher.wxpay.sdk.WXPayUtil;
import cn.teacher.wxpay.util.WXPayConfigImpl;
@Controller
@RequestMapping("wxpay")
public class WXPayController {
private WXPay wxpay;
private WXPayConfigImpl config;
private String out_trade_no;
@Autowired
private BasWxUserForStuDao basWxUserForStuDao;
@RequestMapping(value="/wxpay_memberManagement")
public String memberManagement(HttpServletRequest request,Model model){
String openid ="ogcMwwuHoHeMG5Mp_cPkmYYdY6CU";
return "memberManagement";
}
@RequestMapping(value="/wxpay_packageInfo")
public String packageInfo(HttpServletRequest request){
return "packageInfo";
}
public WXPayController() throws Exception {
config = WXPayConfigImpl.getInstance();
wxpay = new WXPay(config);
out_trade_no = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 掃碼支付 下單
* @throws Exception
*/
@RequestMapping(value = "/wxpay_unifiedOrder", produces = "application/json;charset=UTF-8")//這一步必須有!!
@Transactional
public @ResponseBody String doUnifiedOrder(String bodyname,String fee) throws Exception {//bodyname例如:騰訊支付中心,fee為價格
JSONObject result = new JSONObject();
Map<String, String> resdata = new HashMap<String, String>();
//獲取到使用者的openid
String openid ="ogcMwwuHoHeMG5Mp_cPkmYYdY6CU";
Map<String, String> data = new HashMap<String, String>();
data.put("body", bodyname);
data.put("out_trade_no", out_trade_no);//生成的訂單編號
data.put("fee_type", "CNY");
data.put("total_fee", fee);
data.put("spbill_create_ip", "58.87.76.30");//請求ip地址
data.put("notify_url", "http://xxx.mmath.cn/teacher/uploadwx/paytest");//請求成功返回路徑
data.put("trade_type", "JSAPI");//公眾號支付型別
data.put("openid", openid);
try {
//統一下單,得到prepay_id
Map<String, String> r = wxpay.unifiedOrder(data);
//得到帶預支付prepay_id
String prepay_id= r.get("prepay_id");
//拼接組成新的sign並加密
String timestamp = String.valueOf(new Date().getTime()/1000);
String stringA =""+"appId="+config.getAppID()+"&nonceStr="+r.get("nonce_str") +"&package=prepay_id="+prepay_id+"&signType=MD5"+"&timeStamp=" + timestamp + "&key="+config.getKey();
String sign=WXPayUtil.MD5(stringA).toUpperCase();
//返回頁面資料供呼叫H5使用
result.put("appId", config.getAppID());//appid
result.put("timeStamp", timestamp);//時間戳精確到秒
result.put("nonceStr", r.get("nonce_str"));//訂單編號
result.put("paySign", sign);//sign
result.put("signType", "MD5");//加密方式
result.put("packageStr", "prepay_id=" + prepay_id); //預支付id
result.put("flag", true);//支付方法狀態
//可以在此處新增一個臨時的訂單步驟,狀態為支付中,在回撥介面中修改支付狀態為支付成功或者失敗
} catch (Exception e) {
e.printStackTrace();
}
return JSON.toJSONString(result);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <% String path = request.getContextPath(); %> <!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>個人中心</title> <script type="text/javascript" src="<%=path %>/js/jquery.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <body> <div> <div style=" width: 100%;"> <ul > <li style="width: 80%;float: left;"><p><strong id="bodyname">99元套餐</strong></p><p>六年級下學期下載</p></li> <li style="width: 20%;float: left;"><p><input type="button" value="結算" onclick="pay();" style="background-color: yellow;"></li> <li style="width: 100%;float: left;" > <input name="tab" type="checkbox" value="" onclick="money();"/>趙小小 <input name="tab" type="checkbox" value="" onclick="money();"/>陳大 <input name="tab" type="checkbox" value="" onclick="money();"/>辰辰 合計¥<strong id="m">0</strong> </li> </ul> </div> </div> <script type="text/javascript"> var prepay_id ,paySign,appId ,timeStamp, nonceStr,packageStr ,signType ; /** * 點選支付按鈕進行方法呼叫 */ function pay(){ var fee="20"; var bodyname="XXX支付介面"; var url = "http://XXX.mmath.cn/teacher/wxpay/wxpay_unifiedOrder"; $.ajax({ type:"post", url:url, data: "bodyname="+bodyname+"&fee="+fee, success:function(data) { if(data.flag){ appId = data.appId; paySign = data.paySign; timeStamp = data.timeStamp; nonceStr = data.nonceStr; packageStr = data.packageStr; signType = data.signType; callpay(); }else{ alert("統一下單失敗"); } } }); } /* * 呼叫支付h5頁面 */ function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":appId, //公眾號名稱,由商戶傳入 "timeStamp":timeStamp, //時間戳,自1970年以來的秒數 "nonceStr":nonceStr , //隨機串 "package":packageStr, //預支付交易會話標識 "signType":signType, //微信簽名方式 "paySign":paySign //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert('支付成功'); }else if(res.err_msg == "get_brand_wcpay_request:cancel"){ alert('支付取消'); }else if(res.err_msg == "get_brand_wcpay_request:fail" ){ alert('支付失敗'); } //使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在使用者支付成功後返回 ok,但並不保證它絕對可靠。 } ); } /** * 判斷是否進入支付步驟 */ function callpay(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); } } </script> </body> </html>
其餘的檔案以及工具類
由於上次上傳的檔案沒有宣告以下內容,導致碼農下載完資源後看到個官方demo基本一致,直接棄置不用,所以在此特別宣告。如果介意,不要下載。
(本文專案是在微信官方demo的基礎上進行修改開發的,所以類名方法名和框架結構和官方demo基本一致,但是部分內容會進行修改,請下載前仔細閱讀)
http://download.csdn.net/download/qq_37581708/10198124
好吧,我不知道怎麼弄成免費的,你們可以聯絡我,我私發給你們,或者留下你的QQ~
下面是最後一步處理:回撥介面
/**
* 支付成功後,接收微信返回的回撥方法
*/
@RequestMapping(value="/order", produces = "application/json;charset=UTF-8")
@ResponseBody
public void order(HttpServletRequest request, HttpServletResponse response) throws Exception{
String msg = "success";
response.setContentType("text/xml");
String resXml = "";
BufferedReader reader = null;
reader = request.getReader();
String line = "";
String xmlString = null;
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
xmlString = inputString.toString();
request.getReader().close();
Document doc = null;
try {
// 下面的是通過解析xml字串的
doc = DocumentHelper.parseText(xmlString); // 將字串轉為XML
Element rootElt = doc.getRootElement(); // 獲取根節點
Element recordEle = (Element)rootElt;
String result_code = recordEle.elementTextTrim("result_code");
String return_code = recordEle.elementTextTrim("return_code");
String out_trade_no = recordEle.elementTextTrim("out_trade_no");
String stuNo =out_trade_no.split("_ms_")[1];
//在此處開始進行資料庫訂單記錄狀態插入與修改
if(return_code.indexOf("SUCCESS")!=-1){
if(result_code.indexOf("SUCCESS")!=-1){
//支付成功
wXPayService.updateOrder(out_trade_no, "1",stuNo);
}else{
//支付失敗
wXPayService.updateOrder(out_trade_no, "2","1");
}
//這一步非常重要:返回給微信成功通知,否則會一直回撥。
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
response.getWriter().println(msg);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}