微信支付服务

支付功能的接入是一个网站很关键的功能:快速、便捷、安全。

 

用二维码用作支付识别:

L级(低) 7%的码字可以被恢复。 

M级(中) 的码字的 15%可以被恢复。 

Q 级(四分)的码字的 25%可以被恢复。 

H 级(高) 的码字的 30%可以被恢复。 一般用这个,使用这个识别率高

1.4 二维码生成插件 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

""

需要编码为二维码的值 

下面的代码即可生成一张二维码 

<html>

<head>

<title>二维码入门小 demo</title>

</head>

<body>

<img id="qrious">

<script src="qrious.min.js"></script>

<script>  var qr = new QRious({      element:document.getElementById('qrious'),      size:250,     level:'H',    value:'http://www.itcast.cn'

  });

</script>

</body>

</html>  

前端主要是通过插件对二维码的生成,微信支付接口主要是获得其中代表的数据,url是微信返回来的,二维码生成是插件生成的!

2.1 微信扫码支付申请 

微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信扫一扫完成支付的模式。该模式适用于 PC 网站支付、实体店单品或订单支付、媒体广告支付等场景。 

https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml

2.2 开发文档 

主要是看api列表和支付模式的时序图。

看模式二的流程时序图,在调用统一下单api返回的是预支付订单的链接url.

 

微信支付接口调用的整体思路: 

按 API 要求组装参数,以 XML 方式发送(POST)给微信支付接口(URL),微信支付接口也是以 XML 方式给予响应。程序根据返回的结果(其中包括支付 URL)生成二维码或判断订单状态。

在线微信支付开发文档: 

https://pay.weixin.qq.com/wiki/doc/api/index.html 

 

  1. appid:微信公众账号或开放平台 APP 的唯一标识 
  2. mch_id商户号  (配置文件中的 partner)  微信支付申请会有,最终是要和你做一个结算的,会进到商户号对应的账号里;
  3. partnerkey商户密钥 防止别人用你的账号做交易的一串密码
  4. sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性 

2.3 微信支付 SDK

其实是用于简化开发的小工具包,并不是完全封装,比如对XML的转换以及签名的一个算法等。只是提供一个小工具,这是可选的。

微信支付提供了 SDK, 大家下载后打开源码,install 到本地仓库。 

微信sdk安装到maven仓库:

https://zhuanlan.zhihu.com/p/33543731 

使用微信支付 SDK,maven 工程中引入依赖 

<dependency> 
 	 	<groupId>com.github.wxpay</groupId> 
 	 	<artifactId>wxpay-sdk</artifactId> 
 	 	<version>0.0.3</version> 
 	</dependency> 

我们主要会用到微信支付 SDK 的以下功能: 

  1. 获取随机字符串   参与运算,随机字符串和你的商户号、秘钥等等进行一个加密的算法,并且把签名也给它,在微信端做校验,证明请求合法。
WXPayUtil.generateNonceStr() 
  1. MAP 转换为 XML 字符串(自动添加签名) 第一个是map对象,第二个是密钥
 WXPayUtil.generateSignedXml(param, partnerkey) 
  1. XML 字符串转换为 MAP
WXPayUtil.xmlToMap(result) 

2.4 HttpClient 工具类 

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

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(); //获取结果 

