失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 学支付的无聊日子

学支付的无聊日子

时间:2021-04-10 17:41:02

相关推荐

学支付的无聊日子

正值青春的年纪,却过着每天学习的无聊生活。

一 支付的种类

1 微信支付

官方文档

1.1 小程序支付

产品介绍文档

用户通过分享或扫描二维码进入商户小程序,用户选择购买,完成选购流程;调起微信支付控件,用户开始输入支付密码;

密码验证通过,支付成功。商户后台得到支付成功的通知;

返回商户小程序,显示购买成功;

微信支付公众号下发支付凭证。

(1)生成支付订单

(2)用户付款

付款

@Login@PostMapping("/microAppPayOrder")@ApiOperation("小程序付款")public R microAppPayOrder(@RequestBody PayOrderForm form, @RequestHeader HashMap header) {ValidatorUtils.validateEntity(form);String token = header.get("token").toString();Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());int orderId = form.getOrderId();UserEntity user = new UserEntity();user.setUserId(userId);QueryWrapper wrapper = new QueryWrapper(user);long count = userService.count(wrapper);//判断用户是否存在if (count == 0) {return R.error("用户不存在");}//获取用户账号的openid字符串String openId = userService.getOne(wrapper).getOpenId();//判断用户是否拥有这个订单,并且订单是未支付状态OrderEntity order = new OrderEntity();order.setUserId(userId.intValue());order.setId(orderId);order.setStatus(1);wrapper = new QueryWrapper(order);count = orderService.count(wrapper);if (count == 0) {return R.error("不是有效的订单");}//验证购物券是否有效//验证团购活动是否有效//查询订单详情信息order = new OrderEntity();order.setId(orderId);wrapper = new QueryWrapper(order);order = orderService.getOne(wrapper); //订单对象String amount = order.getAmount().multiply(new BigDecimal("100")).intValue() + ""; //订单金额try {//向微信平台发出请求,创建支付订单WXPay wxPay = new WXPay(myWXPayConfig);HashMap map = new HashMap();map.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串map.put("body", "订单备注");map.put("out_trade_no", order.getCode()); //商品订单流水号map.put("total_fee", amount); //订单金额map.put("spbill_create_ip", "127.0.0.1"); //客户端IPmap.put("notify_url", "http://66931e50./renren-fast/app/wx/recieveMessage"); //通知回调地址map.put("trade_type", "JSAPI"); //调用接口类型map.put("openid", openId); //用户授权Map<String, String> result = wxPay.unifiedOrder(map); //创建支付订单String prepayId = result.get("prepay_id"); //获取支付订单ID// System.out.println(prepayId);if (prepayId != null) {//更新本地商品订单信息,但是不更新商品订单状态order.setPrepayId(prepayId); //保存支付订单IDorder.setPaymentType(1); //支付类型UpdateWrapper updateWrapper = new UpdateWrapper();updateWrapper.eq("id", order.getId());orderService.update(order, updateWrapper);//对返回给小程序的数据生成数字签名map.clear();map.put("appId", appId);String timeStamp = new Date().getTime() + "";map.put("timeStamp", timeStamp);String nonceStr = WXPayUtil.generateNonceStr();map.put("nonceStr", nonceStr);map.put("package", "prepay_id=" + prepayId);map.put("signType", "MD5");String paySign = WXPayUtil.generateSignature(map, key); //生成数字签名return R.ok().put("package", "prepay_id=" + prepayId).put("timeStamp", timeStamp).put("nonceStr", nonceStr).put("paySign", paySign);} else {return R.error("支付订单创建失败");}} catch (Exception e) {e.printStackTrace();return R.error("微信支付模块故障");}}

接收回调信息

@ApiOperation("接收消息通知")@RequestMapping("/recieveMessage")public void recieveMessage(HttpServletRequest request, HttpServletResponse response) throws Exception {request.setCharacterEncoding("utf-8");Reader reader = request.getReader();BufferedReader buffer = new BufferedReader(reader);String line = buffer.readLine();StringBuffer temp = new StringBuffer();while (line != null) {temp.append(line);line = buffer.readLine();}buffer.close();reader.close();String xml=temp.toString();if(WXPayUtil.isSignatureValid(xml,key)){Map<String, String> map = WXPayUtil.xmlToMap(temp.toString());String resultCode = map.get("result_code");String returnCode = map.get("return_code");if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {String outTradeNo = map.get("out_trade_no");UpdateWrapper wrapper = new UpdateWrapper();wrapper.eq("code", outTradeNo);wrapper.set("status", 2);// 更新订单支付状态orderService.update(wrapper);response.setCharacterEncoding("utf-8");response.setContentType("application/xml");Writer writer = response.getWriter();BufferedWriter bufferedWriter = new BufferedWriter(writer);bufferedWriter.write("<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>");bufferedWriter.close();writer.close();}}else{response.sendError(500,"数字签名异常");}}

如果微信平台出现技术故障,支付模块正常,但是消息模块出了问题,那么就会出现支付成功,但是消息发布出去。商户系统自然也就收不到支付结果的通知了。

如果其中一端出现了网络故障,商户系统都不能收到消息通知。

商户系统接收不到支付结果的时候,需要主动去查询支付的结果,到底成功了还是失败了?商户系统什么时候应该发起主动查询呢?难道还要写个定时程序吗?

当然不需要。当小程序上面提示支付成功以后,那么小程序就像商户系统发出 Ajax 请求,告诉商户系统我已经收到付款成功的通知啦,你也去查询一下,这时候商户系统才需要发起主动查询。在小程序上面的SUCCESS回调函能执行,就意味着支付成功了。我们在SUCCESS回调函数里面向商户系统发起Ajax请求即可。商户平台接收到小程序的请求之后,根据支付订单 ID 去查询微信平台,如果已经付款成功,就修改本地商品订单为已支付状态。

主动查询支付结果

@Login@PostMapping("/updateOrderStatus")@ApiOperation("更新商品订单状态")public R updateOrderStatus(@RequestBody UpdateOrderStatusForm form,@RequestHeader HashMap header) {ValidatorUtils.validateEntity(form);String token = header.get("token").toString();int userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());int orderId = form.getOrderId();OrderEntity orderEntity = new OrderEntity();orderEntity.setUserId(userId);orderEntity.setId(orderId);QueryWrapper wrapper = new QueryWrapper(orderEntity);int count = orderService.count(wrapper);if (count == 0) {return R.error("用户与订单不匹配");}orderEntity = orderService.getOne(wrapper);String code = orderEntity.getCode();HashMap map = new HashMap();map.put("appid", appId);map.put("mch_id", mchId);map.put("out_trade_no", code);map.put("nonce_str", WXPayUtil.generateNonceStr());try {String sign = WXPayUtil.generateSignature(map, key);map.put("sign", sign);WXPay wxPay = new WXPay(myWXPayConfig);Map<String, String> result = wxPay.orderQuery(map);String returnCode = result.get("return_code");String resultCode = result.get("result_code");if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {String tradeState = result.get("trade_state");if ("SUCCESS".equals(tradeState)) {UpdateWrapper updateWrapper = new UpdateWrapper();updateWrapper.eq("code", code);updateWrapper.set("status", 2);updateWrapper.set("payment_type",1);orderService.update(updateWrapper);return R.ok("订单状态已修改");} else {return R.ok("订单状态未修改");}}return R.ok("订单状态未修改");} catch (Exception e) {e.printStackTrace();return R.error("查询支付订单失败");}}

1.2 微信 Native 支付

产品介绍文档

商户根据微信支付的规则,为不同商品生成不同的二维码,展示在各种场景,用于用户扫描购买;用户使用微信“扫一扫”扫描二维码后,获取商品支付信息;用户确认支付,输入支付密码;支付完成后会提示用户支付成功,商户后台得到支付成功的通知。

(1)生成支付订单

生成支付订单

@Login@PostMapping("/nativePayOrder")@ApiOperation("native付款")public R nativePayOrder(@RequestBody PayOrderForm form, @RequestHeader HashMap header) {ValidatorUtils.validateEntity(form);String token = header.get("token").toString();Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());int orderId = form.getOrderId();UserEntity user = new UserEntity();user.setUserId(userId);QueryWrapper wrapper = new QueryWrapper(user);long count = userService.count(wrapper);if (count == 0) {return R.error("用户不存在");}OrderEntity order = new OrderEntity();order.setUserId(userId.intValue());order.setId(orderId);order.setStatus(1);wrapper = new QueryWrapper(order);count = orderService.count(wrapper);if (count == 0) {return R.error("不是有效的订单");}//验证购物券是否有效//验证团购活动是否有效order = new OrderEntity();order.setId(orderId);wrapper = new QueryWrapper(order);order = orderService.getOne(wrapper);//向微信平台发出请求,创建支付订单String amount = order.getAmount().multiply(new BigDecimal("100")).intValue() + "";try {WXPay wxPay = new WXPay(myWXPayConfig);HashMap map = new HashMap();map.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串map.put("body", "订单备注");map.put("out_trade_no", order.getCode());map.put("total_fee", amount);map.put("spbill_create_ip", "127.0.0.1");map.put("notify_url", "https://127.0.0.1/test");map.put("trade_type", "NATIVE");String sign=WXPayUtil.generateSignature(map,key);map.put("sign",sign);Map<String, String> result = wxPay.unifiedOrder(map);String prepayId = result.get("prepay_id");// System.out.println(prepayId);String codeUrl=result.get("code_url");if (prepayId != null) {order.setPrepayId(prepayId);UpdateWrapper updateWrapper = new UpdateWrapper();updateWrapper.eq("id", order.getId());orderService.update(order, updateWrapper);return R.ok().put("codeUrl", codeUrl);} else {return R.error("支付订单创建失败");}} catch (Exception e) {e.printStackTrace();return R.error("微信支付模块故障");}}

生成二维码

@GetMapping("/qrcode")public void qrcode(HttpServletRequest request,HttpServletResponse response) throws Exception{String codeUrl=request.getParameter("codeUrl");if(codeUrl!=null&&codeUrl.length()>0){QrConfig qrConfig=new QrConfig();qrConfig.setWidth(250);qrConfig.setHeight(250);qrConfig.setMargin(2);OutputStream out=response.getOutputStream();QrCodeUtil.generate(codeUrl,qrConfig,"jpg",out);out.close();}}

(2)用户付款

网站或售货机与微信是两个平台,无法接收微信平台的支付结果的通知,需要前端定时主动查询订单支付结果

@Login@PostMapping("/searchOrderStatus")@ApiOperation("查询支付订单状态")public R searchOrderStatus(@RequestBody SearchOrderStatusForm form,@RequestHeader HashMap header){ValidatorUtils.validateEntity(form);String token = header.get("token").toString();int userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());int orderId = form.getOrderId();OrderEntity orderEntity = new OrderEntity();orderEntity.setUserId(userId);orderEntity.setId(orderId);QueryWrapper wrapper = new QueryWrapper(orderEntity);int count = orderService.count(wrapper);if (count == 0) {return R.error("用户与订单不匹配");}orderEntity = orderService.getOne(wrapper);String code = orderEntity.getCode();HashMap map = new HashMap();map.put("appid", appId);map.put("mch_id", mchId);map.put("out_trade_no", code);map.put("nonce_str", WXPayUtil.generateNonceStr());try {String sign = WXPayUtil.generateSignature(map, key);map.put("sign", sign);WXPay wxPay = new WXPay(myWXPayConfig);Map<String, String> result = wxPay.orderQuery(map);String returnCode = result.get("return_code");String resultCode = result.get("result_code");if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {String tradeState = result.get("trade_state");if ("SUCCESS".equals(tradeState)) {UpdateWrapper updateWrapper = new UpdateWrapper();updateWrapper.eq("code", code);updateWrapper.set("status", 2);updateWrapper.set("payment_type",1);orderService.update(updateWrapper);return R.ok("订单状态已修改");} else {return R.ok("订单状态未修改");}}return R.ok("订单状态未修改");} catch (Exception e) {e.printStackTrace();return R.error("查询支付订单失败");}}

1.3 微信扫码支付

介绍文档

步骤1:用户选择付款码支付,付款码打开路径:微信->“我”->“支付”->“收付款”;

步骤2:收银员在商户系统操作生成支付订单,用户确认支付金额;

步骤3:商户收银员用扫码设备扫描用户的条码/二维码,商户收银系统提交支付;

步骤4:微信支付后台系统收到支付请求,根据验证密码规则判断是否验证用户的支付密码,不需要验证密码的交易直接发起扣款,需要验证密码的交易会弹出密码输入框。支付成功后微信端会弹出成功页面,支付失败会弹出错误提示。

@Login@PostMapping("/scanCodePayOrder")@ApiOperation("付款码收款")public R scanCodePayOrder(@RequestBody ScanCodePayOrderForm form, @RequestHeader HashMap header) {ValidatorUtils.validateEntity(form);String token = header.get("token").toString();Long userId = Long.parseLong(jwtUtils.getClaimByToken(token).getSubject());int orderId = form.getOrderId();UserEntity user = new UserEntity();user.setUserId(userId);QueryWrapper wrapper = new QueryWrapper(user);long count = userService.count(wrapper);if (count == 0) {return R.error("用户不存在");}OrderEntity order = new OrderEntity();order.setUserId(userId.intValue());order.setId(orderId);order.setStatus(1);wrapper = new QueryWrapper(order);count = orderService.count(wrapper);if (count == 0) {return R.error("不是有效的订单");}//验证购物券是否有效//验证团购活动是否有效order = new OrderEntity();order.setId(orderId);wrapper = new QueryWrapper(order);order = orderService.getOne(wrapper);//向微信平台发出请求,创建支付订单String amount = order.getAmount().multiply(new BigDecimal("100")).intValue() + "";try {WXPay wxPay = new WXPay(myWXPayConfig);HashMap map = new HashMap();map.put("appid",appId);map.put("mch_id",mchId);map.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串map.put("body", "订单备注");map.put("out_trade_no", order.getCode());map.put("total_fee", amount);map.put("spbill_create_ip", "127.0.0.1");map.put("auth_code",form.getAuthCode());String sign=WXPayUtil.generateSignature(map,key);map.put("sign",sign);Map<String, String> result = wxPay.microPay(map);String returnCode = result.get("return_code");String resultCode = result.get("result_code");if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {String prepayId = result.get("transaction_id");order.setPrepayId(prepayId);order.setStatus(2);order.setPaymentType(1);UpdateWrapper updateWrapper = new UpdateWrapper();updateWrapper.eq("id", order.getId());orderService.update(order, updateWrapper);return R.ok("付款成功");}else {return R.error("付款失败");}} catch (Exception e) {e.printStackTrace();return R.error("微信支付模块故障");}}

二 开发中遇到的支付问题

问题1 用户已支付,然后取消订单,没有退款

1.1 问题梳理分析

订单号:SA012104120809590003430563,订单创建时间:-04-12 08:09:59,订单支付时间:-04-12 08:14:00,订单取消时间:-04-12 08:25:12。由于支付过程为异步且和第三方存在交互,存在订单状态更新延时的情况,而在用户取消的一些特殊场景(通过小程序日志分析,该用户在支付完成后跳转到订单页,订单仍然是未支付状态,而此时用户可以取消订单;一般场景应该是支付完成跳转到订单页,订单为已支付,而此时用户是不可以取消订单的),未对取消操作做完整的校验和拦截,导致用户在支付的情况下取消订单,但确未返回现金的情况。

1.2 同样问题订单查询

通过系统查询发现同样的类型单有16单,涉及总金额 1383 元;

1.3 问题修复方案

(1)经过运营,研发等必要核查,将金额退回给用户;

(2)系统对于取消订单操作做必要的前置校验,加入判断订单是否已经支付,已经支付则前置拦截并且让客户感知。(备注:支付完成的订单走的售后流程)

如果觉得《学支付的无聊日子》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。