微信支付流程:
1、在頁面點擊支付發生的動作
將訂單參數傳遞后台->后台根據訂單參數以及微信相關信息->獲取支付所需要的參數->后台處理支付所需要的參數返回給前端->前端獲取到支付參數->發起支付請求->支付成功的頁面會顯示跳回商家所設置的回調路徑->后台根據回調路徑處理相關業務邏輯;
2、程序案例;從官網中下載相關API
頁面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>every thing will be will</title>
<script type="text/javascript" src="../static/js/jquery-3.3.1.min.js"></script>
</head>
<body>
<input type="button" value="進行微信支付" id="payId">
<script type="text/javascript">
$(function(){
var appId,timeStamp,nonceStr,package,signType,paySign;
$("#payId").click(function(){
pay();
});
//從后台獲取參數
function pay(){
var url = "http://localhost:8062/wxpay/order";
$.get(url,function(result) {
appId = result.appId;
timeStamp = result.timeStamp;
nonceStr = result.nonceStr;
package = result.package;
signType = result.signType;
paySign = result.paySign;
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady',
onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady',
onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady',
onBridgeReady);
}
alert("請在微信上進行支付操作!");
onBridgeReady();
} else {
onBridgeReady();
}
});
}
//去微信那邊發起支付請求
function onBridgeReady(){
alert("appId:"+appId+" "+"timeStamp:"+timeStamp+" "+"nonceStr:"+nonceStr+" "+"package:"+package+" "+"signType:"+signType+" "+"paySign:"+paySign+" ");
WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
"appId":appId, //公眾號名稱,由商戶傳入
"timeStamp":timeStamp, //時間戳,自1970年以來的秒數
"nonceStr":nonceStr, //隨機串
"package":package,
"signType":signType, //微信簽名方式:
"paySign":paySign //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
//alert('支付成功');
console.log("支付成功");
//支付成功后跳轉的頁面
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert('支付取消');
}else if(res.err_msg == "get_brand_wcpay_request:fail"){
alert('支付失敗');
alert(JSON.stringify(res));
WeixinJSBridge.call('closeWindow');
} //使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。
});
}
})
</script>
</body>
</html>
后台業務邏輯
所需的參數:
public class WxParam {
public final static String WX_APPID = "";//商家平台ID,微信平台
public final static String WX_BODY = ""; //商品描述
public final static String WX_MCH_ID = "";//商戶ID ,微信平台
public final static String WX_NONCE_STR = "";//隨機字符串,UUID
public final static String WX_OPEN_ID = "";//用戶OPENID
public final static String WX_OUT_TRADE_NO = "";//商戶訂單號
public final static String WX_SPBILL_CREATE_IP = "";//終端IP,從請求頭拿到
public final static String WX_TOTAL_FEE = "";//支付金額,單位是分
public final static String WX_TRADE_TYPE = "";//交易類型;JSAPI
public final static String WX_NOTIFY_URL = "";//通知地址;用戶支付成功后,返回應用程序的接口;
public final static String WX_SIGN = "";//簽名,根據上面10個參數計算獲得
public final static String WX_PATERNERKEY = "";//商家密鑰
}
前端所需參數的處理,以及回調路徑
@Controller
@RequestMapping("/wxpay")
public class WxPayAction {
/**
* 訂單采用微信支付所需的參數接口
* @param request
* @return
*/
@RequestMapping("/order")
@ResponseBody
public Map<String,String> orders(HttpServletRequest request){
try {
String openId = "用戶的openid";
//存放微信支付所需的參數
final Map<String,String> paraMap = new HashMap<>();
// 獲取請求ip地址
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
String uuid = UUID.randomUUID().toString();
//
paraMap.put("appid",WxParam.WX_APPID);
paraMap.put("body","微信測試商品內容" );
paraMap.put("mch_id",WxParam.WX_MCH_ID );
paraMap.put("nonce_str",uuid );
paraMap.put("openid",openId );
paraMap.put("out_trade_no",UUID.randomUUID().toString().replaceAll("-", "") );//訂單號
paraMap.put("spbill_create_ip",ip );//終端IP,從請求頭拿到
paraMap.put("total_fee","1" );//支付金額,1分
paraMap.put("trade_type","JSAPI" );//支付類型
paraMap.put("notify_url","回調url" );
//這里的key是商家密鑰;這一步將回調路徑設置到sign參數里面了
String sign = WXPayUtil.generateSignedXml(paraMap,WxParam.WX_PATERNERKEY);
paraMap.put("sign",sign );
//將map轉換為xml
String xml = WXPayUtil.mapToXml(paraMap);
// 統一下單 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
System.out.println("xml為:" + xml);
//預支付
String xmlStr = HttpRequestUtil.httpsRequest(unifiedorder_url, "POST", xml);
System.out.println("預支付返回的信息:"+xmlStr);
//上面的數據主要是為了獲得預支付id;就相當於微信上提交訂單(訂單包含了回調函數),然后返回一個微信的訂單id;
//以下內容返回前端頁面的json數據
String prepay_id = "";//預支付id
if(xmlStr.indexOf("SUCCESS") != -1){
Map<String,String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String,String> payMap = new HashMap<>();
payMap.put("appId",WxParam.WX_APPID );
//后面為什么要加""
payMap.put("timeStamp",WXPayUtil.getCurrentTimestamp()+"" );
payMap.put("nonceStr",WXPayUtil.generateNonceStr() );
payMap.put("signType","MD5" );
payMap.put("package","prepay_id="+prepay_id);
String paySin = WXPayUtil.generateSignature(payMap, WxParam.WX_PATERNERKEY);
payMap.put("paySign",paySin );
return payMap;
}catch (Exception e){
}
return null;
}
/**
* 回調函數,處理業務邏輯
* @param request
* * @param response
* * @return
*/
@RequestMapping("/notify")
public String wxCallBack(HttpServletRequest request, HttpServletResponse response){
InputStream is = null;
try{
is = request.getInputStream();
InputStreamReader isr=new InputStreamReader(is,"utf-8");
BufferedReader br=new BufferedReader(isr);
StringBuffer buffer=new StringBuffer();
String line=null;
while((line=br.readLine())!=null){
buffer.append(line);
}
//從流中獲取
String xml = buffer.toString();
Map<String,String> notifyMap = WXPayUtil.xmlToMap(xml);
System.out.println("微信返回的回調函數信息:"+xml);
if(notifyMap.get("result_code").equals("SUCCESS")){
String ordersSn = notifyMap.get("out_trade_no");//商戶訂單號
String amountpaid = notifyMap.get("total_fee"); //實際支付金額
BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);// 將分轉換成元-實際支付金額:元
/*
* 以下是自己的業務處理------僅做參考 更新order對應字段/已支付金額/狀態碼
*/
System.out.println("===notify===回調方法已經被調!!!");
}
// 告訴微信服務器收到信息了,回復微信服務器信息用流發送一個xml即可
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
}catch (Exception e){
}finally {
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
用到的工具類
public class HttpRequestUtil {
/*
* 處理https GET/POST請求
* 請求地址、請求方法、參數
* */
public static String httpsRequest(String requestUrl,String requestMethod,String outputStr){
StringBuffer buffer=null;
try{
//創建SSLContext
SSLContext sslContext=SSLContext.getInstance("SSL");
TrustManager[] tm={new MyX509TrustManager()};
//初始化
sslContext.init(null, tm, new java.security.SecureRandom());;
//獲取SSLSocketFactory對象
SSLSocketFactory ssf=sslContext.getSocketFactory();
URL url=new URL(requestUrl);
HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod(requestMethod);
//設置當前實例使用的SSLSoctetFactory
conn.setSSLSocketFactory(ssf);
conn.connect();
//往服務器端寫內容
if(null!=outputStr){
OutputStream os=conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
//讀取服務器端返回的內容
InputStream is=conn.getInputStream();
InputStreamReader isr=new InputStreamReader(is,"utf-8");
BufferedReader br=new BufferedReader(isr);
buffer=new StringBuffer();
String line=null;
while((line=br.readLine())!=null){
buffer.append(line);
}
}catch(Exception e){
e.printStackTrace();
}
return buffer.toString();
}
}
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}