2.5 工程搭建与准备工作 

  1. 建立支付服务接口模块 yougou-pay-interface  jar 
  2. 建立支付服务实现模块 yougou-pay-service war 依赖 yougou-pay-interface yougou-common  spring  dubbox 相关依赖 微信 SDK  (因为不需要连接数据库所以不用引用 dao 工程) 
    <dependency> 
     	 	<groupId>com.github.wxpay</groupId> 
     	 	<artifactId>wxpay-sdk</artifactId> 
     	 	<version>0.0.3</version>  	</dependency> 

    添加 tomcat 插件,运行端口为 9000 添加 spring 配置文件 ,参见其它服务工程  

  3. pinyougou-common 工程中添加工具类 HttpClient.java ,并添加依赖 
      <dependency> 
     	    	<groupId>org.apache.httpcomponents</groupId> 
     	    	<artifactId>httpclient</artifactId>     	 
     	   </dependency> 

    添加配置文件 weixinpay.properties

    appid=wx8397f8696b538317 
    partner=1473426802 
    partnerkey=T6m9iK73b0kn9g5v426MKfHQH7X8rKwb 
    notifyurl=http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify 

    appid 微信公众账号或开放平台 APP 的唯一标识

    partner:财付通平台的商户账号 

    partnerkey:财付通平台的商户密钥 

    notifyurl:  回调地址  给一个符合规范,随便自己定义,在模式二的情况下并没有用到,但必须要给

  4. pinyougou-cart-web 依赖工程 pinyougou-pay-service   
  5. 将二维码插件 QRious  拷贝到 pinyougou-cart-web  plugins 目录中 

3.微信支付二维码生成 

3.1 需求分析与实现思路 

3.1.1 需求分析 

在支付页面上生成支付二维码,并显示订单号和金额用户拿出手机,打开微信扫描页面上的二维码,然后在微信中完成支付 

3.1.2 实现思路 

我们通过 HttpClient 工具类实现对远程支付接口的调用。 

接口链接:

https://api.mch.weixin.qq.com/pay/unifiedorder

具体参数参见“统一下单”API, 构建参数发送给统一下单的 url ,返回的信息中有支付 url,根据 url 生成二维码,显示的订单号和金额也在返回的信息中。 

3.2 后端代码实现 

3.2.1 服务接口层 

1)在 pinyougou-pay-interface 创建包 com.pinyougou.pay.service ,包下建立接口

package com.pinyougou.pay.service; 
import java.util.Map; 
/** 
*微信支付接口 
*@author Administrator 
* */ 
public interface WeixinPayService { 
 
 	/** 
*生成微信支付二维码 
*@param out_trade_no 订单号 
*@param total_fee 金额(分) 
*@return 
 	 */ 
 	public Map createNative(String out_trade_no,String total_fee); 
} 

3.2.2 服务实现层 

pinyougou-pay-service 创建 com.pinyougou.pay.service.impl 包,新建类 

@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", "品优购");//商品描述 
	 	 	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://test.itcast.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<>(); 
}  	 	 
 
} 	} 	

3.2.3 控制层 

pinyougou-cart-web 创建 PayController.java  

/** 
*支付控制层 
*@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");   } 

这里我们订单号通过分布式 ID 生成器生成,金额暂时写死,后续开发我们再对接业务系统得到订单号和金额浏

IdWorker

https://www.cnblogs.com/haoxinyue/p/5208136.html

https://www.cnblogs.com/cs99lzzs/p/9869414.html

览器测试 

3.3 前端代码实现 

3.3.1 服务层 

pinyougou-cart-web 创建 payService.js

app.service('payService',function($http){ 
 	//本地支付 
 	this.createNative=function(){ 
 	 	return $http.get('pay/createNative.do'); 
 	}  
}); 

3.3.2 控制层 

pinyougou-cart-web 创建 payController.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'), 
   	   size:250, 
   	   level:'H', 
   	   value:response.code_url 
   	});  	 	 	 	//金额 
 	 
); 	} 
 	 	
 	}  	 
}); 	
 

3.3.3 页面 

修改 pay.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="pinyougou" ng-controller="payController" ng-init="createNative()"> 

设置二维码图片的 ID

<p class="red"></p>                       
         <div class="fl code"> 
              <img id="qrious"> 
              <div class="saosao"> 
                  <p>请使用微信扫一扫</p> 
                  <p>扫描二维码支付</p> 
         </div> 
</div> 

显示订单号 

订单号:{{out_trade_no}} 

显示金额 

<em  class="orange money">{{money}}</em>元 

4.检测支付状态 

用户是否支付成功,要查看商户是否收到钱的测试

4.1 需求分析及实现思路 

4.1.1 需求分析 

当用户支付成功后跳转到成功页面 

当返回异常时跳转到错误页面 

4.1.2 实现思路 

我们通过 HttpClient 工具类实现对远程支付接口的调用。 

接口链接:https://api.mch.weixin.qq.com/pay/orderquery

具体参数参见“查询订单”API, 我们在 controller 方法中轮询调用查询订单(间隔 3 秒),当返回状态为 success 时,我们会在 controller 方法返回结果。前端代码收到结果后跳转到成功页面。 

4.2 检测支付状态-后端代码 

4.2.1 服务接口层 

pinyougou-pay-interface WeixinPayService.java 中新增方法定义 

	/** 
*查询支付状态 
*@param out_trade_no 
 	 */ 
 	public Map queryPayStatus(String out_trade_no); 

