二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。
L级(低) 7%的码字可以被恢复。
M级(中) 的码字的15%可以被恢复。
Q级(四分)的码字的25%可以被恢复。
H级(高) 的码字的30%可以被恢复。
二维码入门小demo
用此方法可以再页面生成一个简单的二维码
我们可以通过调用微信提供的接口来实现微信支付
首先导入微信支付的依赖
<dependency>
<groupId>com.github.wxpaygroupId>
<artifactId>wxpay-sdkartifactId>
<version>0.0.3version>
dependency>
通过httpClient的方式来访问微信提供的两个接口,
https://api.mch.weixin.qq.com/pay/unifiedorder 用于生成订单
https://api.mch.weixin.qq.com/pay/orderquery 用于查询订单支付状态
微信要求我们一个xml参数传递到他们所提供的接口
这里我们可以通过构建一个由属性名=属性值组成的一个map集合,通过微信提供的WXPayUtil.generateSignedXml(paramMap, partnerkey)方法,传递map集合与签名,生成一个xml
再通过WXPayUtil.xmlToMap(content) 把响应回来的数据返回一个map集合来处理数据
这里的redisTemplate.boundHashOps(“paylog”).get(userId)是为了获取支付信息中的商户订单号 out_trade_no
而改属性是在订单模块中点击立即支付后所生成的paylog对象存入redis中时存入的
@Override
public Map createNative(String userId) throws Exception {
// 获取该userId对应的payLog信息,从redis中
TbPayLog payLog = (TbPayLog) redisTemplate.boundHashOps("paylog").get(userId);
// 调用微信给我们提供的接口
HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
// 提供接口所需参数,用map存储
Map<String, String> paramMap = new HashMap<>();
// 公众账号ID appid 是 String(32) wxd678efh567hg6787 微信支付分配的公众账号ID(企业号corpid即为此appId)
paramMap.put("appid", appid);
// 商户号 mch_id 是 String(32) 1230000109 微信支付分配的商户号
paramMap.put("mch_id", partner);
// 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,长度要求在32位以内。推荐随机数生成算法
String str = WXPayUtil.generateNonceStr();
paramMap.put("nonce_str", str);
// 商品描述 body 是 String(128) 腾讯充值中心-QQ会员充值 商品简单描述,该字段请按照规范传递,具体请见参数规定(微信支付时显示的字)
paramMap.put("body", "品优购支付");
// 商户订单号 out_trade_no 是 String(32) 20150806125346 商户系统内部订单号
String out_trade_no = payLog.getOutTradeNo();
paramMap.put("out_trade_no", out_trade_no);
// 标价金额 total_fee 是 Int 88 订单总金额,单位为分,详见支付金额
paramMap.put("total_fee", "1");
// 终端IP spbill_create_ip 是 String(16) 123.12.12.123 APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
paramMap.put("spbill_create_ip", "127.0.0.1");
// 通知地址 notify_url 是 String(256) http://www.weixin.qq.com/wxpay/pay.php 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
paramMap.put("notify_url", notifyurl);
// 交易类型 trade_type 是 String(16) JSAPI JSAPI公众号支付 NATIVE扫码支付 APP APP支付说明详见参数规定
paramMap.put("trade_type", "NATIVE");
// 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 通过签名算法计算得出的签名值,详见签名生成算法
String xml = WXPayUtil.generateSignedXml(paramMap, partnerkey);
// 使用httpClient把xml设置提交
httpClient.setXmlParam(xml);
httpClient.post();
// 接收微信相应的数据
String content = httpClient.getContent();
// 把响应到的数据转化成map集合返回
Map<String, String> map = WXPayUtil.xmlToMap(content);
System.out.println(map);
map.put("out_trade_no", out_trade_no+"");
map.put("total_fee", "1");
System.out.println(map.get("out_trade_no"));
return map;
}
其中返会的map中有一个属性为交易链接,我们把这个交易连接生成二维码展示到页面即可让用户完成支付
//生成二维码的方法
$scope.createNative=function(){
payService.createNative().success(function(response){
$scope.resultMap=response;
new QRious({
element: document.getElementById('payImg'),
size: 300,
value: response.code_url,
level:'L'
});
$scope.flag=false;
$scope.payMessage="";
//查询支付的方法
$scope.queryOrder(response.out_trade_no);
})
由上面的代码我们可以发现,在生成二维码之后需要立即调用查询支付的方法,因为我们不确定用户何时回支付,因此我们需要写一个循环,在此循环中每3秒查询一次支付状态,一旦支付完成立马跳转到支付成功页面.如果超过一定的时间则提示支付超时,ran用户可以选择重新生成二维码
$scope.queryOrder=function(out_trade_no){
payService.queryOrder(out_trade_no).success(function(response){
if(response.success){
location.href="paysuccess.html#?totalFee=" + $scope.resultMap.total_fee;
}else{
if(response.message=="支付超时"){
$scope.flag=true;
$scope.payMessage="二维码过期,请刷新重新获取二维码"
}else{
location.href="payfail.html";
}
}
})
}
分别调用两个方法,查询支付状态,如果支付成功,则立即修改订单表与支付信息表
//创建支付二维码
@RequestMapping("/queryOrder/{out_trade_no}")
public Result queryOrder(@PathVariable String out_trade_no) {
try {
int times=0;
//创建一个循环,循环访问10次如果10次均未支付,则验证码过期
while(times<10) {
Thread.sleep(3000);
System.out.println(out_trade_no);
Map map = payService.queryOrder(out_trade_no);
System.out.println(map);
times++;
//如果支付状态为success则表示支付成功
if(map.get("trade_state").equals("SUCCESS")) {
//在这里表示支付成功,应该修改payLog支付信息与order订单状态
String userId = SecurityContextHolder.getContext().getAuthentication().getName();
String transaction_id = (String) map.get("transaction_id");
//调用service修改payLog支付信息与order订单状态
payService.updatePayLogAndOrder(transaction_id, userId);
return new Result(true, "支付成功");
}
}
return new Result(false, "支付超时");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "支付失败,请重试");
}
}
调用微信给我们提供的接口,具体思路与生成订单时的思路基本相同
@Override
public Map queryOrder(String out_trade_no) throws Exception {
//调用微信给我们提供的接口
HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
//提供接口所需参数,用map存储
Map<String, String> paramMap = new HashMap<>();
// 公众账号ID appid 是 String(32) wxd678efh567hg6787 微信支付分配的公众账号ID(企业号corpid即为此appId)
paramMap.put("appid", appid);
// 商户号 mch_id 是 String(32) 1230000109 微信支付分配的商户号
paramMap.put("mch_id", partner);
// 随机字符串 nonce_str 是 String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,长度要求在32位以内。推荐随机数生成算法
String str = WXPayUtil.generateNonceStr();
paramMap.put("nonce_str", str);
// 商品描述 body 是 String(128) 腾讯充值中心-QQ会员充值 商品简单描述,该字段请按照规范传递,具体请见参数规定(微信支付时显示的字)
paramMap.put("out_trade_no", out_trade_no+"");
// 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 通过签名算法计算得出的签名值,详见签名生成算法
String xml = WXPayUtil.generateSignedXml(paramMap, partnerkey);
// 使用httpClient把xml设置提交
httpClient.setXmlParam(xml);
httpClient.post();
// 接收微信相应的数据
String content = httpClient.getContent();
// 把响应到的数据转化成map集合返回
Map<String, String> map = WXPayUtil.xmlToMap(content);
return map;
}
从redis数据库中获取paylog对支付信息进行修改并保存
@Override
public void updatePayLogAndOrder(String transaction_id, String userId) {
//根据userId获取支付信息
TbPayLog payLog = (TbPayLog) redisTemplate.boundHashOps("paylog").get(userId);
payLog.setPayTime(new Date());
payLog.setTradeState("1");
payLog.setTransactionId(transaction_id);
//保存支付信息
payLogMapper.updateByPrimaryKey(payLog);
//获取订单Id
String orderList = payLog.getOrderList();
String[] orderIds = orderList.split(",");
for (String orderId : orderIds) {
TbOrder order = orderMapper.selectByPrimaryKey(Long.parseLong(orderId));
order.setPaymentTime(new Date());
order.setStatus("2");
order.setUpdateTime(new Date());
orderMapper.updateByPrimaryKey(order);
}
}
至此所有的信息存入mysql数据库中,支付模块也就做完了