From f4aec9dc9956767ca3f8fdfa12293a48d0f3bd3e Mon Sep 17 00:00:00 2001 From: "jy.hu" Date: Mon, 17 Nov 2014 20:57:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E`=E5=86=B2=E6=AD=A3`=E5=92=8C?= =?UTF-8?q?`=E8=A2=AB=E6=89=AB=E6=94=AF=E4=BB=98`=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- .../com/foxinmy/weixin4j/util/ConfigUtil.java | 8 +- weixin4j-mp/README.md | 8 +- weixin4j-mp/weixin4j-mp-api/README.md | 6 +- .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 36 +++++ .../com/foxinmy/weixin4j/mp/api/PayApi.java | 80 ++++++++--- .../foxinmy/weixin4j/mp/api/weixin.properties | 11 ++ .../weixin4j/mp/payment/ApiResult.java | 14 +- .../weixin4j/mp/payment/MicroPayPackage.java | 127 ++++++++++++++++++ .../weixin4j/mp/payment/PayAction.java | 87 ++++++------ .../foxinmy/weixin4j/mp/payment/PayUtil.java | 120 ++++++++--------- .../weixin4j/mp/payment/v3/PayPackageV3.java | 6 +- .../weixin4j/mp/payment/v3/PrePay.java | 1 - weixin4j-mp/weixin4j-mp-server/README.md | 2 +- .../mp/server/WeixinServerHandler.java | 9 ++ .../mp/startup/WeixinServerBootstrap.java | 2 +- 16 files changed, 375 insertions(+), 150 deletions(-) create mode 100644 weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java diff --git a/README.md b/README.md index 6a9878b3..87a1d362 100644 --- a/README.md +++ b/README.md @@ -70,18 +70,20 @@ weixin4j + **weixin4j-mp**: 新增获取`微信服务器IP地址`接口 - + **weixin4j-mp**: 解决`server工程`打包不能运行问题(`ClassUtil`无法获取jar包里面的类) + + **weixin4j-mp**: 解决`server工程`打包后不能运行问题(`ClassUtil`无法获取jar包里面的类) + **weixin4j-mp**: 新增被动消息的`加密`以及回复消息的`解密` * 2014-11-16 + **weixin4j-mp**: 新增`多客服`接口 + +* 2014-11-17 + + + **weixin4j-mp**: 新增`冲正`和`被扫支付`接口 接下来 ------ -* 被扫支付 - * 企业号API封装 * 微信小店 diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java index 993ee312..5bd3952d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java @@ -17,10 +17,10 @@ import com.foxinmy.weixin4j.model.WeixinAccount; * @see */ public class ConfigUtil { - private static ResourceBundle weixin; + private final static ResourceBundle weixinBundle; static { - weixin = ResourceBundle.getBundle("weixin"); - Set keySet = weixin.keySet(); + weixinBundle = ResourceBundle.getBundle("weixin"); + Set keySet = weixinBundle.keySet(); for (String key : keySet) { if (!key.endsWith("_path")) { continue; @@ -30,7 +30,7 @@ public class ConfigUtil { } public static String getValue(String key) { - return weixin.getString(key); + return weixinBundle.getString(key); } public static WeixinAccount getWeixinAccount() { diff --git a/weixin4j-mp/README.md b/weixin4j-mp/README.md index 72a4a438..67f2f241 100644 --- a/weixin4j-mp/README.md +++ b/weixin4j-mp/README.md @@ -72,10 +72,14 @@ weixin4j-mp + **weixin4j-mp-api**: 新增获取`微信服务器IP地址接口` - + **weixin4j-mp-server**: 解决`server工程`打包不能运行问题(`ClassUtil`无法获取jar包里面的类) + + **weixin4j-mp-server**: 解决`server工程`打包后不能运行问题(`ClassUtil`无法获取jar包里面的类) + **weixin4j-mp-server**: 新增被动消息的`加密`以及回复消息的`解密` * 2014-11-16 - + **weixin4j-mp-api**: 新增`多客服`接口 \ No newline at end of file + + **weixin4j-mp-api**: 新增`多客服`接口 + +* 2014-11-17 + + + **weixin4j-mp-api**: 新增`冲正`和`被扫支付`接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/README.md b/weixin4j-mp/weixin4j-mp-api/README.md index e363c9c8..d6915fc2 100644 --- a/weixin4j-mp/weixin4j-mp-api/README.md +++ b/weixin4j-mp/weixin4j-mp-api/README.md @@ -114,4 +114,8 @@ weixin.properties说明 * 2014-11-16 - + 新增`多客服`接口 \ No newline at end of file + + 新增`多客服`接口 + +* 2014-11-17 + + + 新增`冲正`和`被扫支付`接口 \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index 66d1cb54..13bdb137 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -36,6 +36,7 @@ import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.msg.model.Article; import com.foxinmy.weixin4j.mp.msg.model.BaseMsg; import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify; +import com.foxinmy.weixin4j.mp.payment.ApiResult; import com.foxinmy.weixin4j.mp.payment.Refund; import com.foxinmy.weixin4j.mp.payment.RefundResult; import com.foxinmy.weixin4j.mp.payment.v2.Order; @@ -980,4 +981,39 @@ public class WeixinProxy { public List getcallbackip() throws WeixinException { return helperApi.getcallbackip(); } + + /** + * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 + * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 + * 如需实现相同功能请调用退款接口
调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ * + * @param ca + * 证书文件 + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 撤销结果 + * @see com.foxinmy.weixin4j.mp.api.PayApi + * @throws WeixinException + */ + public ApiResult reverse(InputStream ca, IdQuery idQuery) + throws WeixinException { + return payApi.reverse(ca, idQuery); + } + + /** + * 冲正撤销:默认采用properties中配置的ca文件 + * + * @param idQuery + * transaction_id、out_trade_no 二选一 + * @return 撤销结果 + * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#reverse(InputStream, IdQuery)} + * @throws WeixinException + * @throws IOException + */ + public ApiResult reverse(IdQuery idQuery) throws WeixinException, + IOException { + return payApi.reverse(idQuery); + } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java index 2b1f5fe6..d2d05a05 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java @@ -42,6 +42,7 @@ import com.foxinmy.weixin4j.http.SSLHttpRequest; import com.foxinmy.weixin4j.http.XmlResult; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; +import com.foxinmy.weixin4j.mp.payment.ApiResult; import com.foxinmy.weixin4j.mp.payment.PayUtil; import com.foxinmy.weixin4j.mp.payment.Refund; import com.foxinmy.weixin4j.mp.payment.RefundConverter; @@ -102,7 +103,6 @@ public class PayApi extends BaseApi { Map param = new HashMap(); param.put("appid", weixinAccount.getAppId()); param.put("appkey", weixinAccount.getPaySignKey()); - // 用户购买的openId param.put("openid", openId); param.put("transid", transid); param.put("out_trade_no", outTradeNo); @@ -204,7 +204,7 @@ public class PayApi extends BaseApi { */ public com.foxinmy.weixin4j.mp.payment.v3.Order orderQueryV3(IdQuery idQuery) throws WeixinException { - Map map = baseMap2V3(idQuery); + Map map = baseMapV3(idQuery); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); map.put("sign", sign); String param = map2xml(map); @@ -216,17 +216,16 @@ public class PayApi extends BaseApi { } /** - * 申请退款(请求需要双向证书)
+ * 申请退款(请求需要双向证书)
*

- * 交易时间超过 1 年的订单无法提交退款;
- * 支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失 败后重新提交,要采用原来的 - * out_refund_no。总退款金额不能超过用户实际支付金额。
+ * 交易时间超过 1 年的订单无法提交退款;
支持部分退款,部分退需要设置相同的订单号和不同的 out_refund_no。一笔退款失 + * 败后重新提交,要采用原来的 out_refund_no。总退款金额不能超过用户实际支付金额。
*

* * @param ca * 证书文件 * @param idQuery - * ) 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no * @param outRefundNo * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 @@ -341,7 +340,7 @@ public class PayApi extends BaseApi { SSLHttpRequest request = new SSLHttpRequest(ctx); response = request.get(refund_uri, map); } else if (version == 3) { - Map map = baseMap2V3(idQuery); + Map map = baseMapV3(idQuery); map.put("out_refund_no", outRefundNo); map.put("total_fee", DateUtil.formaFee2Fen(totalFee)); map.put("refund_fee", DateUtil.formaFee2Fen(refundFee)); @@ -362,9 +361,8 @@ public class PayApi extends BaseApi { } /** - * 不同的退款接口选择
- * 默认采用properties中配置的ca文件
- * V2支付则需要传入opUserPasswd参数
+ * 退款申请:默认采用properties中配置的ca文件
V2支付则需要传入opUserPasswd参数 * * @see {@link com.foxinmy.weixin4j.mp.api.PayApi#refund(InputStream, IdQuery, String, double, double, String, String)} */ @@ -376,6 +374,50 @@ public class PayApi extends BaseApi { refundFee, opUserId, opUserPasswd); } + /** + * 冲正订单(需要证书)
当支付返回失败,或收银系统超时需要取消交易,可以调用该接口
接口逻辑:支 + * 付失败的关单,支付成功的撤销支付
7天以内的单可撤销,其他正常支付的单 + * 如需实现相同功能请调用退款接口
调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
+ * + * @param ca + * 证书文件 + * @param idQuery + * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: + * transaction_id> out_trade_no + * @return 撤销结果 + * @throws WeixinException + */ + public ApiResult reverse(InputStream ca, IdQuery idQuery) + throws WeixinException { + SSLHttpRequest request = new SSLHttpRequest(weixinAccount.getMchId(), + ca); + String reverse_uri = getRequestUri("reverse_uri"); + Map map = baseMapV3(idQuery); + String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); + map.put("sign", sign); + String param = map2xml(map); + Response response = request.post(reverse_uri, param); + return response.getAsObject(new TypeReference() { + }); + } + + /** + * 冲正撤销:默认采用properties中配置的ca文件 + * + * @param idQuery + * transaction_id、out_trade_no 二选一 + * @return 撤销结果 + * @see {@link com.foxinmy.weixin4j.mp.api.PayApi#reverse(InputStream, IdQuery)} + * @throws WeixinException + * @throws IOException + */ + public ApiResult reverse(IdQuery idQuery) throws WeixinException, + IOException { + File ca = new File(ConfigUtil.getValue("ca_file")); + return reverse(new FileInputStream(ca), idQuery); + } + /** * native支付URL转短链接 * @@ -385,7 +427,7 @@ public class PayApi extends BaseApi { * @throws WeixinException */ public String getShorturl(String url) throws WeixinException { - Map map = baseMap2V3(null); + Map map = baseMapV3(null); map.put("long_url", url); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); map.put("sign", sign); @@ -402,8 +444,7 @@ public class PayApi extends BaseApi { } /** - * 关闭订单
- * 当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完 + * 关闭订单
当订单支付失败,调用关单接口后用新订单号重新发起支付,如果关单失败,返回已完 * 成支付请按正常支付处理。如果出现银行掉单,调用关单成功后,微信后台会主动发起退款。 * * @param outTradeNo @@ -413,7 +454,7 @@ public class PayApi extends BaseApi { * @throws WeixinException */ public XmlResult closeOrder(String outTradeNo) throws WeixinException { - Map map = baseMap2V3(new IdQuery(outTradeNo, + Map map = baseMapV3(new IdQuery(outTradeNo, IdType.TRADENO)); String sign = PayUtil.paysignMd5(map, weixinAccount.getPaySignKey()); map.put("sign", sign); @@ -477,7 +518,7 @@ public class PayApi extends BaseApi { response = request.get(downloadbill_uri, map); charset = Charset.forName("GBK"); } else if (version == 3) { - Map map = baseMap2V3(null); + Map map = baseMapV3(null); map.put("bill_date", _billDate); map.put("bill_type", billType.name()); String sign = PayUtil @@ -508,8 +549,7 @@ public class PayApi extends BaseApi { } /** - * 退款查询
- * 退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态 + * 退款查询
退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款 3 个工作日后重新查询退款状态 * * @param idQuery * 单号 refund_id、out_refund_no、 out_trade_no 、 transaction_id @@ -535,7 +575,7 @@ public class PayApi extends BaseApi { map.put("sign", sign.toLowerCase()); response = request.get(refundquery_uri, map); } else if (version == 3) { - Map map = baseMap2V3(idQuery); + Map map = baseMapV3(idQuery); String sign = PayUtil .paysignMd5(map, weixinAccount.getPaySignKey()); map.put("sign", sign); @@ -550,7 +590,7 @@ public class PayApi extends BaseApi { * * @return */ - private Map baseMap2V3(IdQuery idQuery) { + private Map baseMapV3(IdQuery idQuery) { Map map = new HashMap(); map.put("appid", weixinAccount.getAppId()); map.put("mch_id", weixinAccount.getMchId()); diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 75382e59..83eb6305 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -102,3 +102,14 @@ downloadbill_v3_uri={mch_base_url}/pay/downloadbill refundquery_v3_uri={mch_base_url}/pay/refundquery # \u9000\u6b3e\u7533\u8bf7 refund_v3_uri={mch_base_url}/secapi/pay/refund +# \u51b2\u6b63\u64a4\u9500 +reverse_uri={mch_base_url}/secapi/pay/reverse +# \u88ab\u626b\u652f\u4ed8 +micropay_uri={mch_base_url}/pay/micropay + + +# \u7edf\u4e00\u8ba2\u5355\u751f\u6210 +unifiedorder_uri={mch_base_url}/pay/unifiedorder +# native\u652f\u4ed8\u94fe\u63a5 +nativepay_v2_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s +nativepay_v3_uri=weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/ApiResult.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/ApiResult.java index 9952d30b..c3f380c0 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/ApiResult.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/ApiResult.java @@ -27,6 +27,7 @@ public class ApiResult extends XmlResult { private String sign;// 签名 非空 @XStreamAlias("device_info") private String deviceInfo;// 微信支付分配的终端设备号 可能为空 + private String recall;// 是否需要继续调用接口 Y- 需要,N-不需要 public ApiResult() { @@ -84,13 +85,18 @@ public class ApiResult extends XmlResult { this.deviceInfo = deviceInfo; } + public String getRecall() { + return recall; + } + + public void setRecall(String recall) { + this.recall = recall; + } + @Override public String toString() { return "ApiResult [appId=" + appId + ", mchId=" + mchId + ", subMchId=" + subMchId + ", nonceStr=" + nonceStr + ", sign=" + sign - + ", deviceInfo=" + deviceInfo + ", getReturnCode()=" - + getReturnCode() + ", getReturnMsg()=" + getReturnMsg() - + ", getResultCode()=" + getResultCode() + ", getErrCode()=" - + getErrCode() + ", getErrCodeDes()=" + getErrCodeDes() + "]"; + + ", deviceInfo=" + deviceInfo + ", recall=" + recall + "]"; } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java new file mode 100644 index 00000000..240b5e0c --- /dev/null +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/MicroPayPackage.java @@ -0,0 +1,127 @@ +package com.foxinmy.weixin4j.mp.payment; + +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; + +import com.foxinmy.weixin4j.model.WeixinAccount; +import com.foxinmy.weixin4j.util.RandomUtil; +import com.thoughtworks.xstream.annotations.XStreamAlias; + +/** + * 刷卡支付 + * + * @className MicroPayPackage + * @author jy + * @date 2014年11月17日 + * @since JDK 1.7 + * @see + */ +@XStreamAlias("xml") +public class MicroPayPackage extends PayPackage { + + private static final long serialVersionUID = 8944928173669656177L; + + private String appid; // 微信分配的公众账号 必须 + private String mch_id; // 微信支付分配的商户号 必须 + private String device_info; // 微信支付分配的终端设备号 非必须 + private String nonce_str; // 随机字符串,不长于 32 位 必须 + private String sign; // 签名 必须 + private String auth_code; // 扫码支付授权码 ,设备读取用 户微信中的条码或者二维码 信息 + + public MicroPayPackage() { + + } + + public MicroPayPackage(WeixinAccount weixinAccount, String body, + String attach, String out_trade_no, double total_fee, + String spbill_create_ip, String auth_code) { + this(weixinAccount.getAppId(), weixinAccount.getMchId(), weixinAccount + .getDeviceInfo(), RandomUtil.generateString(16), body, attach, + out_trade_no, total_fee, spbill_create_ip, null, null, null, + auth_code); + } + + public MicroPayPackage(String appid, String mch_id, String device_info, + String nonce_str, String body, String attach, String out_trade_no, + double total_fee, String spbill_create_ip, Date time_start, + Date time_expire, String goods_tag, String auth_code) { + super(body, attach, out_trade_no, total_fee, spbill_create_ip, + time_start, time_expire, goods_tag, null); + this.appid = appid; + this.mch_id = mch_id; + this.device_info = device_info; + this.nonce_str = nonce_str; + this.auth_code = auth_code; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getMch_id() { + return mch_id; + } + + public void setMch_id(String mch_id) { + this.mch_id = mch_id; + } + + public String getDevice_info() { + return device_info; + } + + public void setDevice_info(String device_info) { + this.device_info = device_info; + } + + public String getNonce_str() { + return nonce_str; + } + + public void setNonce_str(String nonce_str) { + this.nonce_str = nonce_str; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public void setBody(String body) { + super.setBody(StringUtils.isBlank(body) ? "服务费用" : body); + } + + public void setNotify_url(String notify_url) { + super.setNotify_url(notify_url); + } + + public String getAuth_code() { + return auth_code; + } + + public void setAuth_code(String auth_code) { + this.auth_code = auth_code; + } + + @Override + public String toString() { + return "MicroPayPackage [appid=" + appid + ", mch_id=" + mch_id + + ", device_info=" + device_info + ", nonce_str=" + nonce_str + + ", sign=" + sign + ", auth_code=" + auth_code + + ", getBody()=" + getBody() + ", getAttach()=" + getAttach() + + ", getOut_trade_no()=" + getOut_trade_no() + + ", getTotal_fee()=" + getTotal_fee() + + ", getSpbill_create_ip()=" + getSpbill_create_ip() + + ", getTime_start()=" + getTime_start() + + ", getTime_expire()=" + getTime_expire() + + ", getGoods_tag()=" + getGoods_tag() + "]"; + } +} diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayAction.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayAction.java index 0e9e329a..6c5c1ba6 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayAction.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayAction.java @@ -46,9 +46,8 @@ public class PayAction { public JSONObject jsPay() { JSONObject obj = new JSONObject(); PayPackage payPackage = null; - // V3 支付 - // 此处的openid为微信用户的openid WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); + // V3 支付 payPackage = new PayPackageV3(weixinAccount, "用户openid", "商品描述", "系统内部订单号", 1d, "IP地址", TradeType.JSAPI); // V2 支付 @@ -58,7 +57,6 @@ public class PayAction { String jspay = null; try { jspay = PayUtil.createPayJsRequestJson(payPackage, weixinAccount); - jspay = PayUtil.createPayJsRequestJson(payPackage, weixinAccount); } catch (PayException e) { log.error("create jspay error,{}", weixinAccount, e); } @@ -80,7 +78,7 @@ public class PayAction { } /** - * JSAPI(V2)支付成功时的回调通知=
+ * JSAPI(V2)支付成功(前端)时的回调通知
* <xml>
* <OpenId><![CDATA[111222]]></OpenId>
* <AppId><![CDATA[wwwwb4f85f3a797777]]></AppId>
@@ -105,12 +103,9 @@ public class PayAction { /* * 收集url中携带的参数 /pay/notify/back?attach=8&bank_billno=201410293351060& * bank_type=2032&discount=0&fee_type=1&input_charset=UTF-8& - * notify_id=9fKbVf_qg6y- - * wSjtSMV0PLXeEn2oGfTM1s9dWSvR2B9U6iFQRTzmjrMWKUxvh9mpBLvnh8aqFbC_OFk1pTvFnFUO00Lln4fh - * & out_trade_no=D14102900031&partner=1221928801&product_fee=1&sign= - * B9D6E772C271C9B86B8436FC9F5DFC1A& - * sign_type=MD5&time_end=20141029183707 - * &total_fee=1&trade_mode=1&trade_state=0& + * notify_id=9fKbVf_qg6y-wSjtSMV0PLXeEn2oGfTM1s9dWSvR2B9U6iFQRTzmjrMWKUxvh9mpBLvnh8aqFbC_OFk1pTvFnFUO00Lln4fh& + * out_trade_no=D14102900031&partner=1221928801&product_fee=1&sign=B9D6E772C271C9B86B8436FC9F5DFC1A& + * sign_type=MD5&time_end=20141029183707&total_fee=1&trade_mode=1&trade_state=0& * transaction_id=1221928801201410296039230054&transport_fee=0 */ log.info("jspay_notify_orderinfo,{}", objMap); @@ -142,7 +137,7 @@ public class PayAction { } /** - * JSAPI(V3)支付成功时的回调通知 + * JSAPI(V3)支付成功(前端)时的回调通知 * * * @param inputStream @@ -168,39 +163,6 @@ public class PayAction { return XStream.to(new XmlResult()); } - /** - * 告警通知 需要成功返回 success
- * <xml>
- * <AppId><![CDATA[wxf8b4f85f3a794e77]]></AppId>
- * <ErrorType>1001</ErrorType>
- * <Description><![CDATA[错误描述]]></Description>
- * <AlarmContent><![CDATA[错误详情]]></AlarmContent>
- * <TimeStamp>1393860740</TimeStamp>
- * <AppSignature><![CDATA[签名方式跟JsPayRequest中的paySign一样]]></ - * AppSignature>
- * <SignMethod><![CDATA[sha1]]></SignMethod>
- * </xml>
- * 参与签名字段:alarmcontent、appid、appkey、description、errortype、timestamp - * - * @param inputStream - * xml数据 - * @see com.foxinmy.weixin4j.mp.payment.v2.PayWarn - * @return - */ - public String warning(InputStream inputStream) { - PayWarn payWarn = XStream.get(inputStream, PayWarn.class); - log.info("pay_warning,{}", payWarn); - WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); - String sign = payWarn.getPaySign(); - payWarn.setPaySign(null); - payWarn.setSignType(null); - // 验证微信签名 - String vaild_sign = PayUtil.paysignSha(payWarn, - weixinAccount.getPaySignKey()); - log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign); - return "success"; - } - /** * V2.x版本Native支付时POST数据
* <xml>
@@ -288,6 +250,39 @@ public class PayAction { return XStream.to(payReponse); } + /** + * 告警通知 需要成功返回 success
+ * <xml>
+ * <AppId><![CDATA[wxf8b4f85f3a794e77]]></AppId>
+ * <ErrorType>1001</ErrorType>
+ * <Description><![CDATA[错误描述]]></Description>
+ * <AlarmContent><![CDATA[错误详情]]></AlarmContent>
+ * <TimeStamp>1393860740</TimeStamp>
+ * <AppSignature><![CDATA[签名方式跟JsPayRequest中的paySign一样]]></ + * AppSignature>
+ * <SignMethod><![CDATA[sha1]]></SignMethod>
+ * </xml>
+ * 参与签名字段:alarmcontent、appid、appkey、description、errortype、timestamp + * + * @param inputStream + * xml数据 + * @see com.foxinmy.weixin4j.mp.payment.v2.PayWarn + * @return + */ + public String warning(InputStream inputStream) { + PayWarn payWarn = XStream.get(inputStream, PayWarn.class); + log.info("pay_warning,{}", payWarn); + WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); + String sign = payWarn.getPaySign(); + payWarn.setPaySign(null); + payWarn.setSignType(null); + // 验证微信签名 + String vaild_sign = PayUtil.paysignSha(payWarn, + weixinAccount.getPaySignKey()); + log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign); + return "success"; + } + /** * 用户维权 * @@ -308,8 +303,4 @@ public class PayAction { log.info("微信签名----->sign={},vaild_sign={}", sign, feedback.getPaySign()); return "success"; } - - public static void main(String[] args) { - - } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java index edd1c551..44f85416 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/PayUtil.java @@ -1,24 +1,18 @@ package com.foxinmy.weixin4j.mp.payment; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.util.EntityUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.PayException; +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.HttpRequest; +import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.payment.v2.JsPayRequestV2; import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2; @@ -43,8 +37,8 @@ import com.foxinmy.weixin4j.xml.XStream; * @see */ public class PayUtil { - private static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder"; + private static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay"; private static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s"; private static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s"; @@ -203,28 +197,17 @@ public class PayUtil { } public static PrePay createPrePay(PayPackageV3 payPackage) { + PrePay prePay = null; String payJsRequestXml = XStream.to(payPackage).replaceAll("__", "_"); - HttpClient client = null; + HttpRequest request = new HttpRequest(); try { - client = new DefaultHttpClient(); - HttpPost post = new HttpPost(UNIFIEDORDER); - post.setEntity(new StringEntity(payJsRequestXml, - StandardCharsets.UTF_8)); - HttpResponse response = client.execute(post); - StatusLine statusLine = response.getStatusLine(); - if (statusLine.getStatusCode() != HttpStatus.SC_OK) { - return new PrePay("-1", "网络异常[" + statusLine.getStatusCode() - + "," + statusLine.getReasonPhrase() + "]!"); - } - String returnXml = EntityUtils.toString(response.getEntity(), - StandardCharsets.UTF_8); - return XStream.get(returnXml, PrePay.class); - } catch (IOException e) { - e.printStackTrace(); - } finally { - client.getConnectionManager().shutdown(); + Response response = request.post(UNIFIEDORDER, payJsRequestXml); + prePay = response.getAsObject(new TypeReference() { + }); + } catch (WeixinException e) { + prePay = new PrePay(e.getErrorCode(), e.getErrorMsg()); } - return new PrePay("-1", "request fail"); + return prePay; } /** @@ -336,40 +319,55 @@ public class PayUtil { } /** - * 测试js支付请求 + * 提交被扫支付 * - * @return + * @param authCode + * 扫码支付授权码 ,设备读取用 户微信中的条码或者二维码 信息 + * @param body + * 商品描述 + * @param attach + * 附加数据 + * @param orderNo + * 商户内部唯一订单号 + * @param orderFee + * 商品总额 单位元 + * @param ip + * 订单生成的机器 IP + * @param weixinAccount + * 商户信息 + * @return 返回数据 + * @see {@link com.foxinmy.weixin4j.mp.payment.PayUtil#createMicroPay(MicroPayPackage, WeixinAccount)} + * @throws WeixinException */ - private static void createTestPayJsRequestJson() { - // V2.xAPI支付 - PayPackageV2 payPackage = new PayPackageV2("pay_test", "1220403701", - "D123456", 0.01, "http://182.92.74.85:8082/pay/notify", - "192.168.1.1"); - WeixinAccount weixinAccount = new WeixinAccount("wx0d1d598c0c03c999", - "2270e6c67cf4ff48fe2c6d7cc5a42157", - "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "1221966601", - "6b506ef5fefba3142653a9affd2648d8"); - System.out.println(PayUtil.createPayJsRequestJsonV2(payPackage, - weixinAccount)); - // V3.xJSAPI支付 - try { - weixinAccount = new WeixinAccount("wx0d1d598c0c03c999", - "2270e6c67cf4ff48fe2c6d7cc5a42157", - "6b506ef5fefba3142653a9affd2648d8", "10020674", - "oyFLst1bqtuTcxK-ojF8hOGtLQao"); - System.out.println(PayUtil.createPayJsRequestJsonV3( - "oyFLst1bqtuTcxK-ojF8hOGtLQao", "测试", "T001", 1d, - "192.0.0.1", "http://182.92.74.85:8082/pay/notify", - weixinAccount)); - } catch (PayException e) { - e.printStackTrace(); - } - // V2.xNative支付 - System.out.println(PayUtil.createNativePayRequestV2(weixinAccount, - payPackage)); + public static com.foxinmy.weixin4j.mp.payment.v3.Order createMicroPay( + String authCode, String body, String attach, String orderNo, + double orderFee, String ip, WeixinAccount weixinAccount) + throws WeixinException { + MicroPayPackage payPackage = new MicroPayPackage(weixinAccount, body, + attach, orderNo, orderFee, ip, authCode); + return createMicroPay(payPackage, weixinAccount); } - public static void main(String[] args) { - createTestPayJsRequestJson(); + /** + * 提交被扫支付 + * + * @param payPackage + * 订单信息 + * @param weixinAccount + * 商户信息 + * @return 返回数据 + * @throws WeixinException + */ + public static com.foxinmy.weixin4j.mp.payment.v3.Order createMicroPay( + MicroPayPackage payPackage, WeixinAccount weixinAccount) + throws WeixinException { + String sign = paysignMd5(payPackage, weixinAccount.getPaySignKey()); + payPackage.setSign(sign); + String para = XStream.to(payPackage).replaceAll("__", "_"); + HttpRequest request = new HttpRequest(); + Response response = request.post(MICROPAYURL, para); + return response + .getAsObject(new TypeReference() { + }); } } diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java index 73917f89..4b28abc0 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PayPackageV3.java @@ -51,16 +51,14 @@ public class PayPackageV3 extends PayPackage { this(weixinAccount.getAppId(), weixinAccount.getMchId(), weixinAccount .getDeviceInfo(), RandomUtil.generateString(16), body, attach, out_trade_no, total_fee, spbill_create_ip, null, null, null, - notify_url, tradeType, openId, null, weixinAccount - .getPaySignKey()); + notify_url, tradeType, openId, null); } public PayPackageV3(String appid, String mch_id, String device_info, String nonce_str, String body, String attach, String out_trade_no, double total_fee, String spbill_create_ip, Date time_start, Date time_expire, String goods_tag, String notify_url, - TradeType tradeType, String openid, String product_id, - String paySignKey) { + TradeType tradeType, String openid, String product_id) { super(body, attach, out_trade_no, total_fee, spbill_create_ip, time_start, time_expire, goods_tag, notify_url); this.appid = appid; diff --git a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PrePay.java b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PrePay.java index 0782e7b7..4a3acf20 100644 --- a/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PrePay.java +++ b/weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/PrePay.java @@ -25,7 +25,6 @@ public class PrePay extends ApiResult { @XStreamAlias("code_url") private String codeUrl;// trade_type 为 NATIVE 是有 返回,此参数可直接生成二 维码展示出来进行扫码支付 // 可能为空 - public PrePay() { } diff --git a/weixin4j-mp/weixin4j-mp-server/README.md b/weixin4j-mp/weixin4j-mp-server/README.md index 6c7af3f5..752ea0a8 100644 --- a/weixin4j-mp/weixin4j-mp-server/README.md +++ b/weixin4j-mp/weixin4j-mp-server/README.md @@ -53,6 +53,6 @@ weixin4j-mp-server * 2014-11-15 - + 解决`server工程`打包不能运行问题(`ClassUtil`无法获取jar包里面的类) + + 解决`server工程`打包后不能运行问题(`ClassUtil`无法获取jar包里面的类) + 新增被动消息的`加密`以及回复消息的`解密` \ No newline at end of file diff --git a/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/server/WeixinServerHandler.java b/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/server/WeixinServerHandler.java index 0da3473e..f23a133a 100644 --- a/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/server/WeixinServerHandler.java +++ b/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/server/WeixinServerHandler.java @@ -19,6 +19,14 @@ import com.foxinmy.weixin4j.mp.type.EncryptType; import com.foxinmy.weixin4j.mp.util.HttpUtil; import com.foxinmy.weixin4j.util.MessageUtil; +/** + * 微信被动消息处理类 + * @className WeixinServerHandler + * @author jy + * @date 2014年11月16日 + * @since JDK 1.7 + * @see + */ public class WeixinServerHandler extends SimpleChannelInboundHandler { @@ -83,6 +91,7 @@ public class WeixinServerHandler extends HttpResponse httpResponse = HttpUtil .createWeixinMessageResponse(""); ctx.write(httpResponse); + return; } if (httpMessage.getEncryptType() == EncryptType.RAW) { HttpResponse httpResponse = HttpUtil diff --git a/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/startup/WeixinServerBootstrap.java b/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/startup/WeixinServerBootstrap.java index caca53ae..591fa05a 100644 --- a/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/startup/WeixinServerBootstrap.java +++ b/weixin4j-mp/weixin4j-mp-server/src/main/java/com/foxinmy/weixin4j/mp/startup/WeixinServerBootstrap.java @@ -15,7 +15,7 @@ import com.foxinmy.weixin4j.mp.server.WeixinServerInitializer; /** * 微信服务netty启动程序 * - * @className WeixinBootstrap + * @className WeixinServerBootstrap * @author jy * @date 2014年10月12日 * @since JDK 1.7