您當前位置:
首頁 >
php開源 >
綜合技術 > [置頂] 微信:微信掃碼支付、調用統一下單接口、網站支付 + springmvc
[置頂] 微信:微信掃碼支付、調用統一下單接口、網站支付 + springmvc
來源:程序員人生 發布時間:2016-06-16 17:22:10 閱讀次數:7218次
1、場景:公司需要在網站上進行微信支付。
2、API:使用微信開放平臺的接入微信支付.
-掃碼支付。微信支付開發者平臺鏈接
3、分析:
-
接入掃碼支付(包括PC網站支付)包括3個階段,問這里只講使用,也就是第2階段的《啟動設計和開發》。
-
點擊查看開發者文檔(掃碼支付)后,這里感覺微信的文檔沒有支付寶好理解(略微吐槽下~~~),不過我們疏忽1切,直接進入模式2:模式2最簡單直接,不需要在商戶后臺進行配置,推薦大家使用,微信也說流程更加簡單,我這里也講的是模式2,模式1大家有興趣可以自行研究下。
-
如上圖,總流程有14步,主要流程是生成定單、調統1下單API、將返回的支付交易鏈接生成2維碼展現;我這邊主要就是將這3步結合springmvc后,成功生兒2維碼以后,用戶就能夠掃碼支付了。后面的回調跟跟我的另外一篇博文基本類似,大家鑒戒下就好了:支付寶:web頁面掃碼支付、網站支付、支付寶即時到賬 + springmvc
4、實現:
-
準備:根據統1下單接口API我先定義了3個對象:UnifiedOrderRequest(統1下單要求參數(必填))、UnifiedOrderRequestExt(統1下單要求參數(非必填))、UnifiedOrderRespose(統1下單返回參數);具體以下代碼,get、set方法可自行生產,太占篇幅。
UnifiedOrderRequest.class
/**
* 統1下單要求參數(必填)
* @author Y
*
*/
public class UnifiedOrderRequest {
private String appid; //公眾賬號ID
private String mch_id; //商戶號
private String nonce_str; //隨機字符串
private String sign; //簽名
private String body; //商品描寫
private String out_trade_no; //商戶定單號
private String total_fee; //總金額
private String spbill_create_ip; //終端IP
private String notify_url; //通知地址
private String trade_type; //交易類型
}
UnifiedOrderRequestExt.class
/**
* 統1下單要求參數(非必填)
* @author Y
*
*/
public class UnifiedOrderRequestExt extends UnifiedOrderRequest{
private String device_info; //裝備號
private String detail; //商品詳情
private String attach; //附加數據
private String fee_type; //貨幣類型
private String time_start; //交易起始時間
private String time_expire; //交易結束時間
private String goods_tag; //商品標記
private String product_id; //商品ID
private String limit_pay; //指定支付方式
private String openid; //用戶標識
}
UnifiedOrderRespose.class
/**
* 統1下單返回參數
* @author Y
*
*/
public class UnifiedOrderRespose {
private String return_code; //返回狀態碼
private String return_msg; //返回信息
private String appid; //公眾賬號ID
private String mch_id; //商戶號
private String device_info; //裝備號
private String nonce_str; //隨機字符串
private String sign; //簽名
private String result_code; //業務結果
private String err_code; //毛病代碼
private String err_code_des; //毛病代碼描寫
private String trade_type; //交易類型
private String prepay_id; //預支付交易會話標識
private String code_url; //2維碼鏈接
}
-
Controller主入口:
/**
* 創建2維碼
*/
@RequestMapping("createQRCode")
public void createQRCode(String orderId, HttpServletResponse response) {
//生成定單
String orderInfo = createOrderInfo(orderId);
//調統1下單API
String code_url = httpOrder(orderInfo);
//將返回預支付交易鏈接(code_url)生成2維碼圖片
//這里使用的是zxing 說明1(見文末) try {
int width = 200;
int height = 200;
String format = "png";
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "utf⑻");
BitMatrix bitMatrix = new MultiFormatWriter().encode(code_url, BarcodeFormat.QR_CODE, width, height, hints);
OutputStream out = null;
out = response.getOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, format, out);
out.flush();
out.close();
} catch (Exception e) {
}
}
-
生成定單:分兩部份:1部份是業務需求的定單信息,就是發起支付前的定單信息,業務系統自行創建存儲;另外一部份是滿足統1下單API要求的定單信息(也是我們這里要講的)?!皒xxxxx”:是你需要自己填寫的對應信息:
/**
* 生成定單
* @param orderId
* @return
*/
private String createOrderInfo(String orderId) {
//生成定單對象
UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
unifiedOrderRequest.setAppid("xxxxxxxxxxxxx");//公眾賬號ID
unifiedOrderRequest.setMch_id("xxxxxxxxx");//商戶號
unifiedOrderRequest.setNonce_str(StringUtil.makeUUID());//隨機字符串 說明2(見文末) unifiedOrderRequest.setBody("xxxxxx");//商品描寫
unifiedOrderRequest.setOut_trade_no(orderId);//商戶定單號
unifiedOrderRequest.setTotal_fee("x"); //金額需要擴大100倍:1代表支付時是0.01
unifiedOrderRequest.setSpbill_create_ip("xxxxxxxxxxxxx");//終端IP
unifiedOrderRequest.setNotify_url("xxxxxxxxxxxxxx");//通知地址
unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公眾號支付、NATIVE--原生掃碼支付、APP--app支付
unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//簽名說明5(見文末,簽名方法1并給出) //將定單對象轉為xml格式
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_"))); //說明3(見文末) xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
return xStream.toXML(unifiedOrderRequest);
}
-
調統1下單API:根據要求將生成定單中返回的xml向微信給定的統1下單URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder,發送要求,成功并取得2維碼。
/**
* 調統1下單API
* @param orderInfo
* @return
*/
private String httpOrder(String orderInfo) {
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
//加入數據
conn.setRequestMethod("POST");
conn.setDoOutput(true);
BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());
buffOutStr.write(orderInfo.getBytes());
buffOutStr.flush();
buffOutStr.close();
//獲得輸入流
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
StringBuffer sb = new StringBuffer();
while((line = reader.readLine())!= null){
sb.append(line);
}
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//說明3(見文末)
//將要求返回的內容通過xStream轉換為UnifiedOrderRespose對象
xStream.alias("xml", UnifiedOrderRespose.class);
UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
//根據微信文檔return_code 和result_code都為SUCCESS的時候才會返回code_url
//說明4(見文末) if(null!=unifiedOrderRespose
&& "SUCCESS".equals(unifiedOrderRespose.getReturn_code())
&& "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
return unifiedOrderRespose.getCode_url();
}else{
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
-
將返回的支付交易鏈接生成2維碼展現:沒有異常的情況下,在頁面中使用
標簽接收就行。實際使用時,結合前端和業務的需求放置2維碼??梢栽趻叽a支付/案例及規范中找到部份素材和界面規范來設計微信風格的支付頁面。

-
用戶可以通過維系客戶端進行掃碼支付。支付完成后回調我們notify_url設置的url,通過成功的回調來更改業務系統中的定單狀態或1些業務需求。這里回調沒有寫出可以參考支付寶:web頁面掃碼支付、網站支付、支付寶即時到賬
+ springmvc中的回調。
5、說明:
-
2維碼可以查看zxing實現2維碼生成和解析;微信這邊也提供了2維碼的學習,大家有興趣可以看看:http://www.thonky.com/qr-code-tutorial/ 和http://coolshell.cn/articles/10590.html
-
隨機字符串:微信對隨機字符串的要求是不超過32位。我這邊是這樣生成的,用時間戳。
/**
* 創建UUID
* @return
*/
public static synchronized String makeUUID() {
Date date = new Date();
StringBuffer s = new StringBuffer(DateUtil.formatYmdhmsm(date));
return s.append((new Random().nextInt(900) + 100)).toString();
}
-
使用Xstream時,由于微信定義的變量名大部份使用了“_”,但是在Xstream中它是關鍵字,所以會自動變成“__”,引發報錯。詳情請看:XStream異常:對象轉為XML時,會把"_"轉成"__";報錯:(Lcom/thoughtworks/xstream/io/naming/NameCoder;)V
-
獲得2維碼鏈接時,只有在return_code 和result_code都為SUCCESS的時候有返回;這里我就簡單的滿足時返回,不滿足返回null,您寫的時候需要結合業務斟酌下,是不是需要增加判斷,從而滿足不同的業務場景。統1下單API
-
簽名在上面1直沒有詳細說明,首先查看微信的安全規范中簽名算法。key值,需要自己填寫
/**
* 生成簽名
*
* @param appid_value
* @param mch_id_value
* @param productId
* @param nonce_str_value
* @param trade_type
* @param notify_url
* @param spbill_create_ip
* @param total_fee
* @param out_trade_no
* @return
*/
private String createSign(UnifiedOrderRequest unifiedOrderRequest) {
//根據規則創建可排序的map集合
SortedMap packageParams = new TreeMap();
packageParams.put("appid", unifiedOrderRequest.getAppid());
packageParams.put("body", unifiedOrderRequest.getBody());
packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());
packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());
packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());
packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());
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 + "&");
}
}
//第2步拼接key,key設置路徑:微信商戶平臺(pay.weixin.qq.com)-->賬戶設置-->API安全-->密鑰設置
sb.append("key=" +"xxxxxxxxxxxxxxxxx");
String sign = MD5Util.MD5Encode(sb.toString(), "utf⑻")
.toUpperCase();//MD5加密
return sign;
}
相干文章:支付寶:web頁面掃碼支付、網站支付、支付寶即時到賬 + springmvc
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
------分隔線----------------------------
------分隔線----------------------------