1. 程式人生 > 其它 >微信整合支付和退款以及回掉

微信整合支付和退款以及回掉

技術標籤:支付支付微信

  1. 引數整合

    @Data
    @Component
    @ConfigurationProperties(prefix = "weachat")
    public class WeachatProperties {
    		//支付 不同的支付方式 不同的引數列表
    	    //開放平臺:app支付僅需要
    		private String OPAppId;
    		//公眾平臺:NATIVE支付僅需要MPAppId
    		private String MPAppId;
    		//公眾平臺金鑰 微信公眾號支付需要+MPAppId+IDBook
    		private String MPSecret;
    		//證書路徑
    		private String IDBook;
    
    		//支付公共引數
    		//商戶號
    		private String MchId;
    	    //商戶金鑰
    		private String MchKey;
    		//非同步通知地址
    		private String NotifyUrl;
    		//回撥地址
    		private String ReturnUrl;
    		//微信公眾號的訪問地址
    		private String MpUrl;
    		
    }
    

  2. 微信配置

    @Configuration
    public class BestPayConfig {
    	//微信和支付寶的引數
    	@Autowired
    	private WeachatProperties weachat;
    	@Autowired
    	private AliPayProperties alipay;
    
    	@Bean
    	public BestPayService BestPayconfig(WxPayConfig WxPayConfig) {
    		// 支付寶配置
    		AliPayConfig aliPayConfig = new AliPayConfig();
    		aliPayConfig.setAppId(alipay.getAppId());
    		aliPayConfig.setPrivateKey(alipay.getPrivateKey());
    		aliPayConfig.setAliPayPublicKey(alipay.getAliPayPublicKey());
    		aliPayConfig.setNotifyUrl(alipay.getNotifyUrl());// 支付寶非同步通知資訊
    		aliPayConfig.setReturnUrl(alipay.getReturnUrl());// 支付成功之後轉跳到的頁面
    		// 實現支付服務介面==根據不同的支付方式 返回對應的BestPayService物件
    		BestPayServiceImpl bestPay = new BestPayServiceImpl();
    		bestPay.setWxPayConfig(WxPayConfig);// 設定微信配置資訊
    		bestPay.setAliPayConfig(aliPayConfig);// 設定支付寶的配置資訊
    		return bestPay;
    	}
    	
    	//微信單獨配置是為了controller層 支付完成之後 轉跳頁面 而支付寶內部直接設定就好
    	@Bean
    	public WxPayConfig WxPayConfig() {
    		// 微信配置
    		WxPayConfig WxConfig = new WxPayConfig();
    		WxConfig.setAppAppId(weachat.getOPAppId());//商戶平臺繫結的開放平臺移動應用的openid
    		WxConfig.setAppId(weachat.getMPAppId());
    		WxConfig.setAppSecret(weachat.getMPSecret());
    		WxConfig.setMchId(weachat.getMchId());
    		WxConfig.setMchKey(weachat.getMchKey());
    		WxConfig.setKeyPath(weachat.getIDBook());
    		WxConfig.setNotifyUrl(weachat.getNotifyUrl());// 微信非同步通知資訊
    		WxConfig.setReturnUrl(weachat.getReturnUrl());// 微信支付成功的返回頁面
    		return WxConfig;
    	}
    	
    }

  3. 微信引入pom檔案

            <!--best-pay-sdk -->
    		<dependency>
    			<groupId>cn.springboot</groupId>
    			<artifactId>best-pay-sdk</artifactId>
    			<version>1.3.1</version>
    		</dependency>

  4. 微信application.properties配置檔案新增金鑰

    #微信支付
    #公眾平臺
    weachat.MPAppId=xxx
    weachat.MPSecret=xxx
    #開放平臺
    weachat.OPAppId=xxx
    #商戶賬號和金鑰
    weachat.MchId=xxxx
    weachat.MchKey=xxxx
    #退款證書
    weachat.IDBook=/usr/local/java/refuse_cert.p12
    #回撥和支付成功頁面地址
    weachat.NotifyUrl=http://xxx/order/notify
    weachat.ReturnUrl=http://xxx/order/return
    

  5. 微信支付

    // 微信和支付寶支付
    	public PayResponse createPay(String orderId,BestPayTypeEnum payType,String openid) {
    		//查詢訂單
    		OrderForm order=orders.selectByOrderId(orderId);
    		// 校驗當前訂單的支付狀態(支付與未支付)
    		if (!StringUtils.equals(order.getStatus().toString(), OrderStatus.WAITINGPAY.getStatus().toString())) {
    			throw new PayException("訂單支付狀態不正確");
    		}
    		// 支付請求
    		PayRequest request = new PayRequest();
    		request.setOpenid(openid);
    		request.setOrderId(orderId);// 訂單號
    		request.setOrderName(order.getOrderName());// 訂單名字
    		request.setOrderAmount(order.getPrice().doubleValue());// 訂單的總價
    		logger.info("訂單的總價:" + order.getPrice().doubleValue());
    		// 支付方式:微信NATIVE支付、WXPAY_APP方式和支付寶APP、ALIPAY_PC、ALIPAY_WAP方式選擇
    		request.setPayTypeEnum(payType);// 支付方式
    		return payService.pay(request);
    	}

  6. 微信發起支付

    @ResponseBody
    	@Transactional
    	@RequestMapping(value = "/wxpay",method = RequestMethod.POST)
    	public Object WechatPay(@RequestParam("orderId") String orderId,@RequestParam("payType") BestPayTypeEnum paytype,@RequestParam(value = "openid",required = false)String openid) {
    		Map<String, Object> map = new HashMap<String, Object>();
    		logger.info(String.format("微信開始支付:支付方式:%s,支付訂單號碼:%s", paytype, orderId));
    
    		PayResponse response = payService.createPay(orderId,paytype,openid);
    		if (paytype == BestPayTypeEnum.WXPAY_NATIVE) {
    			map.put("orderNo", orderId);
    			map.put("codeUrl", response.getCodeUrl());
    			map.put("returnUrl", WxPayConfig.getReturnUrl());
    			return ServerResponse.createBySuccess(map);
    		} else if (paytype == BestPayTypeEnum.WXPAY_APP) {
    			map.put("nonce_str", response.getNonceStr());
    			map.put("sign", response.getPaySign());
    			map.put("time_stamp", response.getTimeStamp());
    			map.put("prepay_id", response.getPrepayId());
    			map.put("package", response.getPackAge());
    			return ServerResponse.createBySuccess(map);
    		}else if(paytype == BestPayTypeEnum.WXPAY_MP){
    			//JSP把以下引數寫在xml中:公眾平臺微信支付 開發配置 授權獲取使用者的唯一的openid
    			map.put("AppId", response.getAppId());
    			map.put("TimeStamp", response.getTimeStamp());
    			map.put("nonceStr", response.getNonceStr());
    			map.put("PackAge", response.getPackAge());
    			map.put("SignType", response.getSignType());
    			map.put("PaySign", response.getPaySign());
    			return new ModelAndView("WxMpPay",map);
    		}
    		throw new RuntimeException("支付狀態不合法");
    	}

  7. 微信退款

    //微信退款操作 1微信支付型別 2訂單號碼
    	public ServerResponse<String> WxRefundRequest(BestPayTypeEnum type,String orderId){
    		OrderForm orderForm=orders.selectByOrderId(orderId);
    		if(orderForm==null){
    			return ServerResponse.createByError(ResponseCode.ERROR,"退款訂單號不存在");
    		}
    		// 支付請求
    		RefundRequest request = new RefundRequest();
    		request.setPayTypeEnum(type);
    		request.setOrderId(orderId);
    		request.setOrderAmount(orderForm.getPrice().doubleValue());
    		RefundResponse response=payService.refund(request);
    		logger.info("response.getOutTradeNo()==>"+response.getOutTradeNo());
    		//對比之前的支付流水號與現在返回的支付流水號是否一致
    		if(StringUtils.equals(orderForm.getOrderNum(),response.getOutTradeNo())){
    			orderForm.setStatus(OrderStatus.ORDERRFUSE.getStatus());//已退款
    			orderForm.setRefuseTime(new Date());//退款時間
    			 //更新訂單資料訂單資訊
    	        orders.updateById(orderForm);
    		}
    		return ServerResponse.createBySuccess("退款成功",orderId);
    	}

  8. 微信回掉

    // 非同步通知:支付非同步通知驗證是否支付成功
    	@Transactional
    	public String NotiyfiyInfor(String notiyBody) {
    		// 1.驗證簽名方式==防止在URL中修改引數資訊-以驗證微信返回的加密字串是否正確 修改訂單訂單資訊
    		PayResponse response = payService.asyncNotify(notiyBody);
    		// 2. 金額校驗(從資料庫查詢使用者支付訂單的金額與實際微信回撥資訊中的訂單金額做對比)
    		//查詢訂單
    		OrderForm order=orders.selectByOrderId(response.getOrderId());
    		if (order != null) {
    			logger.info(String.format("非同步通知支付的訂單號碼:%s,非同步通知支付的訂單金額:%s", response.getOrderId(),response.getOrderAmount()));
    
    				// 資料庫訂單的金額與非同步通知的訂單金額是否相等
    				if (order.getPrice().compareTo(BigDecimal.valueOf(response.getOrderAmount())) != 0) {
    					throw new PayException("資料庫訂單金額與非同步通知的訂單金額不一致:" + response.getOrderAmount());
    				}
    				// 3. 判斷訂單是否支付成功==>修改訂單的狀態
    				order.setStatus(OrderStatus.PAYED.getStatus());
    				// 交易流水號
    				logger.info("交易流水號==>" + response.getOutTradeNo());
    				order.setOrderNum(response.getOutTradeNo());
    				order.setType(response.getPayPlatformEnum().getName());
    				order.setPayTime(new Date());
    				//更新訂單資料訂單資訊
    				orders.updateById(order);
    				//增加資金流水記錄
    				CashFlow cash=new CashFlow();
    				cash.setId(Md5SaltUtils.getStringId());
    				cash.setOrderFormId(order.getId());
    				cash.setType(OrderStatus.ORDERINCOME.getStatus());
    				cash.setCreateTime(new Date());
    				cashflow.insert(cash);
    			}
    		// 以上校驗全部通過 判斷支付的平臺是微信還是支付寶,返回對應的格式的資訊==>就要告訴微信或者支付寶不要再通知了,否則會有時間間隔的有回撥資訊傳送給我們
    		if (response.getPayPlatformEnum() == BestPayPlatformEnum.WX) {
    			return "<xml>\n" + "<return_code><![CDATA[SUCCESS]]></return_code>\n"
    					+ "  <return_msg><![CDATA[OK]]></return_msg>\n" + "</xml>";
    		} else if (response.getPayPlatformEnum() == BestPayPlatformEnum.ALIPAY) {
    			return "success";
    		}
    		throw new PayException("訂單號不存在");
    	}

  9. 支付成功和回掉的介面

    // 接收的非同步通知
    	@ResponseBody
    	@PostMapping("/notify")
    	public String PayNotify(@RequestBody String notiyBody) {
    		return payService.NotiyfiyInfor(notiyBody);
    	}
    
    	// 支付成功==返回支付成功的頁面
    	@ResponseBody
    	@GetMapping("/return")
    	public String PaySuccessfully() {
    		return "支付成功";
    	}

  10. 微信支付成功的頁面

    微信支付成功的頁面

  11. 需要支付金鑰的同學可以私信聯絡我 可以提供學習使用 點贊+關注+評論哦!!