All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.taotao.cloud.pay.wxpay.wx.WxPay Maven / Gradle / Ivy

There is a newer version: 2024.09
Show newest version
package com.taotao.cloud.pay.wxpay.wx;

import static com.taotao.cloud.pay.wxpay.wx.constants.WxPayConstant.HUNDRED;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import com.taotao.cloud.pay.wxpay.wx.constants.WxPayConstant;
import com.taotao.cloud.pay.wxpay.wx.domain.DefaultWxDomain;
import com.taotao.cloud.pay.wxpay.wx.domain.WxDomain;
import com.taotao.cloud.pay.wxpay.wx.enums.RequestSuffix;
import com.taotao.cloud.pay.wxpay.wx.enums.SignType;
import com.taotao.cloud.pay.wxpay.wx.enums.TradeType;
import com.taotao.cloud.pay.wxpay.wx.response.WxPayCallback;
import com.taotao.cloud.pay.wxpay.wx.response.WxPayOrderQueryResponse;
import com.taotao.cloud.pay.wxpay.wx.response.WxPayResponse;
import com.taotao.cloud.pay.wxpay.wx.utils.WxPayUtil;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lingting 2021/1/26 15:54
 */
public class WxPay {

	private final String appId;

	private final String mchId;

	private final String mckKey;

	private String notifyUrl;

	private String returnUrl;

	/**
	 * 是否使用沙箱
	 */
	private boolean sandbox;

	/**
	 * 域名策略, 可是使用自定义实现
	 */
	private WxDomain domain;

	public WxPay(String appId, String mchId, String mckKey, boolean sandbox) {
		this(appId, mchId, mckKey, sandbox, DefaultWxDomain.of(sandbox));
	}

	public WxPay(String appId, String mchId, String mckKey, boolean sandbox, WxDomain domain) {
		this.sandbox = sandbox;
		this.domain = domain;
		this.mchId = mchId;
		this.appId = appId;

		// 沙箱环境初始化
		if (sandbox) {
			this.mckKey = domain.sandbox(this).getSandboxSignKey();
		} else {
			this.mckKey = mckKey;
		}

	}

	/**
	 * jsApi 支付
	 *
	 * @param sn     订单号
	 * @param amount 支付金额, 单位 元
	 * @param ip     客户端ip
	 * @param body   商品描述
	 */
	public WxPayResponse jsApiPay(String sn, BigDecimal amount, String ip, String body) {
		return jsApiPay(sn, amount, ip, body, notifyUrl);
	}

	public WxPayResponse jsApiPay(String sn, BigDecimal amount, String ip, String body,
		String notifyUrl) {
		return WxPayResponse.of(pay(sn, amount, ip, body, notifyUrl, TradeType.JSAPI));
	}

	/**
	 * app 支付
	 *
	 * @param sn     订单号
	 * @param amount 支付金额, 单位 元
	 * @param ip     客户端ip
	 * @param body   商品描述
	 */
	public WxPayResponse appPay(String sn, BigDecimal amount, String ip, String body) {
		return appPay(sn, amount, ip, body, notifyUrl);
	}

	public WxPayResponse appPay(String sn, BigDecimal amount, String ip, String body,
		String notifyUrl) {
		return WxPayResponse.of(pay(sn, amount, ip, body, notifyUrl, TradeType.APP));
	}

	/**
	 * native 支付
	 *
	 * @param sn     订单号
	 * @param amount 支付金额, 单位 元
	 * @param body   商品描述
	 */
	public WxPayResponse nativePay(String sn, BigDecimal amount, String body) {
		return nativePay(sn, amount, body, notifyUrl);
	}

	public WxPayResponse nativePay(String sn, BigDecimal amount, String body, String notifyUrl) {
		return WxPayResponse.of(pay(sn, amount, null, body, notifyUrl, TradeType.NATIVE));
	}

	/**
	 * web 支付
	 *
	 * @param sn     订单号
	 * @param amount 支付金额, 单位 元
	 * @param ip     客户端ip
	 * @param body   商品描述
	 */
	public WxPayResponse webPay(String sn, BigDecimal amount, String ip, String body) {
		return webPay(sn, amount, ip, body, notifyUrl);
	}

	public WxPayResponse webPay(String sn, BigDecimal amount, String ip, String body,
		String notifyUrl) {
		return WxPayResponse.of(pay(sn, amount, ip, body, notifyUrl, TradeType.MWEB));
	}

