近期,公司内部移动办公系统要实现微信支付模块,用于员工缴费,微信支付页面用h5开发,嵌入移动办公系统,后台是java。
大致流程如下:
1.前端页面生成订单(确定支付金额、订单详情,此步骤根据业务而定)
2.调用后台预支付接口,该接口需要请求微信统一支付接口,拿到返回链接,直接将该链接返回给前端
3.前端拿到连接后,通过iframe请求该链接。
4.该请求会响应一个请求页面,这个页面自动加载,最终会调用“weixin://”协议打开微信
5.如果支付成功,微信会回调后台提供的支付通知接口,该接口接收微信回调和修改本地订单状态。
目前已发现和解决的问题如下:
1. 不能从微信中打开本地app
由于设置了回调页面,而回调页面也是h5开发的,与app无关,所以redirect_url这个参数必须要传。我们的思路是修改app的schemal,如果任意修改,微信会报错参数错误,经过测试只能修改成支付平台中配置的域名,如支付域名是www.abc.com,则对应的schemal也是这个。app拦截schemal,对后面拼接的连接直接进行转发即可。
2. 唤醒微信空白页
这个问题是原因在于前端接收到预支付后返回的url,但是没有成功发送响应请求。代码中再次发送。(这个问题i只有ios13中出现,不是很理解,不过采用这种方法即可)
代码如下
/** 预支付
* 发起支付
*/
@SuppressWarnings("unchecked")
@PostMapping(value = "/pay")
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public Map pay(HttpServletRequest request,@RequestBody Map param) {
String userCode = String.valueOf(String.valueOf(param.get("userCode")));
String ym = String.valueOf(String.valueOf(param.get("ym")));
Order order = orderMapper.selectOrderByThisYear(ym,userCode);
Map map = new HashMap<>();
map.put("result_code", "fail");
if(Objects.isNull(order)) {
map.put("msg", "未查询到可支付的订单,无需支付");
return map;
}
if(order.getStatus() == 3 || order.getStatus() == 2) { //支付成功
map.put("msg", "订单已经完成,无需重复支付");
return map;
}
EntityWrapper wrapper = new EntityWrapper<>();
wrapper.eq("user_id", userCode).eq("period", ym);
Order entity = new Order();
entity.setUserId(userCode);
entity.setOrderNo("");
entity.setStatus(1);
int flag = 0;
if(order.getStatus() == 0 || order.getStatus() == 4) {//交易关闭、取消
flag = 1;
}
if(!Objects.isNull(order.getCreateTime()) && order.getStatus() == 1 && System.currentTimeMillis() - order.getCreateTime().getTime() >= 5 * 60 * 1000 ) {//超时
flag = 2;
}
if(flag != 0) {
orderMapper.update(entity, wrapper);
orderMapper.updateDateTime(ym,userCode);
if(flag == 1) {
map.put("msg", "订单异常,请重新发起支付");
}else if(flag == 2) {
map.put("msg", "订单超时,请重新发起支付");
}
return map;
}
//更新订单创建时间和生成订单号
entity.setCreateTime(new Date());
entity.setOrderNo(System.currentTimeMillis() + "");
orderMapper.update(entity, wrapper);
SortedMap
回调方法
/**
* 异步回调
*/
@PostMapping(value = "/notify")
public Boolean notify(@RequestBody String notifyData) throws Exception {
try {
Map doXMLParse = XMLUtil.doXMLParse(notifyData);
String string = doXMLParse.get("out_trade_no");
EntityWrapper wrapper = new EntityWrapper<>();
wrapper.eq("order_no", string);
Order order = orderService.selectOne(wrapper);
order.setStatus(3);
orderMapper.update(order, wrapper);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
效果展示