4.2.2 服务实现层 

pinyougou-pay-service WeixinPayServiceImpl.java 中实现方法 

 	@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; 
}  

4.2.3 控制层 

pinyougou-cart-web PayController.java 新增方法 

	/** 
*查询支付状态 
*@param out_trade_no 
*@return 
 	 */ 
 	@RequestMapping("/queryPayStatus") 
 	public Result queryPayStatus(String out_trade_no){  	 	
        Result result=null;  	 
 	 	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(); 
}  } 	} 
return result; 

4.3 检测支付状态-前端代码 

4.3.1 服务层 

payService.js 新增方法 

	//查询支付状态  	this.queryPayStatus=function(out_trade_no){ 
 	 	return $http.get('pay/queryPayStatus.do?out_trade_no='+out_trade_no); 
 	} 

4.3.2 控制层 

payController.js 中新增方法 

//查询支付状态  
 	queryPayStatus=function(out_trade_no){ 
 	 	payService.queryPayStatus(out_trade_no).success( 
 	 	 	function(response){ 
 	 	 	 	if(response.success){ 
 	 	 	 	 	location.href="paysuccess.html"; 
 	 	 	 	}else{  	 	 	 	 
 	 	 	 	 	location.href="payfail.html";  	 	 	 	 	 	 	 
 	 	 	 	}  	 	 	 
 	 	 	} 
 	 	); 
 	} 

createNative 方法的回调方法中调用此查询方法 

 	//本地生成二维码 
createNative
 	$scope.	=function(){ 
 	 	payService.createNative().success( 
 	 	 	function(response){ 
 	 
 	 	 	 
      	..........  	      
queryPayStatus(response.out_trade_no);//查询支付状态 	 	 	 
 	 
 	 
 	} 	 	} 
);  
 	 

4.4 查询时间限制 

4.4.1 问题分析 

如果用户到了二维码页面一直未支付,或是关掉了支付页面,我们的代码会一直循环调用微信接口,这样会对程序造成很大的压力。所以我们要加一个时间限制或是循环次数限制,当超过时间或次数时,跳出循环。 

4.4.2 代码完善 

1)修改 pinyougou-cart-web 工程 PayController.java queryPayStatus方法 

 	@RequestMapping("/queryPayStatus") 
 	public Result queryPayStatus(String out_trade_no){ 
 	 	Result result=null;  	 
 	 	int x=0;  	 
 	 	while(true){ 
 	 	 	//调用查询接口  	 	 	.......  	 
 	 	 	try { 
 	 	 	 	Thread.sleep(3000);//间隔三秒 
 	 	 	} catch (InterruptedException e) { 
 	 	 	 	e.printStackTrace(); 
 	 	 	}  
 	 	 	//为了不让循环无休止地运行,我们定义一个循环变量,如果这个变量超过了这个值则退出循环,设置时间为5分钟 
 	 	 	x++; 
 	 	 	if(x>=100){ 
 	 	 	 	result=new  Result(false, "二维码超时"); 
 	 	 	 	break; 
 	 	 	} 
 	 	} 
 	 	return result; 
 	} 

2)修改 payController.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=='二维码超时'){ 
 	 	 	 	 	 	$scope.createNative();//重新生成二维码  	 	 	 	 
 	 	 	 	 	}else{ 
 	 	 	 	 	 	location.href="payfail.html"; 	 	 
 	 	 
} 	} 
 	 	 	 	 		 
 	} 	 	} 
); 			

