diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java index e362e64b..c91e8ac0 100755 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java @@ -47,7 +47,6 @@ public class WxCryptUtil { protected String appidOrCorpid; public WxCryptUtil() { - super(); } /** @@ -106,7 +105,7 @@ public class WxCryptUtil { private static String genRandomStr() { String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < 16; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); @@ -148,12 +147,11 @@ public class WxCryptUtil { String encryptedXml = encrypt(genRandomStr(), plainText); // 生成安全签名 - String timeStamp = Long.toString(System.currentTimeMillis() / 1000l); + String timeStamp = Long.toString(System.currentTimeMillis() / 1000L); String nonce = genRandomStr(); String signature = SHA1.gen(this.token, timeStamp, nonce, encryptedXml); - String result = generateXml(encryptedXml, signature, timeStamp, nonce); - return result; + return generateXml(encryptedXml, signature, timeStamp, nonce); } /** @@ -194,9 +192,7 @@ public class WxCryptUtil { byte[] encrypted = cipher.doFinal(unencrypted); // 使用BASE64对加密后的字符串进行编码 - String base64Encrypted = base64.encodeToString(encrypted); - - return base64Encrypted; + return base64.encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException(e); } @@ -228,8 +224,7 @@ public class WxCryptUtil { } // 解密 - String result = decrypt(cipherText); - return result; + return decrypt(cipherText); } /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java similarity index 79% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java index e3692931..e7a7ea90 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyResponse.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayNotifyResponse.java @@ -1,4 +1,4 @@ -package com.github.binarywang.wxpay.bean; +package com.github.binarywang.wxpay.bean.notify; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; @@ -7,8 +7,11 @@ import com.thoughtworks.xstream.annotations.XStreamOmitField; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.common.util.xml.XStreamInitializer; +/** + * 微信支付订单和退款的异步通知共用的响应类 + */ @XStreamAlias("xml") -public class WxPayOrderNotifyResponse { +public class WxPayNotifyResponse { @XStreamOmitField private transient static final String FAIL = "FAIL"; @XStreamOmitField @@ -21,25 +24,25 @@ public class WxPayOrderNotifyResponse { @XStreamAlias("return_msg") private String returnMsg; - public WxPayOrderNotifyResponse() { + public WxPayNotifyResponse() { super(); } - public WxPayOrderNotifyResponse(String returnCode, String returnMsg) { + public WxPayNotifyResponse(String returnCode, String returnMsg) { super(); this.returnCode = returnCode; this.returnMsg = returnMsg; } public static String fail(String msg) { - WxPayOrderNotifyResponse response = new WxPayOrderNotifyResponse(FAIL, msg); + WxPayNotifyResponse response = new WxPayNotifyResponse(FAIL, msg); XStream xstream = XStreamInitializer.getInstance(); xstream.autodetectAnnotations(true); return xstream.toXML(response); } public static String success(String msg) { - WxPayOrderNotifyResponse response = new WxPayOrderNotifyResponse(SUCCESS, msg); + WxPayNotifyResponse response = new WxPayNotifyResponse(SUCCESS, msg); XStream xstream = XStreamInitializer.getInstance(); xstream.autodetectAnnotations(true); return xstream.toXML(response); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java similarity index 96% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java index c2b4e22e..cd948dfb 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/WxPayOrderNotifyCoupon.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyCoupon.java @@ -1,4 +1,4 @@ -package com.github.binarywang.wxpay.bean; +package com.github.binarywang.wxpay.bean.notify; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java similarity index 98% rename from weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java rename to weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java index a411cd2c..54657ac6 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java @@ -1,6 +1,6 @@ -package com.github.binarywang.wxpay.bean.result; +package com.github.binarywang.wxpay.bean.notify; -import com.github.binarywang.wxpay.bean.WxPayOrderNotifyCoupon; +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.annotations.XStreamAlias; @@ -20,7 +20,6 @@ import java.util.Map; */ @XStreamAlias("xml") public class WxPayOrderNotifyResult extends WxPayBaseResult implements Serializable { - private static final long serialVersionUID = 5389718115223345496L; /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java new file mode 100644 index 00000000..392c1014 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java @@ -0,0 +1,372 @@ +package com.github.binarywang.wxpay.bean.notify; + +import com.github.binarywang.wxpay.bean.result.WxPayBaseResult; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import me.chanjar.weixin.common.util.ToStringUtils; +import me.chanjar.weixin.common.util.xml.XStreamInitializer; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.Serializable; +import java.math.BigInteger; +import java.security.MessageDigest; + +/** + *
+ *  退款结果通知对象
+ *  Created by BinaryWang on 2017/8/27.
+ * 
+ * + * @author Binary Wang + */ +@XStreamAlias("xml") +public class WxPayRefundNotifyResult extends WxPayBaseResult implements Serializable { + private static final long serialVersionUID = 4651725860079259186L; + + /** + * 从xml字符串创建bean对象 + * + * @param xmlString xml字符串 + * @param mchKey 商户密钥 + */ + public static WxPayRefundNotifyResult fromXML(String xmlString, String mchKey) throws WxPayException { + WxPayRefundNotifyResult result = WxPayBaseResult.fromXML(xmlString, WxPayRefundNotifyResult.class); + String reqInfoString = result.getReqInfoString(); + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + + final MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(mchKey.getBytes()); + final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase(); + SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES"); + cipher.init(Cipher.DECRYPT_MODE, key); + result.setReqInfo(ReqInfo.fromXML(new String(cipher.doFinal(Base64.decodeBase64(reqInfoString))))); + } catch (Exception e) { + throw new WxPayException("解密退款通知加密信息时出错", e); + } + + return result; + } + + /** + *
+   * 字段名:加密信息
+   * 变量名:req_info
+   * 是否必填:是
+   * 类型:String(1024)
+   * 描述:加密信息请用商户证书与商户秘钥进行解密
+   * 
+ */ + @XStreamAlias("req_info") + private String reqInfoString; + + private ReqInfo reqInfo; + + /** + * 加密信息字段解密后的内容 + */ + @XStreamAlias("root") + public static class ReqInfo { + @Override + public String toString() { + return ToStringUtils.toSimpleString(this); + } + + /** + *
+     * 字段名:微信订单号
+     * 变量名:transaction_id
+     * 是否必填:是
+     * 类型:String(32)
+     * 示例值:1217752501201407033233368018
+     * 描述:微信订单号
+     * 
+ */ + @XStreamAlias("transaction_id") + private String transactionId; + + /** + *
+     * 字段名:商户订单号
+     * 变量名:out_trade_no
+     * 是否必填:是
+     * 类型:String(32)
+     * 示例值:1217752501201407033233368018
+     * 描述:商户系统内部的订单号
+     * 
+ */ + @XStreamAlias("out_trade_no") + private String outTradeNo; + + /** + *
+     * 字段名:微信退款单号
+     * 变量名:refund_id
+     * 是否必填:是
+     * 类型:String(28)
+     * 示例值:1217752501201407033233368018
+     * 描述:微信退款单号
+     * 
+ */ + @XStreamAlias("refund_id") + private String refundId; + + /** + *
+     * 字段名:商户退款单号
+     * 变量名:out_refund_no
+     * 是否必填:是
+     * 类型:String(64)
+     * 示例值:1217752501201407033233368018
+     * 描述:商户退款单号
+     * 
+ */ + @XStreamAlias("out_refund_no") + private String outRefundNo; + + /** + *
+     * 字段名:订单金额
+     * 变量名:total_fee
+     * 是否必填:是
+     * 类型:Int
+     * 示例值:100
+     * 描述:订单总金额,单位为分,只能为整数,详见支付金额
+     * 
+ */ + @XStreamAlias("total_fee") + private Integer totalFee; + + /** + *
+     * 字段名:结订单金额
+     * 变量名:settlement_total_fee
+     * 是否必填:否
+     * 类型:Int
+     * 示例值:100
+     * 描述:当该订单有使用非充值券时,返回此字段。应结订单金额=订单金额-非充值代金券金额,应结订单金额<=订单金额。
+     * 
+ */ + @XStreamAlias("settlement_total_fee") + private Integer settlementTotalFee; + + /** + *
+     * 字段名:申请退款金额
+     * 变量名:refund_fee
+     * 是否必填:是
+     * 类型:Int
+     * 示例值:100
+     * 描述:退款总金额,单位为分
+     * 
+ */ + @XStreamAlias("refund_fee") + private Integer refundFee; + + /** + *
+     * 字段名:退款金额
+     * 变量名:settlement_refund_fee
+     * 是否必填:是
+     * 类型:Int
+     * 示例值:100
+     * 描述:退款金额=申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
+     * 
+ */ + @XStreamAlias("settlement_refund_fee") + private Integer settlementRefundFee; + + /** + *
+     * 字段名:退款状态
+     * 变量名:refund_status
+     * 是否必填:是
+     * 类型:String(16)
+     * 示例值:SUCCESS
+     * 描述:SUCCESS-退款成功,CHANGE-退款异常,REFUNDCLOSE—退款关闭
+     * 
+ */ + @XStreamAlias("refund_status") + private String refundStatus; + + /** + *
+     * 字段名:退款成功时间
+     * 变量名:success_time
+     * 是否必填:否
+     * 类型: String(20)
+     * 示例值:20160725152626
+     * 描述:-
+     */
+    @XStreamAlias("success_time")
+    private String successTime;
+
+    /**
+     * 
+     * 字段名:退款入账账户
+     * 变量名:refund_recv_accout
+     * 是否必填:是
+     * 类型:String(64)
+     * 示例值:招商银行信用卡0403
+     * 描述:取当前退款单的退款入账方,1)退回银行卡:{银行名称}{卡类型}{卡尾号},2)退回支付用户零钱:支付用户零钱 ,3)退还商户: 商户基本账户,商户结算银行账户,4)退回支付用户零钱通: 支付用户零钱通
+     * 
+ */ + @XStreamAlias("refund_recv_accout") + private String refundRecvAccout; + + /** + *
+     * 字段名:退款资金来源
+     * 变量名:refund_account
+     * 是否必填:是
+     * 类型:String(30)
+     * 示例值:REFUND_SOURCE_RECHARGE_FUNDS
+     * 描述:REFUND_SOURCE_RECHARGE_FUNDS 可用余额退款/基本账户,REFUND_SOURCE_UNSETTLED_FUNDS 未结算资金退款
+     * 
+ */ + @XStreamAlias("refund_account") + private String refundAccount; + + /** + *
+     * 字段名:退款发起来源
+     * 变量名:refund_request_source
+     * 是否必填:是
+     * 类型:String(30)
+     * 示例值:API
+     * 描述:API接口,VENDOR_PLATFORM商户平台
+     * 
+ */ + @XStreamAlias("refund_request_source") + private String refundRequestSource; + + public String getTransactionId() { + return transactionId; + } + + public void setTransactionId(String transactionId) { + this.transactionId = transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public void setOutTradeNo(String outTradeNo) { + this.outTradeNo = outTradeNo; + } + + public String getRefundId() { + return refundId; + } + + public void setRefundId(String refundId) { + this.refundId = refundId; + } + + public String getOutRefundNo() { + return outRefundNo; + } + + public void setOutRefundNo(String outRefundNo) { + this.outRefundNo = outRefundNo; + } + + public Integer getTotalFee() { + return totalFee; + } + + public void setTotalFee(Integer totalFee) { + this.totalFee = totalFee; + } + + public Integer getSettlementTotalFee() { + return settlementTotalFee; + } + + public void setSettlementTotalFee(Integer settlementTotalFee) { + this.settlementTotalFee = settlementTotalFee; + } + + public Integer getRefundFee() { + return refundFee; + } + + public void setRefundFee(Integer refundFee) { + this.refundFee = refundFee; + } + + public Integer getSettlementRefundFee() { + return settlementRefundFee; + } + + public void setSettlementRefundFee(Integer settlementRefundFee) { + this.settlementRefundFee = settlementRefundFee; + } + + public String getRefundStatus() { + return refundStatus; + } + + public void setRefundStatus(String refundStatus) { + this.refundStatus = refundStatus; + } + + public String getSuccessTime() { + return successTime; + } + + public void setSuccessTime(String successTime) { + this.successTime = successTime; + } + + public String getRefundRecvAccout() { + return refundRecvAccout; + } + + public void setRefundRecvAccout(String refundRecvAccout) { + this.refundRecvAccout = refundRecvAccout; + } + + public String getRefundAccount() { + return refundAccount; + } + + public void setRefundAccount(String refundAccount) { + this.refundAccount = refundAccount; + } + + public String getRefundRequestSource() { + return refundRequestSource; + } + + public void setRefundRequestSource(String refundRequestSource) { + this.refundRequestSource = refundRequestSource; + } + + public static ReqInfo fromXML(String xmlString) { + XStream xstream = XStreamInitializer.getInstance(); + xstream.processAnnotations(ReqInfo.class); + return (ReqInfo) xstream.fromXML(xmlString); + } + } + + public String getReqInfoString() { + return reqInfoString; + } + + public void setReqInfoString(String reqInfoString) { + this.reqInfoString = reqInfoString; + } + + public ReqInfo getReqInfo() { + return reqInfo; + } + + public void setReqInfo(ReqInfo reqInfo) { + this.reqInfo = reqInfo; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java new file mode 100644 index 00000000..6688d602 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayAppOrderResult.java @@ -0,0 +1,145 @@ +package com.github.binarywang.wxpay.bean.order; + +/** + *
+ * APP支付调用统一下单接口后的组装所需参数的实现类
+ * 参考 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12
+ * Created by Binary Wang on 2017-9-1.
+ * 
+ * + * @author Binary Wang + */ +public class WxPayAppOrderResult { + private String sign; + private String prepayId; + private String partnerId; + private String appId; + private String packageValue; + private String timeStamp; + private String nonceStr; + + public WxPayAppOrderResult() { + } + + private WxPayAppOrderResult(Builder builder) { + setSign(builder.sign); + setPrepayId(builder.prepayId); + setPartnerId(builder.partnerId); + setAppId(builder.appId); + setPackageValue(builder.packageValue); + setTimeStamp(builder.timeStamp); + setNonceStr(builder.nonceStr); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getSign() { + return this.sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getPrepayId() { + return this.prepayId; + } + + public void setPrepayId(String prepayId) { + this.prepayId = prepayId; + } + + public String getPartnerId() { + return this.partnerId; + } + + public void setPartnerId(String partnerId) { + this.partnerId = partnerId; + } + + public String getAppId() { + return this.appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getPackageValue() { + return this.packageValue; + } + + public void setPackageValue(String packageValue) { + this.packageValue = packageValue; + } + + public String getTimeStamp() { + return this.timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNonceStr() { + return this.nonceStr; + } + + public void setNonceStr(String nonceStr) { + this.nonceStr = nonceStr; + } + + public static final class Builder { + private String sign; + private String prepayId; + private String partnerId; + private String appId; + private String packageValue; + private String timeStamp; + private String nonceStr; + + private Builder() { + } + + public Builder sign(String sign) { + this.sign = sign; + return this; + } + + public Builder prepayId(String prepayId) { + this.prepayId = prepayId; + return this; + } + + public Builder partnerId(String partnerId) { + this.partnerId = partnerId; + return this; + } + + public Builder appId(String appId) { + this.appId = appId; + return this; + } + + public Builder packageValue(String packageValue) { + this.packageValue = packageValue; + return this; + } + + public Builder timeStamp(String timeStamp) { + this.timeStamp = timeStamp; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public WxPayAppOrderResult build() { + return new WxPayAppOrderResult(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java new file mode 100644 index 00000000..d1ebdee0 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayMpOrderResult.java @@ -0,0 +1,133 @@ +package com.github.binarywang.wxpay.bean.order; + +/** + *
+ * 微信公众号支付进行统一下单后组装所需参数的类
+ * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
+ * Created by Binary Wang on 2017-9-1.
+ * 
+ * + * @author Binary Wang + */ +public class WxPayMpOrderResult { + private String appId; + private String timeStamp; + private String nonceStr; + /** + * 由于package为java保留关键字,因此改为packageValue + */ + private String packageValue; + private String signType; + private String paySign; + + private WxPayMpOrderResult(Builder builder) { + setAppId(builder.appId); + setTimeStamp(builder.timeStamp); + setNonceStr(builder.nonceStr); + setPackageValue(builder.packageValue); + setSignType(builder.signType); + setPaySign(builder.paySign); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getAppId() { + return this.appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getTimeStamp() { + return this.timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNonceStr() { + return this.nonceStr; + } + + public void setNonceStr(String nonceStr) { + this.nonceStr = nonceStr; + } + + public String getPackageValue() { + return this.packageValue; + } + + public void setPackageValue(String packageValue) { + this.packageValue = packageValue; + } + + public String getSignType() { + return this.signType; + } + + public void setSignType(String signType) { + this.signType = signType; + } + + public String getPaySign() { + return this.paySign; + } + + public void setPaySign(String paySign) { + this.paySign = paySign; + } + + public WxPayMpOrderResult() { + } + + + public static final class Builder { + private String appId; + private String timeStamp; + private String nonceStr; + private String packageValue; + private String signType; + private String paySign; + + private Builder() { + } + + public Builder appId(String appId) { + this.appId = appId; + return this; + } + + public Builder timeStamp(String timeStamp) { + this.timeStamp = timeStamp; + return this; + } + + public Builder nonceStr(String nonceStr) { + this.nonceStr = nonceStr; + return this; + } + + public Builder packageValue(String packageValue) { + this.packageValue = packageValue; + return this; + } + + public Builder signType(String signType) { + this.signType = signType; + return this; + } + + public Builder paySign(String paySign) { + this.paySign = paySign; + return this; + } + + public WxPayMpOrderResult build() { + return new WxPayMpOrderResult(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java new file mode 100644 index 00000000..3eb0e374 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/order/WxPayNativeOrderResult.java @@ -0,0 +1,48 @@ +package com.github.binarywang.wxpay.bean.order; + +/** + *
+ * 微信扫码支付统一下单后发起支付拼接所需参数实现类
+ * Created by Binary Wang on 2017-9-1.
+ * 
+ * + * @author Binary Wang + */ +public class WxPayNativeOrderResult { + private String codeUrl; + + private WxPayNativeOrderResult(Builder builder) { + setCodeUrl(builder.codeUrl); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public String getCodeUrl() { + return this.codeUrl; + } + + public void setCodeUrl(String codeUrl) { + this.codeUrl = codeUrl; + } + + public WxPayNativeOrderResult() { + } + + public static final class Builder { + private String codeUrl; + + private Builder() { + } + + public Builder codeUrl(String codeUrl) { + this.codeUrl = codeUrl; + return this; + } + + public WxPayNativeOrderResult build() { + return new WxPayNativeOrderResult(this); + } + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java index 92c98bda..d8ab2ab6 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxPayUnifiedOrderResult.java @@ -5,7 +5,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; /** *
  * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"返回的结果
- * 统一下单(详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
+ * 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
  * 
* * @author chanjarster diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java index dc8ce23b..64842b14 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java @@ -71,6 +71,11 @@ public class WxPayConstants { */ public static final String JSAPI = "JSAPI"; + /** + * H5支付 + */ + public static final String MWEB = "MWEB"; + /** * 刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口 */ @@ -84,4 +89,15 @@ public class WxPayConstants { public static final String HMAC_SHA256 = "HMAC-SHA256"; public static final String MD5 = "MD5"; } + + + /** + * 限定支付方式 + */ + public static class LimitPay { + /** + * no_credit--指定不能使用信用卡支付 + */ + public static final String NO_CREDIT = "no_credit"; + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java index 0e375bd6..fe35ed21 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java @@ -1,7 +1,7 @@ package com.github.binarywang.wxpay.converter; -import com.github.binarywang.wxpay.bean.WxPayOrderNotifyCoupon; -import com.github.binarywang.wxpay.bean.result.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyCoupon; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.google.common.base.Function; import com.google.common.collect.Maps; import com.thoughtworks.xstream.annotations.XStreamAlias; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index bf599ba1..0605edfc 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -2,6 +2,8 @@ package com.github.binarywang.wxpay.service; import com.github.binarywang.wxpay.bean.WxPayApiData; import com.github.binarywang.wxpay.bean.coupon.*; +import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -22,7 +24,7 @@ public interface WxPayService { /** *
-   * 查询订单(详见https://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
+   * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
    * 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
    * 需要调用查询接口的情况:
    * ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
@@ -54,7 +56,7 @@ public interface WxPayService {
   WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException;
 
   /**
-   * 统一下单(详见http://com.github.binarywang.wechat.pay.bean.pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
+   * 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)
    * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
    * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
    *
@@ -64,7 +66,7 @@ public interface WxPayService {
 
   /**
    * 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数
-   * 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
+   * 详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
    *
    * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
    */
@@ -113,11 +115,24 @@ public interface WxPayService {
     throws WxPayException;
 
   /**
-   * 读取支付结果通知
-   * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
+   * @deprecated  use WxPayService#parseOrderNotifyResult(String) instead
+   * @see WxPayService#parseOrderNotifyResult(String)
    */
+  @Deprecated
   WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException;
 
+  /**
+   * 解析支付结果通知
+   * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
+   */
+  WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException;
+
+  /**
+   * 解析退款结果通知
+   * 详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_16&index=9
+   */
+  WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException;
+
   /**
    * 发送微信红包给个人用户
    * 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
index 27d4d2dd..f0b22d19 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImpl.java
@@ -3,6 +3,11 @@ package com.github.binarywang.wxpay.service.impl;
 import com.github.binarywang.utils.qrcode.QrcodeUtils;
 import com.github.binarywang.wxpay.bean.WxPayApiData;
 import com.github.binarywang.wxpay.bean.coupon.*;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
+import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
+import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
+import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.config.WxPayConfig;
@@ -97,11 +102,17 @@ public abstract class WxPayServiceAbstractImpl implements WxPayService {
   }
 
   @Override
+  @Deprecated
   public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException {
+    return this.parseOrderNotifyResult(xmlData);
+  }
+
+  @Override
+  public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException {
     try {
-      log.debug("微信支付回调参数详细:{}", xmlData);
+      log.debug("微信支付异步通知请求参数:{}", xmlData);
       WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
-      log.debug("微信支付回调结果对象:{}", result);
+      log.debug("微信支付异步通知请求解析后的对象:{}", result);
       result.checkResult(this);
       return result;
     } catch (WxPayException e) {
@@ -113,6 +124,19 @@ public abstract class WxPayServiceAbstractImpl implements WxPayService {
     }
   }
 
+  @Override
+  public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException {
+    try {
+      log.debug("微信支付退款异步通知参数:{}", xmlData);
+      WxPayRefundNotifyResult result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey());
+      log.debug("微信支付退款异步通知解析后的对象:{}", result);
+      return result;
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new WxPayException("发生异常," + e.getMessage(), e);
+    }
+  }
+
   @Override
   public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
@@ -181,6 +205,65 @@ public abstract class WxPayServiceAbstractImpl implements WxPayService {
     return result;
   }
 
+  public  T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
+    WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
+    String prepayId = unifiedOrderResult.getPrepayId();
+    if (StringUtils.isBlank(prepayId)) {
+      throw new RuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。",
+        unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
+    }
+
+    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
+    String nonceStr = String.valueOf(System.currentTimeMillis());
+    Object payResult = null;
+    switch (request.getTradeType()) {
+      case TradeType.NATIVE: {
+        payResult = WxPayNativeOrderResult.newBuilder().codeUrl(unifiedOrderResult.getCodeURL())
+          .build();
+        break;
+      }
+      case TradeType.APP: {
+        // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数
+        String appId = this.getConfig().getAppId();
+        Map configMap = new HashMap<>();
+        // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改
+        String partnerId = getConfig().getMchId();
+        configMap.put("prepayid", prepayId);
+        configMap.put("partnerid", partnerId);
+        String packageValue = "Sign=WXPay";
+        configMap.put("package", packageValue);
+        configMap.put("timestamp", timestamp);
+        configMap.put("noncestr", nonceStr);
+        configMap.put("appid", appId);
+
+        payResult = WxPayAppOrderResult.newBuilder()
+          .sign(SignUtils.createSign(configMap, this.getConfig().getMchKey()))
+          .prepayId(prepayId)
+          .partnerId(partnerId)
+          .appId(appId)
+          .packageValue(packageValue)
+          .timeStamp(timestamp)
+          .nonceStr(nonceStr)
+          .build();
+        break;
+      }
+      case TradeType.JSAPI: {
+        payResult = WxPayMpOrderResult.newBuilder()
+          .appId(unifiedOrderResult.getAppid())
+          .timeStamp(timestamp)
+          .nonceStr(nonceStr)
+          .packageValue("prepay_id=" + prepayId)
+          .signType(SignType.MD5)
+          .build();
+        ((WxPayMpOrderResult) payResult)
+          .setPaySign(SignUtils.createSign(payResult, this.getConfig().getMchKey()));
+        break;
+      }
+    }
+
+    return (T) payResult;
+  }
+
   @Override
   public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
     request.checkAndSign(this.getConfig());
@@ -508,7 +591,7 @@ public abstract class WxPayServiceAbstractImpl implements WxPayService {
   public WxPayApiData getWxApiData() {
     try {
       return wxApiData.get();
-    }finally {
+    } finally {
       //一般来说,接口请求会在一个线程内进行,这种情况下,每个线程get的会是之前所存入的数据,
       // 但以防万一有同一线程多次请求的问题,所以每次获取完数据后移除对应数据
       wxApiData.remove();
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
similarity index 95%
rename from weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java
rename to weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
index 389b374d..384de4c9 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/result/WxPayOrderNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResultTest.java
@@ -1,5 +1,6 @@
-package com.github.binarywang.wxpay.bean.result;
+package com.github.binarywang.wxpay.bean.notify;
 
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import org.testng.*;
 import org.testng.annotations.*;
 
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
new file mode 100644
index 00000000..cd1777f8
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -0,0 +1,70 @@
+package com.github.binarywang.wxpay.bean.notify;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.testbase.ApiTestModule;
+import org.apache.commons.codec.binary.Base64;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import javax.inject.Inject;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+
+import static org.testng.Assert.assertNotNull;
+
+/**
+ * 
+ *  Created by BinaryWang on 2017/8/27.
+ * 
+ * + * @author Binary Wang + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxPayRefundNotifyResultTest { + @Inject + private WxPayConfig wxPayConfig; + + public void testFromXML() throws WxPayException { + String xmlString = "" + + "SUCCESS" + + "" + + "" + + "" + + ""; + + WxPayRefundNotifyResult refundNotifyResult = WxPayRefundNotifyResult.fromXML(xmlString, this.wxPayConfig.getMchKey()); + + assertNotNull(refundNotifyResult); + System.out.println(refundNotifyResult); + } + + public void encodeReqInfo() throws Exception { + String xml = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + ""; + + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + final MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(this.wxPayConfig.getMchKey().getBytes()); + final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase(); + SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, key); + System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes()))); + } +} diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java index de0fe10e..8d419be8 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceAbstractImplTest.java @@ -2,6 +2,7 @@ package com.github.binarywang.wxpay.service.impl; import com.github.binarywang.utils.qrcode.QrcodeUtils; import com.github.binarywang.wxpay.bean.coupon.*; +import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult; import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -147,6 +148,11 @@ public class WxPayServiceAbstractImplTest { this.logger.info(result.toString()); } + @Test + public void testParseRefundNotifyResult() throws Exception { + // 请参考com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResultTest里的单元测试 + } + /** * Test method for {@link WxPayService#sendRedpack(WxPaySendRedpackRequest)} . */