教你用Java在個(gè)人電腦上實(shí)現(xiàn)微信掃碼支付
Java實(shí)現(xiàn)PC微信掃碼支付
做一個(gè)電商網(wǎng)站支付功能必不可少,那我們今天就來(lái)盤(pán)一盤(pán)微信支付。
業(yè)務(wù)流程:
支付服務(wù)開(kāi)發(fā)前提準(zhǔn)備:
1.SDK下載:SDK
2.利用外網(wǎng)穿透,獲得一個(gè)外網(wǎng)域名:natapp
3.APPID,商戶ID,密鑰
注:上面三個(gè)參數(shù)需要自己申請(qǐng)
開(kāi)發(fā)階段:
導(dǎo)入依賴:
<!--eureka的客戶端依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- http客戶端 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <!-- 二維碼 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency> <!-- 生成二維碼 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.3.3</version> </dependency> <!--websocket 服務(wù)器主動(dòng)發(fā)送請(qǐng)求給websocket--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
微信支付配置類(lèi)
/** * 微信支付配置 */ public class MyWXConfig extends WXPayConfig { //賬戶的APPID @Override public String getAppID() { return "wx307113892f15a42e"; } //商戶ID @Override public String getMchID() { return "1508236581"; } //秘鑰 @Override public String getKey() { return "HJd7sHGHd6djgdgFG5778GFfhghghgfg"; } @Override public InputStream getCertStream() { return null; } @Override public IWXPayDomain getWXPayDomain() { return new WXPayDomain(); } class WXPayDomain implements IWXPayDomain{ @Override public void report(String domain, long elapsedTimeMillis, Exception ex) { } @Override public DomainInfo getDomain(WXPayConfig config) { return new DomainInfo("api.mch.weixin.qq.com",true); } } }
websocket配置類(lèi):
package com.cloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
wensocket工具類(lèi):
package com.cloud.config; import org.springframework.stereotype.Component; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import java.io.IOException; /** * WebSocket工具類(lèi) * ServerEndpoint配置websocket的名稱,和前臺(tái)頁(yè)面對(duì)應(yīng) */ @ServerEndpoint(value = "/eshop") @Component public class WebSocketUtils { //WebSocket的對(duì)話對(duì)象 private static Session session = null; //建立和前臺(tái)頁(yè)面連接后的回調(diào)方法 @OnOpen public void onOpen(Session session){ System.out.println("建立連接"+session); //給連接賦值 WebSocketUtils.session = session; } @OnMessage public void onMessage(String message, Session session){ System.out.println("收到前臺(tái)消息:" + message); } @OnClose public void onClose(Session session) throws IOException { System.out.println("連接關(guān)閉"); session.close(); } /** * 向前臺(tái)發(fā)消息 * @param message * @throws IOException */ public static void sendMessage(String message) throws IOException { System.out.println("發(fā)送消息:" + message); if( WebSocketUtils.session != null) { WebSocketUtils.session.getBasicRemote().sendText(message); } } }
service:
package com.cloud.service; import com.cloud.utils.MyWXConfig; import com.cloud.utils.WXPay; import com.cloud.utils.WXPayUtil; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * 微信支付Service */ @Service public class PayService { /** * 下單 * @param goodsId 商品id * @param price 價(jià)格 * @return 二維碼的URL */ public Map<String, String> makeOrder(String goodsId, Long price) throws Exception { //創(chuàng)建支付對(duì)象 MyWXConfig config = new MyWXConfig(); WXPay wxPay = new WXPay(config); Map<String,String> map = new HashMap<>(); map.put("appid",config.getAppID()); map.put("mch_id",config.getMchID()); map.put("device_info","WEB"); map.put("nonce_str", UUID.randomUUID().toString().replace("-","")); map.put("body","商城購(gòu)物"); String tradeNo = UUID.randomUUID().toString().replace("-", ""); map.put("out_trade_no", tradeNo); map.put("fee_type","CNY"); map.put("total_fee",String.valueOf(price)); map.put("notify_url","http://68dhbz.natappfree.cc/pay/rollback"); //微信對(duì)商戶后臺(tái)的回調(diào)接口 map.put("trade_type","NATIVE"); map.put("product_id",goodsId); //執(zhí)行統(tǒng)一下單 Map<String, String> result = wxPay.unifiedOrder(map); System.out.println("result:"+result); //保存訂單號(hào) result.put("trade_no",tradeNo); return result; } /** * 生成二維碼 * @param url * @param response */ public void makeQRCode(String url, HttpServletResponse response){ //通過(guò)支付鏈接生成二維碼 HashMap<EncodeHintType, Object> hints = new HashMap<>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); hints.put(EncodeHintType.MARGIN, 2); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints); MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream()); System.out.println("創(chuàng)建二維碼完成"); } catch (Exception e) { e.printStackTrace(); } } /** * 檢查訂單狀態(tài) * @param tradeNo * @return * @throws Exception */ public String checkOrder(String tradeNo) throws Exception { MyWXConfig config = new MyWXConfig(); String str = "<xml>"+ "<appid>"+config.getAppID()+"</appid>"+ "<mch_id>"+config.getMchID()+"</mch_id>"+ "<nonce_str>"+UUID.randomUUID().toString().replace("-","")+"</nonce_str>"+ "<out_trade_no>"+tradeNo+"</out_trade_no>"+ "<sign>5E00F9F72173C9449F802411E36208734B8138870ED3F66D8E2821D55B317078</sign>"+ "</xml>"; WXPay pay = new WXPay(config); Map<String,String> map = WXPayUtil.xmlToMap(str); Map<String, String> map2 = pay.orderQuery(map); String state = map2.get("trade_state"); System.out.println("訂單"+tradeNo+",狀態(tài)"+state); return state; } }
controller:
package com.cloud.controller; import com.cloud.config.WebSocketUtils; import com.cloud.service.PayService; import com.cloud.utils.WXPayUtil; import org.apache.tomcat.util.http.fileupload.util.Streams; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; /** * @author yanglihu */ @RestController @RequestMapping("/pay") public class PayController { @Autowired private PayService payService; private String tradeNo; /** * 二維碼生成 */ @GetMapping("/code") public void qrcode(@RequestParam("goodsId")String goodsId, @RequestParam("price")Long price, HttpServletResponse response){ try { Map<String,String> map = payService.makeOrder(goodsId, price); payService.makeQRCode(map.get("code_url"),response); System.out.println("生成訂單號(hào):" + map.get("trade_no")); tradeNo = map.get("trade_no"); } catch (Exception e) { e.printStackTrace(); } } /** * 支付后通知 */ @PostMapping("/rollback") public void notify(HttpServletRequest request, HttpServletResponse response) throws Exception { //獲得微信傳來(lái)的xml字符串 String str = Streams.asString(request.getInputStream()); //將字符串xml轉(zhuǎn)換為Map Map<String, String> map = WXPayUtil.xmlToMap(str); //讀取訂單號(hào) String no = map.get("out_trade_no"); //模擬修改商戶后臺(tái)數(shù)據(jù)庫(kù)訂單狀態(tài) System.out.println("更新訂單狀態(tài):"+no); //給微信發(fā)送消息 response.getWriter().println("<xml>\n" + " <return_code><![CDATA[SUCCESS]]></return_code>\n" + " <return_msg><![CDATA[OK]]></return_msg>\n" + " <appid><![CDATA["+map.get("appid")+"]]></appid>\n" + " <mch_id><![CDATA["+map.get("mch_id")+"]]></mch_id>\n" + " <nonce_str><![CDATA["+map.get("nonce_str")+"]]></nonce_str>\n" + " <openid><![CDATA["+map.get("openid")+"]]></openid>\n" + " <sign><![CDATA["+map.get("sign")+"]]></sign>\n" + " <result_code><![CDATA[SUCCESS]]></result_code>\n" + " <prepay_id><![CDATA["+map.get("prepay_id")+"]]></prepay_id>\n" + " <trade_type><![CDATA[NATIVE]]></trade_type>\n" + "</xml>"); WebSocketUtils.sendMessage("ok"); } /** * 檢查訂單狀態(tài) */ @PostMapping("checkOrder") public String checkOrder() throws Exception { System.out.println("trade_no:" + tradeNo); if(StringUtils.isEmpty(tradeNo)){ return null; } String success = payService.checkOrder(tradeNo); System.out.println("check:" + success); return success; } }
支付頁(yè)面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE"> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> <title>樂(lè)優(yōu)商城--微信支付頁(yè)</title> <link rel="icon" href="/assets/img/favicon.ico" rel="external nofollow" rel="external nofollow" > <link rel="stylesheet" type="text/css" href="css/webbase.css" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" type="text/css" href="css/pages-weixinpay.css" rel="external nofollow" /> </head> <body> <!--頁(yè)面頂部白條條,由js動(dòng)態(tài)加載--> <script type="text/javascript" src="plugins/jquery/jquery.min.js"></script> <div class="top"></div> <script type="text/javascript">$(".top").load("shortcut.html");</script> <div class="checkout py-container pay"> <div class="checkout-steps"> <div class="fl weixin">微信支付</div> <div class="fl sao"> <p class="red">二維碼已過(guò)期,刷新頁(yè)面重新獲取二維碼。</p> <div class="fl code"> <img src="http://api.eshop.com/pay/code?goodsId=11&price=1" alt=""> <div class="saosao"> <p>請(qǐng)使用微信掃一掃</p> <p>掃描二維碼支付</p> </div> </div> <div class="fl phone"> </div> </div> <div class="clearfix"></div> <p><a href="pay.html" rel="external nofollow" target="_blank">> 其他支付方式</a></p> </div> </div> </div> <script type="text/javascript" src="js/plugins/jquery/jquery.min.js"></script> <script type="text/javascript" src="js/plugins/jquery.easing/jquery.easing.min.js"></script> <script type="text/javascript" src="js/plugins/sui/sui.min.js"></script> <script type="text/javascript" src="js/widget/nav.js"></script> <script type="text/javascript"> $(function(){ $("ul.payType li").click(function(){ $(this).css("border","2px solid #E4393C").siblings().css("border-color","#ddd"); }) }) </script> <script> var websocket = null; //判斷當(dāng)前瀏覽器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://localhost:8888/eshop"); } else{ alert('Not support websocket') } //接收到消息的回調(diào)方法 websocket.onmessage = function(event){ console.log(event.data); if(event.data == "ok"){ location.href = "paysuccess.html"; } } </script> </body> </html>
成功頁(yè)面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE"> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> <title>樂(lè)優(yōu)商城--支付頁(yè)-成功</title> <link rel="icon" href="/assets/img/favicon.ico" rel="external nofollow" rel="external nofollow" > <link rel="stylesheet" type="text/css" href="css/webbase.css" rel="external nofollow" rel="external nofollow" /> <link rel="stylesheet" type="text/css" href="css/pages-paysuccess.css" rel="external nofollow" /> </head> <body> <!--head--> <!--頁(yè)面頂部白條條,由js動(dòng)態(tài)加載--> <script type="text/javascript" src="plugins/jquery/jquery.min.js"></script> <div class="top"></div> <script type="text/javascript">$(".top").load("shortcut.html");</script> <div class="cart py-container"> <!--主內(nèi)容--> <div class="paysuccess"> <div class="success"> <h3><img src="img/_/right.png" width="48" height="48"> 恭喜您,支付成功啦!</h3> <div class="paydetail"> <p>支付方式:微信支付</p> <p>支付金額:¥1006.00元</p> <p class="button"><a href="home-index.html" rel="external nofollow" class="sui-btn btn-xlarge btn-danger">查看訂單</a> <a href="index.html" rel="external nofollow" class="sui-btn btn-xlarge ">繼續(xù)購(gòu)物</a></p> </div> </div> </div> </div> <script type="text/javascript" src="js/plugins/jquery/jquery.min.js"></script> <script type="text/javascript" src="js/plugins/jquery.easing/jquery.easing.min.js"></script> <script type="text/javascript" src="js/plugins/sui/sui.min.js"></script> <script type="text/javascript" src="components/ui-modules/nav/nav-portal-top.js"></script> </body> </html>
java后臺(tái)顯示
到此這篇關(guān)于教你用Java在個(gè)人電腦上實(shí)現(xiàn)微信掃碼支付的文章就介紹到這了,更多相關(guān)Java微信掃碼支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java必學(xué)必會(huì)之this關(guān)鍵字
java必學(xué)必會(huì)之this關(guān)鍵字,java中this的用法進(jìn)行了詳細(xì)的分析介紹,感興趣的小伙伴們可以參考一下2015-12-12springboot 中 thymeleaf 常用的語(yǔ)法完整實(shí)例
在 Spring Boot 項(xiàng)目中,Thymeleaf 是一個(gè)常用的模板引擎,它提供了豐富的語(yǔ)法來(lái)動(dòng)態(tài)渲染 HTML 頁(yè)面,下面給大家介紹springboot 中 thymeleaf 常用的語(yǔ)法完整實(shí)例,感興趣的朋友一起看看吧2024-03-03Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析
這篇文章主要介紹了Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析,裝飾模式能夠?qū)崿F(xiàn)動(dòng)態(tài)的為對(duì)象添加功能,是從一個(gè)對(duì)象外部來(lái)給對(duì)象添加功能,通常給對(duì)象添加功能,要么直接修改對(duì)象添加相應(yīng)的功能,要么派生對(duì)應(yīng)的子類(lèi)來(lái)擴(kuò)展,抑或是使用對(duì)象組合的方式,需要的朋友可以參考下2023-12-12在springboot中如何使用filter設(shè)置要排除的URL
這篇文章主要介紹了在springboot中如何使用filter設(shè)置要排除的URL,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java使用File類(lèi)遍歷目錄及文件實(shí)例代碼
本篇文章主要介紹了Java使用File類(lèi)遍歷目錄及文件實(shí)例代碼,詳細(xì)的介紹了File類(lèi)的使用,有興趣的可以了解一下。2017-04-04關(guān)于@Query注解的用法(Spring Data JPA)
這篇文章主要介紹了關(guān)于@Query注解的用法(Spring Data JPA),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03