日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java SpringMVC实现PC端网页微信扫码支付完整版

發布時間:2024/1/17 java 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java SpringMVC实现PC端网页微信扫码支付完整版 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:前期微信支付掃盲知識

前提條件是已經有申請了微信支付功能的公眾號,然后我們需要得到公眾號APPID和微信商戶號,這個分別在微信公眾號和微信支付商家平臺上面可以發現。其實在你申請成功支付功能之后,微信會通過郵件把Mail轉給你的,有了這些信息之后,我們就可以去微信支付服務支持頁面:https://pay.weixin.qq.com/service_provider/index.shtml

打開這個頁面,點擊右上方的鏈接【開發文檔】會進入到API文檔說明頁面,看起來如下

?

選擇紅色圓圈的掃碼支付就是我們要做接入方式,鼠標移動到上面會提示你去查看開發文檔,如果這個都不知道怎么查看,可以洗洗睡了,你真的不合適做程序員,地址如下:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1在瀏覽器中打開之后會看到

?

我們重點要關注和閱讀的內容我已經用紅色橢圓標注好了,首先閱讀【接口規則】里面的協議規范,開玩笑這個都不讀你就想做微信支付,這個就好比你要去泡妞,得先收集點基本背景信息,了解對方特點,不然下面還怎么溝通。事實證明只有會泡妞得程序員才是好銷售。跑題了我們接下來要看一下【場景介紹】中的案例與規范,只看一下記得一定要微信支付的LOGO下載下來,是為了最后放到我們自己的掃碼支付網頁上,這樣看上去比較專業一點。之后重點關注【模式二】

我們這里就是要采用模式二的方式實現PC端頁面掃碼支付功能。

??? 微信官方對模式二的解釋是這樣的“商戶后臺系統先調用微信支付的統一下單接口,微信后臺系統返回鏈接參數code_url,商戶后臺系統將code_url值生成二維碼圖片,用戶使用微信客戶端掃碼后發起支付。注意:code_url有效期為2小時,過期后掃碼不能再發起支付”??疵靼琢税删褪俏覀兪紫纫{用微信提供統一下單接口,得到一個關鍵信息code_url(至于這個code_url是什么鬼,我也不知道),然后我們通過自己的程序把這個URL生成一個二維碼,生成二維碼我這里用了Google的zxing庫。然后把這個二維碼顯示在你的PC端網頁上就行啦。這樣終端用戶一掃碼就支付啦,支付就完成啦,看到這里你肯定很激動,發現微信支付如此簡單,等等還有個事情我們還不知道,客戶知道付錢了,我們服務器端還不知道呢,以微信開發人員的智商他們早就想到這個問題了,所以讓你在調用統一下單接口的時候其中有個必填的參數就是回調URL,就是如果客戶端付款成功之后微信會通過這個URL向我們自己的服務器提交一些數據,然后我們后臺解析這些數據,完成我們自己操作。這樣我們才知道客戶是否真的已經通過微信付款了。這樣整個流程才結束,這個就是模式二。微信用一個時序圖示這樣表示這個過程的。

?

表達起來比較復雜,看上去比較吃力,總結一下其實我們服務器該做的事情就如下件:

1. 通過統一下單接口傳入正確的參數(當然要包括我們的回調URL)與簽名驗證,從返回數據中得到code_url的對應數據

2. 根據code_url的數據我們自己生成一個二維碼圖片,顯示在瀏覽器網頁上

3. 在回調的URL中添加我們自己業務邏輯處理。

?

至此掃盲結束了,你終于知道掃碼支付什么個什么樣的流程了,下面我們就一起來扒扒它的相關API使用,做好每步處理。

二:開發過程

在開發代碼之前,請先準備幾件事情。

1. 添加ZXing的maven依賴

2. 添加jdom的maven依賴

3.下載Java版本SDK演示程序,地址在這里

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

我們需要MD5Util.java和XMLUtil.java兩個文件

4. 我們使用HttpClient版本是4.5.1,記得添加Maven依賴

上面準備工作做好以后,繼續往下看:

首先我們要調用微信的統一下單接口,我們點擊【API列表】中的統一下單會看到這樣頁面:

?

以本人調用實際情況為例,如下的參數是必須要有的,為了大家的方便我已經把它變成一個POJO的對象, 代碼如下:

[java]?view plaincopy
  • public?class?UnifiedorderDto?implements?WeiXinConstants?{??
  • ??
  • ????private?String?appid;??
  • ????private?String?body;??
  • ????private?String?device_info;??
  • ????private?String?mch_id;??
  • ????private?String?nonce_str;??
  • ????private?String?notify_url;??
  • ????private?String?openId;??
  • ????private?String?out_trade_no;??
  • ????private?String?spbill_create_ip;??
  • ????private?int?total_fee;??
  • ????private?String?trade_type;??
  • ????private?String?product_id;??
  • ????private?String?sign;??
  • ??????
  • ????public?UnifiedorderDto()?{??
  • ????????this.appid?=?APPID;??
  • ????????this.mch_id?=?WXPAYMENTACCOUNT;??
  • ????????this.device_info?=?DEVICE_INFO_WEB;??
  • ????????this.notify_url?=?CALLBACK_URL;??
  • ????????this.trade_type?=?TRADE_TYPE_NATIVE;??
  • ????}??
  • ??
  • ????public?String?getAppid()?{??
  • ????????return?appid;??
  • ????}??
  • ??
  • ????public?void?setAppid(String?appid)?{??
  • ????????this.appid?=?appid;??
  • ????}??
  • ??
  • ????public?String?getBody()?{??
  • ????????return?body;??
  • ????}??
  • ??
  • ????public?void?setBody(String?body)?{??
  • ????????this.body?=?body;??
  • ????}??
  • ??
  • ????public?String?getDevice_info()?{??
  • ????????return?device_info;??
  • ????}??
  • ??
  • ????public?void?setDevice_info(String?device_info)?{??
  • ????????this.device_info?=?device_info;??
  • ????}??
  • ??
  • ????public?String?getMch_id()?{??
  • ????????return?mch_id;??
  • ????}??
  • ??
  • ????public?void?setMch_id(String?mch_id)?{??
  • ????????this.mch_id?=?mch_id;??
  • ????}??
  • ??
  • ????public?String?getNonce_str()?{??
  • ????????return?nonce_str;??
  • ????}??
  • ??
  • ????public?void?setNonce_str(String?nonce_str)?{??
  • ????????this.nonce_str?=?nonce_str;??
  • ????}??
  • ??
  • ????public?String?getNotify_url()?{??
  • ????????return?notify_url;??
  • ????}??
  • ??
  • ????public?void?setNotify_url(String?notify_url)?{??
  • ????????this.notify_url?=?notify_url;??
  • ????}??
  • ??
  • ????public?String?getOpenId()?{??
  • ????????return?openId;??
  • ????}??
  • ??
  • ????public?void?setOpenId(String?openId)?{??
  • ????????this.openId?=?openId;??
  • ????}??
  • ??
  • ????public?String?getOut_trade_no()?{??
  • ????????return?out_trade_no;??
  • ????}??
  • ??
  • ????public?void?setOut_trade_no(String?out_trade_no)?{??
  • ????????this.out_trade_no?=?out_trade_no;??
  • ????}??
  • ??
  • ????public?String?getSpbill_create_ip()?{??
  • ????????return?spbill_create_ip;??
  • ????}??
  • ??
  • ????public?void?setSpbill_create_ip(String?spbill_create_ip)?{??
  • ????????this.spbill_create_ip?=?spbill_create_ip;??
  • ????}??
  • ??
  • ????public?int?getTotal_fee()?{??
  • ????????return?total_fee;??
  • ????}??
  • ??
  • ????public?void?setTotal_fee(int?total_fee)?{??
  • ????????this.total_fee?=?total_fee;??
  • ????}??
  • ??
  • ????public?String?getTrade_type()?{??
  • ????????return?trade_type;??
  • ????}??
  • ??
  • ????public?void?setTrade_type(String?trade_type)?{??
  • ????????this.trade_type?=?trade_type;??
  • ????}??
  • ??
  • ????public?String?getSign()?{??
  • ????????return?sign;??
  • ????}??
  • ??
  • ????public?void?setSign(String?sign)?{??
  • ????????this.sign?=?sign;??
  • ????}??
  • ??
  • ????public?String?getProduct_id()?{??
  • ????????return?product_id;??
  • ????}??
  • ??
  • ????public?void?setProduct_id(String?product_id)?{??
  • ????????this.product_id?=?product_id;??
  • ????}??
  • ????public?String?generateXMLContent()?{??
  • ????????String?xml?=?"<xml>"?+??
  • ???????????"<appid>"?+?this.appid?+?"</appid>"?+???
  • ???????????"<body>"?+?this.body?+?"</body>"?+???
  • ???????????"<device_info>WEB</device_info>"?+???
  • ???????????"<mch_id>"?+?this.mch_id?+?"</mch_id>"?+???
  • ???????????"<nonce_str>"?+?this.nonce_str?+?"</nonce_str>"?+??
  • ???????????"<notify_url>"?+?this.notify_url?+?"</notify_url>"?+???
  • ???????????"<out_trade_no>"?+?this.out_trade_no?+?"</out_trade_no>"?+???
  • ???????????"<product_id>"?+?this.product_id?+?"</product_id>"?+??
  • ???????????"<spbill_create_ip>"?+?this.spbill_create_ip+?"</spbill_create_ip>"?+??
  • ???????????"<total_fee>"?+?String.valueOf(this.total_fee)?+?"</total_fee>"?+???
  • ???????????"<trade_type>"?+?this.trade_type?+?"</trade_type>"?+???
  • ???????????"<sign>"?+?this.sign?+?"</sign>"?+???
  • ????????"</xml>";??
  • ????????return?xml;??
  • ????}??
  • ??????
  • ????public?String?makeSign()?{??
  • ????????String?content?="appid="?+?this.appid?+???
  • ???????????????????"&body="?+?this.body?+???
  • ???????????????????"&device_info=WEB"?+???
  • ???????????????????"&mch_id="?+?this.mch_id?+???
  • ???????????????????"&nonce_str="?+?this.nonce_str?+???
  • ???????????????????"?ify_url="?+?this.notify_url?+??
  • ???????????????????"&out_trade_no="?+?this.out_trade_no?+???
  • ???????????????????"&product_id="?+?this.product_id?+???
  • ???????????????????"&spbill_create_ip="?+?this.spbill_create_ip+??
  • ???????????????????"&total_fee="?+?String.valueOf(this.total_fee)?+??
  • ???????????????????"&trade_type="?+?this.trade_type;??
  • ????????content?=?content?+?"&key="?+?WeiXinConstants.MD5_API_KEY;??
  • ????????String?esignature?=?WeiXinPaymentUtil.MD5Encode(content,?"utf-8");??
  • ????????return?esignature.toUpperCase();??
  • ????}??
  • ??????
  • }??
  • 其中各個成員變量的解釋可以參見【統一下單接口】的說明即可。

    有這個之后我們就要要設置的內容填寫進去,去調用該接口得到返回數據,從中拿到code_url的數據然后據此生成一個二維圖片,把圖片的地址返回給PC端網頁,然后它就會顯示出來,這里要特別說明一下,我們自己PC端網頁在點擊微信支付的時候就會通過ajax方式調用我們自己后臺的SpringMVC Controller然后在Controller的對應方法中通過HTTPClient完成對微信統一下單接口調用解析返回的XML數據得到code_url的值,生成二維碼之后返回給前臺網頁。Controller中實現的代碼如下:

    ?

    [java]?view plaincopy
  • Map<String,Object>?result=new?HashMap<String,Object>();??
  • ????????UnifiedorderDto?dto?=?new?UnifiedorderDto();??
  • ????????if(cash?==?null?||?"".equals(cash))?{??
  • ????????????result.put("error",?"cash?could?not?be?zero");??
  • ????????????return?result;??
  • ????????}??
  • ????????int?totalfee?=?100*Integer.parseInt(cash);??
  • ????????logger.info("total?recharge?cash?:?"?+?totalfee);??
  • ????????dto.setProduct_id(String.valueOf(System.currentTimeMillis()));??
  • ????????dto.setBody("repair");??
  • ????????dto.setNonce_str(String.valueOf(System.nanoTime()));??
  • ????????LoginInfo?loginInfo?=?LoginInfoUtil.getLoginInfo();??
  • ????????//?通過我們后臺訂單號+UUID為身份識別標志??
  • ????????dto.setOut_trade_no("你的訂單號+關鍵信息,微信回調之后傳回,你可以驗證");??
  • ????????dto.setTotal_fee(totalfee);??
  • ????????dto.setSpbill_create_ip("127.0.0.1");??
  • ????????//?generate?signature??
  • ????????dto.setSign(dto.makeSign());??
  • ????????logger.info("sign?:?"?+?dto.makeSign());??
  • ????????logger.info("xml?content?:?"?+?dto.generateXMLContent());??
  • ????????try?{??
  • ????????????HttpClient?httpClient?=?HttpClientBuilder.create().build();???
  • ????????????HttpPost?post?=?new?HttpPost(WeiXinConstants.UNIFIEDORDER_URL);??
  • ????????????post.addHeader("Content-Type",?"text/xml;?charset=UTF-8");??
  • ????????????StringEntity?xmlEntity?=?new?StringEntity(dto.generateXMLContent(),?ContentType.TEXT_XML);??
  • ????????????post.setEntity(xmlEntity);??
  • ????????????HttpResponse?httpResponse?=?httpClient.execute(post);??
  • ????????????String?responseXML?=?EntityUtils.toString(httpResponse.getEntity(),?"UTF-8");??
  • ????????????logger.info("response?xml?content?:?"?+?responseXML);??
  • ????????????//?parse?CODE_URL?CONTENT??
  • ????????????Map<String,?String>?resultMap?=?(Map<String,?String>)XMLUtil.doXMLParse(responseXML);??
  • ????????????logger.info("response?code_url?:?"?+?resultMap.get("code_url"));??
  • ????????????String?codeurl?=?resultMap.get("code_url");??
  • ????????????if(codeurl?!=?null?&&?!"".equals(codeurl))?{??
  • ????????????????String?imageurl?=?generateQrcode(codeurl);??
  • ????????????????result.put("QRIMAGE",?imageurl);??
  • ????????????}??
  • ????????????post.releaseConnection();??
  • ????????}?catch(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????result.put("success",?"1");??
  • ????????return?result;??
  • ?

    生成二維碼的代碼如下:

    [java]?view plaincopy
  • private?String?generateQrcode(String?codeurl)?{??
  • ????File?foldler?=?new?File(basePath?+?"qrcode");??
  • ????if(!foldler.exists())?{??
  • ????????foldler.mkdirs();??
  • ????}??
  • ??????
  • ????String?f_name?=?UUIDUtil.uuid()?+?".png";??
  • ???????try?{??
  • ????????File?f?=?new?File(basePath?+?"qrcode",?f_name);??
  • ????????FileOutputStream?fio?=?new?FileOutputStream(f);??
  • ????????MultiFormatWriter?multiFormatWriter?=?new?MultiFormatWriter();??
  • ????????Map?hints?=?new?HashMap();??
  • ????????hints.put(EncodeHintType.CHARACTER_SET,?"UTF-8");?//設置字符集編碼類型??
  • ????????BitMatrix?bitMatrix?=?null;??
  • ???????????bitMatrix?=?multiFormatWriter.encode(codeurl,?BarcodeFormat.QR_CODE,?300,?300,hints);??
  • ???????????BufferedImage?image?=?toBufferedImage(bitMatrix);??
  • ???????????//輸出二維碼圖片流??
  • ???????????ImageIO.write(image,?"png",?fio);??
  • ???????????return?("qrcode/"?+?f_name);??
  • ???????}?catch?(Exception?e1)?{??
  • ???????????e1.printStackTrace();??
  • ???????????return?null;??
  • ???????}???????
  • }??
  • 此時如何客戶端微信掃碼之后,微信就會通過回調我們制定URL返回數據給我們。在回調方法中完成我們自己的處理,這里要特別注意的是你的回調接口必須通過HTTP POST方法實現,否則無法接受到XML數據?;卣{處理的代碼如下:

    ?

    [java]?view plaincopy
  • @RequestMapping(value?=?"/your_callback_url",?method?=?RequestMethod.POST)??
  • @ResponseBody??
  • public?void?finishPayment(HttpServletRequest?request,?HttpServletResponse?response)?{??
  • ????try?{??
  • ????????logger.info("start?to?callback?from?weixin?server:?"?+?request.getRemoteHost());??
  • ????????Map<String,?String>?resultMap?=?new?HashMap<String,?String>();??
  • ????????InputStream?inputStream?=?request.getInputStream();??
  • ????????//?讀取輸入流??
  • ????????SAXBuilder?saxBuilder=?new?SAXBuilder();??
  • ????????Document?document?=?saxBuilder.build(inputStream);??
  • ????????//?得到xml根元素??
  • ????????Element?root?=?document.getRootElement();??
  • ????????//?得到根元素的所有子節點??
  • ????????List?list?=?root.getChildren();??
  • ????????Iterator?it?=?list.iterator();??
  • ????????while(it.hasNext())?{??
  • ????????????Element?e?=?(Element)?it.next();??
  • ????????????String?k?=?e.getName();??
  • ????????????String?v?=?"";??
  • ????????????List?children?=?e.getChildren();??
  • ????????????if(children.isEmpty())?{??
  • ????????????????v?=?e.getTextNormalize();??
  • ????????????}?else?{??
  • ????????????????v?=?XMLUtil.getChildrenText(children);??
  • ????????????}??
  • ????????????resultMap.put(k,?v);??
  • ????????}??
  • ??????????
  • ????????//?驗證簽名!!!??
  • ????????/*?
  • ????????String[]?keys?=?resultMap.keySet().toArray(new?String[0]);?
  • ????????Arrays.sort(keys);?
  • ????????String?kvparams?=?"";?
  • ????????for(int?i=0;?i<keys.length;?i++)?{?
  • ????????????if(keys[i].equals("esign"))?{?
  • ????????????????continue;?
  • ????????????}?
  • ????????????//?簽名算法?
  • ????????????if(i?==?0)?{?
  • ????????????????kvparams?+=?(keys[i]?+?"="?+?resultMap.get(keys[i]));?
  • ????????????}?else?{?
  • ????????????????kvparams?+=?("&"?+?keys[i]?+?"="?+?resultMap.get(keys[i]));?
  • ????????????}?
  • ????????}?
  • ????????String?esign?=?kvparams?+?"&key="?+?WeiXinConstants.MD5_API_KEY;?
  • ????????String?md5esign?=?WeiXinPaymentUtil.MD5Encode(esign,?"UTF-8");?
  • ????????if(!md5esign.equals(resultMap.get("sign")))?{?
  • ????????????return;?
  • ????????}*/??
  • ??????????
  • ????????//關閉流??
  • ????????//?釋放資源??
  • ????????inputStream.close();??
  • ????????inputStream?=?null;??
  • ????????String?returnCode?=?resultMap.get("return_code");??
  • ????????String?outtradeno?=?resultMap.get("out_trade_no");??
  • ????????//?以分為單位??
  • ????????int?nfee?=?Integer.parseInt(resultMap.get("total_fee"));??
  • ????????logger.info("out?trade?no?:?"?+?outtradeno);??
  • ????????logger.info("total_fee?:?"?+?nfee);??
  • ????????//?業務處理流程??
  • ????????if("SUCCESS".equals(returnCode))?{????????????????
  • ????????????//?TODO:?your?business?process?add?here??
  • ????????????response.getWriter().print(XMLUtil.getRetResultXML(resultMap.get("return_code"),?resultMap.get("return_code")));??
  • ????????}?else?{??
  • ????????????response.getWriter().print(XMLUtil.getRetResultXML(resultMap.get("return_code"),?resultMap.get("return_msg")));??
  • ????????}??
  • ????}??
  • ????catch(IOException?ioe)?{??
  • ????????ioe.printStackTrace();??
  • ????}?catch?(JDOMException?e1)?{??
  • ????????e1.printStackTrace();??
  • ????}??
  • }??
  • ?

    微信官方Java版Demo用到的XMLUtil和MD5Util的兩個類記得拿過來改一下,演示代碼可以在它的官方演示頁面找到,相關maven依賴如下:

    ?

    [html]?view plaincopy
  • <dependency>??
  • ????<groupId>jdom</groupId>??
  • ????<artifactId>jdom</artifactId>??
  • ????<version>1.1</version>??
  • </dependency>??
  • <dependency>??
  • ????<groupId>com.google.zxing</groupId>??
  • ????<artifactId>core</artifactId>??
  • ????<version>3.3.0</version>??
  • </dependency>??
  • ?

    最后要特別注意的是關于簽名,簽名生成MD5的類我是從微信官網直接下載Java版Demo程序獲取的,建議你也是,因為這個是確保MD5簽名是一致的最佳選擇。具體的生成簽名的算法可以查看微信官方文檔,這里也強烈建議大家一定要官方API說明,你開發中所遇到各種問題90%都是因為不看官方文檔,而是輕信某人博客!這個才是我寫這篇文章的真正目的和用意,根據官方文檔,用我的Java代碼實現,微信PC端網頁掃碼支付必定在你的WEB應用中飛起來。

    轉載于:https://www.cnblogs.com/wanghuaijun/p/6249185.html

    總結

    以上是生活随笔為你收集整理的Java SpringMVC实现PC端网页微信扫码支付完整版的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。