二維碼
(1) 容錯級別
L級(低) 7%的碼字可以被恢復。
M級(中) 的碼字的15%可以被恢復。
Q級(四分)的碼字的25%可以被恢復。
H級(高) 的碼字的30%可以被恢復。
(2) 二維碼生成插件qrious
qrious是一款基於HTML5 Canvas的純JS二維碼生成插件。通過qrious.js可以快速生成各種二維碼,你可以控制二維碼的尺寸顏色,還可以將生成的二維碼進行Base64編碼。
qrious.js二維碼插件的可用配置參數如下:
參數 |
類型 |
默認值 |
描述 |
background |
String |
"white" |
二維碼的背景顏色。 |
foreground |
String |
"black" |
二維碼的前景顏色。 |
level |
String |
"L" |
二維碼的誤差校正級別(L, M, Q, H)。 |
mime |
String |
"image/png" |
二維碼輸出為圖片時的MIME類型。 |
size |
Number |
100 |
二維碼的尺寸,單位像素。 |
value |
String |
"" |
需要編碼為二維碼的值 |
web引入qrious.js
qrious.min.js
微信支付SDK
(1) 解壓WxPayAPI_JAVA_v3.zip
(2) 將解壓的maven工程導入到IDE(eclipse)
(3) 打成jar包,並安裝到maven倉庫
mvn install:install-file -Dfile=d:\setup\wxpay-sdk-0.0.3.jar -DgroupId=com.github.wxpay -DartifactId=wxpay-sdk -Dversion=0.0.3 -Dpackaging=jar
(4) 在要使用微信掃碼支付的工程引入依賴
<dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency>
HttpClient工具類
HttpClient是Apache Jakarta Common下的子項目,用來提供高效的、最新的、功能豐富的支持HTTP協議的客戶端編程工具包,並且它支持HTTP協議最新的版本和建議。HttpClient已經應用在很多的項目中,比如Apache Jakarta上很著名的另外兩個開源項目Cactus和HTMLUnit都使用了HttpClient。
HttpClient通俗的講就是模擬了瀏覽器的行為,如果我們需要在后端向某一地址提交數據獲取結果,就可以使用HttpClient.
關於HttpClient(原生)相對比較麻煩,進行封裝,使用封裝后的工具類HttpClient(對原生HttpClient進行了封裝)
HttpClient工具類使用的步驟
HttpClient client=new HttpClient(請求的url地址); client.setHttps(true);//是否是https協議 client.setXmlParam(xmlParam);//發送的xml數據 client.post();//執行post請求 String result = client.getContent(); //獲取結果
添加配置文件weixinpay.properties
## 微信公眾賬號或開放平台APP的唯一標識
appid=****************
## 財付通平台的商戶賬號
partner=*********
## 財付通平台的商戶密鑰
partnerkey=*********************************
## 回調地址
notifyurl=http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify
將二維碼插件QRious拷貝到web 的plugins目錄中
后端代碼(ServiceImpl)
@Service public class WeixinPayServiceImpl implements WeixinPayService { @Value("${appid}") private String appid; @Value("${partner}") private String partner; @Value("${partnerkey}") private String partnerkey; /** * 生成二維碼 * @return */ public Map createNative(String out_trade_no,String total_fee){ //1.創建參數 Map<String,String> param=new HashMap();//創建參數 param.put("appid", appid);//公眾號 param.put("mch_id", partner);//商戶號 param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串 param.put("body", "xxx");//商品描述 param.put("out_trade_no", out_trade_no);//商戶訂單號 param.put("total_fee",total_fee);//總金額(分) param.put("spbill_create_ip", "127.0.0.1");//IP param.put("notify_url", "http://www.xxx.cn");//回調地址(隨便寫) param.put("trade_type", "NATIVE");//交易類型 try { //2.生成要發送的xml String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey); System.out.println(xmlParam); HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); client.setHttps(true); client.setXmlParam(xmlParam); client.post(); //3.獲得結果 String result = client.getContent(); System.out.println(result); Map<String, String> resultMap = WXPayUtil.xmlToMap(result); Map<String, String> map=new HashMap<>(); map.put("code_url", resultMap.get("code_url"));//支付地址 map.put("total_fee", total_fee);//總金額 map.put("out_trade_no",out_trade_no);//訂單號 return map; } catch (Exception e) { e.printStackTrace(); return new HashMap<>(); } } }
后端代碼(Controller)
/** * 支付控制層 * @author Administrator * */ @RestController @RequestMapping("/pay") public class PayController { @Reference private WeixinPayService weixinPayService; /** * 生成二維碼 * @return */ @RequestMapping("/createNative") public Map createNative(){ IdWorker idworker=new IdWorker(); return weixinPayService.createNative(idworker.nextId()+"","1"); } }
前端代碼,先引入angular.js
angular.min.js
base.js
var app = angular.module('xxx', []);
Service.js
app.service('payService',function($http){ //本地支付 this.createNative=function(){ return $http.get('pay/createNative.do'); } });
Controller.js
app.controller('payController' ,function($scope ,payService){ //本地生成二維碼 $scope.createNative=function(){ payService.createNative().success( function(response){ $scope.money= (response.total_fee/100).toFixed(2) ; //金額 $scope.out_trade_no= response.out_trade_no;//訂單號 //二維碼 var qr = new QRious({ element:document.getElementById('qrious'),// 根據id選擇元素 size:250, level:'H', value:response.code_url }); } ); } });
html頁面
引入js
<script type="text/javascript" src="plugins/angularjs/angular.min.js"> </script> <script type="text/javascript" src="js/base.js"> </script> <script type="text/javascript" src="js/service/payService.js"> </script> <script type="text/javascript" src="js/controller/payController.js"> </script> <script type="text/javascript" src="plugins/qrious.min.js"></script>
指令
<body ng-app="xxx" ng-controller="payController" ng-init="createNative()">
html代碼
<p class="red"></p> <div class="fl code"> <img id="qrious"> <div class="saosao"> <p>請使用微信掃一掃</p> <p>掃描二維碼支付</p> </div> </div>
微信掃碼支付狀態
后端(ServiceImpl)
@Override public Map queryPayStatus(String out_trade_no) { Map param=new HashMap(); param.put("appid", appid);//公眾賬號ID param.put("mch_id", partner);//商戶號 param.put("out_trade_no", out_trade_no);//訂單號 param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串 String url="https://api.mch.weixin.qq.com/pay/orderquery"; try { String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey); HttpClient client=new HttpClient(url); client.setHttps(true); client.setXmlParam(xmlParam); client.post(); String result = client.getContent(); Map<String, String> map = WXPayUtil.xmlToMap(result); System.out.println(map); return map; } catch (Exception e) { e.printStackTrace(); return null; } }
后端代碼(Controller)
/** * 查詢支付狀態 * @param out_trade_no * @return */ @RequestMapping("/queryPayStatus") public Result queryPayStatus(String out_trade_no){ Result result=null;
int x = 0; while(true){ //調用查詢接口 Map<String,String> map = weixinPayService.queryPayStatus(out_trade_no); if(map==null){//出錯 result=new Result(false, "支付出錯"); break; } if(map.get("trade_state").equals("SUCCESS")){//如果成功 result=new Result(true, "支付成功"); break; } try { Thread.sleep(3000);//間隔三秒 } catch (InterruptedException e) { e.printStackTrace(); }
//為了不讓循環無休止地運行,我們定義一個循環變量,如果這個變量超過了這個值則退出循環,設置時間為5分鍾
x++;
if(x>=100){
result=new Result(false, "二維碼超時");
//1.調用微信的關閉訂單接口
Map<String,String> payresult = weixinPayService.closePay(out_trade_no);
if( !"SUCCESS".equals(payresult.get("result_code")) ){//如果返回結果是正常關閉
if("ORDERPAID".equals(payresult.get("err_code"))){
result=new Result(true, "支付成功");
seckillOrderService.saveOrderFromRedisToDb(userId, Long.valueOf(out_trade_no), map.get("transaction_id"));
}
}
if(result.isSuccess()==false){
System.out.println("超時,取消訂單");
//2.調用刪除
seckillOrderService.deleteOrderFromRedis(userId, Long.valueOf(out_trade_no));
}
break;
} } return result; }
前端js
Controller.js
//查詢支付狀態 queryPayStatus=function(out_trade_no){ payService.queryPayStatus(out_trade_no).success( function(response){ if(response.success){ location.href="paysuccess.html"; }else{
if(response.message=='二維碼超時'){
location.href="payTimeOut.html";
}else{
location.href="payfail.html";
} } } ); }
Service.js
修改createNative方法
//本地生成二維碼 $scope.createNative=function(){ payService.createNative().success( function(response){ .......... queryPayStatus(response.out_trade_no);//查詢支付狀態 } ); }
關閉微信掃碼支付
后端代碼(ServiceImpl)
@Override public Map closePay(String out_trade_no) { Map param=new HashMap(); param.put("appid", appid);//公眾賬號ID param.put("mch_id", partner);//商戶號 param.put("out_trade_no", out_trade_no);//訂單號 param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串 String url="https://api.mch.weixin.qq.com/pay/closeorder"; try { String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey); HttpClient client=new HttpClient(url); client.setHttps(true); client.setXmlParam(xmlParam); client.post(); String result = client.getContent(); Map<String, String> map = WXPayUtil.xmlToMap(result); System.out.println(map); return map; } catch (Exception e) { e.printStackTrace(); return null; } }
后端代碼(Controller)
修改queryPayStatus方法
前端代碼
修改queryPayStatus方法