me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl Maven / Gradle / Ivy
The newest version!
package me.chanjar.weixin.mp.api.impl;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.joor.Reflect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.api.WxMpPayService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.pay.WxMpPayCallback;
import me.chanjar.weixin.mp.bean.pay.WxMpPayRefundResult;
import me.chanjar.weixin.mp.bean.pay.WxMpPayResult;
import me.chanjar.weixin.mp.bean.pay.WxRedpackResult;
import me.chanjar.weixin.mp.bean.pay.WxSendRedpackRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.pay.WxUnifiedOrderResult;
/**
* Created by Binary Wang on 2016/7/28.
*
* @author binarywang (https://github.com/binarywang)
*/
public class WxMpPayServiceImpl implements WxMpPayService {
private static final List TRADE_TYPES = Lists.newArrayList("JSAPI",
"NATIVE", "APP");
private final Logger log = LoggerFactory.getLogger(WxMpPayServiceImpl.class);
private WxMpService wxMpService;
public WxMpPayServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}
@Override
public WxMpPayResult getJSSDKPayResult(String transactionId,
String outTradeNo) throws WxErrorException {
String nonce_str = System.currentTimeMillis() + "";
SortedMap packageParams = new TreeMap();
packageParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId());
packageParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId());
if (transactionId != null && !"".equals(transactionId.trim())) {
packageParams.put("transaction_id", transactionId);
} else if (outTradeNo != null && !"".equals(outTradeNo.trim())) {
packageParams.put("out_trade_no", outTradeNo);
} else {
throw new IllegalArgumentException(
"Either 'transactionId' or 'outTradeNo' must be given.");
}
packageParams.put("nonce_str", nonce_str);
packageParams.put("sign", this.createSign(packageParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
StringBuilder request = new StringBuilder("");
for (Map.Entry para : packageParams.entrySet()) {
request.append(String.format("<%s>%s%s>", para.getKey(),
para.getValue(), para.getKey()));
}
request.append(" ");
String url = "https://api.mch.weixin.qq.com/pay/orderquery";
String responseContent = this.wxMpService.post(url, request.toString());
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxMpPayResult.class);
return (WxMpPayResult) xstream.fromXML(responseContent);
}
@Override
public WxMpPayCallback getJSSDKCallbackData(String xmlData) {
try {
XStream xstream = XStreamInitializer.getInstance();
xstream.alias("xml", WxMpPayCallback.class);
return (WxMpPayCallback) xstream.fromXML(xmlData);
} catch (Exception e) {
e.printStackTrace();
}
return new WxMpPayCallback();
}
@Override
public WxMpPayRefundResult refundPay(Map parameters)
throws WxErrorException {
SortedMap refundParams = new TreeMap(parameters);
refundParams.put("appid",
this.wxMpService.getWxMpConfigStorage().getAppId());
refundParams.put("mch_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId());
refundParams.put("nonce_str", System.currentTimeMillis() + "");
refundParams.put("op_user_id",
this.wxMpService.getWxMpConfigStorage().getPartnerId());
String sign = this.createSign(refundParams,
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
refundParams.put("sign", sign);
StringBuilder request = new StringBuilder("");
for (Map.Entry para : refundParams.entrySet()) {
request.append(String.format("<%s>%s%s>", para.getKey(),
para.getValue(), para.getKey()));
}
request.append(" ");
String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
String responseContent = this.wxMpService.post(url, request.toString());
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxMpPayRefundResult.class);
WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult) xstream
.fromXML(responseContent);
if (!"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getResultCode())
|| !"SUCCESS".equalsIgnoreCase(wxMpPayRefundResult.getReturnCode())) {
WxError error = new WxError();
error.setErrorCode(-1);
error.setErrorMsg("return_code:" + wxMpPayRefundResult.getReturnCode()
+ ";return_msg:" + wxMpPayRefundResult.getReturnMsg()
+ ";result_code:" + wxMpPayRefundResult.getResultCode() + ";err_code"
+ wxMpPayRefundResult.getErrCode() + ";err_code_des"
+ wxMpPayRefundResult.getErrCodeDes());
throw new WxErrorException(error);
}
return wxMpPayRefundResult;
}
@Override
public boolean checkJSSDKCallbackDataSignature(Map kvm,
String signature) {
return signature.equals(this.createSign(kvm,
this.wxMpService.getWxMpConfigStorage().getPartnerKey()));
}
@Override
public WxRedpackResult sendRedpack(WxSendRedpackRequest request)
throws WxErrorException {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxSendRedpackRequest.class);
xstream.processAnnotations(WxRedpackResult.class);
request.setWxAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");
String sign = this.createSign(xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
if (request.getAmtType() != null) {
//裂变红包
url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack";
}
String responseContent = this.wxMpService.post(url, xstream.toXML(request));
WxRedpackResult redpackResult = (WxRedpackResult) xstream
.fromXML(responseContent);
if ("FAIL".equals(redpackResult.getResultCode())) {
throw new WxErrorException(WxError.newBuilder()
.setErrorMsg(
redpackResult.getErrCode() + ":" + redpackResult.getErrCodeDes())
.build());
}
return redpackResult;
}
private Map xmlBean2Map(Object bean) {
Map result = Maps.newHashMap();
for (Entry entry : Reflect.on(bean).fields().entrySet()) {
Reflect reflect = entry.getValue();
if (reflect.get() == null) {
continue;
}
try {
Field field = bean.getClass().getDeclaredField(entry.getKey());
if (field.isAnnotationPresent(XStreamAlias.class)) {
result.put(field.getAnnotation(XStreamAlias.class).value(),
reflect.get().toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @return 签名字符串
*/
private String createSign(Map packageParams, String signKey) {
SortedMap sortedMap = new TreeMap(packageParams);
StringBuffer toSign = new StringBuffer();
for (String key : sortedMap.keySet()) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}
toSign.append("key=" + signKey);
return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
}
@Override
public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
throws WxErrorException {
checkParameters(request);
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxUnifiedOrderRequest.class);
xstream.processAnnotations(WxUnifiedOrderResult.class);
request.setAppid(this.wxMpService.getWxMpConfigStorage().getAppId());
request.setMchId(this.wxMpService.getWxMpConfigStorage().getPartnerId());
request.setNonceStr(System.currentTimeMillis() + "");
String sign = this.createSign(xmlBean2Map(request),
this.wxMpService.getWxMpConfigStorage().getPartnerKey());
request.setSign(sign);
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String responseContent = this.wxMpService.post(url, xstream.toXML(request));
WxUnifiedOrderResult result = (WxUnifiedOrderResult) xstream
.fromXML(responseContent);
if ("FAIL".equals(result.getResultCode())) {
throw new WxErrorException(WxError.newBuilder()
.setErrorMsg(result.getErrCode() + ":" + result.getErrCodeDes())
.build());
}
return result;
}
private void checkParameters(WxUnifiedOrderRequest request) {
List nullFields = Lists.newArrayList();
for (Entry entry : Reflect.on(request).fields()
.entrySet()) {
Reflect reflect = entry.getValue();
try {
Field field = request.getClass().getDeclaredField(entry.getKey());
if (field.isAnnotationPresent(Required.class)
&& reflect.get() == null) {
nullFields.add(entry.getKey());
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (!nullFields.isEmpty()) {
throw new IllegalArgumentException("必填字段[" + nullFields + "]必须提供值");
}
if (!TRADE_TYPES.contains(request.getTradeType())) {
throw new IllegalArgumentException(
"trade_type目前必须为" + TRADE_TYPES + "其中之一");
}
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
}
if ("NATIVE".equals(request.getTradeType())
&& request.getProductId() == null) {
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
}
}
@Override
public Map getPayInfo(WxUnifiedOrderRequest request) throws WxErrorException {
WxUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
if (!"SUCCESS".equalsIgnoreCase(unifiedOrderResult.getReturnCode())
|| !"SUCCESS".equalsIgnoreCase(unifiedOrderResult.getResultCode())) {
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1)
.setErrorMsg("return_code:" + unifiedOrderResult.getReturnCode() + ";return_msg:"
+ unifiedOrderResult.getReturnMsg() + ";result_code:" + unifiedOrderResult.getResultCode() + ";err_code"
+ unifiedOrderResult.getErrCode() + ";err_code_des" + unifiedOrderResult.getErrCodeDes())
.build());
}
String prepayId = unifiedOrderResult.getPrepayId();
if (StringUtils.isBlank(prepayId)) {
throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).",
unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
}
Map payInfo = new HashMap();
payInfo.put("appId", this.wxMpService.getWxMpConfigStorage().getAppId());
// 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
payInfo.put("nonceStr", System.currentTimeMillis() + "");
payInfo.put("package", "prepay_id=" + prepayId);
payInfo.put("signType", "MD5");
if ("NATIVE".equals(request.getTradeType())) {
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL());
}
String finalSign = this.createSign(payInfo, this.wxMpService.getWxMpConfigStorage().getPartnerKey());
payInfo.put("paySign", finalSign);
return payInfo;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy