Java 微信支付接口(统一下单,异步回调,订单退款,取消订单)

一.准备工作

APP绑定微信商户平台获取商户id(mchID)、证书(商户后台下载)、支付签名密钥(商户后台设置api密钥)、退款签名密钥(商户后台设置api密钥ipv3)等

1.导入微信支付SDK



	com.github.wxpay
	wxpay-sdk
	0.0.3

2.配置微信参数类

@Component
@ConfigurationProperties
@PropertySource("classpath:config/wxconfig.properties") --需自己创建相应的配置文件
@Data
public class WxConfig implements WXPayConfig {

    /**
     * appid
     */
    public String appID;

    /**
     * 商户id
     */
    public String mchID;

    /**
     * 密钥
     */
    public String key;

    /**
     * 退款密钥
     */
    public String refundKey;

    /**
     * 连接超时时间
     */
    public int httpConnectTimeoutMs;

    /**
     * 读取超时时间
     */
    public int httpReadTimeoutMs;

    /**
     * 证书
     */
    public InputStream certStream;

    /**
     * 证书路径
     */
    public String certPath;

    /**
     * 微信异步通知地址
     */
    public String wxNotifyUrl;


    public InputStream getCertStream() {
        byte [] certData=null;
        InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(this.getCertPath());
        try {
            certData = IOUtils.toByteArray(certStream);
            certStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new ByteArrayInputStream(certData);
    }

}

二.统一下单

需注入第一步种的配置类

/*微信统一下单接口*/
    public Map wxPayOrder(HashMap param) throws Exception{
        Double price = Double.valueOf(param.get("price").toString());
        String paymentDetailNo = param.get("paymentDetailNo").toString();

        /*转换金额为分*/
        Map respData = null;
        BigDecimal totalPrice  = new BigDecimal(price.toString()); //单位是元
        String totalFee = totalPrice.multiply(new BigDecimal(100)).toBigInteger().toString();

        WXPay wxPay = new WXPay(wxconfig, WXPayConstants.SignType.MD5, false);

        /*调起支付一次签名 得到第一个sign进行下单*/
        Map data = new TreeMap<>();
        data.put("appid",wxconfig.getAppID());
        data.put("mch_id",wxconfig.getMchID());				//商户号
        data.put("trade_type","APP");                         //支付场景 APP 微信app支付 JSAPI 公众号支付  NATIVE 扫码支付
        data.put("notify_url",wxconfig.getWxNotifyUrl());     //回调地址
        data.put("spbill_create_ip","127.0.0.1");            //终端ip
        data.put("total_fee",totalFee);       					//订单总金额
        data.put("fee_type","CNY");                           //默认人民币
        data.put("out_trade_no",paymentDetailNo);  		    //交易号
        data.put("body","**APP-购买业务");			//购买显示信息
        data.put("nonce_str",WXPayUtil.generateNonceStr());    // 随机字符串小于32位
        String s=WXPayUtil.generateSignature(data, wxconfig.getKey());
        data.put("sign",s);

        /** wxPay.unifiedOrder 这个方法中调用微信统一下单接口 */
        respData = wxPay.unifiedOrder(data);
        if (respData.get("result_code").equals("SUCCESS")){
            //返回给APP端的参数并进行签名得到第二个sign,APP端再调起支付接口
            Map repData = new TreeMap<>();
            repData.put("appid",wxconfig.getAppID());
            repData.put("partnerid",wxconfig.getMchID());
            repData.put("prepayid",respData.get("prepay_id"));
            repData.put("package","Sign=WXPay");
            repData.put("noncestr",respData.get("nonce_str"));
            repData.put("timestamp",String.valueOf(System.currentTimeMillis()/1000));
            String sign = WXPayUtil.generateSignature(repData,wxconfig.getKey()); //调用sdk方法签名

            respData.put("sign",sign);
            respData.put("timestamp",repData.get("timestamp"));
            respData.put("package","Sign=WXPay");

     

        }

        return respData;
    }

三.异步回调接口

 /*微信支付异步回调 支付异常的情况回滚并调用退款接口进行退款*/
	@Override
	@Transactional(readOnly = false,  propagation = Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
	public Boolean wxPayNotifyUrl(Map map) throws Exception {
		log.info(">>>>微信支付回调...<<<<");

		String out_trade_no = map.get("out_trade_no");
		String return_code = map.get("return_code");

		if(return_code.equals("SUCCESS")){
			log.info(">>>>微信调起成功...<<<<");
			PaymentDetailVo entity = paymentDao.queryPaymentDetail(out_trade_no);

			/*微信重复调起-->校验如果已经支付则直接返回*/
			if(entity.getDetailStatus() == 1){
				return true;
			}

			/*判断sign签名是否一致*/
			if(WXPayUtil.isSignatureValid(map, wxconfig.getKey())){
				log.info(">>>>微信签名通过...<<<<");

				/*校验api返回的金额与流水单的金额是否一致*/
				if(map.get("total_fee") == null){
					log.error("API返回无金额!");
                    /*调用退款接口 */
					wxRefund(out_trade_no,entity.getUserId(), entity.getPaymentStatus());
					throw new Exception("API返回无金额!");
				}
                /*转换金额为元*/
				BigDecimal totalPrice  = new BigDecimal(entity.getPaymentPrice().toString()); //单位是元
				String paymentPrive = totalPrice.multiply(new BigDecimal(100)).toBigInteger().toString();
				String total_fee = map.get("total_fee").toString();
				if(!total_fee.equals(paymentPrive)){
					log.error("API返回的交易金额与流水单的金额不一致,存在假通知的危险!");
					wxRefund(out_trade_no,entity.getUserId(), entity.getPaymentStatus());
					throw new Exception("API返回的交易金额与流水单的金额不一致,存在假通知的危险!");
				}

				HashMap param = new HashMap();
				param.put("no", entity.getPaymentNo());

				/*异步回调成功,修改订单状态*/
				...


				log.info(">>>>微信异步回调完毕...<<<<");
			}else{
				log.error("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
				wxRefund(out_trade_no,entity.getUserId(), Integer.valueOf(map.get("type").toString()));
				throw new Exception("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
			}
		}else {
			return false;
		}
		return true;
	}

四.退款接口

/*微信退款*/
private Boolean wxDoingRefund(HashMap param) {
		Double price = Double.valueOf(param.get("price").toString());
		String paymentDetailNo = param.get("paymentDetailNo").toString();
		String out_trade_no = param.get("out_trade_no").toString();

		Map respData = null;
		BigDecimal totalPrice  = new BigDecimal(price); //此时的单位是元
		String totalFee = totalPrice.multiply(new BigDecimal(100)).toBigInteger().toString();
		try {
			WXPay wxPay = new WXPay(wxconfig, WXPayConstants.SignType.MD5, false);

			Map data = new TreeMap<>();
			data.put("appid",wxconfig.getAppID());
			data.put("mch_id",wxconfig.getMchID());				//商户号
			data.put("total_fee",totalFee);       					//订单总金额
			data.put("refund_fee",totalFee);       				//退款总金额
			data.put("out_trade_no",out_trade_no);					//商户订单号
			data.put("out_refund_no",paymentDetailNo);				//商户退款单号
			data.put("refund_desc","支付异常");
			data.put("nonce_str",WXPayUtil.generateNonceStr());	// 随机字符串小于32位
			String s=WXPayUtil.generateSignature(data, wxconfig.getRefundKey());
			data.put("sign",s);
			/** wxPay.refund 这个方法中调用微信退款接口 */
			respData = wxPay.refund(data);
			if (respData.get("return_code").equals("SUCCESS")){
				log.info(">>>>微信退款成功...>>>>");
				
				return true;

			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return false;
	}

五.关闭订单

关闭订单——以下情况需要调用关单接口:
* 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
* 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
* 订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟
/*微信关闭订单*/
public Boolean cloaseOrder(String out_trade_no) throws Exception{
		WXPay wxPay = new WXPay(wxconfig, WXPayConstants.SignType.MD5, false);
		Map respData = null;
		Map data = new TreeMap<>();
		data.put("appid",wxconfig.getAppID());
		data.put("mch_id",wxconfig.getMchID());								//商户号
		data.put("out_trade_no",out_trade_no);									//商户订单号
		data.put("nonce_str",WXPayUtil.generateNonceStr());  				 	// 随机字符串小于32位
		String s=WXPayUtil.generateSignature(data, wxconfig.getRefundKey());
		data.put("sign",s);
		/** wxPay.cloaseOrder 这个方法中调用微信退款接口 */
		respData = wxPay.closeOrder(data);
		if (respData.get("return_code").equals("SUCCESS")){
			log.info(">>>>微信关闭订单成功...>>>>");
			return true;
		}
		return false;
	}

 

你可能感兴趣的:(解决方案)