countDownLatch及ScheduledThreadPoolExecutor在微信支付里的应用
前言
最近做微信支付,考虑到安全问题,公司线上支付的服务器不能开端口给微信进行调用。
所以之前的项目里都是微信下单后,跳转一个中间页面,调用后台进行查看是否支付成功。
但是这样出现用户明明支付了订单,还是待付款的订单。原因有长时间不输密码了,断网了等等因素引起的。当用户量上去后,这种频率出现的概率就会变大。
countDownLatch和ScheduledThreadPoolExecutor结合处理
微信查询处理的代码优化后:
public HashMap<String, String> wxOrderQuery(OnlinePayRecord onlinePayRecord, HashMap<String, String> params) {
HashMap<String, String> returnMap = new HashMap<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
long starttime = System.currentTimeMillis();
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
try {
scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
long nowtime = System.currentTimeMillis();
WXOrderQueryRsp wxOrderQueryRsp = null;
try {
//请求微信订单查询
wxOrderQueryRsp = wxService.orderQuery(onlinePayRecord, params);
if ("SUCCESS".equals(wxOrderQueryRsp.getTrade_state())) {
logger.info("调取微信订单查询接口结束,支付成功");
onlinePayRecord.setTransactionId(wxOrderQueryRsp.getTransaction_id());
onlinePayRecord.setTimeEnd(wxOrderQueryRsp.getTime_end());
onlinePayRecord.setTradeState("PAYSUC");
onlinePayRecord.setTradeStateDesc("支付成功");
returnMap.put("tradeState", "PAYSUC");
returnMap.put("tradeStateDesc", "支付成功");
returnMap.put("timeEnd",onlinePayRecord.getTimeEnd());
scheduledThreadPoolExecutor.shutdown();
countDownLatch.countDown();
} else {
while ((nowtime - starttime) > 300000) {
onlinePayRecord.setTradeState(wxOrderQueryRsp.getTrade_state());
onlinePayRecord.setTradeStateDesc(wxOrderQueryRsp.getTrade_state_desc());
returnMap.put("tradeState", wxOrderQueryRsp.getTrade_state());
returnMap.put("tradeStateDesc", wxOrderQueryRsp.getTrade_state_desc());
countDownLatch.countDown();
scheduledThreadPoolExecutor.shutdown();
}
}
returnMap.put("payType", onlinePayRecord.getPayType());
returnMap.put("outTradeNo", wxOrderQueryRsp.getOut_trade_no());
returnMap.put("transactionId", wxOrderQueryRsp.getTransaction_id());
} catch (Exception e) {
e.printStackTrace();
}
}, 1, 1, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
logger.info("请求异常");
returnMap.put("tradeState", "ERROR");
returnMap.put("tradeStateDesc", "请求异常");
returnMap.put("payType", onlinePayRecord.getPayType());
returnMap.put("outTradeNo", onlinePayRecord.getOutTradeNo());
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return returnMap;
}
不了解ScheduledThreadPoolExecutor,和countDownLatch的看我之前的几篇博客。
利用ScheduledThreadPoolExecutor定时线程池,进行轮询。并且加入countDownLatch.await()等待特性,countDownLatch当减到0时,await方法就可以过去,否则一直阻塞在那里。
但是不能一直阻塞,退出阻塞的条件就是支付成功,或者5分钟以后依然未支付。此处的时间看具体需求。
给大家个小例子
@RestController
public class IndexController {
@Autowired
private EmployeesDao employeesDao;
@RequestMapping("/updateage")
public String processUserData() throws InterruptedException {
Employees emp=new Employees();
emp.setId(4);
emp.setAge(23);
emp.setPosition("pos");
emp.setName("Jordan");
employeesDao.save(emp);
return null;
}
@RequestMapping("/frontReg")
public Map frontReg() {
Map map= weixinpay(4);
return map;
}
public Map weixinpay(int wwz311) {
System.out.println("调用");
CountDownLatch countDownLatch = new CountDownLatch(1);
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);
long starttime = System.currentTimeMillis();
Map map=new HashMap();
scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
Employees emp=employeesDao.findAll().get(0);
System.out.println(emp.getAge());
if(emp.getAge()==23){
//当年龄是23时中断线程,同时
//countDownLatch-1
map.put("flag","修改Jordan震年龄成功:"+emp.getAge());
scheduledThreadPoolExecutor.shutdown();
countDownLatch.countDown();
}else{
long nowtime = System.currentTimeMillis();
while ((nowtime - starttime) > 20000) {
map.put("flag","修改Jordan年龄失败:"+emp.getAge());
countDownLatch.countDown();
scheduledThreadPoolExecutor.shutdown();
}
}
map.put("data","success");
}, 0, 1, TimeUnit.SECONDS);
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return map;
}
}
dao层就不给大家了,JPA基本方法,表就一条数据:
Employees 表
当我访问http://localhost:8761/frontReg
,如图:
当我访问http://localhost:8761/frontReg
,同时过俩秒访问http://localhost:8761/udateage
,如图:
这其实就是模拟了上边的微信回调的demo
总结
优化后微信回调,用来解决当不能让微信进行回调系统接口时,我们可以在微信下单的方法后,起个线程,进行异步处理。轮询微信查询订单状态,超时判定为未支付。