	/**
	 * 发起支付
	 *
	 * @param sn        订单号
	 * @param amount    金额, 单位 元
	 * @param ip        ip
	 * @param body      描述
	 * @param notifyUrl 通知
	 * @param tradeType 支付类型
	 */
	public Map pay(String sn, BigDecimal amount, String ip, String body,
		String notifyUrl,
		TradeType tradeType) {
		Map params = new HashMap<>(6);
		params.put("body", body);
		params.put("out_trade_no", sn);
		params.put("total_fee", yuanToFen(amount));
		params.put("spbill_create_ip", ip);
		params.put("notify_url", notifyUrl);
		params.put("trade_type", tradeType.toString());

		return request(params, RequestSuffix.UNIFIEDORDER);
	}

	/**
	 * 查询订单
	 *
	 * @param sn   平台订单号
	 * @param wxSn 微信订单号
	 * @return com.hccake.extend.pay.wx.response.WxPayOrderQueryResponse
	 */
	public WxPayOrderQueryResponse query(String sn, String wxSn) {
		Assert.isFalse(CharSequenceUtil.isBlank(sn) && CharSequenceUtil.isBlank(wxSn),
			"参数 sn 和 wxSn 不能同时为空!");
		Map params = new HashMap<>(6);
		params.put("out_trade_no", sn);
		params.put("transaction_id", wxSn);
		return WxPayOrderQueryResponse.of(request(params, RequestSuffix.ORDERQUERY));
	}

	/**
	 * 向微信发起请求
	 *
	 * @param params 参数
	 * @param rs     请求后缀
	 */
	public Map request(Map params, RequestSuffix rs) {
		Map map = new HashMap<>(params.size() + 3);
		map.putAll(params);

		// 添加必须参数
		map.put("appid", appId);
		map.put("mch_id", mchId);
		map.put("nonce_str", WxPayUtil.generateNonceStr());
		// 设置签名类型; 沙箱使用 md5, 正式使用 hmac sha256
		map.put(WxPayConstant.FIELD_SIGN_TYPE,
			sandbox ? SignType.MD5.getStr() : SignType.HMAC_SHA256.getStr());
		// 签名
		map.put(WxPayConstant.FIELD_SIGN, WxPayUtil.sign(map, mckKey));

		return domain.request(map, rs);
	}

	/**
	 * 金额单位转换, 元 转为 分
	 *
	 * @param amount 支付金额, 单位 元
	 * @return java.lang.String
	 */
	public String yuanToFen(BigDecimal amount) {
		return amount.multiply(HUNDRED).setScale(2, RoundingMode.UP).toBigInteger().toString();
	}

	/**
	 * 验证回调签名
	 *
	 * @param callback 回调数据
	 * @return java.lang.Boolean
	 */
	public boolean checkSign(WxPayCallback callback) {
		// 原签名不存在时, 直接失败
		if (CharSequenceUtil.isBlank(callback.getSign())) {
			return false;
		}

		Map params = new HashMap<>(callback.getRaw());

		// 存在签名类型, 直接验签
		if (params.containsKey(WxPayConstant.FIELD_SIGN_TYPE)) {
			return WxPayUtil.sign(params, mckKey).equals(callback.getSign());
		}

		// 两种签名类型都试一次
		if (WxPayUtil.sign(params, SignType.HMAC_SHA256, mckKey).equals(callback.getSign())) {
			return true;
		}

		return WxPayUtil.sign(params, SignType.MD5, mckKey).equals(callback.getSign());
	}

	public String getAppId() {
		return appId;
	}

	public String getMchId() {
		return mchId;
	}

	public String getMckKey() {
		return mckKey;
	}

	public String getNotifyUrl() {
		return notifyUrl;
	}

	public void setNotifyUrl(String notifyUrl) {
		this.notifyUrl = notifyUrl;
	}

	public String getReturnUrl() {
		return returnUrl;
	}

	public void setReturnUrl(String returnUrl) {
		this.returnUrl = returnUrl;
	}

	public boolean isSandbox() {
		return sandbox;
	}

	public void setSandbox(boolean sandbox) {
		this.sandbox = sandbox;
	}

	public WxDomain getDomain() {
		return domain;
	}

	public void setDomain(WxDomain domain) {
		this.domain = domain;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy