詳解JAVA后端實現(xiàn)統(tǒng)一掃碼支付:微信篇
最近做完了一個項目,正好沒事做,產(chǎn)品經(jīng)理就給我安排了一個任務(wù)。
做一個像收錢吧這樣可以統(tǒng)一掃碼收錢的功能。
一開始并不知道是怎么實現(xiàn)的,咨詢了好幾個朋友,才知道大概的業(yè)務(wù)流程:先是開一個網(wǎng)頁用來判斷支付平臺,是微信還是支付寶,判斷過后就好辦了,直接照搬微信支付和支付寶的官方文檔。不過微信的文檔感覺有點坑,得多花點心思。
現(xiàn)在講講怎么實現(xiàn)微信支付網(wǎng)頁支付,也就是公眾號支付:
1.判斷支付平臺,在判斷是微信平臺時,必須使用window.location打開網(wǎng)頁,使用其他方法在IOS版微信無法打開網(wǎng)頁,至少現(xiàn)在的新版微信無法打開。對應(yīng)的連接是請求獲取code的鏈接。第2步會講到。
<html>
<head>
<title>判斷客戶平臺</title>
<basefont face="微軟雅黑" size="2" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="exporter-version" content="Evernote Windows/303244 (zh-CN, DDL); Windows/6.1.7601 Service Pack 1 (Win64);"/>
<script type="text/javascript" src="jquery-3.1.1.min.js"></script>
<style>
body, td {
font-family: 微軟雅黑;
font-size: 10pt;
}
</style>
</head>
<body>
<script type="text/javascript">
window.onload = function(){
if(isWeiXin()){
window.location='http://www.xxoo.com/InterfaceAPI/code';
} else if(isZFB()){
alert('支付寶即將開放....');
//var p = document.getElementsByTagName('p');
//p[0].innerHTML = window.navigator.userAgent;
}else{
alert('請使用微信或者支付寶App掃碼');
}
}
function isWeiXin(){
var ua = window.navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
return true;
}else{
return false;
}
}
function isZFB(){
var ua = window.navigator.userAgent.toLowerCase();
if(ua.match(/AlipayClient/i) =='alipayclient'){
return true;
}else{
return false;
}
}
</script>
</body></html>
2.這里是獲取code,回調(diào)地址必須使用URLEncoder的utf-8編碼,這里最終只獲取openid,需要獲取UserInfo其他信息的自行測試,只需要修改一下 scope 的參數(shù),
@RequestMapping({ "code" })
public void getCode(HttpServletRequest request, HttpServletResponse response) {
try {
//回調(diào)地址
String redirect_uri = URLEncoder.encode(
"http://www.xxoo.com/InterfaceAPI/openid?codeID=7837283",
"utf-8");
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
+ WechatConfig.APP_ID
+ "&redirect_uri="
+ redirect_uri
+ "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
response.sendRedirect(url);
} catch (Exception e) {
e.printStackTrace();
}
}
3.里面有一個codeid的參數(shù),不要在意這個,是用來測試用的。這里只需要openid,下面是使用get方法獲取json返回結(jié)果,獲取到openid后,重定向到支付頁面。
@RequestMapping({ "openid" })
public void getOpenid(String codeID, String code,
HttpServletResponse response) {
try {
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
+ WechatConfig.APP_ID
+ "&secret="
+ WechatConfig.APP_SECRET
+ "&code="
+ code
+ "&grant_type=authorization_code";
if (code != null) {
String json = WebUtils.get(requestUrl, null);
WechatResult result = new Gson().fromJson(json,
WechatResult.class);
OPEN_ID = result.getOpenid();
System.out.println("====OPEN_ID====" + OPEN_ID);
response.sendRedirect("http://www.xxoo.com/InterfaceAPI/pay.html");
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.在前端支付頁面輸入要支付的金額,提交到后臺
$.ajax({
type: "POST",
dataType: "html",
url: "http://www.xxoo.com/InterfaceAPI/weixinPay",
data: "value="+self.input.value,
timeout:10000,
cache: true,
async: true,
error: function(data){
//alert(data+"---value-->"+self.input.value);
}, },});
5.后端獲取金額然后在后端統(tǒng)一下單,公眾號支付有兩個地方不一樣,一是支付類型要改為 JSAPI,二是需要獲取openid
@RequestMapping({ "weixinPay" })
public void weixinPay(HttpServletRequest request,
HttpServletResponse response) {
String value = request.getParameter("value");
WechatTradeTest wechat = new WechatTradeTest();
String json = wechat.testunifiedOrder(Integer.valueOf(value), OPEN_ID);
//這里返回json到前端
write(json, response);
}
6.統(tǒng)一下單成功后返回的結(jié)果例子:
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[JSAPI]]></trade_type> </xml>
7.返回的參數(shù)需要重新簽名并返回到前端,簽名方法與統(tǒng)一下單時的簽名是一樣的!簽名時必須要帶上微信商戶返回是以Json格式返回到前端。
public String testunifiedOrder(int fee,String openid) {
WechatUnifiedOrder request = new WechatUnifiedOrder();
request.setBody("測試商品");
request.setDetail("一個好商品");
request.setGoods_tag("測試");
request.setOut_trade_no(System.currentTimeMillis() + "");
request.setFee_type("CNY");
request.setTotal_fee(1);
request.setSpbill_create_ip("192.168.88.26");
request.setTime_start(System.currentTimeMillis() + "");
request.setOpenid(openid);
//下單成功后返回
WechatUnifiedOrder.Response response = WechatConfig.getInstance()
.unifiedOrder(request);
response.setTime_start(request.getTime_start());
WeichatData data = new WeichatData();
data.setAppId(response.getAppid());
data.setTimeStamp(request.getTime_start());
data.setNonceStr(response.getNonce_str());
data.setPrepay_id(response.getPrepay_id());
data.setSignType("MD5");
TreeMap<String, String> requestMap = new TreeMap<String, String>();
requestMap.put("appId", response.getAppid());
requestMap.put("timeStamp", response.getTime_start());
requestMap.put("nonceStr", response.getNonce_str());
requestMap.put("package", "prepay_id="+response.getPrepay_id());
requestMap.put("signType","MD5");
data.setPaySign(sign(requestMap).toUpperCase());
return new Gson().toJson(data);
}
8.前端需要解析json,獲取對應(yīng)的值,喚醒微信支付
success: function(data){
if(data!=null){
var obj=eval("("+data+")");
appId = obj["appId"];
//timeStamp = new Date().getTime();
timeStamp = obj["timeStamp"];
nonceStr = obj["nonceStr"];
package = obj["prepay_id"];
paySign = obj["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);
}
}else{
onBridgeReady();
}
}else{
alert("支付失敗");
}
},
//微信回調(diào)
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" :appId,
"timeStamp":timeStamp,
"nonceStr" :nonceStr,
"package" :"prepay_id="+package,
"signType" :"MD5",
"paySign" : paySign
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
}else {
}
}
);
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java基礎(chǔ)--自己動手實現(xiàn)一個LRU
這篇文章主要介紹了運用方案如何實現(xiàn)LUR,文章中通過代碼講解的非常詳細(xì),對大家的工作或?qū)W習(xí)有一定的參考價值,感興趣的朋友可以參考一下2021-08-08
java8學(xué)習(xí)教程之lambda表達(dá)式的使用方法
Java8最值得學(xué)習(xí)的特性就是Lambda表達(dá)式,下面這篇文章主要給大家介紹了關(guān)于java8學(xué)習(xí)教程之lambda表達(dá)式使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09
java.lang.UnsupportedOperationException的問題解決
本文主要介紹了java.lang.UnsupportedOperationException的問題解決,該錯誤表示調(diào)用的方法不被支持或不可用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07
Java I/O深入學(xué)習(xí)之File和RandomAccessFile
這篇文章主要介紹了Java I/O深入學(xué)習(xí)之File和RandomAccessFile, I/O系統(tǒng)即輸入/輸出系統(tǒng),對于一門程序語言來說,創(chuàng)建一個好的輸入/輸出系統(tǒng)并非易事。在充分理解Java I/O系統(tǒng)以便正確地運用之前,我們需要學(xué)習(xí)相當(dāng)數(shù)量的類。,需要的朋友可以參考下2019-06-06
關(guān)于兩個BeanUtils.copyProperties()的用法及區(qū)別
這篇文章主要介紹了關(guān)于兩個BeanUtils.copyProperties()的用法及區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06

