diff --git a/CHANGE.md b/CHANGE.md index 5eb954de..870f18bb 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -629,4 +629,8 @@ * 2016-01-26 - + weixin4j-qy:新增上传图文消息内的图片接口 \ No newline at end of file + + weixin4j-qy:新增上传图文消息内的图片接口 + +* 2016-01-29 + + + 新增Weixin4jSettings配置类 \ No newline at end of file diff --git a/pom.xml b/pom.xml index d3625866..80cfdcc7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.foxinmy weixin4j - 1.6.6 + 1.6.7 pom weixin4j https://github.com/foxinmy/weixin4j diff --git a/weixin4j-base/pom.xml b/weixin4j-base/pom.xml index 6e57f42d..9a7f3468 100644 --- a/weixin4j-base/pom.xml +++ b/weixin4j-base/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.6.6 + 1.6.7 weixin4j-base weixin4j-base diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java index ee494ba5..00394f22 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java @@ -5,11 +5,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor; -import com.foxinmy.weixin4j.model.WeixinAccount; -import com.foxinmy.weixin4j.token.FileTokenStorager; -import com.foxinmy.weixin4j.token.TokenStorager; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; /** * API基础 @@ -45,21 +40,4 @@ public abstract class BaseApi { m.appendTail(sb); return sb.toString(); } - - /** - * 默认使用weixin4j.properties文件中的公众号信息 - */ - public final static WeixinAccount DEFAULT_WEIXIN_ACCOUNT; - - /** - * 默认token使用File的方式存储 - */ - public final static TokenStorager DEFAULT_TOKEN_STORAGER; - - static { - DEFAULT_WEIXIN_ACCOUNT = Weixin4jConfigUtil.getWeixinAccount(); - DEFAULT_TOKEN_STORAGER = new FileTokenStorager( - Weixin4jConfigUtil.getValue("token.path", - Weixin4jConst.DEFAULT_TOKEN_PATH)); - } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CashApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CashApi.java index 97aab882..982556ce 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CashApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CashApi.java @@ -48,7 +48,7 @@ public class CashApi { * 发放红包 企业向微信用户个人发现金红包 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param redpacket * 红包信息 * @return 发放结果 @@ -71,7 +71,7 @@ public class CashApi { WeixinResponse response = null; try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor .post(redpacket.getTotalNum() > 1 ? PayURLConsts.MCH_REDPACK_GROUPSEND_URL : PayURLConsts.MCH_REDPACKSEND_URL, param); @@ -92,7 +92,7 @@ public class CashApi { * 查询红包记录 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param outTradeNo * 商户发放红包的商户订单号 * @return 红包记录 @@ -116,7 +116,7 @@ public class CashApi { WeixinResponse response = null; try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor.post(PayURLConsts.MCH_REDPACKQUERY_URL, param); } finally { @@ -136,7 +136,7 @@ public class CashApi { * 企业付款 实现企业向个人付款,针对部分有开发能力的商户, 提供通过API完成企业付款的功能。 比如目前的保险行业向客户退保、给付、理赔。 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param mpPayment * 付款信息 * @return 付款结果 @@ -160,7 +160,7 @@ public class CashApi { WeixinResponse response = null; try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor.post(PayURLConsts.MCH_ENPAYMENT_URL, param); } finally { @@ -184,7 +184,7 @@ public class CashApi { * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param outTradeNo * 商户调用企业付款API时使用的商户订单号 * @return 付款记录 @@ -206,7 +206,7 @@ public class CashApi { WeixinResponse response = null; try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor.post(PayURLConsts.MCH_ENPAYQUERY_URL, param); } finally { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CouponApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CouponApi.java index cf052520..af4c0def 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CouponApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/CouponApi.java @@ -44,7 +44,7 @@ public class CouponApi { * 发放代金券(需要证书) * * @param ca - * 证书文件(后缀为*.p12) + * 后缀为*.p12的证书文件 * @param couponStockId * 代金券批次id * @param partnerTradeNo @@ -81,7 +81,7 @@ public class CouponApi { WeixinResponse response = null; try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor.post(PayURLConsts.MCH_COUPONSEND_URL, param); } finally { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/Pay3Api.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/Pay3Api.java index c320df0d..1d9255eb 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/Pay3Api.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/Pay3Api.java @@ -29,12 +29,12 @@ import com.foxinmy.weixin4j.payment.MicroPayPackage; import com.foxinmy.weixin4j.payment.PayURLConsts; import com.foxinmy.weixin4j.payment.mch.APPPayRequest; import com.foxinmy.weixin4j.payment.mch.ApiResult; -import com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult; import com.foxinmy.weixin4j.payment.mch.JSAPIPayRequest; import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.MchPayRequest; import com.foxinmy.weixin4j.payment.mch.NATIVEPayRequest; import com.foxinmy.weixin4j.payment.mch.NativePayResponse; +import com.foxinmy.weixin4j.payment.mch.OpenIdResult; import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.RefundRecord; @@ -51,8 +51,6 @@ import com.foxinmy.weixin4j.util.DigestUtil; import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.StringUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; import com.foxinmy.weixin4j.xml.XmlStream; @@ -496,7 +494,7 @@ public class Pay3Api { *

* * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -539,7 +537,7 @@ public class Pay3Api { map.put("sign", sign); String param = XmlStream.map2xml(map); WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); response = weixinExecutor.post(PayURLConsts.MCH_REFUNDAPPLY_URL, param); } finally { @@ -559,7 +557,7 @@ public class Pay3Api { * 退款申请(全额退款) * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -582,7 +580,7 @@ public class Pay3Api { * color="red">调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
* * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -594,7 +592,7 @@ public class Pay3Api { throws WeixinException { try { WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( - weixinAccount.getMchId(), ca); + weixinAccount.getCertificateKey(), ca); Map map = baseMap(idQuery); String sign = DigestUtil.paysignMd5(map, weixinAccount.getPaySignKey()); @@ -681,13 +679,15 @@ public class Pay3Api { * @param billType * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 * REFUND,返回当日退款订单 + * @param billPath + * 对账单保存路径 * @return excel表格 * @since V3 * @see 下载对账单API * @throws WeixinException */ - public File downloadBill(Date billDate, BillType billType) + public File downloadBill(Date billDate, BillType billType, String billPath) throws WeixinException { if (billDate == null) { Calendar now = Calendar.getInstance(); @@ -698,11 +698,9 @@ public class Pay3Api { billType = BillType.ALL; } String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); - String bill_path = Weixin4jConfigUtil.getValue("bill.path", - Weixin4jConst.DEFAULT_BILL_PATH); String fileName = String.format("%s_%s_%s.txt", formatBillDate, billType.name().toLowerCase(), weixinAccount.getId()); - File file = new File(String.format("%s/%s", bill_path, fileName)); + File file = new File(String.format("%s/%s", billPath, fileName)); if (file.exists()) { return file; } @@ -820,13 +818,12 @@ public class Pay3Api { * @param authCode * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 * @return 查询结果 - * @see com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult + * @see com.foxinmy.weixin4j.payment.mch.OpenIdResult * @see 授权码查询OPENID * @throws WeixinException */ - public AuthCodeOpenIdResult authCode2openId(String authCode) - throws WeixinException { + public OpenIdResult authCode2openId(String authCode) throws WeixinException { Map map = baseMap(null); map.put("auth_code", authCode); String sign = DigestUtil.paysignMd5(map, weixinAccount.getPaySignKey()); @@ -834,7 +831,7 @@ public class Pay3Api { String param = XmlStream.map2xml(map); WeixinResponse response = weixinExecutor.post( PayURLConsts.MCH_AUTHCODE_OPENID_URL, param); - return response.getAsObject(new TypeReference() { + return response.getAsObject(new TypeReference() { }); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinPayAccount.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinPayAccount.java index 7ad28e93..395bb4f6 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinPayAccount.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinPayAccount.java @@ -32,6 +32,10 @@ public class WeixinPayAccount extends WeixinAccount { * 微信支付分配的商户号(商户平台版) */ private String mchId; + /** + * 加载支付证书文件的密码(商户平台版) + */ + private String certificateKey; /** * 微信支付分配的子商户号,受理模式下必填(商户平台版) */ @@ -40,10 +44,6 @@ public class WeixinPayAccount extends WeixinAccount { * 微信支付分配的设备号(商户平台版) */ private String deviceInfo; - /** - * 微信支付版本号(如果无则按照mchId来做判断) - */ - private int version; /** * 商户平台版本(V3)字段 @@ -57,8 +57,9 @@ public class WeixinPayAccount extends WeixinAccount { * @param mchId * 微信支付分配的商户号(必填) */ - public WeixinPayAccount(String appId, String appSecret, String paySignKey, String mchId) { - this(appId, appSecret, paySignKey, mchId, null, null, null, null); + public WeixinPayAccount(String appId, String appSecret, String paySignKey, + String mchId) { + this(appId, appSecret, paySignKey, mchId, null, null, null, null, null); } /** @@ -72,6 +73,8 @@ public class WeixinPayAccount extends WeixinAccount { * 支付密钥字符串(必填) * @param mchId * 微信支付分配的商户号(V3商户平台版必填) + * @param certificateKey + * 加载支付证书文件的密码(商户平台版) * @param subMchId * 微信支付分配的子商户号,受理模式下必填(V3商户平台版 非必须) * @param deviceInfo @@ -82,13 +85,19 @@ public class WeixinPayAccount extends WeixinAccount { * 财付通商户权限密钥Key(V2版本必填) */ @JSONCreator - public WeixinPayAccount(@JSONField(name = "id") String appId, @JSONField(name = "secret") String appSecret, - @JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "mchId") String mchId, - @JSONField(name = "subMchId") String subMchId, @JSONField(name = "deviceInfo") String deviceInfo, - @JSONField(name = "partnerId") String partnerId, @JSONField(name = "partnerKey") String partnerKey) { + public WeixinPayAccount(@JSONField(name = "id") String appId, + @JSONField(name = "secret") String appSecret, + @JSONField(name = "paySignKey") String paySignKey, + @JSONField(name = "mchId") String mchId, + @JSONField(name = "certificateKey") String certificateKey, + @JSONField(name = "subMchId") String subMchId, + @JSONField(name = "deviceInfo") String deviceInfo, + @JSONField(name = "partnerId") String partnerId, + @JSONField(name = "partnerKey") String partnerKey) { super(appId, appSecret); this.paySignKey = paySignKey; this.mchId = mchId; + this.certificateKey = certificateKey; this.subMchId = subMchId; this.deviceInfo = deviceInfo; this.partnerId = partnerId; @@ -119,17 +128,16 @@ public class WeixinPayAccount extends WeixinAccount { return deviceInfo; } - public int getVersion() { - if (version == 0) { - return StringUtil.isNotBlank(mchId) ? 3 : 2; - } - return version; + public String getCertificateKey() { + return StringUtil.isBlank(certificateKey) ? mchId : certificateKey; } @Override public String toString() { - return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + paySignKey + ", partnerId=" + partnerId - + ", partnerKey=" + partnerKey + ", mchId=" + mchId + ", subMchId=" + subMchId + ", deviceInfo=" - + deviceInfo + ", version=" + getVersion() + "]"; + return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + + paySignKey + ", partnerId=" + partnerId + ", partnerKey=" + + partnerKey + ", mchId=" + mchId + ", certificateKey=" + + getCertificateKey() + ", subMchId=" + subMchId + + ", deviceInfo=" + deviceInfo + "]"; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java index 360f8e4d..0b8f72f6 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.Date; -import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.api.CashApi; import com.foxinmy.weixin4j.api.CouponApi; import com.foxinmy.weixin4j.api.Pay3Api; @@ -18,25 +17,24 @@ import com.foxinmy.weixin4j.payment.coupon.CouponDetail; import com.foxinmy.weixin4j.payment.coupon.CouponResult; import com.foxinmy.weixin4j.payment.coupon.CouponStock; import com.foxinmy.weixin4j.payment.mch.ApiResult; -import com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult; import com.foxinmy.weixin4j.payment.mch.MPPayment; import com.foxinmy.weixin4j.payment.mch.MPPaymentRecord; import com.foxinmy.weixin4j.payment.mch.MPPaymentResult; import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.MchPayRequest; import com.foxinmy.weixin4j.payment.mch.NativePayResponse; +import com.foxinmy.weixin4j.payment.mch.OpenIdResult; import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.Redpacket; import com.foxinmy.weixin4j.payment.mch.RedpacketRecord; import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult; import com.foxinmy.weixin4j.payment.mch.RefundRecord; +import com.foxinmy.weixin4j.settings.Weixin4jPaySettings; import com.foxinmy.weixin4j.type.BillType; import com.foxinmy.weixin4j.type.CurrencyType; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.TradeType; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 微信支付接口实现 @@ -54,26 +52,26 @@ public class WeixinPayProxy { private final CouponApi couponApi; private final CashApi cashApi; - private final WeixinPayAccount payAccount; + private final Weixin4jPaySettings settings; /** - * 使用weixin4j.properties配置的账号信息 + * 使用weixin4j.properties配置的支付账号信息 */ public WeixinPayProxy() { - this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), - WeixinPayAccount.class)); + this(new Weixin4jPaySettings()); } /** * - * @param weixinAccount - * 支付相关的公众号账号信息 + * @param settings + * 支付相关配置信息 + * @see com.foxinmy.weixin4j.settings.Weixin4jPaySettings */ - public WeixinPayProxy(WeixinPayAccount payAccount) { - this.payAccount = payAccount; - this.pay3Api = new Pay3Api(payAccount); - this.couponApi = new CouponApi(payAccount); - this.cashApi = new CashApi(payAccount); + public WeixinPayProxy(Weixin4jPaySettings settings) { + this.settings = settings; + this.pay3Api = new Pay3Api(settings.getPayAccount()); + this.couponApi = new CouponApi(settings.getPayAccount()); + this.cashApi = new CashApi(settings.getPayAccount()); } /** @@ -82,9 +80,7 @@ public class WeixinPayProxy { * @return */ public WeixinPayAccount getPayAccount() { - // clone ... - String text = JSON.toJSONString(payAccount); - return JSON.parseObject(text, WeixinPayAccount.class); + return this.settings.getPayAccount(); } /** @@ -429,7 +425,7 @@ public class WeixinPayProxy { *

* * @param ca - * 证书文件(后缀为*.p12) + * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -461,7 +457,7 @@ public class WeixinPayProxy { } /** - * 退款申请(全额退款)采用properties中配置的ca文件 + * 退款申请(全额退款) * * @throws IOException * @@ -470,12 +466,9 @@ public class WeixinPayProxy { public com.foxinmy.weixin4j.payment.mch.RefundResult refundApply( IdQuery idQuery, String outRefundNo, double totalFee) throws WeixinException, IOException { - return pay3Api - .refundApply( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - idQuery, outRefundNo, totalFee); + return pay3Api.refundApply( + new FileInputStream(settings.getCertificatePath()), idQuery, + outRefundNo, totalFee); } /** @@ -521,7 +514,7 @@ public class WeixinPayProxy { */ public File downloadBill(Date billDate, BillType billType) throws WeixinException { - return pay3Api.downloadBill(billDate, billType); + return pay3Api.downloadBill(billDate, billType, settings.getBillPath()); } /** @@ -546,7 +539,7 @@ public class WeixinPayProxy { } /** - * 冲正撤销:默认采用properties中配置的ca文件 + * 冲正撤销 * * @param idQuery * transaction_id、out_trade_no 二选一 @@ -557,12 +550,8 @@ public class WeixinPayProxy { */ public ApiResult reverseOrder(IdQuery idQuery) throws WeixinException, IOException { - return pay3Api - .reverseOrder( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - idQuery); + return pay3Api.reverseOrder( + new FileInputStream(settings.getCertificatePath()), idQuery); } /** @@ -635,7 +624,7 @@ public class WeixinPayProxy { * 发放代金券(需要证书) * * @param ca - * 证书文件(后缀为*.p12) + * 后缀为*.p12的证书文件 * @param couponStockId * 代金券批次id * @param partnerTradeNo @@ -659,18 +648,15 @@ public class WeixinPayProxy { } /** - * 发放代金券采用properties中配置的ca文件 + * 发放代金券 * * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendCoupon(InputStream, String, String, String, String)} */ public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, String openId) throws WeixinException, IOException { - return couponApi - .sendCoupon( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - couponStockId, partnerTradeNo, openId, null); + return couponApi.sendCoupon( + new FileInputStream(settings.getCertificatePath()), + couponStockId, partnerTradeNo, openId, null); } /** @@ -711,7 +697,7 @@ public class WeixinPayProxy { * 发放红包 企业向微信用户个人发现金红包 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param redpacket * 红包信息 * @return 发放结果 @@ -728,25 +714,21 @@ public class WeixinPayProxy { } /** - * 发放红包采用properties中配置的ca文件 + * 发放红包 * * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendRedpack(InputStream, Redpacket)} */ public RedpacketSendResult sendRedpack(Redpacket redpacket) throws WeixinException, IOException { - return cashApi - .sendRedpack( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - redpacket); + return cashApi.sendRedpack( + new FileInputStream(settings.getCertificatePath()), redpacket); } /** * 查询红包记录 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param outTradeNo * 商户发放红包的商户订单号 * @return 红包记录 @@ -762,25 +744,21 @@ public class WeixinPayProxy { } /** - * 查询红包采用properties中配置的ca文件 + * 查询红包 * * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#queryRedpack(InputStream,String)} */ public RedpacketRecord queryRedpack(String outTradeNo) throws WeixinException, IOException { - return cashApi - .queryRedpack( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - outTradeNo); + return cashApi.queryRedpack( + new FileInputStream(settings.getCertificatePath()), outTradeNo); } /** * 企业付款 实现企业向个人付款,针对部分有开发能力的商户, 提供通过API完成企业付款的功能。 比如目前的保险行业向客户退保、给付、理赔。 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param mpPayment * 付款信息 * @return 付款结果 @@ -797,25 +775,21 @@ public class WeixinPayProxy { } /** - * 企业付款采用properties中配置的ca文件 + * 企业付款 * * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPayment(InputStream, MPPayment)} */ public MPPaymentResult mpPayment(MPPayment mpPayment) throws WeixinException, IOException { - return cashApi - .mchPayment( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - mpPayment); + return cashApi.mchPayment( + new FileInputStream(settings.getCertificatePath()), mpPayment); } /** * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 * * @param ca - * 证书文件(V3版本后缀为*.p12) + * 后缀为*.p12的证书文件 * @param outTradeNo * 商户调用企业付款API时使用的商户订单号 * @return 付款记录 @@ -831,18 +805,14 @@ public class WeixinPayProxy { } /** - * 企业付款查询采用properties中配置的ca文件 + * 企业付款查询 * * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPaymentQuery(InputStream, String)} */ public MPPaymentRecord mpPaymentQuery(String outTradeNo) throws WeixinException, IOException { - return cashApi - .mchPaymentQuery( - new FileInputStream(Weixin4jConfigUtil - .getClassPathValue("certificate.file", - Weixin4jConst.DEFAULT_CAFILE_PATH)), - outTradeNo); + return cashApi.mchPaymentQuery( + new FileInputStream(settings.getCertificatePath()), outTradeNo); } /** @@ -852,15 +822,14 @@ public class WeixinPayProxy { * 扫码支付授权码,设备读取用户微信中的条码或者二维码信息 * @return 查询结果 * @see com.foxinmy.weixin4j.api.CashApi - * @see com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult + * @see com.foxinmy.weixin4j.payment.mch.OpenIdResult * @see 授权码查询OPENID * @throws WeixinException */ - public AuthCodeOpenIdResult authCode2openId(String authCode) - throws WeixinException { + public OpenIdResult authCode2openId(String authCode) throws WeixinException { return pay3Api.authCode2openId(authCode); } - public final static String VERSION = "1.6.6"; + public final static String VERSION = "1.6.7"; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/coupon/CouponDetail.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/coupon/CouponDetail.java index b13b1459..e3965bd1 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/coupon/CouponDetail.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/coupon/CouponDetail.java @@ -80,7 +80,6 @@ public class CouponDetail extends ApiResult { @XmlElement(name = "coupon_type") @JSONField(name = "coupon_type") private int couponType; - /** * 代金券描述 */ diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NativePayNotify.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NativePayNotify.java index c1bd4ac9..47130e80 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NativePayNotify.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/NativePayNotify.java @@ -5,8 +5,10 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import com.alibaba.fastjson.annotation.JSONField; + /** - * Native支付回调时POST的信息 + * Native支付回调时POST的信息 * * @className PayNativeNotify * @author jy @@ -16,27 +18,37 @@ import javax.xml.bind.annotation.XmlRootElement; */ @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) -public class NativePayNotify extends ApiResult { +public class NativePayNotify extends OpenIdResult { private static final long serialVersionUID = 4515471400239795492L; - + /** + * 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效 + */ + @XmlElement(name = "is_subscribe") + @JSONField(name = "is_subscribe") + private String isSubscribe; /** * 产品ID 可视为订单ID */ @XmlElement(name = "product_id") + @JSONField(name = "product_id") private String productId; protected NativePayNotify() { // jaxb required } - + public String getProductId() { return productId; } + public String getIsSubscribe() { + return isSubscribe; + } + @Override public String toString() { - return "NativePayNotify [productId=" + productId + ", " - + super.toString() + "]"; + return "NativePayNotify [productId=" + productId + ", isSubscribe=" + + isSubscribe + ", " + super.toString() + "]"; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AuthCodeOpenIdResult.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/OpenIdResult.java similarity index 84% rename from weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AuthCodeOpenIdResult.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/OpenIdResult.java index 8904e3ac..31dccb33 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/AuthCodeOpenIdResult.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/OpenIdResult.java @@ -10,7 +10,7 @@ import com.alibaba.fastjson.annotation.JSONField; /** * authcode2openid * - * @className AuthCodeOpenIdResult + * @className OpenIdResult * @author jy * @date 2015年7月23日 * @since JDK 1.6 @@ -18,7 +18,7 @@ import com.alibaba.fastjson.annotation.JSONField; */ @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) -public class AuthCodeOpenIdResult extends ApiResult { +public class OpenIdResult extends ApiResult { private static final long serialVersionUID = 902743989722741814L; @@ -35,7 +35,7 @@ public class AuthCodeOpenIdResult extends ApiResult { @Override public String toString() { - return "AuthCodeOpenIdResult [openId=" + openId + ", " + return "OpenIdResult [openId=" + openId + ", " + super.toString() + "]"; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java index 7e8ad95b..3cea660d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/mch/Redpacket.java @@ -144,10 +144,6 @@ public class Redpacket implements Serializable { return amtType; } - public void setAmtType(String amtType) { - this.amtType = amtType; - } - public String getClientIp() { return clientIp; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jHttpSettings.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jHttpSettings.java new file mode 100644 index 00000000..e26af308 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jHttpSettings.java @@ -0,0 +1,14 @@ +package com.foxinmy.weixin4j.settings; + +/** + * 微信请求配置相关(待实现 + * + * @className Weixin4jHttpSettings + * @author jy + * @date 2016年1月28日 + * @since JDK 1.6 + * @see + */ +public class Weixin4jHttpSettings { + +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jPaySettings.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jPaySettings.java new file mode 100644 index 00000000..54bc5580 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jPaySettings.java @@ -0,0 +1,108 @@ +package com.foxinmy.weixin4j.settings; + +import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.model.WeixinPayAccount; +import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; + +/** + * 微信支付配置相关 + * + * @className Weixin4jPaySettings + * @author jy + * @date 2016年1月28日 + * @since JDK 1.6 + * @see + */ +public class Weixin4jPaySettings { + + private final WeixinPayAccount payAccount; + + public Weixin4jPaySettings() { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinPayAccount.class)); + } + + public Weixin4jPaySettings(WeixinPayAccount payAccount) { + this.payAccount = payAccount; + } + + /** + * 支付账号信息 + * + * @return + */ + public WeixinPayAccount getPayAccount() { + return this.payAccount; + } + + private String billPath; + + /** + * 对账单保存路径 + * + * @param billPath + * 硬盘目录 + */ + public Weixin4jPaySettings billPath(String billPath) { + this.billPath = billPath; + return this; + } + + /** + * 默认对账单保存路径 + */ + public static final String DEFAULT_BILL_PATH = "/tmp/weixin4j/bill"; + + /** + * 对账单保存路径,默认值为{@link #DEFAULT_BILL_PATH} + * + * @return + */ + public String getBillPath() { + if (StringUtil.isBlank(billPath)) { + this.billPath = Weixin4jConfigUtil.getClassPathValue("bill.path", + DEFAULT_BILL_PATH); + } + return this.billPath; + } + + private String certificatePath; + + /** + * ca证书存放路径 + * + * @param certificatePath + * 硬盘目录 + * @return + */ + public Weixin4jPaySettings certificatePath(String certificatePath) { + this.certificatePath = certificatePath; + return this; + } + + /** + * 默认ca证书存放路径 + */ + public static final String DEFAULT_CAFILE_PATH = "classpath:ca.p12"; + + /** + * ca证书存放路径,默认值为{@link #DEFAULT_CAFILE_PATH} + * + * @return + */ + public String getCertificatePath() { + if (StringUtil.isBlank(certificatePath)) { + this.certificatePath = Weixin4jConfigUtil.getClassPathValue( + "certificate.path", DEFAULT_CAFILE_PATH); + } + return this.certificatePath; + } + + @Override + public String toString() { + return "Weixin4jPaySettings [payAccount=" + payAccount + ", billPath=" + + getBillPath() + ", certificatePath=" + getCertificatePath() + + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jSettings.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jSettings.java new file mode 100644 index 00000000..1eeff35d --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/settings/Weixin4jSettings.java @@ -0,0 +1,168 @@ +package com.foxinmy.weixin4j.settings; + +import com.foxinmy.weixin4j.model.WeixinAccount; +import com.foxinmy.weixin4j.token.FileTokenStorager; +import com.foxinmy.weixin4j.token.TokenStorager; +import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; + +/** + * 微信基础配置相关 + * + * @className Weixin4jSettings + * @author jy + * @date 2016年1月28日 + * @since JDK 1.6 + * @see + */ +public class Weixin4jSettings { + + private final WeixinAccount account; + + public Weixin4jSettings() { + this(Weixin4jConfigUtil.getWeixinAccount()); + } + + /** + * + * @param id + * 应用唯一标识 appid/corpid + * @param secret + * 应用接口密钥 + */ + public Weixin4jSettings(String id, String secret) { + this(new WeixinAccount(id, secret)); + } + + public Weixin4jSettings(WeixinAccount account) { + this.account = account; + } + + /** + * 微信账号信息 + */ + public WeixinAccount getAccount() { + return this.account; + } + + private String tokenPath; + + /** + * 使用FileTokenStorager时token的存放路径 + * + * @param tokenPath + * 硬盘目录 + * @return + */ + public Weixin4jSettings setTokenPath(String tokenPath) { + this.tokenPath = tokenPath; + return this; + } + + /** + * 默认token的存放路径 + */ + public static final String DEFAULT_TOKEN_PATH = "/tmp/weixin4j/token"; + + /** + * 使用FileTokenStorager时token的存放路径,默认值为{@link #DEFAULT_TOKEN_PATH} + */ + public String getTokenPath() { + if (StringUtil.isBlank(tokenPath)) { + tokenPath = Weixin4jConfigUtil.getClassPathValue("token.path", + DEFAULT_TOKEN_PATH); + } + return tokenPath; + } + + private String qrcodePath; + + /** + * 二维码保存路径 + * + * @param qrcodePath + * 硬盘目录 + */ + public Weixin4jSettings setQrcodePath(String qrcodePath) { + this.qrcodePath = qrcodePath; + return this; + } + + /** + * 默认二维码保存路径 + */ + public static final String DEFAULT_QRCODE_PATH = "/tmp/weixin4j/qrcode"; + + /** + * 二维码保存路径,默认值为{@link #DEFAULT_QRCODE_PATH} + */ + public String getQrcodePath() { + if (StringUtil.isBlank(qrcodePath)) { + this.qrcodePath = Weixin4jConfigUtil.getClassPathValue( + "qrcode.path", DEFAULT_QRCODE_PATH); + } + return this.qrcodePath; + } + + private String mediaPath; + + /** + * 媒体文件保存路径 + * + * @param mediaPath + * 硬盘目录 + */ + public Weixin4jSettings setMediaPath(String mediaPath) { + this.mediaPath = mediaPath; + return this; + } + + /** + * 默认媒体文件保存路径 + */ + public static final String DEFAULT_MEDIA_PATH = "/tmp/weixin4j/media"; + + /** + * 媒体文件保存路径,默认值为{@link #DEFAULT_MEDIA_PATH} + */ + public String getMediaPath() { + if (StringUtil.isBlank(mediaPath)) { + this.mediaPath = Weixin4jConfigUtil.getClassPathValue("media.path", + DEFAULT_MEDIA_PATH); + } + return this.mediaPath; + } + + private TokenStorager tokenStorager; + + /** + * token存储 + * + * @param tokenStorager + * @return + */ + public Weixin4jSettings setTokenStorager(TokenStorager tokenStorager) { + this.tokenStorager = tokenStorager; + return this; + } + + /** + * 获取token存储方式 默认为FileTokenStorager + * + * @return + */ + public TokenStorager getTokenStorager() { + if (tokenStorager == null) { + this.tokenStorager = new FileTokenStorager(getTokenPath()); + } + return this.tokenStorager; + } + + @Override + public String toString() { + return "Weixin4jSettings [account=" + account + ", tokenPath=" + + getTokenPath() + ", qrcodePath=" + getQrcodePath() + + ", mediaPath=" + getMediaPath() + ", tokenStorager=" + + getTokenStorager() + "]"; + } +} diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java index 04fee404..c20fb517 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/CacheStorager.java @@ -44,7 +44,7 @@ public interface CacheStorager { T evict(String cacheKey); /** - * 清除所有缓存对象(请慎重) + * 清除所有缓存对象(请慎重) */ void clear(); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java index 90767b6e..bb4263ed 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/DigestUtil.java @@ -1,11 +1,16 @@ package com.foxinmy.weixin4j.util; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import com.foxinmy.weixin4j.model.Consts; +import com.foxinmy.weixin4j.payment.mch.NativePayNotify; +import com.foxinmy.weixin4j.xml.XmlStream; /** * 签名工具类 @@ -130,4 +135,12 @@ public final class DigestUtil { return sb.toString(); } + + public static void main(String[] args) throws FileNotFoundException { + NativePayNotify notify = XmlStream.fromXML(new FileInputStream( + new File("/Users/jy/Downloads/weixin4j.xml")), + NativePayNotify.class); + notify.setSign(null); + System.err.println(paysignMd5(notify, "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ")); + } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java index c6e53da5..0afc53bf 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConfigUtil.java @@ -75,7 +75,7 @@ public class Weixin4jConfigUtil { value = getValue(key); } catch (MissingResourceException e) { ; - }catch (NullPointerException e){ + } catch (NullPointerException e) { ; } return value; @@ -88,8 +88,7 @@ public class Weixin4jConfigUtil { * @return */ public static String getClassPathValue(String key) { - return new File(getValue(key).replaceFirst(CLASSPATH_PREFIX, - CLASSPATH_VALUE)).getPath(); + return getValue(key).replaceFirst(CLASSPATH_PREFIX, CLASSPATH_VALUE); } /** @@ -99,18 +98,18 @@ public class Weixin4jConfigUtil { * @return */ public static String getClassPathValue(String key, String defaultValue) { - return new File(getValue(key, defaultValue).replaceFirst( - CLASSPATH_PREFIX, CLASSPATH_VALUE)).getPath(); + return getValue(key, defaultValue).replaceFirst(CLASSPATH_PREFIX, + CLASSPATH_VALUE); } public static WeixinAccount getWeixinAccount() { - if (weixinBundle == null) { - return null; - } WeixinAccount account = null; try { account = JSON .parseObject(getValue("account"), WeixinAccount.class); + } catch (NullPointerException e) { + System.err + .println("'weixin4j.account' key not found in weixin4j.properties."); } catch (MissingResourceException e) { System.err .println("'weixin4j.account' key not found in weixin4j.properties."); diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java deleted file mode 100644 index 8c28a5e1..00000000 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.foxinmy.weixin4j.util; - -/** - * 常量配置 - * - * @className Weixin4jConst - * @author jy - * @date 2015年7月1日 - * @since JDK 1.6 - * @see - */ -public final class Weixin4jConst { - /** - * 使用FileTokenStorager时token的存放路径 - */ - public static final String DEFAULT_TOKEN_PATH = "/tmp/weixin4j/token"; - /** - * 二维码保存路径 - */ - public static final String DEFAULT_QRCODE_PATH = "/tmp/weixin4j/qrcode"; - /** - * 媒体文件保存路径 - */ - public static final String DEFAULT_MEDIA_PATH = "/tmp/weixin4j/media"; - /** - * 对账单保存路径 - */ - public static final String DEFAULT_BILL_PATH = "/tmp/weixin4j/bill"; - /** - * ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12) - */ - public static final String DEFAULT_CAFILE_PATH = "classpath:ca.p12"; -} diff --git a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/HttpClientTest.java b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/HttpClientTest.java index 050b427d..bd03cd54 100644 --- a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/HttpClientTest.java +++ b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/HttpClientTest.java @@ -67,7 +67,9 @@ public class HttpClientTest { } public static void main(String[] args) throws Exception { + for(int i=0;i<100000;i++){ test1(); + } System.out.println("---------------------"); test2(); System.out.println("---------------------"); diff --git a/weixin4j-mp/README.md b/weixin4j-mp/README.md index 82a51670..08abac50 100644 --- a/weixin4j-mp/README.md +++ b/weixin4j-mp/README.md @@ -58,21 +58,27 @@ weixin4j.properties说明 完整填写示例(properties中换行用右斜杆\\) - weixin4j.account={"id":"appId","secret":"appSecret",\ - "mchId":"V3.x版本下的微信商户号",\ - "partnerId":"V2版本下的财付通的商户号",\ - "partnerKey":"V2版本下的财付通商户权限密钥Key",\ - "paySignKey":"微信支付中调用API的密钥"} + weixin4j.account={"id":"appid","secret":"appsecret",\ + "mchId":"V3.x版本下的微信商户号 微信支付时需要填入",\ + "certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\ + "partnerId":"V2版本下的财付通的商户号 微信支付时需要填入",\ + "partnerKey":"V2版本下的财付通商户权限密钥Key 微信支付时需要填入",\ + "paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"} + # 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.token.path=/tmp/weixin4j/token + # 二维码保存路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.qrcode.path=/tmp/weixin4j/qrcode + # 媒体文件保存路径(如果不填则默认为Weixin4jConst#DEFAULT_MEDIA_PATH) weixin4j.media.path=/tmp/weixin4j/media + # 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH) weixin4j.bill.path=/tmp/weixin4j/bill # ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12) weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 - #classpath路径下:weixin4j.certificate.file=classpath:xxxxx.p12 + # classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH) + # weixin4j.certificate.file=classpath:xxxxx.pfx - #公众号登陆授权的重定向路径(使用OauthApi时需要填写) + # 用户oauth授权后重定向的url(在使用OauthApi时填写) weixin4j.user.oauth.redirect.uri=http://xxx 2.实例化微信公众号接口代理对象,调用具体的API方法 diff --git a/weixin4j-mp/pom.xml b/weixin4j-mp/pom.xml index 97aba641..80926742 100644 --- a/weixin4j-mp/pom.xml +++ b/weixin4j-mp/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.6.6 + 1.6.7 weixin4j-mp weixin4j-mp diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index 364e97ed..60b9a952 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -14,6 +14,7 @@ import com.foxinmy.weixin4j.model.MediaItem; import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.MediaUploadResult; import com.foxinmy.weixin4j.model.Pageable; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.api.DataApi; import com.foxinmy.weixin4j.mp.api.GroupApi; @@ -21,7 +22,6 @@ import com.foxinmy.weixin4j.mp.api.HelperApi; import com.foxinmy.weixin4j.mp.api.MassApi; import com.foxinmy.weixin4j.mp.api.MediaApi; import com.foxinmy.weixin4j.mp.api.MenuApi; -import com.foxinmy.weixin4j.mp.api.MpApi; import com.foxinmy.weixin4j.mp.api.NotifyApi; import com.foxinmy.weixin4j.mp.api.QrApi; import com.foxinmy.weixin4j.mp.api.TmplApi; @@ -47,8 +47,8 @@ import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.mp.type.DatacubeType; import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.mp.type.Lang; +import com.foxinmy.weixin4j.settings.Weixin4jSettings; import com.foxinmy.weixin4j.token.TokenHolder; -import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.tuple.MassTuple; import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpVideo; @@ -80,45 +80,26 @@ public class WeixinProxy { private final DataApi dataApi; private final TokenHolder tokenHolder; - private String appId; + private Weixin4jSettings settings; /** * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 */ public WeixinProxy() { - this(MpApi.DEFAULT_TOKEN_STORAGER); - } - - /** - * 默认使用weixin4j.properties配置的账号信息 - * - * @param tokenStorager - */ - public WeixinProxy(TokenStorager tokenStorager) { - this(MpApi.DEFAULT_WEIXIN_ACCOUNT.getId(), MpApi.DEFAULT_WEIXIN_ACCOUNT - .getSecret(), tokenStorager); + this(new Weixin4jSettings()); } /** * - * @param appid - * @param appsecret + * @param settings + * 配置信息 + * @see com.foxinmy.weixin4j.settings.Weixin4jSettings */ - public WeixinProxy(String appid, String appsecret) { - this(appid, appsecret, MpApi.DEFAULT_TOKEN_STORAGER); - } - - /** - * - * @param appid - * @param appsecret - * @param tokenStorager - */ - public WeixinProxy(String appid, String appsecret, - TokenStorager tokenStorager) { - this(new TokenHolder(new WeixinTokenCreator(appid, appsecret), - tokenStorager)); - this.appId = appid; + public WeixinProxy(Weixin4jSettings settings) { + this(new TokenHolder(new WeixinTokenCreator(settings.getAccount() + .getId(), settings.getAccount().getSecret()), + settings.getTokenStorager())); + this.settings = settings; } /** @@ -143,12 +124,12 @@ public class WeixinProxy { } /** - * 获取appid + * 获取微信账号信息 * * @return */ - public String getAppId() { - return this.appId; + public WeixinAccount getWeixinAccount() { + return this.settings.getAccount(); } /** @@ -168,8 +149,9 @@ public class WeixinProxy { * @return */ public TokenHolder getTicketHolder(TicketType ticketType) { - return new TokenHolder(new WeixinTicketCreator(this.appId, ticketType, - this.tokenHolder), this.tokenHolder.getTokenStorager()); + return new TokenHolder(new WeixinTicketCreator(getWeixinAccount() + .getId(), ticketType, this.tokenHolder), + this.tokenHolder.getTokenStorager()); } /** @@ -248,10 +230,8 @@ public class WeixinProxy { * * @param mediaId * 存储在微信服务器上的媒体标识 - * @param mediaType - * 媒体类型 * @param isMaterial - * 是否永久素材 + * 是否下载永久素材 * @return 写入硬盘后的文件对象 * @throws WeixinException * @see 下载临时媒体文件 @@ -246,12 +248,10 @@ public class MediaApi extends MpApi { * href="http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材 * @see {@link #downloadMedia(String,boolean)} */ - public File downloadMediaFile(String mediaId, boolean isMaterial) - throws WeixinException { - String media_path = Weixin4jConfigUtil.getValue("media.path", - Weixin4jConst.DEFAULT_MEDIA_PATH); + public File downloadMediaFile(String mediaId, boolean isMaterial, + String mediaPath) throws WeixinException { final String prefixName = String.format("%s.", mediaId); - File[] files = new File(media_path).listFiles(new FilenameFilter() { + File[] files = new File(mediaPath).listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith(prefixName); @@ -261,7 +261,7 @@ public class MediaApi extends MpApi { return files[0]; } MediaDownloadResult result = downloadMedia(mediaId, isMaterial); - File file = new File(media_path + File.separator + result.getFileName()); + File file = new File(mediaPath + File.separator + result.getFileName()); OutputStream os = null; try { if (file.createNewFile()) { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java index c01584a4..53f88922 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java @@ -7,11 +7,12 @@ import com.alibaba.fastjson.TypeReference; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.model.OauthToken; import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.type.Lang; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** * oauth授权 @@ -25,13 +26,23 @@ import com.foxinmy.weixin4j.util.StringUtil; */ public class OauthApi extends MpApi { + private final WeixinAccount account; + + public OauthApi() { + this(Weixin4jConfigUtil.getWeixinAccount()); + } + + public OauthApi(WeixinAccount account) { + this.account = account; + } + /** * @see {@link #getAuthorizeURL(String, String,String)} * * @return 请求授权的URL */ public String getAuthorizeURL() { - String appId = DEFAULT_WEIXIN_ACCOUNT.getId(); + String appId = account.getId(); String redirectUri = Weixin4jConfigUtil .getValue("user.oauth.redirect.uri"); return getAuthorizeURL(appId, redirectUri, "state", "snsapi_base"); @@ -67,8 +78,7 @@ public class OauthApi extends MpApi { * @return */ public OauthToken getOauthToken(String code) throws WeixinException { - return getOauthToken(code, DEFAULT_WEIXIN_ACCOUNT.getId(), - DEFAULT_WEIXIN_ACCOUNT.getSecret()); + return getOauthToken(code, account.getId(), account.getSecret()); } /** @@ -100,7 +110,7 @@ public class OauthApi extends MpApi { * @return */ public OauthToken refreshToken(String refreshToken) throws WeixinException { - return refreshToken(DEFAULT_WEIXIN_ACCOUNT.getId(), refreshToken); + return refreshToken(account.getId(), refreshToken); } /** diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java index 73196d4f..d4dc832e 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/Pay2Api.java @@ -40,6 +40,9 @@ import com.foxinmy.weixin4j.mp.payment.v2.RefundRecordV2; import com.foxinmy.weixin4j.mp.payment.v2.RefundResultV2; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.payment.PayRequest; +import com.foxinmy.weixin4j.settings.Weixin4jSettings; +import com.foxinmy.weixin4j.settings.Weixin4jPaySettings; +import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.type.BillType; @@ -51,8 +54,6 @@ import com.foxinmy.weixin4j.util.DigestUtil; import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.StringUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; /** @@ -66,23 +67,27 @@ import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; */ public class Pay2Api extends MpApi { - private final WeixinPayAccount weixinAccount; + private final Weixin4jPaySettings settings; private final TokenHolder tokenHolder; public Pay2Api() { - this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), - WeixinPayAccount.class)); + this(new Weixin4jPaySettings()); } - public Pay2Api(WeixinPayAccount weixinAccount) { - this(weixinAccount, DEFAULT_TOKEN_STORAGER); + public Pay2Api(Weixin4jPaySettings settings) { + this(settings, new FileTokenStorager( + Weixin4jSettings.DEFAULT_TOKEN_PATH)); } - public Pay2Api(WeixinPayAccount weixinAccount, TokenStorager tokenStorager) { - this.weixinAccount = weixinAccount; - this.tokenHolder = new TokenHolder(new WeixinTokenCreator( - weixinAccount.getId(), weixinAccount.getSecret()), - tokenStorager); + public Pay2Api(Weixin4jPaySettings settings, TokenStorager tokenStorager) { + this.settings = settings; + this.tokenHolder = new TokenHolder( + new WeixinTokenCreator(settings.getPayAccount().getId(), + settings.getPayAccount().getSecret()), tokenStorager); + } + + public WeixinPayAccount getPayAccount() { + return this.settings.getPayAccount(); } /** @@ -137,20 +142,20 @@ public class Pay2Api extends MpApi { double totalFee, String notifyUrl, String createIp, String attach, Date timeStart, Date timeExpire, double transportFee, double productFee, String goodsTag) { - PayPackageV2 payPackage = new PayPackageV2( - weixinAccount.getPartnerId(), body, outTradeNo, totalFee, - notifyUrl, createIp); + PayPackageV2 payPackage = new PayPackageV2(settings.getPayAccount() + .getPartnerId(), body, outTradeNo, totalFee, notifyUrl, + createIp); payPackage.setAttach(attach); payPackage.setTimeStart(timeStart); payPackage.setTimeExpire(timeExpire); payPackage.setTransportFee(transportFee); payPackage.setProductFee(productFee); payPackage.setGoodsTag(goodsTag); - PayRequest payRequest = new PayRequest(weixinAccount.getId(), - DigestUtil.packageSign(payPackage, - weixinAccount.getPartnerKey())); - payRequest.setPaySign(DigestUtil.paysignSha(payRequest, - weixinAccount.getPaySignKey())); + PayRequest payRequest = new PayRequest(getPayAccount().getId(), + DigestUtil.packageSign(payPackage, getPayAccount() + .getPartnerKey())); + payRequest.setPaySign(DigestUtil.paysignSha(payRequest, getPayAccount() + .getPaySignKey())); payRequest.setSignType(SignType.SHA1); return JSON.toJSONString(payRequest); } @@ -166,14 +171,14 @@ public class Pay2Api extends MpApi { Map map = new HashMap(); String timestamp = DateUtil.timestamp2string(); String noncestr = RandomUtil.generateString(16); - map.put("appid", weixinAccount.getId()); + map.put("appid", getPayAccount().getId()); map.put("timestamp", timestamp); map.put("noncestr", noncestr); map.put("productid", productId); - map.put("appkey", weixinAccount.getPaySignKey()); + map.put("appkey", getPayAccount().getPaySignKey()); String sign = DigestUtil.paysignSha(map, null); String ordernative_v2_uri = getRequestUri("ordernative_v2_uri"); - return String.format(ordernative_v2_uri, sign, weixinAccount.getId(), + return String.format(ordernative_v2_uri, sign, getPayAccount().getId(), productId, timestamp, noncestr); } @@ -193,23 +198,23 @@ public class Pay2Api extends MpApi { StringBuilder sb = new StringBuilder(); sb.append(idQuery.getType().getName()).append("=") .append(idQuery.getId()); - sb.append("&partner=").append(weixinAccount.getPartnerId()); + sb.append("&partner=").append(getPayAccount().getPartnerId()); String part = sb.toString(); - sb.append("&key=").append(weixinAccount.getPartnerKey()); + sb.append("&key=").append(getPayAccount().getPartnerKey()); String sign = DigestUtil.MD5(sb.toString()).toUpperCase(); sb.delete(0, sb.length()); sb.append(part).append("&sign=").append(sign); String timestamp = DateUtil.timestamp2string(); JSONObject obj = new JSONObject(); - obj.put("appid", weixinAccount.getId()); - obj.put("appkey", weixinAccount.getPaySignKey()); + obj.put("appid", getPayAccount().getId()); + obj.put("appkey", getPayAccount().getPaySignKey()); obj.put("package", sb.toString()); obj.put("timestamp", timestamp); String signature = DigestUtil.paysignSha(obj, null); obj.clear(); - obj.put("appid", weixinAccount.getId()); + obj.put("appid", getPayAccount().getId()); obj.put("package", sb.toString()); obj.put("timestamp", timestamp); obj.put("app_signature", signature); @@ -271,20 +276,20 @@ public class Pay2Api extends MpApi { // 填写为 1.0 时,操作员密码为明文 // 填写为 1.1 时,操作员密码为 MD5(密码)值 map.put("service_version", "1.1"); - map.put("partner", weixinAccount.getPartnerId()); + map.put("partner", getPayAccount().getPartnerId()); map.put("out_refund_no", outRefundNo); map.put("total_fee", DateUtil.formaFee2Fen(totalFee)); map.put("refund_fee", DateUtil.formaFee2Fen(refundFee)); map.put(idQuery.getType().getName(), idQuery.getId()); if (StringUtil.isBlank(opUserId)) { - opUserId = weixinAccount.getPartnerId(); + opUserId = getPayAccount().getPartnerId(); } map.put("op_user_id", opUserId); if (mopara != null && !mopara.isEmpty()) { map.putAll(mopara); } - String sign = DigestUtil.paysignMd5(map, - weixinAccount.getPartnerKey()); + String sign = DigestUtil.paysignMd5(map, getPayAccount() + .getPartnerKey()); map.put("sign", sign.toUpperCase()); SSLContext ctx = null; @@ -319,8 +324,8 @@ public class Pay2Api extends MpApi { KeyManagerFactory kmf = KeyManagerFactory .getInstance(com.foxinmy.weixin4j.model.Consts.SunX509); ks = KeyStore.getInstance(com.foxinmy.weixin4j.model.Consts.PKCS12); - ks.load(ca, weixinAccount.getPartnerId().toCharArray()); - kmf.init(ks, weixinAccount.getPartnerId().toCharArray()); + ks.load(ca, getPayAccount().getPartnerId().toCharArray()); + kmf.init(ks, getPayAccount().getPartnerId().toCharArray()); ctx = SSLContext.getInstance(com.foxinmy.weixin4j.model.Consts.TLS); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), @@ -451,23 +456,22 @@ public class Pay2Api extends MpApi { billType = BillType.ALL; } String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); - String bill_path = Weixin4jConfigUtil.getValue("bill.path", - Weixin4jConst.DEFAULT_BILL_PATH); String fileName = String.format("%s_%s_%s.txt", formatBillDate, - billType.name().toLowerCase(), weixinAccount.getId()); - File file = new File(String.format("%s/%s", bill_path, fileName)); + billType.name().toLowerCase(), getPayAccount().getId()); + File file = new File(String.format("%s/%s", settings.getBillPath(), + fileName)); if (file.exists()) { return file; } String downloadbill_uri = getRequestUri("downloadbill_v2_uri"); Map map = new LinkedHashMap(); - map.put("spid", weixinAccount.getPartnerId()); + map.put("spid", getPayAccount().getPartnerId()); map.put("trans_time", DateUtil.fortmat2yyyy_MM_dd(billDate)); map.put("stamp", DateUtil.timestamp2string()); map.put("cft_signtype", "0"); map.put("mchtype", Integer.toString(billType.getVal())); - map.put("key", weixinAccount.getPartnerKey()); + map.put("key", getPayAccount().getPartnerKey()); String sign = DigestUtil.MD5(MapUtil.toJoinString(map, false, false)); map.put("sign", sign.toLowerCase()); WeixinResponse response = weixinExecutor.get(downloadbill_uri, map); @@ -517,9 +521,10 @@ public class Pay2Api extends MpApi { String refundquery_uri = getRequestUri("refundquery_v2_uri"); Map map = new HashMap(); map.put("input_charset", Consts.UTF_8.name()); - map.put("partner", weixinAccount.getPartnerId()); + map.put("partner", getPayAccount().getPartnerId()); map.put(idQuery.getType().getName(), idQuery.getId()); - String sign = DigestUtil.paysignMd5(map, weixinAccount.getPartnerKey()); + String sign = DigestUtil.paysignMd5(map, getPayAccount() + .getPartnerKey()); map.put("sign", sign.toLowerCase()); WeixinResponse response = weixinExecutor.get(refundquery_uri, map); return ListsuffixResultDeserializer.deserialize(response.getAsString(), @@ -549,8 +554,8 @@ public class Pay2Api extends MpApi { Token token = tokenHolder.getToken(); Map map = new HashMap(); - map.put("appid", weixinAccount.getId()); - map.put("appkey", weixinAccount.getPaySignKey()); + map.put("appid", getPayAccount().getId()); + map.put("appkey", getPayAccount().getPaySignKey()); map.put("openid", openId); map.put("transid", transid); map.put("out_trade_no", outTradeNo); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java index 2c27f379..1a1ca292 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java @@ -13,8 +13,6 @@ import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRResult; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.util.IOUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 二维码相关API @@ -55,7 +53,8 @@ public class QrApi extends MpApi { QRResult result = response.getAsObject(new TypeReference() { }); qr_uri = getRequestUri("qr_image_uri"); - response = weixinExecutor.get(String.format(qr_uri, result.getTicket())); + response = weixinExecutor + .get(String.format(qr_uri, result.getTicket())); try { result.setContent(IOUtil.toByteArray(response.getBody())); } catch (IOException e) { @@ -72,6 +71,8 @@ public class QrApi extends MpApi { * * @param parameter * 二维码参数 + * @param qrcodePath + * 二维码保存路径 * @return 硬盘存储的文件对象 * @throws WeixinException * @see 0 && file.exists()) { return file; } diff --git a/weixin4j-mp/src/main/resources/weixin4j.properties b/weixin4j-mp/src/main/resources/weixin4j.properties index 7815943b..ff52cfd4 100644 --- a/weixin4j-mp/src/main/resources/weixin4j.properties +++ b/weixin4j-mp/src/main/resources/weixin4j.properties @@ -1,23 +1,24 @@ # \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath # \u516c\u4f17\u53f7\u4fe1\u606f weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ -"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ -"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ -"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ -"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} +"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ +"certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\ +"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ +"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ +"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84 +# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.token.path=/tmp/weixin4j/token -# \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84 +# \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.qrcode.path=/tmp/weixin4j/qrcode -# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 +# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH) weixin4j.media.path=/tmp/weixin4j/media -# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84 +# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH) weixin4j.bill.path=/tmp/weixin4j/bill # ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12) weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 -# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199 +# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_CAFILE_PATH) # weixin4j.certificate.file=classpath:xxxxx.pfx -# \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url +# \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) weixin4j.user.oauth.redirect.uri= \ No newline at end of file diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index 40011b1a..9e81cd50 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -94,7 +94,8 @@ public class MediaTest extends TokenTest { @Test public void download2() throws WeixinException, IOException { - File file = mediaApi.downloadMediaFile("8790403529", true); + File file = mediaApi.downloadMediaFile("8790403529", true, + "/tmp/weixin4j/media"); Assert.assertTrue(file.exists()); } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java index ac04bac9..74be7575 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java @@ -19,12 +19,11 @@ import com.foxinmy.weixin4j.payment.mch.ApiResult; import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.PrePay; -import com.foxinmy.weixin4j.token.FileTokenStorager; +import com.foxinmy.weixin4j.settings.Weixin4jPaySettings; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdType; import com.foxinmy.weixin4j.type.TradeType; import com.foxinmy.weixin4j.util.DigestUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; public class PayTest { protected final static Pay2Api PAY2; @@ -33,14 +32,13 @@ public class PayTest { protected final static WeixinPayAccount ACCOUNT3; static { ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", - "请填入v2版本的paysignkey", null, null, null, "请填入v2版本的partnerId", - "请填入v2版本的partnerKey"); - PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager( - Weixin4jConfigUtil - .getValue("token.path", "/tmp/weixin4j/token"))); + "请填入v2版本的paysignkey", null, null, null, null, + "请填入v2版本的partnerId", "请填入v2版本的partnerKey"); + PAY2 = new Pay2Api(new Weixin4jPaySettings(ACCOUNT2)); ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret", - "请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null); - PAY3 = new WeixinPayProxy(ACCOUNT3); + "请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null, + null); + PAY3 = new WeixinPayProxy(new Weixin4jPaySettings(ACCOUNT3)); } /** * 商户证书文件 @@ -55,7 +53,6 @@ public class PayTest { @Test public void refundV2() throws WeixinException { - File caFile = new File("证书文件,如12333.pfx"); IdQuery idQuery = new IdQuery("D15020300005", IdType.TRADENO); System.err.println(PAY2.refundApply(caFile, idQuery, "1422925555037", 16d, 16d, "1221928801", "111111", null, null, null)); @@ -84,7 +81,8 @@ public class PayTest { System.err.println(order); String sign = order.getSign(); order.setSign(null); - String valiSign = DigestUtil.paysignMd5(order, ACCOUNT3.getPaySignKey()); + String valiSign = DigestUtil + .paysignMd5(order, ACCOUNT3.getPaySignKey()); System.err .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); Assert.assertEquals(valiSign, sign); @@ -98,7 +96,8 @@ public class PayTest { // 这里的验证签名需要把details循环拼接 String sign = record.getSign(); record.setSign(null); - String valiSign = DigestUtil.paysignMd5(record, ACCOUNT3.getPaySignKey()); + String valiSign = DigestUtil.paysignMd5(record, + ACCOUNT3.getPaySignKey()); System.err .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); Assert.assertEquals(valiSign, sign); @@ -118,7 +117,6 @@ public class PayTest { @Test public void refundV3() throws WeixinException, IOException { - File caFile = new File("签名文件如123.p12"); IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO); com.foxinmy.weixin4j.payment.mch.RefundResult result = PAY3 .refundApply(new FileInputStream(caFile), idQuery, "TT_R" @@ -127,7 +125,8 @@ public class PayTest { System.err.println(result); String sign = result.getSign(); result.setSign(null); - String valiSign = DigestUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); + String valiSign = DigestUtil.paysignMd5(result, + ACCOUNT3.getPaySignKey()); System.err .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); Assert.assertEquals(valiSign, sign); @@ -154,7 +153,8 @@ public class PayTest { System.err.println(result); String sign = result.getSign(); result.setSign(null); - String valiSign = DigestUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); + String valiSign = DigestUtil.paysignMd5(result, + ACCOUNT3.getPaySignKey()); System.err .println(String.format("sign=%s,valiSign=%s", sign, valiSign)); Assert.assertEquals(valiSign, sign); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java index ed60d93e..a1d809f7 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/QRTest.java @@ -29,19 +29,23 @@ public class QRTest extends TokenTest { @Test public void temp_qr() throws WeixinException, IOException { - File file = qrApi.createQRFile(QRParameter.createTemporary(1200, 1200)); + File file = qrApi.createQRFile(QRParameter.createTemporary(1200, 1200), + "/tmp/weixin4j/qrcode"); Assert.assertTrue(file.exists()); } @Test public void forever_qr_int() throws WeixinException, IOException { - File file = qrApi.createQRFile(QRParameter.createPermanenceInt(2)); + File file = qrApi.createQRFile(QRParameter.createPermanenceInt(2), + "/tmp/weixin4j/qrcode"); Assert.assertTrue(file.exists()); } @Test public void forever_qr_str() throws WeixinException, IOException { - File file = qrApi.createQRFile(QRParameter.createPermanenceStr("1200中文")); + File file = qrApi.createQRFile( + QRParameter.createPermanenceStr("1200中文"), + "/tmp/weixin4j/qrcode"); Assert.assertTrue(file.exists()); } } diff --git a/weixin4j-qy/CHANGE.md b/weixin4j-qy/CHANGE.md index 79464071..7d427724 100644 --- a/weixin4j-qy/CHANGE.md +++ b/weixin4j-qy/CHANGE.md @@ -168,3 +168,7 @@ * 2016-01-23 + 新增获取客服列表接口 + +* 2016-01-26 + + + 新增上传图文消息内的图片接口 \ No newline at end of file diff --git a/weixin4j-qy/README.md b/weixin4j-qy/README.md index 1f9163bc..8b6b6c5d 100644 --- a/weixin4j-qy/README.md +++ b/weixin4j-qy/README.md @@ -25,13 +25,13 @@ weixin4j-qy * PartyApi `部门管理API` -* ProviderApi `服务商API` + * ProviderApi `服务商API` -* SuiteApi `第三方应用API` + * SuiteApi `第三方应用API` -* TagApi `标签管理API` + * TagApi `标签管理API` -* UserApi `成员管理API` + * UserApi `成员管理API` 如何使用 @@ -61,25 +61,32 @@ weixin4j.properties说明 示例(properties中换行用右斜杆\\) weixin4j.account={"id":"corpid","secret":"corpsecret",\ - "suites":[{"id":"应用套件的id","secret":"应用套件的secret"}],\ - "providerSecret:"第三方提供商secret(企业号登陆)",\ - "chatSecret":"消息服务secret(企业号消息服务,暂时没用到)"} + "suites":[{"id":"应用套件的id","secret":"应用套件的secret"}],\ + "providerSecret":"第三方提供商secret(企业号登陆)",\ + "chatSecret":"消息服务secret(企业号消息服务,暂时没用到)",\ + "mchId":"微信商户号 微信支付时需要填入",\ + "certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\ + "paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"} + # 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.token.path=/tmp/weixin4j/token + # 二维码保存路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH) + weixin4j.qrcode.path=/tmp/weixin4j/qrcode + # 媒体文件保存路径(如果不填则默认为Weixin4jConst#DEFAULT_MEDIA_PATH) weixin4j.media.path=/tmp/weixin4j/media + # 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH) weixin4j.bill.path=/tmp/weixin4j/bill - # ca证书存放的完整路径 (证书文件后缀为*.p12) + # ca证书存放的完整路径 weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 - #classpath路径下:weixin4j.certificate.file=classpath:xxxxx.p12 + # classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH) + # weixin4j.certificate.file=classpath:xxxxx.pfx - #企业号用户身份授权后重定向的url(使用OauthApi时需要填写) - weixin4j.user.oauth.redirect.uri=http://xxx - - #企业号第三方管理员授权后重定向的url(使用OauthApi时需要填写) - weixin4j.third.oauth.redirect.uri=http://xxx - - #企业号第三方应用套件授权后重定向的url(使用OauthApi时需要填写) - weixin4j.suite.oauth.redirect.uri=http://xxx + # 企业号用户身份授权后重定向的url(在使用OauthApi时填写) + weixin4j.user.oauth.redirect.uri= + # 企业号第三方提供商授权后重定向的url(在使用OauthApi时填写) + weixin4j.third.oauth.redirect.uri= + # 企业号第三方应用套件授权后重定向的url(在使用OauthApi时填写) + weixin4j.suite.oauth.redirect.uri= 2.实例化微信企业号接口代理对象,调用具体的API方法 diff --git a/weixin4j-qy/pom.xml b/weixin4j-qy/pom.xml index d9d7656f..a2a0cf20 100644 --- a/weixin4j-qy/pom.xml +++ b/weixin4j-qy/pom.xml @@ -5,7 +5,7 @@ com.foxinmy weixin4j - 1.6.6 + 1.6.7 weixin4j-qy weixin4j-qy diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index 64f7d38c..ada1e02a 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -14,6 +14,7 @@ import com.foxinmy.weixin4j.model.MediaItem; import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.MediaUploadResult; import com.foxinmy.weixin4j.model.Pageable; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.qy.api.AgentApi; import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.ChatApi; @@ -22,7 +23,6 @@ import com.foxinmy.weixin4j.qy.api.MediaApi; import com.foxinmy.weixin4j.qy.api.MenuApi; import com.foxinmy.weixin4j.qy.api.NotifyApi; import com.foxinmy.weixin4j.qy.api.PartyApi; -import com.foxinmy.weixin4j.qy.api.QyApi; import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.message.ChatMessage; @@ -47,6 +47,7 @@ import com.foxinmy.weixin4j.qy.type.ChatType; import com.foxinmy.weixin4j.qy.type.InviteType; import com.foxinmy.weixin4j.qy.type.KfType; import com.foxinmy.weixin4j.qy.type.UserStatus; +import com.foxinmy.weixin4j.settings.Weixin4jSettings; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.tuple.MpArticle; @@ -76,50 +77,27 @@ public class WeixinProxy { private final ChatApi chatApi; private final TokenHolder tokenHolder; - private String corpId; + + private Weixin4jSettings settings; /** * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 */ public WeixinProxy() { - this(QyApi.DEFAULT_TOKEN_STORAGER); - } - - /** - * 默认使用weixin4j.properties配置的账号信息 - * - * @param tokenStorager - * token存储策略 - */ - public WeixinProxy(TokenStorager tokenStorager) { - this(QyApi.DEFAULT_WEIXIN_ACCOUNT.getId(), QyApi.DEFAULT_WEIXIN_ACCOUNT - .getSecret(), tokenStorager); - } - - /** - * corpid,corpsecret - * - * @param corpid - * @param corpsecret - */ - public WeixinProxy(String corpid, String corpsecret) { - this(corpid, corpsecret, QyApi.DEFAULT_TOKEN_STORAGER); + this(new Weixin4jSettings()); } /** * - * @param corpid - * 企业号ID - * @param corpsecret - * 企业号secret - * @param tokenStorager - * 企业号token存储器 + * @param settings + * 配置信息 + * @see com.foxinmy.weixin4j.settings.Weixin4jSettings */ - public WeixinProxy(String corpid, String corpsecret, - TokenStorager tokenStorager) { - this(new TokenHolder(new WeixinTokenCreator(corpid, corpsecret), - tokenStorager)); - this.corpId = corpid; + public WeixinProxy(Weixin4jSettings settings) { + this(new TokenHolder(new WeixinTokenCreator(settings.getAccount() + .getId(), settings.getAccount().getSecret()), + settings.getTokenStorager())); + this.settings = settings; } /** @@ -133,7 +111,7 @@ public class WeixinProxy { public WeixinProxy(WeixinTokenSuiteCreator tokenCreator, TokenStorager tokenStorager) { this(new TokenHolder(tokenCreator, tokenStorager)); - this.corpId = tokenCreator.getAuthCorpId(); + this.settings = new Weixin4jSettings(tokenCreator.getAuthCorpId(), null); } /** @@ -167,12 +145,12 @@ public class WeixinProxy { } /** - * 企业号ID + * 获取微信账号信息 * * @return */ - public String getCorpId() { - return this.corpId; + public WeixinAccount getWeixinAccount() { + return this.settings.getAccount(); } /** @@ -183,8 +161,9 @@ public class WeixinProxy { * @return */ public TokenHolder getTicketHolder(TicketType ticketType) { - return new TokenHolder(new WeixinTicketCreator(this.corpId, ticketType, - this.tokenHolder), this.tokenHolder.getTokenStorager()); + return new TokenHolder(new WeixinTicketCreator(getWeixinAccount() + .getId(), ticketType, this.tokenHolder), + this.tokenHolder.getTokenStorager()); } /** @@ -312,6 +291,25 @@ public class WeixinProxy { return menuApi.deleteMenu(agentid); } + /** + * 上传图文消息内的图片:用于上传图片到企业号服务端,接口返回图片url,请注意,该url仅可用于图文消息的发送, + * 且每个企业每天最多只能上传100张图片。 + * + * @param is + * 图片数据 + * @param fileName + * 文件名 + * @see 上传图文消息内的图片 + * @return 图片url + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @throws WeixinException + */ + public String uploadImage(InputStream is, String fileName) + throws WeixinException { + return mediaApi.uploadImage(is, fileName); + } + /** * 上传媒体文件 *

@@ -348,7 +346,7 @@ public class WeixinProxy { * 企业应用Id(大于0时视为获取永久媒体文件) * @param mediaId * 存储在微信服务器上的媒体标识 - * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 + * @return 写入硬盘后的文件对象 * @throws WeixinException * @see com.foxinmy.weixin4j.qy.api.MediaApi * @see com.foxinmy.weixin4j.type.MediaType @@ -356,7 +354,8 @@ public class WeixinProxy { */ public File downloadMediaFile(int agentid, String mediaId) throws WeixinException { - return mediaApi.downloadMediaFile(agentid, mediaId); + return mediaApi.downloadMediaFile(agentid, mediaId, + settings.getMediaPath()); } /** @@ -1334,5 +1333,5 @@ public class WeixinProxy { return chatApi.sendChatMessage(message); } - public final static String VERSION = "1.6.6"; + public final static String VERSION = "1.6.7"; } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java index 2f50b211..a5d42e03 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java @@ -3,19 +3,22 @@ package com.foxinmy.weixin4j.qy; import java.util.HashMap; import java.util.Map; +import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.qy.api.ProviderApi; -import com.foxinmy.weixin4j.qy.api.QyApi; import com.foxinmy.weixin4j.qy.api.SuiteApi; import com.foxinmy.weixin4j.qy.model.OUserInfo; import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; import com.foxinmy.weixin4j.qy.suite.SuiteTicketHolder; import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator; import com.foxinmy.weixin4j.qy.type.LoginTargetType; +import com.foxinmy.weixin4j.settings.Weixin4jSettings; +import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** * 微信第三方应用接口实现 @@ -34,20 +37,16 @@ public class WeixinSuiteProxy { private ProviderApi providerApi; public WeixinSuiteProxy() { - this(QyApi.DEFAULT_TOKEN_STORAGER); + this(Weixin4jSettings.DEFAULT_TOKEN_PATH); } /** * - * @param suiteId - * 应用ID - * @param suiteSecret - * 应用secret - * @throws WeixinException + * @param tokenPath + * 使用文件存储token的保存路径 */ - public WeixinSuiteProxy(String suiteId, String suiteSecret) { - this(QyApi.DEFAULT_TOKEN_STORAGER, null, null, new WeixinAccount( - suiteId, suiteSecret)); + public WeixinSuiteProxy(String tokenPath) { + this(new FileTokenStorager(tokenPath)); } /** @@ -56,7 +55,8 @@ public class WeixinSuiteProxy { * token存储 */ public WeixinSuiteProxy(TokenStorager tokenStorager) { - this(tokenStorager, QyApi.DEFAULT_WEIXIN_ACCOUNT); + this(tokenStorager, JSON.parseObject( + Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class)); } /** @@ -76,14 +76,14 @@ public class WeixinSuiteProxy { * * @param tokenStorager * token存储 - * @param corpId + * @param providerCorpId * 服务商的企业号ID 使用服务商API时必填项 * @param providerSecret * 服务商secret 使用服务商API时必填项 * @param suites * 套件信息 使用套件API时必填项 */ - public WeixinSuiteProxy(TokenStorager tokenStorager, String corpId, + public WeixinSuiteProxy(TokenStorager tokenStorager, String providerCorpId, String providerSecret, WeixinAccount... suites) { if (suites != null) { this.suiteMap = new HashMap(); @@ -94,11 +94,11 @@ public class WeixinSuiteProxy { this.suiteMap.put(null, suiteMap.get(suites[0].getId())); } } - if (StringUtil.isNotBlank(corpId) + if (StringUtil.isNotBlank(providerCorpId) && StringUtil.isNotBlank(providerSecret)) { this.providerApi = new ProviderApi(new TokenHolder( - new WeixinProviderTokenCreator(corpId, providerSecret), - tokenStorager)); + new WeixinProviderTokenCreator(providerCorpId, + providerSecret), tokenStorager)); } } @@ -160,5 +160,5 @@ public class WeixinSuiteProxy { return providerApi.getLoginUrl(corpId, targetType, agentId); } - public final static String VERSION = "1.6.6"; + public final static String VERSION = "1.6.7"; } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java index 6b55593a..f3b162f7 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java @@ -51,8 +51,6 @@ import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.RegexUtil; import com.foxinmy.weixin4j.util.StringUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; -import com.foxinmy.weixin4j.util.Weixin4jConst; import com.foxinmy.weixin4j.util.WeixinErrorUtil; /** @@ -199,17 +197,17 @@ public class MediaApi extends QyApi { * 企业应用Id(大于0时视为获取永久媒体文件) * @param mediaId * 存储在微信服务器上的媒体标识 - * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 + * @param mediaPath + * 媒体素材保存路径 + * @return 写入硬盘后的文件对象 * @throws WeixinException * @see com.foxinmy.weixin4j.type.MediaType * @see {@link #downloadMedia(int,String)} */ - public File downloadMediaFile(int agentid, String mediaId) + public File downloadMediaFile(int agentid, String mediaId, String mediaPath) throws WeixinException { - String media_path = Weixin4jConfigUtil.getValue("media.path", - Weixin4jConst.DEFAULT_MEDIA_PATH); final String prefixName = String.format("%d_%s.", agentid, mediaId); - File[] files = new File(media_path).listFiles(new FilenameFilter() { + File[] files = new File(mediaPath).listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith(prefixName); @@ -219,7 +217,7 @@ public class MediaApi extends QyApi { return files[0]; } MediaDownloadResult result = downloadMedia(agentid, mediaId); - File file = new File(media_path + File.separator + result.getFileName()); + File file = new File(mediaPath + File.separator + result.getFileName()); OutputStream os = null; try { if (file.createNewFile()) { diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java index 198a75ce..b45845cc 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/OauthApi.java @@ -4,6 +4,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import com.foxinmy.weixin4j.model.Consts; +import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** @@ -21,6 +22,15 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E6%8E%88%E6%9D%83">企业号第三方套件应用授权说明 */ public class OauthApi extends QyApi { + private final WeixinAccount account; + + public OauthApi() { + this(Weixin4jConfigUtil.getWeixinAccount()); + } + + public OauthApi(WeixinAccount account) { + this.account = account; + } /** * 企业号用户身份授权 @@ -30,7 +40,7 @@ public class OauthApi extends QyApi { * @return 请求授权的URL */ public String getUserAuthorizeURL() { - String corpId = DEFAULT_WEIXIN_ACCOUNT.getId(); + String corpId = account.getId(); String redirectUri = Weixin4jConfigUtil .getValue("user.oauth.redirect.uri"); return getUserAuthorizeURL(corpId, redirectUri, "state"); @@ -69,7 +79,7 @@ public class OauthApi extends QyApi { * @return 请求授权的URL */ public String getThirdAuthorizeURL() { - String corpId = DEFAULT_WEIXIN_ACCOUNT.getId(); + String corpId = account.getId(); String redirectUri = Weixin4jConfigUtil .getValue("third.oauth.redirect.uri"); return getThirdAuthorizeURL(corpId, redirectUri, "state"); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java index ae83125a..e31ca225 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java @@ -2,10 +2,7 @@ package com.foxinmy.weixin4j.qy.api; import java.util.ResourceBundle; -import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.api.BaseApi; -import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** * 微信企业号API @@ -20,16 +17,9 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; public class QyApi extends BaseApi { private final static ResourceBundle WEIXIN_BUNDLE; - /** - * 默认使用weixin4j.properties文件中的企业号信息 - */ - public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT; - static { WEIXIN_BUNDLE = ResourceBundle .getBundle("com/foxinmy/weixin4j/qy/api/weixin"); - DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( - Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class); } @Override diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java index 3321ab1f..338115ff 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/SuiteApi.java @@ -47,9 +47,6 @@ public class SuiteApi extends QyApi { * * @param suiteTicketHolder * 套件ticket存取 - * @param tokenStorager - * 应用token存储器 - * @throws WeixinException */ public SuiteApi(SuiteTicketHolder suiteTicketHolder) { this.suiteTicketHolder = suiteTicketHolder; diff --git a/weixin4j-qy/src/main/resources/weixin4j.properties b/weixin4j-qy/src/main/resources/weixin4j.properties index 5dfa1735..ac7dfcd1 100644 --- a/weixin4j-qy/src/main/resources/weixin4j.properties +++ b/weixin4j-qy/src/main/resources/weixin4j.properties @@ -1,26 +1,29 @@ # \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath # \u4f01\u4e1a\u53f7\u4fe1\u606f -weixin4j.account={"id":"id","secret":"secret",\ +weixin4j.account={"id":"wx5132afc5da26d661","secret":"GsnKLVDI1pWArdB60Ze4iP2cwFvcW5KCAs2vLJldipilmSYxtbkcAiBcGSHHvu_I",\ "suites":[{"id":"\u5e94\u7528\u5957\u4ef6\u7684id","secret":"\u5e94\u7528\u5957\u4ef6\u7684secret"}],\ "providerSecret":"\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546secret(\u4f01\u4e1a\u53f7\u767b\u9646)",\ -"chatSecret":"\u6d88\u606f\u670d\u52a1secret(\u4f01\u4e1a\u53f7\u6d88\u606f\u670d\u52a1,\u6682\u65f6\u6ca1\u7528\u5230)"} +"chatSecret":"\u6d88\u606f\u670d\u52a1secret(\u4f01\u4e1a\u53f7\u6d88\u606f\u670d\u52a1,\u6682\u65f6\u6ca1\u7528\u5230)",\ +"mchId":"\u5fae\u4fe1\u5546\u6237\u53f7 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ +"certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\ +"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84 +# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) weixin4j.token.path=/tmp/weixin4j/token -# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 +# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH) weixin4j.media.path=/tmp/weixin4j/media -# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84 +# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH) weixin4j.bill.path=/tmp/weixin4j/bill # ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12) weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 -# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199 +# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_CAFILE_PATH) # weixin4j.certificate.file=classpath:xxxxx.pfx -# \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url +# \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) weixin4j.user.oauth.redirect.uri= -# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url +# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) weixin4j.third.oauth.redirect.uri= -# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url +# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) weixin4j.suite.oauth.redirect.uri= \ No newline at end of file diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java index dd2e4e69..2b0aff37 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java @@ -47,7 +47,8 @@ public class MediaTest extends TokenTest { File file = mediaApi .downloadMediaFile( 0, - "1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw"); + "1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw", + "/tmp/weixin4j/media"); Assert.assertTrue(file.exists()); } diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java index c07753c8..d593b63b 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java @@ -28,8 +28,8 @@ public class TokenTest { WeixinAccount weixinAccount = Weixin4jConfigUtil.getWeixinAccount(); tokenHolder = new TokenHolder(new WeixinTokenCreator( weixinAccount.getId(), weixinAccount.getSecret()), - new FileTokenStorager(Weixin4jConfigUtil.getValue( - "token.path", "/tmp/weixin4j/token"))); + new FileTokenStorager(Weixin4jConfigUtil.getValue("token.path", + "/tmp/weixin4j/token"))); } @Test diff --git a/weixin4j-server/pom.xml b/weixin4j-server/pom.xml index 0849f287..5cbe6f68 100644 --- a/weixin4j-server/pom.xml +++ b/weixin4j-server/pom.xml @@ -5,10 +5,10 @@ com.foxinmy weixin4j - 1.6.6 + 1.6.7 weixin4j-server - 1.1.5 + 1.1.6 weixin4j-server https://github.com/foxinmy/weixin4j/tree/master/weixin4j-server 微信消息netty服务器 diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java index 8e0f040e..1c25cbaf 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java @@ -315,5 +315,5 @@ public final class WeixinServerBootstrap { return this; } - public final static String VERSION = "1.1.5"; + public final static String VERSION = "1.1.6"; } \ No newline at end of file