4.5 支付成功页面显示金额 

4.5.1 问题分析 

现在我们支付成功页面显示的是固定的值,怎么显示真正的支付金额呢?我们这里可以使用 angularJS 的页面传参来解决。 

4.5.2 代码完善 

  1. 修改 payController.js  跳转页面传参 
    //查询支付状态  
     	queryPayStatus=function(out_trade_no){ 
     	 	payService.queryPayStatus(out_trade_no).success( 
     	 	 	function(response){ 
     	 	 	 	if(response.success){ 
     	 	 	 	 	location.href="paysuccess.html#?money="+$scope.money; 
     	 	 	 	}else{ 
     	 	 	 	 	if(response.message=='二维码超时'){ 
     	 	 	 	 	 	$scope.createNative();//重新生成二维码  	 	 	 	 
     	 	 	 	 	}else{ 
     	 	 	 	 	 	location.href="payfail.html"; 
     	 
     		 
    } 	} 
    
     	} 	 	} 
    ); 			

     

  2. payController.js 中引入$location 服务 ,新增方法 
	//获取金额 
 	$scope.getMoney=function(){ 
 	 	return $location.search()['money']; 
 	} 
  1. 修改页面 paysuccess.html ,引入 JS (pay.html 相同) body 添加指令 

      ng-app="pinyougou" ng-controller="payController" 

     用表达式显示金额 

<p	>支付金额:¥{{getMoney()}}元</p

5.支付日志 

5.1 需求分析 

我们现在系统还有两个问题需要解决:(1)系统中无法查询到支付记录(2)支付后订单状态没有改变我们现在就来解决这两个问题。 

实现思路:(1)在用户下订单时,判断如果为微信支付,就想支付日志表添加一条记录,信息包括支付总金额、订单 ID(多个)、用户 ID 、下单时间等信息,支付状态为 0(未支付) 

  1. 生成的支付日志对象放入 redis 中,以用户 ID 作为 key,这样在生成支付二维码时就可以从 redis 中提取支付日志对象中的金额和订单号。 
  2. 当用户支付成功后,修改支付日志的支付状态为 1(已支付),并记录微信传递给我们的交易流水号。根据订单 ID(多个)修改订单的状态为 2(已付款)。 

5.2 表结构分析 tb_paylog  支付日志表 

字段 

类型 

长度 

含义 

out_trade_no

varchar

30

支付订单号 

create_time

datatime

 

创建时间 

pay_time

datatime

 

支付完成时间 

total_fee

bigint

 

支付金额(分) 

transaction_id

varchar

30

交易流水号 

trade_state

varchar

1

交易状态 

pay_type

varchar

1

支付类型: 

1:微信 

2:支付宝 

3:网银 

order_list

varchar

200

订单表 ID 串,用逗号分隔 

5.3 插入日志记录 

修改 pinyougou-order-service 工程 OrderServiceImpl.java add 方法。 

内容:判断如果支付方式为微信支付,向数据库插入支付日志记录,并放入 redis 存储 

	 	@Autowired 
	 	private TbPayLogMapper payLogMapper; 
	 	/** 
	 	 * 增加 
	 	 */ 
 	public void add(TbOrder order) {  	 	
       List<Cart> cartList = (List<Cart>)  
       redisTemplate.boundHashOps("cartList").get( order.getUserId() );   
       List<String> orderIdList=new ArrayList();//订单ID列表 
	 	 	double total_money=0;//总金额 (元) 
	 	 	for(Cart cart:cartList){ 
 	 	 	long orderId = idWorker.nextId();               ......  	 	 
	 	 	 	orderIdList.add(orderId+"");//添加到订单列表  
	 	 	 	total_money+=money;//累加到总金额  
	 	 	} 
	 	 	if("1".equals(order.getPaymentType())){//如果是微信支付  	 
	 	 	 	TbPayLog payLog=new TbPayLog(); 
	 	 	 	String outTradeNo=  idWorker.nextId()+"";//支付订单号 
	 	 	 	payLog.setOutTradeNo(outTradeNo);//支付订单号 
	 	 	 	payLog.setCreateTime(new Date());//创建时间 
	 	 	 	//订单号列表,逗号分隔 
 	 	 	String ids=orderIdList.toString().replace("[", "").replace("]", "").replace(" ", ""); 
 	 	 	payLog.setOrderList(ids);//订单号列表,逗号分隔 
 	 	 	payLog.setPayType("1");//支付类型 
 	 	 	payLog.setTotalFee( (long)(total_money*100 ) );//总金额(分) 
 	 	 	payLog.setTradeState("0");//支付状态 
 	 	 	payLog.setUserId(order.getUserId());//用户ID  	 	 
 	 	 	payLogMapper.insert(payLog);//插入到支付日志表  	 	 
 	 	 	redisTemplate.boundHashOps("payLog").put(order.getUserId(), payLog);//
放入缓存  	 	  	 	}  	 
 	 	redisTemplate.boundHashOps("cartList").delete(order.getUserId());  	 
 	} 

5.4 读取支付日志 

5.4.1 服务接口层 

pinyougou-order-interface 工程的 OrderService.java 新增方法 

/** 
*根据用户查询payLog 
*@param userId 
*@return 
 	 */ 
 	public TbPayLog searchPayLogFromRedis(String userId); 

5.4.2 服务实现层 

pinyougou-order-service OrderServiceImpl.java 实现方法 

	@Override 
 	public TbPayLog searchPayLogFromRedis(String userId) { 
 	 	return (TbPayLog) redisTemplate.boundHashOps("payLog").get(userId);  	 
 	} 

5.4.3 控制层 

修改 pinyougou-cart-web 工程 PayController.java createNative 方法 

实现思路:调用获取支付日志对象的方法,得到订单号和金额 

@Reference 
 	private OrderService orderService; 
 	/** 
*生成二维码 
*@return 
 	 */ 
 	@RequestMapping("/createNative") 
 	public Map createNative(){ 
 	 	//获取当前用户 	 	 
 	 	String 
userId=SecurityContextHolder.getContext().getAuthentication().getName(); 
 	 	//到redis查询支付日志 
 	 	TbPayLog payLog = orderService.searchPayLogFromRedis(userId); 
 	 	//判断支付日志存在 
 	 	if(payLog!=null){ 
 	 	 	return weixinPayService.createNative(payLog.getOutTradeNo(),payLog.getTotalFee()+""); 
 	 	}else{ 
 	 	 	return new HashMap(); 
 	 	}  	 
 	} 

5.5 修改订单状态 

5.5.1 服务接口层 

pinyougou-order-interface OrderService.java 新增方法定义 

/** 
*修改订单状态 
*@param out_trade_no 支付订单号 
*@param transaction_id 微信返回的交易流水号 
 	 */ 
 	public void updateOrderStatus(String out_trade_no,String transaction_id); 

5.5.2 服务实现层 

pinyougou-order-service 工程 OrderServiceImpl.java 实现该方法.

这个方法主要做三件事:

 1. 修改支付日志状态 

 2.修改关联的订单的状态 

 3.清除缓存中的支付日志对象 

@Override 

	 	public void updateOrderStatus(String out_trade_no, String transaction_id) { 
	 	 	//1.修改支付日志状态 
	 	 	TbPayLog payLog = payLogMapper.selectByPrimaryKey(out_trade_no); 
	 	 	payLog.setPayTime(new Date()); 
	 	 	payLog.setTradeState("1");//已支付 
	 	 	payLog.setTransactionId(transaction_id);//交易号 
	 	 	payLogMapper.updateByPrimaryKey(payLog);  	 
	 	 	//2.修改订单状态 
 	 	String orderList = payLog.getOrderList();//获取订单号列表  	 	
        String[] orderIds = orderList.split(",");//获取订单号数组 
 	 	 
	 	 	for(String orderId:orderIds){ 
	 	 	 	TbOrder order = 
orderMapper.selectByPrimaryKey( Long.parseLong(orderId) ); 
	 	 	 	if(order!=null){ 
	 	 	 	 	order.setStatus("2");//已付款 
	 	 	 	 	orderMapper.updateByPrimaryKey(order); 
	 	 	 	}  	 	 
	 	 	} 
	 	 	//清除redis缓存数据  	 
	 	 	redisTemplate.boundHashOps("payLog").delete(payLog.getUserId()); 
	 	} 

