com.github.binarywang.wxpay.bean.request.BaseWxPayRequest Maven / Gradle / Ivy
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import lombok.experimental.Accessors;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.util.BeanUtils;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES;
/**
*
* 微信支付请求对象共用的参数存放类
* Created by Binary Wang on 2016-10-24.
*
*
* @author Binary Wang
*/
@Data
@Accessors(chain = true)
public abstract class BaseWxPayRequest implements Serializable {
private static final long serialVersionUID = -4766915659779847060L;
/**
*
* 字段名:公众账号ID.
* 变量名:appid
* 是否必填:是
* 类型:String(32)
* 示例值:wxd678efh567hg6787
* 描述:微信分配的公众账号ID(企业号corpid即为此appId)
*
*/
@XStreamAlias("appid")
protected String appid;
/**
*
* 字段名:商户号.
* 变量名:mch_id
* 是否必填:是
* 类型:String(32)
* 示例值:1230000109
* 描述:微信支付分配的商户号
*
*/
@XStreamAlias("mch_id")
protected String mchId;
/**
*
* 字段名:服务商模式下的子商户公众账号ID.
* 变量名:sub_appid
* 是否必填:是
* 类型:String(32)
* 示例值:wxd678efh567hg6787
* 描述:微信分配的子商户公众账号ID
*
*/
@XStreamAlias("sub_appid")
protected String subAppId;
/**
*
* 字段名:服务商模式下的子商户号.
* 变量名:sub_mch_id
* 是否必填:是
* 类型:String(32)
* 示例值:1230000109
* 描述:微信支付分配的子商户号,开发者模式下必填
*
*/
@XStreamAlias("sub_mch_id")
protected String subMchId;
/**
*
* 字段名:随机字符串.
* 变量名:nonce_str
* 是否必填:是
* 类型:String(32)
* 示例值:5K8264ILTKCH16CQ2502SI8ZNMTM67VS
* 描述:随机字符串,不长于32位。推荐随机数生成算法
*
*/
@XStreamAlias("nonce_str")
protected String nonceStr;
/**
*
* 字段名:签名.
* 变量名:sign
* 是否必填:是
* 类型:String(32)
* 示例值:C380BEC2BFD727A4B6845133519F3AD6
* 描述:签名,详见签名生成算法
*
*/
@XStreamAlias("sign")
protected String sign;
/**
*
* 签名类型.
* sign_type
* 否
* String(32)
* HMAC-SHA256
* 签名类型,目前支持HMAC-SHA256和MD5
*
*/
@XStreamAlias("sign_type")
private String signType;
/**
* 企业微信签名
*/
@XStreamAlias("workwx_sign")
private String workWxSign;
public String getWorkWxSign() {
return workWxSign;
}
public void setWorkWxSign(String workWxSign) {
this.workWxSign = workWxSign;
}
/**
* 将单位为元转换为单位为分.
*
* @param yuan 将要转换的元的数值字符串
* @return the integer
*/
public static Integer yuanToFen(String yuan) {
return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
}
/**
* 检查请求参数内容,包括必填参数以及特殊约束.
*/
private void checkFields() throws WxPayException {
//check required fields
try {
BeanUtils.checkRequiredFields(this);
} catch (WxErrorException e) {
throw new WxPayException(e.getError().getErrorMsg(), e);
}
//check other parameters
this.checkConstraints();
}
/**
* 检查约束情况.
*
* @throws WxPayException the wx pay exception
*/
protected abstract void checkConstraints() throws WxPayException;
/**
* 是否需要nonce_str
*/
protected boolean needNonceStr() {
return true;
}
/**
* 如果配置中已经设置,可以不设置值.
*
* @param appid 微信公众号appid
*/
public void setAppid(String appid) {
this.appid = appid;
}
/**
* 如果配置中已经设置,可以不设置值.
*
* @param mchId 微信商户号
*/
public void setMchId(String mchId) {
this.mchId = mchId;
}
/**
* 默认采用时间戳为随机字符串,可以不设置.
*
* @param nonceStr 随机字符串
*/
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
/**
* To xml string.
*
* @return the string
*/
public String toXML() {
//涉及到服务商模式的两个参数,在为空值时置为null,以免在请求时将空值传给微信服务器
this.setSubAppId(StringUtils.trimToNull(this.getSubAppId()));
this.setSubMchId(StringUtils.trimToNull(this.getSubMchId()));
if (XmlConfig.fastMode) {
return toFastXml();
}
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(this.getClass());
return xstream.toXML(this);
}
/**
* 使用快速算法组装xml
*/
private String toFastXml() {
try {
Document document = DocumentHelper.createDocument();
Element root = document.addElement(xmlRootTagName());
Map signParams = getSignParams();
signParams.put("sign", sign);
for (Map.Entry entry : signParams.entrySet()) {
if (entry.getValue() == null) {
continue;
}
Element elm = root.addElement(entry.getKey());
elm.addText(entry.getValue());
}
return document.asXML();
} catch (Exception e) {
throw new WxRuntimeException("generate xml error", e);
}
}
/**
* 返回xml结构的根节点名称
*
* @return 默认返回"xml", 特殊情况可以在子类中覆盖
*/
protected String xmlRootTagName() {
return "xml";
}
/**
* 签名时,是否忽略appid.
*
* @return the boolean
*/
protected boolean ignoreAppid() {
return false;
}
/**
* 签名时,是否忽略sub_appid.
*
* @return the boolean
*/
protected boolean ignoreSubAppId() {
return false;
}
protected boolean ignoreSubMchId() {
return false;
}
/**
* 是否是企业微信字段
*/
protected boolean isWxWorkSign() {
return false;
}
/**
* 签名时,忽略的参数.
*
* @return the string [ ]
*/
protected String[] getIgnoredParamsForSign() {
return new String[0];
}
/**
* 获取签名时需要的参数.
* 注意:不含sign属性
*/
public Map getSignParams() {
Map map = new HashMap<>(8);
map.put("appid", appid);
map.put("mch_id", mchId);
map.put("sub_appid", subAppId);
map.put("sub_mch_id", subMchId);
map.put("nonce_str", nonceStr);
map.put("sign_type", signType);
storeMap(map);
return map;
}
/**
* 将属性组装到一个Map中,供签名和最终发送XML时使用.
* 这里需要将所有的属性全部保存进来,签名的时候会自动调用getIgnoredParamsForSign进行忽略,
* 不用担心。否则最终生成的XML会缺失。
*
* @param map 传入的属性Map
*/
abstract protected void storeMap(Map map);
/**
*
* 检查参数,并设置签名.
* 1、检查参数(注意:子类实现需要检查参数的而外功能时,请在调用父类的方法前进行相应判断)
* 2、补充系统参数,如果未传入则从配置里读取
* 3、生成签名,并设置进去
*
*
* @param config 支付配置对象,用于读取相应系统配置信息
* @throws WxPayException the wx pay exception
*/
public void checkAndSign(WxPayConfig config) throws WxPayException {
this.checkFields();
if (!ignoreAppid()) {
if (StringUtils.isBlank(getAppid())) {
this.setAppid(config.getAppId());
}
}
if (StringUtils.isBlank(getMchId())) {
this.setMchId(config.getMchId());
}
if (!ignoreSubAppId()) {
if (StringUtils.isBlank(getSubAppId())) {
this.setSubAppId(config.getSubAppId());
}
}
if (!ignoreSubMchId()) {
if (StringUtils.isBlank(getSubMchId())) {
this.setSubMchId(config.getSubMchId());
}
}
if (StringUtils.isBlank(getSignType())) {
if (config.getSignType() != null && !ALL_SIGN_TYPES.contains(config.getSignType())) {
throw new WxPayException("非法的signType配置:" + config.getSignType() + ",请检查配置!");
}
this.setSignType(StringUtils.trimToNull(config.getSignType()));
} else {
if (!ALL_SIGN_TYPES.contains(this.getSignType())) {
throw new WxPayException("非法的sign_type参数:" + this.getSignType());
}
}
if (needNonceStr() && StringUtils.isBlank(getNonceStr())) {
this.setNonceStr(String.valueOf(System.currentTimeMillis()));
}
//设置签名字段的值
this.setSign(SignUtils.createSign(this, this.getSignType(), config.getMchKey(), this.getIgnoredParamsForSign()));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy