支付之订单重复支付


layout: post title: "支付之订单重复支付" subtitle: " "如何防止订单重复支付"" date: 2018-10-17 06:00:00 author: "青乡" header-img: "img/post-bg-2015.jpg" catalog: true tags: - 支付

重复支付到底指什么?什么情况下会导致重复支付呢?

下游商家的同一笔订单,在支付系统生成了2笔订单,支付的时候就会支付2次。

所以,问题的关键在于避免支付系统生成2笔订单,或者说,要确保支付系统只生成1笔订单。这是第一点,就是只生成1笔订单。

第二点,现在要对这笔订单数据进行支付,如果商家重复点击支付按钮,支付系统这边只有1笔订单,而且取到的订单数据始终是同一笔订单数据。


总结
支付系统确保2点
1.生成订单的时候,确保只生成1笔订单数据
2.支付的时候,确保取到的始终是同一笔订单数据


流程图

如何确保支付系统只生成1笔订单数据

技术
1.缓存
2.token //UUID


步骤
1.生成订单 //把订单数据放到缓存
cache.add(token,order); //token传给商家客户端

//代码

/**
	 * 收款码参数验证网关
	 * @return
	 */
	@RequestMapping("/checkpay")
	public ModelAndView checkpay(MerchantDTO merchantDTO){
		ModelAndView mav=new ModelAndView("dopay");
		try {
			//1.校验参数
			log.info("merchantDTO info is :"+merchantDTO);
	     	ValidateHelper.asertPass(merchantDTO);
	     	
	     	payService.handleAbnormalUser(merchantDTO.getMerchantId());
	     	
//	     	//2.组装订单对象
	     	Order order = payService.bizCheckMerchant(merchantDTO); //生成订单数据
	     	
	     	String tokenId = UUIDValueGenerator.generateValue();
	     	
//			//3.存储商户信息在缓存
			cache.add(tokenId, 5*60, order); //订单数据放到缓存
			
			mav.addObject("tokenId",tokenId); //token传给客户端
			mav.addObject("siteId",merchantDTO.getSiteId());
			
		} catch (ValidateException ve) {
			log.info(ve.getMessage());
			mav.addObject("msg", ve.getMessage());
			mav.setViewName("error");
		}catch (BizException be){
			log.info(be.getMessage());
			mav.addObject("msg", be.getMessage());
			mav.setViewName("error");
		}catch (Exception e){
			log.info(e.getMessage());
			mav.addObject("msg", e.getMessage());
			mav.setViewName("error");
		}
		return mav;
	}
复制代码

2.支付 //从缓存取订单数据
cache.get(token);

/**
	 * 收款码充值支付网关
	 * @author 
	 * @param request response dopayDTO
	 */
	@RequestMapping("/dopay")
	public void dopay(HttpServletRequest request, HttpServletResponse response, @ModelAttribute DopayDTO dopayDTO ){
		ResposeDTO rseponseDTO = new ResposeDTO();
		try {
			
			//1.校验参数
			log.info("dopayDTO info is :"+dopayDTO);
	     	ValidateHelper.asertPass(dopayDTO);
			Order order = (Order) cache.get(dopayDTO.getTokenId()); //支付的时候:从缓存取订单数据
			
			if(null == order){ //缓存数据失效
				throw new BizException("订单已失效");
			}
			
			//金额校验
			if(!dopayDTO.getOrderMoney().toString().matches("^(?!(0[0-9]{0,}$))[0-9]{1,}[.]{0,}[0-9]{0,2}$")){
				rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_INPUTYZ.getCode());
				rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_INPUTYZ.getDesc());
				outJson(rseponseDTO, response);
				return;
				
			}
			if(Double.valueOf(dopayDTO.getOrderMoney().toString())>Double.valueOf(MAXPAYAMT)){
				rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_MAXAMT.getCode());
				rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_MAXAMT.getDesc());
				outJson(rseponseDTO, response);
				return;

			}
			
			if(Double.valueOf(dopayDTO.getOrderMoney().toString())<Double.valueOf(MINPAYAMT)){
				rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_MINAMT.getCode());
				rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_MINAMT.getDesc());
				outJson(rseponseDTO, response);
				return;
			}
		
			//2.处理业务
			GetPayCommandResponse getPayCommandResponse =  payService.bizDopay(dopayDTO,order); //1.保存订单到数据库 2.调用支付服务
			
			//3.返回参数
			rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_SUCCESS.getCode());
			rseponseDTO.setPostAddress(getPayCommandResponse.getPostAddress());
			rseponseDTO.setParamsMap(getPayCommandResponse.getParams());
			outJson(rseponseDTO, response);
			
		} catch (ValidateException ve) {
			log.error(ve.getMessage(),ve);
			rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_ERROR.getCode());
			rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_ERROR.getDesc());
			outJson(rseponseDTO, response);
		}catch (BizException be){
			log.error(be.getMessage(),be);
			rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_ERROR.getCode());
			rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_ERROR.getDesc());
			outJson(rseponseDTO, response);
		}catch (Exception e) {
			log.error(e.getMessage(),e);
			rseponseDTO.setStatus(ResponseStatus.MOBILE_STATUS_ERROR.getCode());
			rseponseDTO.setRemark(ResponseStatus.MOBILE_STATUS_ERROR.getDesc());
			outJson(rseponseDTO, response);
		}
		
	}
复制代码

幂等

能解决上文提到的问题,就叫幂等。

就是同一笔数据,不能重复处理。或者说,同一笔数据,处理结果一样。


什么操作幂等?什么操作不幂等?
1.查询 //天然幂等 2.修改 //不幂等,需要解决幂等的问题

如何防止重复提交

就是如何防止重复电点击提交按钮?
前端处理,置灰按钮。

参考

tech.meituan.com/distributed…

转载于:https://juejin.im/post/5c09ffc6e51d451dc066fcc3

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CLPHP 订单系统 2018 WEB、WAP 自适应版——竞价页订单系统,快速下单,有邮件提醒,短信提醒。 功能强大、安全、稳定、防注入、不会空单、丢单等。本系统完全开源没有任何加密 CLPHP 订单系统 2018 WEB、WAP 自适应版主要功能: 1.颠覆传统,增加产品型号、产品尺寸、产品颜色等产品多选项选择,满足亲们多样求 2.超乎想象,自带十六种可自适应电脑站和手机站的样式,一套源码解决亲 PC 端、WAP 端使用订单系统问题,全部为全新界面,更加美观、大气 3.带邮件提醒+手机短信提醒{手机邮箱开启短信提示功能即可},特别增强对将 QQ 邮箱设置为订单发件箱的支持;邮件标题进一步优化,显示订单编号、姓名、联系电话 4.产品套餐选择支持单选、复选、下拉选择,迎合亲们的各种喜好 5.带订单来路页面和下单页面地址检测 6.支持下单人 IP 追踪 7.支持设置同一 IP 下单间隔时间,防重复提交;增强恶意空单拦截,有效应对恶意客户拦截传递过程中的订单信息后提交空单行为 8.升级优化邮件系统内核到最新 9.对空间要求更宽泛,fsockopen、pfsockopen 和 stream_socket_client 三个函数只要开一个即可使用,支持绝大多数的 PHP 空间 10.相关提示更加人性化,拥有本订单系统的亲们能根据错误提示快速明了订单系统无法正常工作的原因,方便对症下药,迅速安装配置 11、增强支付宝付款接口,在支付宝业务调整,免签接口失效后,本店第一时间升级了订单系统,提供了收款码收款(支付宝收款码获取方法及替换方法见附送的 WORD 文档)及支付宝商户(即时到账、担保交易)双接口,方便买家根据自己的求切换使用 12、新增微信付款接口,客户无加好友,直接扫描二维码(微信支付付款二维码获取方法及替换方法见附送的 WORD 文档)完成支付。 13、加入伪数据库功能,订单提交失败自动写入设置好的数据文件中,确保不漏一单 请注意您空间要支持 PHP 或全能空间,空间不能禁用 SMTP.纯 ASP 空间不能使用本订单系统。 请注册一个 163 邮箱用来发信,(当然也可用其它邮箱发信,只是麻烦些)再注册一个手机邮箱用来收订单,同时手机邮箱请设置手机通知邮件到达免费提醒功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值