5.5.3 控制层 

修改 pinyougou-cart-web PayController.java。在微信支付接口有成功返回状态时,调用修改状态的方法 

/** 
*查询支付状态 
*@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, "支付成功"); 
 	 	 	 	//修改订单状态 
 	 	 	 	orderService.updateOrderStatus(out_trade_no, 
map.get("transaction_id")); 
 	 	 	 	break; 
 	 	 	}  	 	 
 	 	 	try { 
 	 	 	 	Thread.sleep(3000);//间隔三秒  	 	 	
} catch (InterruptedException e) { 
 	 	 	 	e.printStackTrace(); 
 	 	 	}  
   //为了不让循环无休止地运行,我们定义一个循环变量,如果这个变量超过了这个值则退出循环,设置时间为5分钟 
 	 	     ......  	 	 
 	 	} 
 	 	return result; 
 	} 

5.6 支付日志显示

需求:在运营商后台中,显示支付日志列表,实现按日期、状态、用户进行查询。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是微信支付服务器预支付订单的代码示例: ```python import requests from hashlib import md5 import xml.etree.ElementTree as ET # 微信支付参数 appid = '你的appid' mch_id = '你的商户号' key = '你的API秘钥' notify_url = '支付结果通知地址' # 生成签名函数 def create_sign(params): # 将参数按照ASCII码从小到大排序 params = sorted(params.items(), key=lambda x:x[0]) # 拼接成字符串 raw_str = '&'.join(['{}={}'.format(k, v) for k, v in params]) # 加上API秘钥 raw_str += '&key={}'.format(key) # 计算MD5值并转换为大写 sign = md5(raw_str.encode('utf-8')).hexdigest().upper() return sign # 生成预支付订单函数 def create_prepay_order(openid, out_trade_no, total_fee): # 构造请求参数 params = { 'appid': appid, 'mch_id': mch_id, 'nonce_str': '随机字符串', 'body': '商品描述', 'out_trade_no': out_trade_no, 'total_fee': total_fee, 'spbill_create_ip': '调用支付接口的机器IP', 'notify_url': notify_url, 'trade_type': 'JSAPI', 'openid': openid } # 生成签名 sign = create_sign(params) params['sign'] = sign # 将请求参数转换为XML格式 xml_data = '<xml>' + ''.join(['<{}>{}</{}>'.format(k, v, k) for k, v in params.items()]) + '</xml>' # 发送请求 response = requests.post('https://api.mch.weixin.qq.com/pay/unifiedorder', data=xml_data.encode('utf-8')) # 解析响应结果 root = ET.fromstring(response.content) if root.find('return_code').text == 'SUCCESS' and root.find('result_code').text == 'SUCCESS': # 预支付订单生成成功,返回JS API调用参数 prepay_id = root.find('prepay_id').text params = { 'appId': appid, 'timeStamp': str(int(time.time())), 'nonceStr': '随机字符串', 'package': 'prepay_id={}'.format(prepay_id), 'signType': 'MD5' } sign = create_sign(params) params['paySign'] = sign return params else: # 预支付订单生成失败,返回错误信息 err_msg = root.find('return_msg').text return {'err_msg': err_msg} ``` 其中,`create_sign`函数用于生成签名,`create_prepay_order`函数用于生成预支付订单并返回JS API调用参数,`openid`为用户的openid,`out_trade_no`为商户订单号,`total_fee`为订单金额(单位为分)。需要注意的是,`notify_url`为支付结果通知地址,需要在商户后台进行配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值