diff --git a/weixin4j-base/CHANGE.md b/weixin4j-base/CHANGE.md index 3b7b3213..b7b4677d 100644 --- a/weixin4j-base/CHANGE.md +++ b/weixin4j-base/CHANGE.md @@ -164,4 +164,8 @@ + type包拆分card/mch - + 新增card卡券相关类 \ No newline at end of file + + 新增card卡券相关类 + +* 2016-08-22 + + + 删除`Weixin4jSettings`配置类 \ No newline at end of file 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 bbf98a0b..07a3b416 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 @@ -1,7 +1,5 @@ package com.foxinmy.weixin4j.api; -import java.io.IOException; -import java.io.InputStream; import java.math.BigDecimal; import java.util.Date; import java.util.Map; @@ -48,8 +46,6 @@ public class CashApi extends MchApi { /** * 发放红包 企业向微信用户个人发现金红包 * - * @param certificate - * 后缀为*.p12的证书文件 * @param redpacket * 红包信息 * @return 发放结果 @@ -63,27 +59,16 @@ public class CashApi extends MchApi { * 发放裂变红包接口 * @throws WeixinException */ - public RedpacketSendResult sendRedpack(InputStream certificate, - Redpacket redpacket) throws WeixinException { + public RedpacketSendResult sendRedpack(Redpacket redpacket) + throws WeixinException { super.declareMerchant(redpacket); JSONObject obj = (JSONObject) JSON.toJSON(redpacket); obj.put("wxappid", obj.remove("appid")); obj.put("sign", weixinSignature.sign(obj)); String param = XmlStream.map2xml(obj); - WeixinResponse response = null; - try { - response = createSSLRequestExecutor(certificate) - .post(redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri") - : getRequestUri("redpack_send_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + WeixinResponse response = createSSLRequestExecutor() + .post(redpacket.getTotalNum() > 1 ? getRequestUri("groupredpack_send_uri") + : getRequestUri("redpack_send_uri"), param); String text = response.getAsString() .replaceFirst("", "") .replaceFirst("", ""); @@ -93,8 +78,6 @@ public class CashApi extends MchApi { /** * 查询红包记录 * - * @param certificate - * 后缀为*.p12的证书文件 * @param outTradeNo * 商户发放红包的商户订单号 * @return 红包记录 @@ -107,26 +90,15 @@ public class CashApi extends MchApi { * 查询裂变红包接口 * @throws WeixinException */ - public RedpacketRecord queryRedpack(InputStream certificate, - String outTradeNo) throws WeixinException { + public RedpacketRecord queryRedpack(String outTradeNo) + throws WeixinException { Map para = createBaseRequestMap(null); para.put("bill_type", "MCHT"); para.put("mch_billno", outTradeNo); para.put("sign", weixinSignature.sign(para)); String param = XmlStream.map2xml(para); - WeixinResponse response = null; - try { - response = createSSLRequestExecutor(certificate).post( - getRequestUri("redpack_query_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + WeixinResponse response = createSSLRequestExecutor().post( + getRequestUri("redpack_query_uri"), param); return response.getAsObject(new TypeReference() { }); } @@ -143,8 +115,6 @@ public class CashApi extends MchApi { *
  • 每个用户每天最多可付款10次,可以在商户平台--API安全进行设置 *
  • 给同一个用户付款时间间隔不得低于15秒 * - * @param certificate - * 后缀为*.p12的证书文件 * @param payment * 付款信息 * @return 付款结果 @@ -155,27 +125,16 @@ public class CashApi extends MchApi { * 企业付款接口 * @throws WeixinException */ - public CorpPaymentResult sendCorpPayment(InputStream certificate, - CorpPayment payment) throws WeixinException { + public CorpPaymentResult sendCorpPayment(CorpPayment payment) + throws WeixinException { super.declareMerchant(payment); JSONObject obj = (JSONObject) JSON.toJSON(payment); obj.put("mchid", obj.remove("mch_id")); obj.put("mch_appid", obj.remove("appid")); obj.put("sign", weixinSignature.sign(obj)); String param = XmlStream.map2xml(obj); - WeixinResponse response = null; - try { - response = createSSLRequestExecutor(certificate).post( - getRequestUri("corppayment_send_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + WeixinResponse response = createSSLRequestExecutor().post( + getRequestUri("corppayment_send_uri"), param); String text = response.getAsString() .replaceFirst("", "") .replaceFirst("", "") @@ -187,8 +146,6 @@ public class CashApi extends MchApi { /** * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 * - * @param certificate - * 后缀为*.p12的证书文件 * @param outTradeNo * 商户调用企业付款API时使用的商户订单号 * @return 付款记录 @@ -198,8 +155,8 @@ public class CashApi extends MchApi { * 企业付款查询接口 * @throws WeixinException */ - public CorpPaymentRecord queryCorpPayment(InputStream certificate, - String outTradeNo) throws WeixinException { + public CorpPaymentRecord queryCorpPayment(String outTradeNo) + throws WeixinException { JSONObject obj = new JSONObject(); obj.put("nonce_str", RandomUtil.generateString(16)); obj.put("mch_id", weixinAccount.getMchId()); @@ -207,19 +164,8 @@ public class CashApi extends MchApi { obj.put("partner_trade_no", outTradeNo); obj.put("sign", weixinSignature.sign(obj)); String param = XmlStream.map2xml(obj); - WeixinResponse response = null; - try { - response = createSSLRequestExecutor(certificate).post( - getRequestUri("corppayment_query_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + WeixinResponse response = createSSLRequestExecutor().post( + getRequestUri("corppayment_query_uri"), param); return response.getAsObject(new TypeReference() { }); } 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 c180c0fb..91a9087b 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 @@ -1,7 +1,5 @@ package com.foxinmy.weixin4j.api; -import java.io.IOException; -import java.io.InputStream; import java.util.Map; import com.alibaba.fastjson.TypeReference; @@ -21,7 +19,8 @@ import com.foxinmy.weixin4j.xml.XmlStream; * @author jinyu(foxinmy@gmail.com) * @date 2015年3月25日 * @since JDK 1.6 - * @see 代金券 + * @see 代金券 */ public class CouponApi extends MchApi { @@ -32,8 +31,6 @@ public class CouponApi extends MchApi { /** * 发放代金券(需要证书) * - * @param certificate - * 后缀为*.p12的证书文件 * @param couponStockId * 代金券批次id * @param partnerTradeNo @@ -48,9 +45,8 @@ public class CouponApi extends MchApi { * href="https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3">发放代金券接口 * @throws WeixinException */ - public CouponResult sendCoupon(InputStream certificate, - String couponStockId, String partnerTradeNo, String openId, - String opUserId) throws WeixinException { + public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, + String openId, String opUserId) throws WeixinException { Map map = createBaseRequestMap(null); map.put("coupon_stock_id", couponStockId); map.put("partner_trade_no", partnerTradeNo); @@ -66,19 +62,8 @@ public class CouponApi extends MchApi { map.put("type", "XML"); map.put("sign", weixinSignature.sign(map)); String param = XmlStream.map2xml(map); - WeixinResponse response = null; - try { - response = createSSLRequestExecutor(certificate).post( - getRequestUri("coupon_send_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + WeixinResponse response = createSSLRequestExecutor().post( + getRequestUri("coupon_send_uri"), param); return response.getAsObject(new TypeReference() { }); } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java index 86f41639..46e432ea 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/MchApi.java @@ -1,5 +1,8 @@ package com.foxinmy.weixin4j.api; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; @@ -55,10 +58,22 @@ public class MchApi extends BaseApi { * @return * @throws WeixinException */ - protected WeixinRequestExecutor createSSLRequestExecutor( - InputStream certificate) throws WeixinException { + protected WeixinRequestExecutor createSSLRequestExecutor() + throws WeixinException { + InputStream certificateFile; + try { + File certificate = new File(weixinAccount.getCertificateFile()); + if (!certificate.exists() || !certificate.isFile()) { + throw new WeixinException("invalid certificate file : " + + certificate.toString()); + } + certificateFile = new FileInputStream( + weixinAccount.getCertificateFile()); + } catch (IOException e) { + throw new WeixinException("IO Error on createSSLRequestExecutor", e); + } return weixinExecutor.createSSLRequestExecutor( - weixinAccount.getCertificateKey(), certificate); + weixinAccount.getCertificateKey(), certificateFile); } /** diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java index a1c1eab9..ebea6196 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/PayApi.java @@ -2,11 +2,9 @@ package com.foxinmy.weixin4j.api; import java.io.BufferedReader; import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -213,7 +211,7 @@ public class PayApi extends MchApi { * "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4">模式一 * */ - public String createNativePayRequestURL(String productId) { + public String createNativePayRequest(String productId) { Map map = new HashMap(); String timestamp = DateUtil.timestamp2string(); String noncestr = RandomUtil.generateString(16); @@ -435,8 +433,6 @@ public class PayApi extends MchApi { * ,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。 *

    * - * @param certificate - * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -458,36 +454,28 @@ public class PayApi extends MchApi { * @since V3 * @throws WeixinException */ - public RefundResult applyRefund(InputStream certificate, IdQuery idQuery, - String outRefundNo, double totalFee, double refundFee, - CurrencyType refundFeeType, String opUserId) throws WeixinException { + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee, double refundFee, CurrencyType refundFeeType, + String opUserId) throws WeixinException { WeixinResponse response = null; - try { - Map map = createBaseRequestMap(idQuery); - map.put("out_refund_no", outRefundNo); - map.put("total_fee", Integer.toString(DateUtil.formatYuan2Fen(totalFee))); - map.put("refund_fee", Integer.toString(DateUtil.formatYuan2Fen(refundFee))); - if (StringUtil.isBlank(opUserId)) { - opUserId = weixinAccount.getMchId(); - } - map.put("op_user_id", opUserId); - if (refundFeeType == null) { - refundFeeType = CurrencyType.CNY; - } - map.put("refund_fee_type", refundFeeType.name()); - map.put("sign", weixinSignature.sign(map)); - String param = XmlStream.map2xml(map); - response = createSSLRequestExecutor(certificate).post( - getRequestUri("refund_apply_uri"), param); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } + Map map = createBaseRequestMap(idQuery); + map.put("out_refund_no", outRefundNo); + map.put("total_fee", + Integer.toString(DateUtil.formatYuan2Fen(totalFee))); + map.put("refund_fee", + Integer.toString(DateUtil.formatYuan2Fen(refundFee))); + if (StringUtil.isBlank(opUserId)) { + opUserId = weixinAccount.getMchId(); } + map.put("op_user_id", opUserId); + if (refundFeeType == null) { + refundFeeType = CurrencyType.CNY; + } + map.put("refund_fee_type", refundFeeType.name()); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + response = createSSLRequestExecutor().post( + getRequestUri("refund_apply_uri"), param); return response.getAsObject(new TypeReference() { }); } @@ -495,8 +483,6 @@ public class PayApi extends MchApi { /** * 退款申请(全额退款) * - * @param certificate - * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -504,12 +490,11 @@ public class PayApi extends MchApi { * 商户系统内部的退款单号,商 户系统内部唯一,同一退款单号多次请求只退一笔 * @param totalFee * 订单总金额,单位为元 - * @see {@link #applyRefund(InputStream, IdQuery, String, double, double,CurrencyType, String)} + * @see {@link #applyRefund(IdQuery, String, double, double,CurrencyType, String)} */ - public RefundResult applyRefund(InputStream certificate, IdQuery idQuery, - String outRefundNo, double totalFee) throws WeixinException { - return applyRefund(certificate, idQuery, outRefundNo, totalFee, - totalFee, null, null); + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee) throws WeixinException { + return applyRefund(idQuery, outRefundNo, totalFee, totalFee, null, null); } /** @@ -518,8 +503,6 @@ public class PayApi extends MchApi { * 如需实现相同功能请调用退款接口
    调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
    * - * @param certificate - * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -527,25 +510,14 @@ public class PayApi extends MchApi { * @since V3 * @throws WeixinException */ - public MerchantResult reverseOrder(InputStream certificate, IdQuery idQuery) - throws WeixinException { - try { - Map map = createBaseRequestMap(idQuery); - map.put("sign", weixinSignature.sign(map)); - String param = XmlStream.map2xml(map); - WeixinResponse response = createSSLRequestExecutor(certificate) - .post(getRequestUri("order_reverse_uri"), param); - return response.getAsObject(new TypeReference() { - }); - } finally { - if (certificate != null) { - try { - certificate.close(); - } catch (IOException e) { - ; - } - } - } + public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException { + Map map = createBaseRequestMap(idQuery); + map.put("sign", weixinSignature.sign(map)); + String param = XmlStream.map2xml(map); + WeixinResponse response = createSSLRequestExecutor().post( + getRequestUri("order_reverse_uri"), param); + return response.getAsObject(new TypeReference() { + }); } /** @@ -614,17 +586,16 @@ public class PayApi extends MchApi { * @param billType * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 * REFUND,返回当日退款订单 - * @param billPath - * 对账单保存路径 - * @return excel表格 + * @param outputStream + * 输出流 * @since V3 * @see * 下载对账单API * @throws WeixinException */ - public File downloadBill(Date billDate, BillType billType, String billPath) - throws WeixinException { + public void downloadBill(Date billDate, BillType billType, + OutputStream outputStream) throws WeixinException { if (billDate == null) { Calendar now = Calendar.getInstance(); now.add(Calendar.DAY_OF_MONTH, -1); @@ -634,14 +605,6 @@ public class PayApi extends MchApi { billType = BillType.ALL; } String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); - String fileName = String.format("weixin4j_bill_%s_%s_%s.txt", - formatBillDate, billType.name().toLowerCase(), - weixinAccount.getId()); - File file = new File(String.format("%s%s%s", billPath, File.separator, - fileName)); - if (file.exists()) { - return file; - } Map map = createBaseRequestMap(null); map.put("bill_date", formatBillDate); map.put("bill_type", billType.name()); @@ -653,8 +616,8 @@ public class PayApi extends MchApi { BufferedReader reader = null; BufferedWriter writer = null; try { - writer = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(file), Consts.UTF_8)); + writer = new BufferedWriter(new OutputStreamWriter(outputStream, + Consts.UTF_8)); reader = new BufferedReader(new InputStreamReader( response.getBody(), Consts.UTF_8)); String line = null; @@ -676,7 +639,6 @@ public class PayApi extends MchApi { ; } } - return file; } /** diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/cache/FileCacheStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/cache/FileCacheStorager.java index fdff41b3..0501d50d 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/cache/FileCacheStorager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/cache/FileCacheStorager.java @@ -21,6 +21,18 @@ public class FileCacheStorager implements CacheStorager private final File tmpdir; private final String SEPARATOR = File.separator; + /** + * 默认缓存路径:java.io.tmpdir + */ + public FileCacheStorager() { + this(System.getProperty("java.io.tmpdir")); + } + + /** + * + * @param path + * 缓存文件报错 + */ public FileCacheStorager(String path) { this.tmpdir = new File(String.format("%s%s%s", path, SEPARATOR, ALLKEY)); this.tmpdir.mkdirs(); @@ -28,14 +40,17 @@ public class FileCacheStorager implements CacheStorager @Override public T lookup(String key) { - File cacheFile = new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key)); + File cacheFile = new File(String.format("%s%s%s", + tmpdir.getAbsolutePath(), SEPARATOR, key)); try { if (cacheFile.exists()) { - T cache = SerializationUtils.deserialize(new FileInputStream(cacheFile)); + T cache = SerializationUtils.deserialize(new FileInputStream( + cacheFile)); if (cache.getCreateTime() < 0) { return cache; } - if ((cache.getCreateTime() + cache.getExpires() - CUTMS) > System.currentTimeMillis()) { + if ((cache.getCreateTime() + cache.getExpires() - CUTMS) > System + .currentTimeMillis()) { return cache; } } @@ -48,8 +63,10 @@ public class FileCacheStorager implements CacheStorager @Override public void caching(String key, T cache) { try { - SerializationUtils.serialize(cache, - new FileOutputStream(new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key)))); + SerializationUtils.serialize( + cache, + new FileOutputStream(new File(String.format("%s%s%s", + tmpdir.getAbsolutePath(), SEPARATOR, key)))); } catch (IOException e) { throw new RuntimeException(e); } @@ -58,10 +75,12 @@ public class FileCacheStorager implements CacheStorager @Override public T evict(String key) { T cache = null; - File cacheFile = new File(String.format("%s%s%s", tmpdir.getAbsolutePath(), SEPARATOR, key)); + File cacheFile = new File(String.format("%s%s%s", + tmpdir.getAbsolutePath(), SEPARATOR, key)); try { if (cacheFile.exists()) { - cache = SerializationUtils.deserialize(new FileInputStream(cacheFile)); + cache = SerializationUtils.deserialize(new FileInputStream( + cacheFile)); cacheFile.delete(); } } catch (IOException e) { diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java index 70ddea1b..f24cf664 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/weixin/WeixinRequestExecutor.java @@ -124,8 +124,7 @@ public class WeixinRequestExecutor { * @return 微信响应 * @throws WeixinException */ - public WeixinResponse doRequest(HttpRequest request) - throws WeixinException { + public WeixinResponse doRequest(HttpRequest request) throws WeixinException { try { if (logger.isEnabled(InternalLogLevel.DEBUG)) { logger.debug("weixin request >> " + request.getMethod() + " " @@ -227,6 +226,12 @@ public class WeixinRequestExecutor { new java.security.SecureRandom()); return createSSLRequestExecutor(sslContext); } catch (Exception e) { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ignore) { + } + } throw new WeixinException("Key load error", e); } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java index 8e548b4c..a25f8755 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/Token.java @@ -95,10 +95,6 @@ public class Token implements Cacheable { return extra; } - public void setExtra(Map extra) { - this.extra = extra; - } - public Token pushExtra(String name, String value) { this.extra.put(name, value); return this; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinAccount.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinAccount.java index 3eba3f99..53520d2a 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinAccount.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/WeixinAccount.java @@ -21,11 +21,11 @@ public class WeixinAccount implements Serializable { /** * 唯一的身份标识 */ - private String id; + private final String id; /** * 调用接口的密钥 */ - private String secret; + private final String secret; @JSONCreator public WeixinAccount(@JSONField(name = "id") String id, 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 74d7ab98..2f2d0a7b 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 @@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.model; import com.alibaba.fastjson.annotation.JSONCreator; import com.alibaba.fastjson.annotation.JSONField; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** * 微信支付账户 @@ -19,20 +20,23 @@ public class WeixinPayAccount extends WeixinAccount { /** * 公众号支付请求中用于加密的密钥 */ - private String paySignKey; + private final String paySignKey; /** * 微信支付分配的商户号 */ - private String mchId; + private final String mchId; /** * 加载支付证书文件的密码(默认为商户号) */ private String certificateKey; + /** + * 商户证书文件(默认加载classpath:ca.p12) + */ + private String certificateFile; /** * 微信支付分配的设备号 */ private String deviceInfo; - /** * 财付通商户身份的标识 */ @@ -58,7 +62,27 @@ public class WeixinPayAccount extends WeixinAccount { * 微信支付分配的商户号(必填) */ public WeixinPayAccount(String id, String paySignKey, String mchId) { - this(id, null, paySignKey, mchId, null, null, null, null, null); + this(id, paySignKey, mchId, mchId, "classpath:ca.p12"); + } + + /** + * 支付商户信息 + * + * @param id + * 公众号唯一的身份ID(必填) + * @param paySignKey + * 支付密钥字符串(必填) + * @param mchId + * 微信支付分配的商户号(必填) + * @param certificateKey + * 加载支付证书文件的密码(默认为商户号) + * @param certificateFile + * 商户证书文件(默认加载classpath:ca.p12) + */ + public WeixinPayAccount(String id, String paySignKey, String mchId, + String certificateKey, String certificateFile) { + this(id, null, paySignKey, mchId, certificateKey, certificateFile, + null, null, null, null); } /** @@ -74,6 +98,8 @@ public class WeixinPayAccount extends WeixinAccount { * 微信支付分配的商户号(必填) * @param certificateKey * 加载支付证书文件的密码(默认为商户号) + * @param certificateFile + * 商户证书文件(默认加载classpath:ca.p12) * @param deviceInfo * 微信支付分配的设备号(非必填) * @param partnerId @@ -89,6 +115,7 @@ public class WeixinPayAccount extends WeixinAccount { @JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "mchId") String mchId, @JSONField(name = "certificateKey") String certificateKey, + @JSONField(name = "certificateFile") String certificateFile, @JSONField(name = "deviceInfo") String deviceInfo, @JSONField(name = "partnerId") String partnerId, @JSONField(name = "subId") String subId, @@ -97,6 +124,7 @@ public class WeixinPayAccount extends WeixinAccount { this.paySignKey = paySignKey; this.mchId = mchId; this.certificateKey = certificateKey; + this.certificateFile = certificateFile; this.deviceInfo = deviceInfo; this.partnerId = partnerId; this.subId = subId; @@ -131,12 +159,40 @@ public class WeixinPayAccount extends WeixinAccount { return subMchId; } + public void setCertificateKey(String certificateKey) { + this.certificateKey = certificateKey; + } + + public String getCertificateFile() { + return Weixin4jConfigUtil.replaceClassPathValue(certificateFile); + } + + public void setCertificateFile(String certificateFile) { + this.certificateFile = certificateFile; + } + + public void setDeviceInfo(String deviceInfo) { + this.deviceInfo = deviceInfo; + } + + public void setPartnerId(String partnerId) { + this.partnerId = partnerId; + } + + public void setSubId(String subId) { + this.subId = subId; + } + + public void setSubMchId(String subMchId) { + this.subMchId = subMchId; + } + @Override public String toString() { return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + paySignKey + ", mchId=" + mchId + ", certificateKey=" - + certificateKey + ", deviceInfo=" + deviceInfo - + ", partnerId=" + partnerId + ", subId=" + subId - + ", subMchId=" + subMchId + "]"; + + certificateKey + ",certificateFile =" + certificateFile + + ", deviceInfo=" + deviceInfo + ", partnerId=" + partnerId + + ", subId=" + subId + ", subMchId=" + subMchId + "]"; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/media/MediaCounter.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/media/MediaCounter.java index 6b87a0c1..160454a2 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/media/MediaCounter.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/media/MediaCounter.java @@ -23,7 +23,7 @@ public class MediaCounter implements Serializable { @JSONField(name = "total_count") private int totalCount; /** - * 文件素材总数目(企业号都有) + * 文件素材总数目(企业号独有) */ @JSONField(name = "file_count") private int fileCount; 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 6688d2ea..0c07aacf 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 @@ -1,9 +1,7 @@ package com.foxinmy.weixin4j.payment; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; +import java.io.OutputStream; import java.util.Date; import com.alibaba.fastjson.JSON; @@ -37,7 +35,6 @@ import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult; import com.foxinmy.weixin4j.payment.mch.RefundRecord; import com.foxinmy.weixin4j.payment.mch.RefundResult; import com.foxinmy.weixin4j.payment.mch.SettlementRecord; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.sign.WeixinSignature; import com.foxinmy.weixin4j.type.CurrencyType; import com.foxinmy.weixin4j.type.CustomsCity; @@ -73,32 +70,34 @@ public class WeixinPayProxy { */ private final CustomsApi customsApi; /** - * 配置信息 + * 商户信息 */ - private final Weixin4jSettings settings; + private final WeixinPayAccount weixinPayAccount; /** - * 使用weixin4j.properties配置的支付账号信息 + * 微信支付接口实现(使用weixin4j.properties配置的account商户信息) */ public WeixinPayProxy() { - this( - new Weixin4jSettings(JSON.parseObject( - Weixin4jConfigUtil.getValue("account"), - WeixinPayAccount.class))); + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinPayAccount.class)); } /** - * - * @param settings - * 支付相关配置信息 - * @see com.foxinmy.weixin4j.setting.Weixin4jSettings + * 微信支付接口实现 + * + * @param weixinPayAccount + * 微信商户信息 */ - public WeixinPayProxy(Weixin4jSettings settings) { - this.settings = settings; - this.payApi = new PayApi(settings.getAccount()); - this.couponApi = new CouponApi(settings.getAccount()); - this.cashApi = new CashApi(settings.getAccount()); - this.customsApi = new CustomsApi(settings.getAccount()); + public WeixinPayProxy(WeixinPayAccount weixinPayAccount) { + if (weixinPayAccount == null) { + throw new IllegalArgumentException( + "weixinPayAccount must not be empty"); + } + this.weixinPayAccount = weixinPayAccount; + this.payApi = new PayApi(weixinPayAccount); + this.couponApi = new CouponApi(weixinPayAccount); + this.cashApi = new CashApi(weixinPayAccount); + this.customsApi = new CustomsApi(weixinPayAccount); } /** @@ -107,7 +106,7 @@ public class WeixinPayProxy { * @return */ public WeixinPayAccount getWeixinPayAccount() { - return settings.getAccount(); + return weixinPayAccount; } /** @@ -227,8 +226,8 @@ public class WeixinPayProxy { * "https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4">模式一 * */ - public String createNativePayRequestURL(String productId) { - return payApi.createNativePayRequestURL(productId); + public String createNativePayRequest(String productId) { + return payApi.createNativePayRequest(productId); } /** @@ -431,8 +430,6 @@ public class WeixinPayProxy { * ,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。 *

    * - * @param certificate - * 后缀为*.p12的证书文件 * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -456,11 +453,11 @@ public class WeixinPayProxy { * @since V3 * @throws WeixinException */ - public RefundResult applyRefund(InputStream certificate, IdQuery idQuery, - String outRefundNo, double totalFee, double refundFee, - CurrencyType refundFeeType, String opUserId) throws WeixinException { - return payApi.applyRefund(certificate, idQuery, outRefundNo, totalFee, - refundFee, refundFeeType, opUserId); + public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, + double totalFee, double refundFee, CurrencyType refundFeeType, + String opUserId) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee, refundFee, + refundFeeType, opUserId); } /** @@ -468,13 +465,11 @@ public class WeixinPayProxy { * * @throws IOException * - * @see {@link #applyRefund(InputStream, IdQuery, String, double, double, String,CurrencyType)} + * @see {@link #applyRefund(IdQuery, String, double, double, String,CurrencyType)} */ public RefundResult applyRefund(IdQuery idQuery, String outRefundNo, - double totalFee) throws WeixinException, IOException { - return payApi.applyRefund( - new FileInputStream(settings.getCertificateFile0()), idQuery, - outRefundNo, totalFee); + double totalFee) throws WeixinException { + return payApi.applyRefund(idQuery, outRefundNo, totalFee); } /** @@ -512,7 +507,7 @@ public class WeixinPayProxy { * @param billType * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 * REFUND,返回当日退款订单 - * @return excel表格 + * @para outputStream 输出流 * @since V2 & V3 * @see com.foxinmy.weixin4j.api.PayApi * @see * @throws WeixinException */ - public File downloadBill(Date billDate, BillType billType) - throws WeixinException { - return payApi.downloadBill(billDate, billType, settings.getTmpdir0()); + public void downloadBill(Date billDate, BillType billType, + OutputStream outputStream) throws WeixinException { + payApi.downloadBill(billDate, billType, outputStream); } /** @@ -531,8 +526,6 @@ public class WeixinPayProxy { * 如需实现相同功能请调用退款接口
    调用扣款接口后请勿立即调用撤销,需要等待5秒以上。先调用查单接口,如果没有确切的返回,再调用撤销
    * - * @param certificate - * 证书文件(V2版本后缀为*.pfx,V3版本后缀为*.p12) * @param idQuery * 商户系统内部的订单号, transaction_id 、 out_trade_no 二选一,如果同时存在优先级: * transaction_id> out_trade_no @@ -541,25 +534,8 @@ public class WeixinPayProxy { * @since V3 * @throws WeixinException */ - public MerchantResult reverseOrder(InputStream certificate, IdQuery idQuery) - throws WeixinException { - return payApi.reverseOrder(certificate, idQuery); - } - - /** - * 冲正撤销 - * - * @param idQuery - * transaction_id、out_trade_no 二选一 - * @return 撤销结果 - * @see {@link #reverseOrder(InputStream, IdQuery)} - * @throws WeixinException - * @throws IOException - */ - public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException, - IOException { - return payApi.reverseOrder( - new FileInputStream(settings.getCertificateFile0()), idQuery); + public MerchantResult reverseOrder(IdQuery idQuery) throws WeixinException { + return payApi.reverseOrder(idQuery); } /** @@ -634,8 +610,6 @@ public class WeixinPayProxy { /** * 发放代金券(需要证书) * - * @param certificate - * 后缀为*.p12的证书文件 * @param couponStockId * 代金券批次id * @param partnerTradeNo @@ -652,23 +626,10 @@ public class WeixinPayProxy { * 发放代金券接口
    * @throws WeixinException */ - public CouponResult sendCoupon(InputStream certificate, - String couponStockId, String partnerTradeNo, String openId, - String opUserId) throws WeixinException { - return couponApi.sendCoupon(certificate, couponStockId, partnerTradeNo, - openId, opUserId); - } - - /** - * 发放代金券 - * - * @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(settings.getCertificateFile0()), - couponStockId, partnerTradeNo, openId, null); + String openId, String opUserId) throws WeixinException { + return couponApi.sendCoupon(couponStockId, partnerTradeNo, openId, + opUserId); } /** @@ -710,8 +671,6 @@ public class WeixinPayProxy { /** * 发放红包 企业向微信用户个人发现金红包 * - * @param certificate - * 后缀为*.p12的证书文件 * @param redpacket * 红包信息 * @return 发放结果 @@ -726,27 +685,14 @@ public class WeixinPayProxy { * 发放裂变红包接口 * @throws WeixinException */ - public RedpacketSendResult sendRedpack(InputStream certificate, - Redpacket redpacket) throws WeixinException { - return cashApi.sendRedpack(certificate, redpacket); - } - - /** - * 发放红包 - * - * @see {@link #sendRedpack(InputStream, Redpacket)} - */ public RedpacketSendResult sendRedpack(Redpacket redpacket) - throws WeixinException, IOException { - return cashApi.sendRedpack( - new FileInputStream(settings.getCertificateFile0()), redpacket); + throws WeixinException { + return cashApi.sendRedpack(redpacket); } /** * 查询红包记录 * - * @param certificate - * 后缀为*.p12的证书文件 * @param outTradeNo * 商户发放红包的商户订单号 * @return 红包记录 @@ -760,22 +706,9 @@ public class WeixinPayProxy { * 查询裂变红包接口 * @throws WeixinException */ - public RedpacketRecord queryRedpack(InputStream certificate, - String outTradeNo) throws WeixinException { - return cashApi.queryRedpack(certificate, outTradeNo); - } - - /** - * 查询红包 - * - * @see {@link #queryRedpack(InputStream,String)} - */ public RedpacketRecord queryRedpack(String outTradeNo) - throws WeixinException, IOException { - return cashApi - .queryRedpack( - new FileInputStream(settings.getCertificateFile0()), - outTradeNo); + throws WeixinException { + return cashApi.queryRedpack(outTradeNo); } /** @@ -790,8 +723,6 @@ public class WeixinPayProxy { *
  • 每个用户每天最多可付款10次,可以在商户平台--API安全进行设置 *
  • 给同一个用户付款时间间隔不得低于15秒 * - * @param certificate - * 后缀为*.p12的证书文件 * @param payment * 付款信息 * @return 付款结果 @@ -803,27 +734,14 @@ public class WeixinPayProxy { * 企业付款接口 * @throws WeixinException */ - public CorpPaymentResult sendCorpPayment(InputStream certificate, - CorpPayment payment) throws WeixinException { - return cashApi.sendCorpPayment(certificate, payment); - } - - /** - * 企业付款 - * - * @see {@link #sendCorpPayment(InputStream, CorpPayment)} - */ public CorpPaymentResult sendCorpPayment(CorpPayment payment) - throws WeixinException, IOException { - return cashApi.sendCorpPayment( - new FileInputStream(settings.getCertificateFile0()), payment); + throws WeixinException { + return cashApi.sendCorpPayment(payment); } /** * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 * - * @param certificate - * 后缀为*.p12的证书文件 * @param outTradeNo * 商户调用企业付款API时使用的商户订单号 * @return 付款记录 @@ -834,22 +752,9 @@ public class WeixinPayProxy { * 企业付款查询接口 * @throws WeixinException */ - public CorpPaymentRecord queryCorpPayment(InputStream certificate, - String outTradeNo) throws WeixinException { - return cashApi.queryCorpPayment(certificate, outTradeNo); - } - - /** - * 企业付款查询 - * - * @see {@link #CorpPaymentRecord(InputStream, String)} - */ public CorpPaymentRecord queryCorpPayment(String outTradeNo) - throws WeixinException, IOException { - return cashApi - .queryCorpPayment( - new FileInputStream(settings.getCertificateFile0()), - outTradeNo); + throws WeixinException { + return cashApi.queryCorpPayment(outTradeNo); } /** diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/setting/Weixin4jSettings.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/setting/Weixin4jSettings.java deleted file mode 100644 index aa9d95dd..00000000 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/setting/Weixin4jSettings.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.foxinmy.weixin4j.setting; - -import com.foxinmy.weixin4j.cache.CacheStorager; -import com.foxinmy.weixin4j.cache.FileCacheStorager; -import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.util.StringUtil; -import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; - -/** - * 微信配置相关 - * - * @className Weixin4jSettings - * @author jinyu(foxinmy@gmail.com) - * @date 2016年1月28日 - * @since JDK 1.6 - * @see - */ -public class Weixin4jSettings { - /** - * 账号信息 - */ - private final T account; - /** - * 系统临时目录 - */ - private String tmpdir; - /** - * Token的存储方式 默认为FileCacheStorager - */ - private CacheStorager cacheStorager; - /** - * 支付接口需要的证书文件(*.p12) - */ - private String certificateFile; - - public Weixin4jSettings(T account) { - this.account = account; - } - - public T getAccount() { - return account; - } - - public String getTmpdir() { - return tmpdir; - } - - public void setTmpdir(String tmpdir) { - this.tmpdir = tmpdir; - } - - public String getTmpdir0() { - if (StringUtil.isBlank(tmpdir)) { - return Weixin4jConfigUtil.getValue("weixin4j.tmpdir", - System.getProperty("java.io.tmpdir")); - } - return tmpdir; - } - - public CacheStorager getCacheStorager() { - return cacheStorager; - } - - public CacheStorager getCacheStorager0() { - if (cacheStorager == null) { - return new FileCacheStorager(getTmpdir0()); - } - return cacheStorager; - } - - public void setCacheStorager(CacheStorager cacheStorager) { - this.cacheStorager = cacheStorager; - } - - public String getCertificateFile() { - return certificateFile; - } - - public String getCertificateFile0() { - if (StringUtil.isBlank(certificateFile)) { - return Weixin4jConfigUtil.getClassPathValue( - "weixin4j.certificate.file", "classpath:ca.p12"); - } - return certificateFile; - } - - public void setCertificateFile(String certificateFile) { - this.certificateFile = certificateFile; - } - - @Override - public String toString() { - return "Weixin4jSettings [account=" + account + ", tmpdir=" + tmpdir - + ", cacheStorager=" + cacheStorager + ", certificateFile=" - + certificateFile + "]"; - } -} \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java index 44538c57..b9d27151 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenManager.java @@ -13,10 +13,10 @@ import com.foxinmy.weixin4j.model.Token; * @date 2015年6月12日 * @since JDK 1.6 * @see TokenCreator + * @see com.foxinmy.weixin4j.token.TokenCreator * @see com.foxinmy.weixin4j.cache.CacheStorager */ public class TokenManager extends CacheManager { - /** * * @param tokenCreator 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 23ec87d4..91cc81da 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 @@ -20,7 +20,8 @@ public class Weixin4jConfigUtil { private final static String CLASSPATH_VALUE; private static ResourceBundle weixinBundle; static { - CLASSPATH_VALUE = Thread.currentThread().getContextClassLoader().getResource("").getPath(); + CLASSPATH_VALUE = Thread.currentThread().getContextClassLoader() + .getResource("").getPath(); try { weixinBundle = ResourceBundle.getBundle(Consts.WEIXIN4J); } catch (MissingResourceException e) { @@ -77,7 +78,7 @@ public class Weixin4jConfigUtil { * @return */ public static String getClassPathValue(String key) { - return getValue(key).replaceFirst(CLASSPATH_PREFIX, CLASSPATH_VALUE); + return replaceClassPathValue(getValue(key)); } /** @@ -87,7 +88,11 @@ public class Weixin4jConfigUtil { * @return */ public static String getClassPathValue(String key, String defaultValue) { - return getValue(key, defaultValue).replaceFirst(CLASSPATH_PREFIX, CLASSPATH_VALUE); + return replaceClassPathValue(getValue(key, defaultValue)); + } + + public static String replaceClassPathValue(String value) { + return value.replaceFirst(CLASSPATH_PREFIX, CLASSPATH_VALUE); } /** @@ -98,11 +103,14 @@ public class Weixin4jConfigUtil { public static WeixinAccount getWeixinAccount() { WeixinAccount account = null; try { - account = JSON.parseObject(getValue("account"), WeixinAccount.class); + account = JSON + .parseObject(getValue("account"), WeixinAccount.class); } catch (NullPointerException e) { - System.err.println("'weixin4j.account' key not found in weixin4j.properties."); + 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."); + System.err + .println("'weixin4j.account' key not found in weixin4j.properties."); } return account; } diff --git a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CashTest.java b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CashTest.java index 680ee70a..c7c04683 100644 --- a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CashTest.java +++ b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CashTest.java @@ -1,8 +1,5 @@ package com.foxinmy.weixin4j.base.test; -import java.io.FileInputStream; -import java.io.IOException; - import org.junit.Assert; import org.junit.Test; @@ -28,43 +25,39 @@ import com.foxinmy.weixin4j.util.Consts; public class CashTest extends PayTest { @Test - public void sendRedpacket() throws WeixinException, IOException { + public void sendRedpacket() throws WeixinException { Redpacket redpacket = new Redpacket("HB001", "无忧钱庄", "oyFLst1bqtuTcxK-ojF8hOGtLQao", 1d, 1, "红包测试", "127.0.0.1", "快来领取红包吧!", "来就送钱"); - RedpacketSendResult result = PAY.sendRedpack( - new FileInputStream(caFile), redpacket); + RedpacketSendResult result = PAY.sendRedpack(redpacket); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); } @Test - public void queryRedpacket() throws WeixinException, IOException { + public void queryRedpacket() throws WeixinException { String outTradeNo = "HB001"; - RedpacketRecord result = PAY.queryRedpack(new FileInputStream(caFile), - outTradeNo); + RedpacketRecord result = PAY.queryRedpack(outTradeNo); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); } @Test - public void sendCorpPayment() throws WeixinException, IOException { + public void sendCorpPayment() throws WeixinException { CorpPayment payment = new CorpPayment("MP001", "ofW1gwok9vZIyle0YbA-eQe83Uk8", CorpPaymentCheckNameType.NO_CHECK, "企业付款测试", 1d, "127.0.0.1"); - CorpPaymentResult result = PAY.sendCorpPayment(new FileInputStream( - caFile), payment); + CorpPaymentResult result = PAY.sendCorpPayment(payment); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); } @Test - public void queryCorpPayment() throws WeixinException, IOException { - CorpPaymentRecord result = PAY.queryCorpPayment(new FileInputStream(caFile), - "MP001"); + public void queryCorpPayment() throws WeixinException { + CorpPaymentRecord result = PAY.queryCorpPayment("MP001"); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); diff --git a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CouponTest.java b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CouponTest.java index cc6c203a..f5e77f62 100644 --- a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CouponTest.java +++ b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/CouponTest.java @@ -1,7 +1,5 @@ package com.foxinmy.weixin4j.base.test; -import java.io.FileInputStream; -import java.io.IOException; import java.util.Date; import org.junit.Assert; @@ -26,11 +24,11 @@ import com.foxinmy.weixin4j.util.DateUtil; public class CouponTest extends PayTest { @Test - public void sendCoupon() throws WeixinException, IOException { + public void sendCoupon() throws WeixinException { String partnerTradeNo = String.format("%s%s%s", ACCOUNT.getMchId(), DateUtil.fortmat2yyyyMMdd(new Date()), "1"); - CouponResult result = PAY.sendCoupon(new FileInputStream(caFile), - "123", partnerTradeNo, "oyFLst1bqtuTcxK-ojF8hOGtLQao", null); + CouponResult result = PAY.sendCoupon("123", partnerTradeNo, + "oyFLst1bqtuTcxK-ojF8hOGtLQao", null); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); diff --git a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java index 786a9ab3..126b1f51 100644 --- a/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java +++ b/weixin4j-base/src/test/java/com/foxinmy/weixin4j/base/test/PayTest.java @@ -1,8 +1,8 @@ package com.foxinmy.weixin4j.base.test; -import java.io.File; -import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.util.Calendar; import java.util.Date; @@ -20,12 +20,12 @@ import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.RefundRecord; import com.foxinmy.weixin4j.payment.mch.RefundResult; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.sign.WeixinPaymentSignature; import com.foxinmy.weixin4j.sign.WeixinSignature; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdType; import com.foxinmy.weixin4j.type.TradeType; +import com.foxinmy.weixin4j.type.mch.BillType; import com.foxinmy.weixin4j.util.Consts; /** @@ -43,17 +43,15 @@ public class PayTest { protected final static WeixinPayProxy PAY; static { - ACCOUNT = new WeixinPayAccount("wx0d1d598c0c03c999", - "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ", "10020674"); + ACCOUNT = new WeixinPayAccount( + "appid", + "paysignKey", + "mchId", + "证书密码,为空取mchid", + "证书路径,绝对路径&classpath路径:/path/to/certificate.p12,或者填写classpath:path/to/certificate.p12"); SIGNATURE = new WeixinPaymentSignature(ACCOUNT.getPaySignKey()); - PAY = new WeixinPayProxy( - new Weixin4jSettings(ACCOUNT)); + PAY = new WeixinPayProxy(ACCOUNT); } - /** - * 商户证书文件 - */ - protected File caFile = new File( - "/Users/jy/workspace/feican/canyi-weixin-parent/canyi-weixin-service/src/main/resources/10020674.p12"); @Test public void queryOrder() throws WeixinException { @@ -86,22 +84,22 @@ public class PayTest { } @Test - public void downbill() throws WeixinException { + public void downbill() throws WeixinException, IOException { Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, 2016); c.set(Calendar.MONTH, 3); c.set(Calendar.DAY_OF_MONTH, 4); System.err.println(c.getTime()); - File file = PAY.downloadBill(c.getTime(), null); - System.err.println(file); + OutputStream os = new FileOutputStream("/tmp/bill20160813.txt"); + PAY.downloadBill(c.getTime(), BillType.ALL, os); } @Test public void refund() throws WeixinException, IOException { IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO); - RefundResult result = PAY.applyRefund(new FileInputStream(caFile), - idQuery, "TT_R" + System.currentTimeMillis(), 0.01d, 0.01d, - null, "10020674"); + RefundResult result = PAY.applyRefund(idQuery, + "TT_R" + System.currentTimeMillis(), 0.01d, 0.01d, null, + "10020674"); Assert.assertEquals(Consts.SUCCESS, result.getReturnCode()); Assert.assertEquals(Consts.SUCCESS, result.getResultCode()); System.err.println(result); diff --git a/weixin4j-example/src/main/resources/spring-bean.xml b/weixin4j-example/src/main/resources/spring-bean.xml index a25626ac..0d003ef8 100644 --- a/weixin4j-example/src/main/resources/spring-bean.xml +++ b/weixin4j-example/src/main/resources/spring-bean.xml @@ -8,37 +8,31 @@ + - - - - - - - - - - + + + + + + + + + + + + + - - - + @@ -47,19 +41,15 @@ - - - - - - - - - + + + + + + + - - - + @@ -67,18 +57,19 @@ + class="com.foxinmy.weixin4j.example.server.Weixin4jServerStartupWithThread" + init-method="start" destroy-method="stop"> - + - diff --git a/weixin4j-example/src/main/resources/weixin4j.properties b/weixin4j-example/src/main/resources/weixin4j.properties index bdc62530..90213cd9 100644 --- a/weixin4j-example/src/main/resources/weixin4j.properties +++ b/weixin4j-example/src/main/resources/weixin4j.properties @@ -1,18 +1,25 @@ +# weixin4j\u7684\u914d\u7f6e\u6587\u4ef6:\u5982\u679c\u6ca1\u6709\u8bf7\u6784\u9020\u76f8\u5e94\u53c2\u6570\u4f20\u5165 \u5982\u679c\u6709\u8bf7\u4fdd\u8bc1\u5728classpath\u7684\u6839\u76ee\u5f55\u4e0b + # \u516c\u4f17\u53f7\u4fe1\u606f \u8bf7\u6309\u9700\u586b\u5199 weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ +"components":[{"id":"\u5e94\u7528\u7ec4\u4ef6\u7684id","secret":"\u5e94\u7528\u7ec4\u4ef6\u7684secret"}],\ "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",\ +"certificateFile":"\u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3(\u9000\u6b3e\u7b49)\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u8def\u5f84,classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199classpath:xxxxx.p12,\u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6",\ "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# weixin4j\u7684\u4e34\u65f6\u76ee\u5f55 -# \u53ef\u80fd\u5b58\u653etoken\u6587\u4ef6\u3001\u4e8c\u7ef4\u7801\u6587\u4ef6\u3001\u5a92\u4f53\u6587\u4ef6\u3001\u5bf9\u8d26\u5355\u6587\u4ef6\u7b49 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6java.io.tmpdir\u4e34\u65f6\u76ee\u5f55 -weixin4j.tmpdir= -# \u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 -# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199 -# weixin4j.certificate.file=classpath:xxxxx.p12 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6 -weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 +# \u516c\u4f17\u53f7\u5fae\u4fe1\u7f51\u9875oauth\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN +weixin4j.user.oauth.redirect.uri= -# \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 +# \u7f51\u7ad9\u626b\u63cf\u767b\u9646oauth\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN +weixin4j.open.user.oauth.redirect.uri= + +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528ComponentApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=zh_CN +weixin4j.component.oauth.redirect.uri= + +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u66ff\u6388\u6743\u516c\u4f17\u53f7\u53d1\u8d77\u7f51\u9875\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528ComponentApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590&token=&lang=zh_CN +weixin4j.component.user.oauth.redirect.uri= \ No newline at end of file diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinComponentProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinComponentProxy.java index d033b9eb..b1adc13b 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinComponentProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinComponentProxy.java @@ -3,17 +3,17 @@ package com.foxinmy.weixin4j.mp; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; -import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.cache.CacheStorager; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.api.ComponentApi; import com.foxinmy.weixin4j.mp.model.WeixinMpAccount; import com.foxinmy.weixin4j.mp.type.URLConsts; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.TicketManager; import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.StringUtil; @@ -38,41 +38,66 @@ public class WeixinComponentProxy { */ private Map componentMap; /** - * 配置相关 + * 微信账号信息 */ - private final Weixin4jSettings settings; + private final WeixinMpAccount weixinMpAccount; /** - * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 + * 微信第三方组件接口实现(使用weixin4j.properties配置的account#components账号信息, + * 使用FileCacheStorager文件方式缓存TOKEN) */ public WeixinComponentProxy() { - this(new Weixin4jSettings( - JSON.parseObject(Weixin4jConfigUtil.getValue("account"), WeixinMpAccount.class))); + this(new FileCacheStorager()); } /** - * - * @param settings - * 配置信息 + * 微信第三方组件接口实现(使用weixin4j.properties配置的account#components账号信息) + * + * @param cacheStorager + * token管理 */ - public WeixinComponentProxy(Weixin4jSettings settings) { - this.settings = settings; - List components = settings.getAccount().getComponents(); - this.componentMap = new HashMap(components.size()); - for (WeixinAccount component : components) { - this.componentMap.put(component.getId(), new ComponentApi( - new TicketManager(component.getId(), component.getSecret(), settings.getCacheStorager0()))); - } - this.componentMap.put(null, componentMap.get(components.get(0).getId())); + public WeixinComponentProxy(CacheStorager cacheStorager) { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinMpAccount.class), cacheStorager); } /** - * 公众号信息 + * 微信第三方组件接口实现 + * + * @param weixinMpAccount + * 账号信息 + * @param cacheStorager + * token管理 + */ + public WeixinComponentProxy(WeixinMpAccount weixinMpAccount, + CacheStorager cacheStorager) { + if (weixinMpAccount == null) { + throw new IllegalArgumentException( + "weixinPayAccount must not be empty"); + } + if (cacheStorager == null) { + throw new IllegalArgumentException( + "cacheStorager must not be empty"); + } + this.weixinMpAccount = weixinMpAccount; + this.componentMap = new HashMap(weixinMpAccount + .getComponents().size()); + for (WeixinAccount component : weixinMpAccount.getComponents()) { + this.componentMap.put(component.getId(), new ComponentApi( + new TicketManager(component.getId(), component.getSecret(), + cacheStorager))); + } + this.componentMap.put(null, componentMap.get(weixinMpAccount + .getComponents().get(0).getId())); + } + + /** + * 获取微信账号信息 * * @return */ - public WeixinMpAccount getWeixinAccount() { - return this.settings.getAccount(); + public WeixinMpAccount getWeixinMpAccount() { + return this.weixinMpAccount; } /** @@ -103,17 +128,20 @@ public class WeixinComponentProxy { * @param componentId * 组件ID * @return 预授权码 + * @see #cacheComponentTicket(String, String) * @see com.foxinmy.weixin4j.mp.api.ComponentApi * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getTicketManager() * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getPreCodeManager() * @throws WeixinException */ - public String getPreComponentTicket(String componentId) throws WeixinException { - Token token = component(componentId).getTicketManager().getTicket(); + public String getPreComponentTicket(String componentId) + throws WeixinException { + ComponentApi component = component(componentId); + Token token = component.getTicketManager().getTicket(); if (token == null || StringUtil.isBlank(token.getAccessToken())) { throw new WeixinException("maybe oauth first?"); } - return token.getAccessToken(); + return component.getPreCodeManager().getAccessToken(); } /** @@ -125,27 +153,34 @@ public class WeixinComponentProxy { * 组件ticket内容 * @throws WeixinException */ - public void cacheComponentTicket(String componentId, String componentTicket) throws WeixinException { - component(componentId).getTicketManager().cachingTicket(componentTicket); + public void cacheComponentTicket(String componentId, String componentTicket) + throws WeixinException { + component(componentId).getTicketManager() + .cachingTicket(componentTicket); } /** - * 应用组件授权 需先缓存ticket - * - * @see {@link #getComponentAuthorizeURL(String, String,String)} + * 应用组件授权 需先缓存ticket
  • + * redirectUri默认填写weixin4j.properties#component.oauth.redirect.uri
  • + * state默认填写state + * * @param componentId * 组件ID - * @see {@link #cacheComponentTicket(String, String)} + * @see {@link #getComponentAuthorizationURL(String, String,String)} * @return 请求授权的URL * @throws WeixinException */ - public String getComponentAuthorizeURL(String componentId) throws WeixinException { - String redirectUri = Weixin4jConfigUtil.getValue("component.oauth.redirect.uri"); - return getComponentAuthorizeURL(componentId, redirectUri, "state"); + public String getComponentAuthorizationURL(String componentId) + throws WeixinException { + String redirectUri = Weixin4jConfigUtil + .getValue("component.oauth.redirect.uri"); + return getComponentAuthorizationURL(componentId, redirectUri, "state"); } /** - * 应用组件授权 需先缓存ticket + * 应用组件授权 需先缓存ticket,在授权完成之后需要调用ComponentApi#exchangeAuthInfo方法 + * ,否则无法缓存token相关导致后续的组件接口调用失败 * * @param componentId * 组件ID @@ -153,16 +188,21 @@ public class WeixinComponentProxy { * 授权后重定向url * @param state * 回调后原样返回 + * @see #cacheComponentTicket(String, String) * @see com.foxinmy.weixin4j.mp.api.ComponentApi * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getTicketManager() * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getPreCodeManager() + * @see com.foxinmy.weixin4j.mp.api.ComponentApi#exchangeAuthInfo(String) + * @see 应用组件授权 * @return 请求授权的URL * @throws WeixinException */ - public String getComponentAuthorizeURL(String componentId, String redirectUri, String state) - throws WeixinException { + public String getComponentAuthorizationURL(String componentId, + String redirectUri, String state) throws WeixinException { try { - return String.format(URLConsts.COMPONENT_OAUTH_URL, componentId, getPreComponentTicket(componentId), + return String.format(URLConsts.COMPONENT_OAUTH_URL, componentId, + getPreComponentTicket(componentId), URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state); } catch (UnsupportedEncodingException e) { ; @@ -181,8 +221,8 @@ public class WeixinComponentProxy { * @return */ public WeixinProxy getWeixinProxy(String componentId, String authAppId) { - return new WeixinProxy(component(componentId).getRefreshTokenManager(authAppId), - component(componentId).getTokenManager()); + return new WeixinProxy(component(componentId).getRefreshTokenManager( + authAppId), component(componentId).getTokenManager()); } public final static String VERSION = "1.7.1"; 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 7a76e35d..9e4506d7 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 @@ -4,9 +4,12 @@ import java.io.InputStream; import java.util.Date; import java.util.List; +import com.foxinmy.weixin4j.cache.CacheStorager; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.model.Button; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.card.CardCoupon; import com.foxinmy.weixin4j.model.card.CardCoupons; @@ -28,6 +31,7 @@ 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.NotifyApi; +import com.foxinmy.weixin4j.mp.api.OauthApi; import com.foxinmy.weixin4j.mp.api.QrApi; import com.foxinmy.weixin4j.mp.api.TagApi; import com.foxinmy.weixin4j.mp.api.TmplApi; @@ -56,8 +60,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.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.PerTicketManager; +import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.tuple.MassTuple; import com.foxinmy.weixin4j.tuple.MpArticle; @@ -77,7 +81,10 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; * @see api文档 */ public class WeixinProxy { - + /** + * 授权API + */ + private final OauthApi oauthApi; /** * 媒体素材API */ @@ -131,64 +138,94 @@ public class WeixinProxy { */ private final CardApi cardApi; /** - * token实现 + * token管理 */ private final TokenManager tokenManager; /** - * 配置信息 + * 账号信息 */ - private Weixin4jSettings settings; + private final WeixinAccount weixinAccount; + /** + * token存储 + */ + private final CacheStorager cacheStorager; /** - * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 + * 微信接口实现(使用weixin4j.properties配置的account账号信息, + * 使用FileCacheStorager文件方式缓存TOKEN) */ public WeixinProxy() { - this(new Weixin4jSettings( - Weixin4jConfigUtil.getWeixinAccount())); + this(new FileCacheStorager()); } /** - * - * @param settings - * 微信配置信息 - * @see com.foxinmy.weixin4j.setting.Weixin4jSettings + * 微信接口实现(使用weixin4j.properties配置的account账号信息) + * + * @param cacheStorager + * token管理 */ - public WeixinProxy(Weixin4jSettings settings) { - this(new TokenManager(new WeixinTokenCreator(settings.getAccount() - .getId(), settings.getAccount().getSecret()), - settings.getCacheStorager0())); - this.settings = settings; + public WeixinProxy(CacheStorager cacheStorager) { + this(Weixin4jConfigUtil.getWeixinAccount(), cacheStorager); } /** - * 第三方组件(永久刷新令牌机制) + * 微信接口实现 + * + * @param weixinAccount + * 账号信息 + * @param cacheStorager + * token管理 + */ + public WeixinProxy(WeixinAccount weixinAccount, + CacheStorager cacheStorager) { + this(weixinAccount, new WeixinTokenCreator(weixinAccount.getId(), + weixinAccount.getSecret()), cacheStorager); + } + + /** + * 第三方组件方式创建微信接口实现(永久刷新令牌机制) * * @param perTicketManager * 第三方组件永久刷新token - * {@link com.foxinmy.weixin4j.mp.api.ComponentApi#getPerCodeManager(String)} * @param componentTokenManager * 第三方组件凭证token - * {@link com.foxinmy.weixin4j.mp.api.ComponentApi#getTokenManager} * @see com.foxinmy.weixin4j.mp.api.ComponentApi + * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getPerCodeManager(String) + * @see com.foxinmy.weixin4j.mp.api.ComponentApi#getTokenManager */ public WeixinProxy(PerTicketManager perTicketManager, TokenManager componentTokenManager) { - this(new TokenManager(new WeixinTokenComponentCreator(perTicketManager, - componentTokenManager), perTicketManager.getCacheStorager())); - this.settings = new Weixin4jSettings(new WeixinAccount( - perTicketManager.getAuthAppId(), null)); - this.settings.setCacheStorager(perTicketManager.getCacheStorager()); + this(new WeixinAccount(perTicketManager.getThirdId(), + perTicketManager.getThirdSecret()), + new WeixinTokenComponentCreator(perTicketManager, + componentTokenManager), perTicketManager + .getCacheStorager()); } /** - * 注意:TokenCreator 需为 WeixinTokenCreator - * - * @see com.foxinmy.weixin4j.mp.token.WeixinTokenCreator + * 微信接口实现 + * + * @param settings + * 配置信息 * @param tokenManager * token管理 */ - private WeixinProxy(TokenManager tokenManager) { - this.tokenManager = tokenManager; + private WeixinProxy(WeixinAccount weixinAccount, TokenCreator tokenCreator, + CacheStorager cacheStorager) { + if (weixinAccount == null) { + throw new IllegalArgumentException("settings must not be empty"); + } + if (tokenCreator == null) { + throw new IllegalArgumentException("tokenCreator must not be empty"); + } + if (cacheStorager == null) { + throw new IllegalArgumentException( + "cacheStorager must not be empty"); + } + this.tokenManager = new TokenManager(tokenCreator, cacheStorager); + this.weixinAccount = weixinAccount; + this.cacheStorager = cacheStorager; + this.oauthApi = new OauthApi(weixinAccount); this.mediaApi = new MediaApi(tokenManager); this.notifyApi = new NotifyApi(tokenManager); this.customApi = new CustomApi(tokenManager); @@ -210,7 +247,7 @@ public class WeixinProxy { * @return */ public WeixinAccount getWeixinAccount() { - return this.settings.getAccount(); + return weixinAccount; } /** @@ -222,6 +259,16 @@ public class WeixinProxy { return this.tokenManager; } + /** + * 获取oauth授权API + * + * @see com.foxinmy.weixin4j.mp.api.OauthApi + * @return + */ + public OauthApi getOauthApi() { + return oauthApi; + } + /** * 获取JSSDK Ticket的tokenManager * @@ -230,9 +277,8 @@ public class WeixinProxy { * @return */ public TokenManager getTicketManager(TicketType ticketType) { - return new TokenManager(new WeixinTicketCreator(getWeixinAccount() - .getId(), ticketType, this.tokenManager), - this.settings.getCacheStorager0()); + return new TokenManager(new WeixinTicketCreator(weixinAccount.getId(), + ticketType, this.tokenManager), this.cacheStorager); } /** @@ -1537,7 +1583,7 @@ public class WeixinProxy { * @throws WeixinException */ public ApiResult clearQuota() throws WeixinException { - return helperApi.clearQuota(getWeixinAccount().getId()); + return helperApi.clearQuota(weixinAccount.getId()); } /** diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ComponentApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ComponentApi.java index 9acbe93d..a0033cbd 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ComponentApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/ComponentApi.java @@ -1,5 +1,7 @@ package com.foxinmy.weixin4j.mp.api; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; @@ -14,12 +16,15 @@ import com.foxinmy.weixin4j.mp.component.WeixinComponentPreCodeCreator; import com.foxinmy.weixin4j.mp.component.WeixinComponentTokenCreator; import com.foxinmy.weixin4j.mp.component.WeixinTokenComponentCreator; import com.foxinmy.weixin4j.mp.model.AuthorizerOption; +import com.foxinmy.weixin4j.mp.model.OauthToken; import com.foxinmy.weixin4j.mp.model.AuthorizerOption.AuthorizerOptionName; import com.foxinmy.weixin4j.mp.model.ComponentAuthInfo; import com.foxinmy.weixin4j.token.PerTicketManager; import com.foxinmy.weixin4j.token.TicketManager; import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenManager; +import com.foxinmy.weixin4j.util.Consts; +import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; /** * 第三方应用组件 @@ -101,6 +106,110 @@ public class ComponentApi extends MpApi { ticketManager.getCacheStorager()); } + /** + * 第三方组件代替授权公众号发起网页授权:获取code
  • + * redirectUri默认填写weixin4j.properties#component.user.oauth.redirect.uri
  • + * scope默认填写snsapi_base
  • + * state默认填写state + * + * @param authAppId + * 公众号的appid + * @see #getAuthorizationURL(String, String, String, String) + * @see 第三方组件代替授权公众号发起网页授权 + */ + public String getUserAuthorizationURL(String authAppId) { + String redirectUri = Weixin4jConfigUtil + .getValue("component.user.oauth.redirect.uri"); + return getUserAuthorizationURL(authAppId, redirectUri, "snsapi_base", + "state"); + } + + /** + * 第三方组件代替授权公众号发起网页授权:获取code + * + * @param authAppId + * 公众号的appid + * @param redirectUri + * 重定向地址,这里填写的应是服务开发方的回调地址 + * @param scope + * 应用授权作用域,snsapi_base/snsapi_userinfo + * @param state + * 重定向后会带上state参数,开发者可以填写任意参数值,最多128字节 + * @return oauth授权URL + * @see 第三方组件代替授权公众号发起网页授权 + */ + public String getUserAuthorizationURL(String authAppId, String redirectUri, + String scope, String state) { + String sns_component_user_auth_uri = getRequestUri("sns_component_user_auth_uri"); + try { + return String.format(sns_component_user_auth_uri, authAppId, + URLEncoder.encode(redirectUri, Consts.UTF_8.name()), scope, + state, this.ticketManager.getThirdId()); + } catch (UnsupportedEncodingException e) { + ; + } + return ""; + } + + /** + * 第三方组件代替授权公众号发起网页授权:换取token + * + * @param authAppId + * 公众号的appid + * @param code + * 用户同意授权获取的code + * @return token信息 + * @see #getUserAuthorizationURL(String, String, String, String) + * @see com.foxinmy.weixin4j.mp.model.OauthToken + * @throws WeixinException + */ + public OauthToken getAuthorizationToken(String authAppId, String code) + throws WeixinException { + String sns_component_user_token_uri = getRequestUri("sns_component_user_token_uri"); + String accessToken = tokenManager.getAccessToken(); + WeixinResponse response = weixinExecutor.get(String.format( + sns_component_user_token_uri, authAppId, code, + ticketManager.getThirdId(), accessToken)); + JSONObject result = response.getAsJson(); + OauthToken token = new OauthToken(result.getString("access_token"), + result.getLongValue("expires_in") * 1000l); + token.setOpenId(result.getString("openid")); + token.setScope(result.getString("scope")); + token.setRefreshToken(result.getString("refresh_token")); + return token; + } + + /** + * 第三方组件代替授权公众号发起网页授权:刷新token + * + * @param authAppId + * 公众号的appid + * @param refreshToken + * 填写通过access_token获取到的refresh_token参数 + * @return token信息 + * @see #getAuthorizationToken(String, String) + * @see OauthApi#getAuthorizationUser(OauthToken) + * @see com.foxinmy.weixin4j.mp.model.OauthToken + * @throws WeixinException + */ + public OauthToken refreshAuthorizationToken(String authAppId, + String refreshToken) throws WeixinException { + String sns_component_token_refresh_uri = getRequestUri("sns_component_token_refresh_uri"); + String accessToken = tokenManager.getAccessToken(); + WeixinResponse response = weixinExecutor.get(String.format( + sns_component_token_refresh_uri, authAppId, + ticketManager.getThirdId(), accessToken, refreshToken)); + JSONObject result = response.getAsJson(); + OauthToken token = new OauthToken(result.getString("access_token"), + result.getLongValue("expires_in") * 1000l); + token.setOpenId(result.getString("openid")); + token.setScope(result.getString("scope")); + token.setRefreshToken(result.getString("refresh_token")); + return token; + } + /** * 使用授权码换取公众号的接口调用凭据和授权信息:用于使用授权码换取授权公众号的授权信息, * 并换取authorizer_access_token和authorizer_refresh_token。 @@ -111,6 +220,7 @@ public class ComponentApi extends MpApi { * @param authCode * 授权code * @return 第三方组件授权信息 + * @see {@link com.foxinmy.weixin4j.mp.WeixinComponentProxy#getComponentAuthorizeURL(String, String, String)} * @see com.foxinmy.weixin4j.mp.model.ComponentAuthInfo * @throws WeixinException */ @@ -169,22 +279,23 @@ public class ComponentApi extends MpApi { WeixinResponse response = weixinExecutor.post( String.format(component_get_authorizer_uri, tokenManager.getAccessToken()), obj.toJSONString()); - obj = response.getAsJson().getJSONObject("authorizer_info"); - ComponentAuthInfo info = JSON - .toJavaObject(obj, ComponentAuthInfo.class); - info.setServiceType(obj.getJSONObject("service_type_info").getIntValue( + obj = response.getAsJson(); + JSONObject auth = obj.getJSONObject("authorizer_info"); + ComponentAuthInfo info = JSON.toJavaObject(auth, + ComponentAuthInfo.class); + info.setServiceType(auth.getJSONObject("service_type_info") + .getIntValue("id")); + info.setVerifyType(auth.getJSONObject("verify_type_info").getIntValue( "id")); - info.setVerifyType(obj.getJSONObject("verify_type_info").getIntValue( - "id")); - JSONArray privilegesObj = obj.getJSONObject("authorization_info") - .getJSONArray("func_info"); + auth = obj.getJSONObject("authorization_info"); + JSONArray privilegesObj = auth.getJSONArray("func_info"); List privileges = new ArrayList(privilegesObj.size()); for (int i = 0; i < privilegesObj.size(); i++) { privileges.add(privilegesObj.getJSONObject(i) .getJSONObject("funcscope_category").getInteger("id")); } info.setPrivileges(privileges); - info.setAppId(authAppId); + info.setAppId(auth.getString("appid")); return info; } 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 dd012517..460e828d 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 @@ -21,8 +21,6 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; * @author jinyu(foxinmy@gmail.com) * @date 2015年3月6日 * @since JDK 1.6 - * @see 微信登陆 */ public class OauthApi extends MpApi { @@ -45,20 +43,23 @@ public class OauthApi extends MpApi { } /** - * 公众号base静默oauth授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri + * 公众号网页获取用户资料oauth授权:请求code
  • + * redirectUri默认填写weixin4j.properties#user.oauth.redirect.uri
  • + * scope默认填写snsapi_base
  • + * state默认填写state * - * @see {@link #getAuthorizeURL(String, String,String)} + * @see {@link #getUserAuthorizationURL(String, String,String)} * * @return 请求授权的URL */ - public String getAuthorizeURL() { + public String getUserAuthorizationURL() { String redirectUri = Weixin4jConfigUtil .getValue("user.oauth.redirect.uri"); - return getAuthorizeURL(redirectUri, "state", "snsapi_base"); + return getUserAuthorizationURL(redirectUri, "state", "snsapi_base"); } /** - * 请求CODE + * 公众号网页获取用户资料oauth授权:请求code * * @param redirectUri * 重定向地址
    @@ -86,7 +87,8 @@ public class OauthApi extends MpApi { * ,这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。
    * @return 请求授权的URL */ - public String getAuthorizeURL(String redirectUri, String state, String scope) { + public String getUserAuthorizationURL(String redirectUri, String state, + String scope) { String sns_user_auth_uri = getRequestUri("sns_user_auth_uri"); try { return String.format(sns_user_auth_uri, account.getId(), @@ -99,15 +101,17 @@ public class OauthApi extends MpApi { } /** - * code换取token + * 公众号网页获取用户资料oauth授权:code换取token * * @param code * 用户同意授权获取的code, * code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次 * ,5分钟未被使用自动过期。 * @return oauthtoken信息 + * @see #getUserAuthorizationURL(String, String,String) + * @see #getAuthorizationUser(OauthToken) */ - public OauthToken getOauthToken(String code) throws WeixinException { + public OauthToken getAuthorizationToken(String code) throws WeixinException { String user_token_uri = getRequestUri("sns_user_token_uri"); WeixinResponse response = weixinExecutor.get(String.format( user_token_uri, account.getId(), account.getSecret(), code)); @@ -122,23 +126,29 @@ public class OauthApi extends MpApi { } /** - * 刷新token:由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新, - * refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。 + * 公众号网页获取用户资料oauth授权:刷新token,由于access_token拥有较短的有效期,当access_token超时后, + * 可以使用refresh_token进行刷新, refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。 * * * @param refreshToken * 填写通过access_token获取到的refresh_token参数 - * {@link #getOauthToken(String)} + * @see {@link #getAuthorizationToken(String)} * @see com.foxinmy.weixin4j.mp.model.OauthToken * @return oauthtoken信息 */ - public OauthToken refreshToken(String refreshToken) throws WeixinException { + public OauthToken refreshAuthorizationToken(String refreshToken) + throws WeixinException { String sns_token_refresh_uri = getRequestUri("sns_token_refresh_uri"); WeixinResponse response = weixinExecutor.get(String.format( sns_token_refresh_uri, account.getId(), refreshToken)); - - return response.getAsObject(new TypeReference() { - }); + JSONObject result = response.getAsJson(); + OauthToken token = new OauthToken(result.getString("access_token"), + result.getLongValue("expires_in") * 1000l); + token.setUnionId(result.getString("unionid")); + token.setOpenId(result.getString("openid")); + token.setScope(result.getString("scope")); + token.setRefreshToken(result.getString("refresh_token")); + return token; } /** @@ -150,7 +160,7 @@ public class OauthApi extends MpApi { * 用户标识 * @return 验证结果 */ - public boolean authAccessToken(String oauthToken, String openId) { + public boolean verifyAuthorizationToken(String oauthToken, String openId) { String sns_auth_token_uri = getRequestUri("sns_auth_token_uri"); try { weixinExecutor.get(String.format(sns_auth_token_uri, oauthToken, @@ -163,7 +173,7 @@ public class OauthApi extends MpApi { } /** - * oauth获取用户信息(需scope为 snsapi_userinfo) + * oauth授权获取用户信息(需scope为 snsapi_userinfo) * * @param token * 授权信息(token&openid) @@ -173,11 +183,11 @@ public class OauthApi extends MpApi { * href="https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN">授权获取用户信息 * @see com.foxinmy.weixin4j.mp.model.User * @see com.foxinmy.weixin4j.mp.model.OauthToken - * @see {@link #getOauthToken(String)} - * @see {@link #getUser(String,Sring,Lang)} + * @see {@link #getAuthorizationUser(String,Sring,Lang)} */ - public User getUser(OauthToken token) throws WeixinException { - return getUser(token.getAccessToken(), token.getOpenId(), Lang.zh_CN); + public User getAuthorizationUser(OauthToken token) throws WeixinException { + return getAuthorizationUser(token.getAccessToken(), token.getOpenId(), + Lang.zh_CN); } /** @@ -193,10 +203,11 @@ public class OauthApi extends MpApi { * @throws WeixinException * @see 授权获取用户信息 + * @see {@link #getAuthorizationToken(String)} * @see com.foxinmy.weixin4j.mp.model.OauthToken * @see com.foxinmy.weixin4j.mp.model.User */ - public User getUser(String oauthToken, String openid, Lang lang) + public User getAuthorizationUser(String oauthToken, String openid, Lang lang) throws WeixinException { String user_info_uri = getRequestUri("sns_user_info_uri"); WeixinResponse response = weixinExecutor.get(String.format( @@ -207,28 +218,32 @@ public class OauthApi extends MpApi { } /** - * 微信开放平台oauth授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri - * - * @see {@link #getOpenAuthorizeURL(String, String)} + * 微信开放平台oauth授权(扫码登陆)
  • + * redirectUri默认填写weixin4j.properties#open.user.oauth.redirect.uri
  • + * state默认填写state * + * @see {@link #getOpenAuthorizationURL(String, String)} * @return 请求授权的URL */ - public String getOpenAuthorizeURL() { + public String getOpenAuthorizationURL() { String redirectUri = Weixin4jConfigUtil - .getValue("user.oauth.redirect.uri"); - return getOpenAuthorizeURL(redirectUri, "state"); + .getValue("open.user.oauth.redirect.uri"); + return getOpenAuthorizationURL(redirectUri, "state"); } /** - * 微信开放平台oauth授权:请求CODE + * 微信开放平台oauth授权(扫码登陆):请求CODE * * @param redirectUri * 重定向地址 域名与审核时填写的授权域名一致 * @param state * 用于保持请求和回调的状态,授权请求后原样带回给第三方 * @return 请求授权的URL + * @see 网站扫描登陆oauth授权 + * @see #getAuthorizationToken(String) */ - public String getOpenAuthorizeURL(String redirectUri, String state) { + public String getOpenAuthorizationURL(String redirectUri, String state) { String open_user_auth_uri = getRequestUri("open_user_auth_uri"); try { return String.format(open_user_auth_uri, account.getId(), diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayOldApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayOldApi.java index cf2e8c79..c6d48c62 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayOldApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayOldApi.java @@ -25,6 +25,8 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.parser.Feature; +import com.foxinmy.weixin4j.cache.CacheStorager; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.entity.FormUrlEntity; import com.foxinmy.weixin4j.http.weixin.ApiResult; @@ -38,7 +40,6 @@ import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPayAccount; import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPaymentSignature; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.payment.PayRequest; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.sign.WeixinPaymentSignature; import com.foxinmy.weixin4j.sign.WeixinSignature; import com.foxinmy.weixin4j.token.TokenManager; @@ -66,44 +67,80 @@ import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; */ public class PayOldApi extends MpApi { - private final Weixin4jSettings settings; - private final WeixinOldPayAccount weixinAccount; + private final WeixinOldPayAccount weixinPayAccount; private final TokenManager tokenManager; private final WeixinSignature weixinMD5Signature; - private final WeixinOldPaymentSignature weixinOldSignature; + private final WeixinOldPaymentSignature weixinSignature; /** - * 默认使用weixin4j.properties配置信息 + * 支付对象(使用weixin4j.properties配置的account商户信息,使用FileCacheStorager文件方式缓存TOKEN) */ public PayOldApi() { - this(new Weixin4jSettings(JSON.parseObject( - Weixin4jConfigUtil.getValue("account"), - WeixinOldPayAccount.class))); + this(new FileCacheStorager()); } /** - * - * @param settings - * 微信配置信息 + * 支付对象(使用weixin4j.properties配置的account商户信息) */ - public PayOldApi(Weixin4jSettings settings) { - this.settings = settings; - this.weixinAccount = settings.getAccount(); + public PayOldApi(CacheStorager cacheStorager) { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinOldPayAccount.class), cacheStorager); + } + + /** + * 支付对象 + * + * @param weixinPayAccount + * 商户信息 + * @param cacheStorager + * token管理 + */ + public PayOldApi(WeixinOldPayAccount weixinPayAccount, + CacheStorager cacheStorager) { + if (weixinPayAccount == null) { + throw new IllegalArgumentException( + "weixinPayAccount must not be empty"); + } + if (cacheStorager == null) { + throw new IllegalArgumentException( + "cacheStorager must not be empty"); + } + this.weixinPayAccount = weixinPayAccount; this.tokenManager = new TokenManager(new WeixinTokenCreator( - weixinAccount.getId(), weixinAccount.getSecret()), - settings.getCacheStorager0()); + weixinPayAccount.getId(), weixinPayAccount.getSecret()), + cacheStorager); this.weixinMD5Signature = new WeixinPaymentSignature( - weixinAccount.getPartnerKey()); - this.weixinOldSignature = new WeixinOldPaymentSignature( - weixinAccount.getPaySignKey(), weixinAccount.getPartnerKey()); + weixinPayAccount.getPartnerKey()); + this.weixinSignature = new WeixinOldPaymentSignature( + weixinPayAccount.getPaySignKey(), + weixinPayAccount.getPartnerKey()); } + /** + * 返回商户信息 + * + * @return + */ public WeixinOldPayAccount getWeixinPayAccount() { - return this.weixinAccount; + return weixinPayAccount; } + /** + * token管理 + * + * @return + */ + public TokenManager getTokenManager() { + return this.tokenManager; + } + + /** + * 返回签名对象 + * + * @return + */ public WeixinOldPaymentSignature getWeixinPaymentSignature() { - return this.weixinOldSignature; + return this.weixinSignature; } /** @@ -124,7 +161,7 @@ public class PayOldApi extends MpApi { public String createPayJsRequestJson(String body, String outTradeNo, double totalFee, String notifyUrl, String createIp) { PayPackageV2 payPackage = new PayPackageV2( - weixinAccount.getPartnerId(), body, outTradeNo, totalFee, + weixinPayAccount.getPartnerId(), body, outTradeNo, totalFee, notifyUrl, createIp); return createPayJsRequestJson(payPackage); } @@ -137,9 +174,9 @@ public class PayOldApi extends MpApi { * @return 支付json串 */ public String createPayJsRequestJson(PayPackageV2 payPackage) { - PayRequest payRequest = new PayRequest(weixinAccount.getId(), - weixinOldSignature.sign(payPackage)); - payRequest.setPaySign(weixinOldSignature.sign(payRequest)); + PayRequest payRequest = new PayRequest(weixinPayAccount.getId(), + weixinSignature.sign(payPackage)); + payRequest.setPaySign(weixinSignature.sign(payRequest)); payRequest.setSignType(SignType.SHA1); return JSON.toJSONString(payRequest); } @@ -155,14 +192,14 @@ public class PayOldApi extends MpApi { Map map = new HashMap(); String timestamp = DateUtil.timestamp2string(); String noncestr = RandomUtil.generateString(16); - map.put("appid", weixinAccount.getId()); + map.put("appid", weixinPayAccount.getId()); map.put("timestamp", timestamp); map.put("noncestr", noncestr); map.put("productid", productId); - map.put("appkey", weixinAccount.getPaySignKey()); - String sign = weixinOldSignature.sign(map); + map.put("appkey", weixinPayAccount.getPaySignKey()); + String sign = weixinSignature.sign(map); String nativepay_uri = getRequestUri("nativepay_old_uri"); - return String.format(nativepay_uri, sign, weixinAccount.getId(), + return String.format(nativepay_uri, sign, weixinPayAccount.getId(), productId, timestamp, noncestr); } @@ -182,23 +219,23 @@ public class PayOldApi 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(weixinPayAccount.getPartnerId()); String part = sb.toString(); - sb.append("&key=").append(weixinAccount.getPartnerKey()); + sb.append("&key=").append(weixinPayAccount.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", weixinPayAccount.getId()); + obj.put("appkey", weixinPayAccount.getPaySignKey()); obj.put("package", sb.toString()); obj.put("timestamp", timestamp); - String signature = weixinOldSignature.sign(obj); + String signature = weixinSignature.sign(obj); obj.clear(); - obj.put("appid", weixinAccount.getId()); + obj.put("appid", weixinPayAccount.getId()); obj.put("package", sb.toString()); obj.put("timestamp", timestamp); obj.put("app_signature", signature); @@ -259,7 +296,7 @@ public class PayOldApi extends MpApi { // 填写为 1.0 时,操作员密码为明文 // 填写为 1.1 时,操作员密码为 MD5(密码)值 map.put("service_version", "1.1"); - map.put("partner", weixinAccount.getPartnerId()); + map.put("partner", weixinPayAccount.getPartnerId()); map.put("out_refund_no", outRefundNo); map.put("total_fee", Integer.toString(DateUtil.formatYuan2Fen(totalFee))); @@ -267,7 +304,7 @@ public class PayOldApi extends MpApi { Integer.toString(DateUtil.formatYuan2Fen(refundFee))); map.put(idQuery.getType().getName(), idQuery.getId()); if (StringUtil.isBlank(opUserId)) { - opUserId = weixinAccount.getPartnerId(); + opUserId = weixinPayAccount.getPartnerId(); } map.put("op_user_id", opUserId); if (mopara != null && !mopara.isEmpty()) { @@ -280,7 +317,7 @@ public class PayOldApi extends MpApi { KeyStore ks = null; String jksPwd = ""; File jksFile = new File(String.format("%s%stenpay_cacert.jks", - settings.getTmpdir0(), File.separator)); + System.getProperty("java.io.tmpdir"), File.separator)); // create jks ca if (!jksFile.exists()) { CertificateFactory cf = CertificateFactory @@ -307,8 +344,8 @@ public class PayOldApi extends MpApi { KeyManagerFactory kmf = KeyManagerFactory .getInstance(Consts.SunX509); ks = KeyStore.getInstance(Consts.PKCS12); - ks.load(certificate, weixinAccount.getPartnerId().toCharArray()); - kmf.init(ks, weixinAccount.getPartnerId().toCharArray()); + ks.load(certificate, weixinPayAccount.getPartnerId().toCharArray()); + kmf.init(ks, weixinPayAccount.getPartnerId().toCharArray()); ctx = SSLContext.getInstance(Consts.TLS); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), @@ -442,7 +479,7 @@ public class PayOldApi extends MpApi { String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); String fileName = String.format("weixin4j_bill_%s_%s_%s.txt", formatBillDate, billType.name().toLowerCase(), - weixinAccount.getId()); + weixinPayAccount.getId()); File file = new File(String.format("%s%s%s", billPath, File.separator, fileName)); if (file.exists()) { @@ -451,12 +488,12 @@ public class PayOldApi extends MpApi { String downloadbill_uri = getRequestUri("downloadbill_old_uri"); Map map = new HashMap(); - map.put("spid", weixinAccount.getPartnerId()); + map.put("spid", weixinPayAccount.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", weixinPayAccount.getPartnerKey()); String sign = DigestUtil.MD5(MapUtil.toJoinString(map, false, false)); map.put("sign", sign.toLowerCase()); WeixinResponse response = weixinExecutor.get(String.format("%s?%s", @@ -507,7 +544,7 @@ public class PayOldApi extends MpApi { String refundquery_uri = getRequestUri("refundquery_old_uri"); Map map = new HashMap(); map.put("input_charset", Consts.UTF_8.name()); - map.put("partner", weixinAccount.getPartnerId()); + map.put("partner", weixinPayAccount.getPartnerId()); map.put(idQuery.getType().getName(), idQuery.getId()); String sign = weixinMD5Signature.sign(map); map.put("sign", sign.toLowerCase()); @@ -540,15 +577,15 @@ public class PayOldApi extends MpApi { Token token = tokenManager.getCache(); Map map = new HashMap(); - map.put("appid", weixinAccount.getId()); - map.put("appkey", weixinAccount.getPaySignKey()); + map.put("appid", weixinPayAccount.getId()); + map.put("appkey", weixinPayAccount.getPaySignKey()); map.put("openid", openId); map.put("transid", transid); map.put("out_trade_no", outTradeNo); map.put("deliver_timestamp", DateUtil.timestamp2string()); map.put("deliver_status", status ? "1" : "0"); map.put("deliver_msg", statusMsg); - map.put("app_signature", weixinOldSignature.sign(map)); + map.put("app_signature", weixinSignature.sign(map)); map.put("sign_method", SignType.SHA1.name().toLowerCase()); WeixinResponse response = weixinExecutor.post( diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 7968a3a7..06f748f5 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -9,12 +9,23 @@ tenpay_base_url=http://mch.tenpay.com tenpay_ssl_base_url=https://mch.tenpay.com tenpay_gw_base_url=https://gw.tenpay.com -# \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f +# \u7f51\u9875oauth\u6388\u6743URL sns_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect -sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code -sns_token_refresh_uri=https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s -sns_auth_token_uri=https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s -sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743URL +sns_component_user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&component_appid=%s#wechat_redirect +# \u7f51\u9875oauth\u6388\u6743\u83b7\u53d6token +sns_user_token_uri={api_base_url}/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743\u83b7\u53d6token +sns_component_user_token_uri={api_base_url}/sns/oauth2/component/access_token?appid=%s&code=%s&grant_type=authorization_code&component_appid=%s&component_access_token=%s +# \u7f51\u9875oauth\u6388\u6743\u5237\u65b0token +sns_token_refresh_uri={api_base_url}/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u516c\u4f17\u53f7\u7f51\u9875oauth\u6388\u6743\u5237\u65b0token +sns_component_token_refresh_uri={api_base_url}/sns/oauth2/component/refresh_token?appid=%s&grant_type=refresh_token&component_appid=%s&component_access_token=%s&refresh_token=%s +# \u7f51\u9875oauthoauth\u6388\u6743\u9a8c\u8bc1token +sns_auth_token_uri={api_base_url}/sns/auth?access_token=%s&openid=%s +# \u7f51\u9875oauth\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f +sns_user_info_uri={api_base_url}/sns/userinfo?access_token=%s&openid=%s&lang=%s +# \u5f00\u653e\u5e73\u53f0\u626b\u7801\u767b\u9646\u6388\u6743 open_user_auth_uri=https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect # \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/OauthToken.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/OauthToken.java index 690725e2..fa3fd0b7 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/OauthToken.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/OauthToken.java @@ -18,7 +18,7 @@ public class OauthToken extends Token { /** * 用户的openid */ - @JSONField(name = "openId") + @JSONField(name = "openid") private String openId; /** * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段 diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/WeixinMpAccount.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/WeixinMpAccount.java index fa37d15b..8752f3ad 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/WeixinMpAccount.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/WeixinMpAccount.java @@ -12,8 +12,7 @@ import com.foxinmy.weixin4j.model.WeixinAccount; * @className WeixinMpAccount * @author jinyu * @date Jul 6, 2016 - * @since JDK 1.8 - * @see + * @since JDK 1.6 */ public class WeixinMpAccount extends WeixinAccount { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java index 8d371d04..d209f58d 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/URLConsts.java @@ -14,15 +14,18 @@ public final class URLConsts { /** * 公众平台获取token的url */ - public static final String ASSESS_TOKEN_URL = BASE_URL + "/token?grant_type=client_credential&appid=%s&secret=%s"; + public static final String ASSESS_TOKEN_URL = BASE_URL + + "/token?grant_type=client_credential&appid=%s&secret=%s"; /** * 公众平台jssdk获取token的url */ - public static final String JS_TICKET_URL = BASE_URL + "/ticket/getticket?access_token=%s&type=%s"; + public static final String JS_TICKET_URL = BASE_URL + + "/ticket/getticket?access_token=%s&type=%s"; /** * 开放平台获取token的url */ - public static final String COMPONENT_TOKEN_URL = BASE_URL + "/component/api_component_token"; + public static final String COMPONENT_TOKEN_URL = BASE_URL + + "/component/api_component_token"; /** * 开放平台获取预授权码的url */ @@ -36,6 +39,5 @@ public final class URLConsts { /** * 开放平台oauth授权的url */ - public static final String COMPONENT_OAUTH_URL = BASE_URL - + "/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s"; + public static final String COMPONENT_OAUTH_URL = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=%s&pre_auth_code=%s&redirect_uri=%s"; } diff --git a/weixin4j-mp/src/main/resources/weixin4j.properties b/weixin4j-mp/src/main/resources/weixin4j.properties index ef4f9102..90213cd9 100644 --- a/weixin4j-mp/src/main/resources/weixin4j.properties +++ b/weixin4j-mp/src/main/resources/weixin4j.properties @@ -5,20 +5,21 @@ weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed0 "components":[{"id":"\u5e94\u7528\u7ec4\u4ef6\u7684id","secret":"\u5e94\u7528\u7ec4\u4ef6\u7684secret"}],\ "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",\ +"certificateFile":"\u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3(\u9000\u6b3e\u7b49)\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u8def\u5f84,classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199classpath:xxxxx.p12,\u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6",\ "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# weixin4j\u7684\u4e34\u65f6\u76ee\u5f55 -# \u53ef\u80fd\u5b58\u653etoken\u6587\u4ef6\u3001\u4e8c\u7ef4\u7801\u6587\u4ef6\u3001\u5a92\u4f53\u6587\u4ef6\u3001\u5bf9\u8d26\u5355\u6587\u4ef6\u7b49 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6java.io.tmpdir\u4e34\u65f6\u76ee\u5f55 -weixin4j.tmpdir= -# \u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 -# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199 -# weixin4j.certificate.file=classpath:xxxxx.p12 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6 -weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 - -# \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) +# \u516c\u4f17\u53f7\u5fae\u4fe1\u7f51\u9875oauth\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN weixin4j.user.oauth.redirect.uri= -# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528ComponentApi\u65f6\u586b\u5199) -weixin4j.component.oauth.redirect.uri= \ No newline at end of file +# \u7f51\u7ad9\u626b\u63cf\u767b\u9646oauth\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN +weixin4j.open.user.oauth.redirect.uri= + +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528ComponentApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1453779503&token=&lang=zh_CN +weixin4j.component.oauth.redirect.uri= + +# \u7b2c\u4e09\u65b9\u7ec4\u4ef6\u4ee3\u66ff\u6388\u6743\u516c\u4f17\u53f7\u53d1\u8d77\u7f51\u9875\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528ComponentApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttps://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590&token=&lang=zh_CN +weixin4j.component.user.oauth.redirect.uri= \ No newline at end of file diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelperTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelperTest.java index 23f44513..dd19833d 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelperTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/HelperTest.java @@ -44,6 +44,6 @@ public class HelperTest extends TokenTest { @Test public void clearQuota() throws WeixinException { - System.err.println(helperApi.clearQuota(settings.getAccount().getId())); + System.err.println(helperApi.clearQuota(weixinAccount.getId())); } } 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 ee9db14c..643806f9 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 @@ -7,10 +7,11 @@ import java.util.Calendar; import org.junit.Test; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.mp.api.PayOldApi; import com.foxinmy.weixin4j.mp.oldpayment.WeixinOldPayAccount; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdType; @@ -24,14 +25,14 @@ import com.foxinmy.weixin4j.type.IdType; * @see */ public class PayTest { - protected final static PayOldApi PAY2; - protected final static Weixin4jSettings settings; + private final static PayOldApi PAY2; + private final static WeixinOldPayAccount WEIXIN_OLD_PAY_ACCOUNT; static { - settings = new Weixin4jSettings( - new WeixinOldPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", - "请填入v2版本的paysignkey", "请填入v2版本的partnerId", - "请填入v2版本的partnerKey")); - PAY2 = new PayOldApi(settings); + WEIXIN_OLD_PAY_ACCOUNT = new WeixinOldPayAccount("请填入v2版本的appid", + "请填入v2版本的appSecret", "请填入v2版本的paysignkey", "请填入v2版本的partnerId", + "请填入v2版本的partnerKey"); + PAY2 = new PayOldApi(WEIXIN_OLD_PAY_ACCOUNT, + new FileCacheStorager()); } /** * 商户证书文件 diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java index 33d8f01a..6d8194b0 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java @@ -4,10 +4,11 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; @@ -22,15 +23,14 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; public class TokenTest { protected TokenManager tokenManager; - protected Weixin4jSettings settings; + protected WeixinAccount weixinAccount; @Before public void setUp() { - this.settings = new Weixin4jSettings( - Weixin4jConfigUtil.getWeixinAccount()); - tokenManager = new TokenManager(new WeixinTokenCreator(settings - .getAccount().getId(), settings.getAccount().getSecret()), - settings.getCacheStorager0()); + this.weixinAccount = Weixin4jConfigUtil.getWeixinAccount(); + tokenManager = new TokenManager(new WeixinTokenCreator( + weixinAccount.getId(), weixinAccount.getSecret()), + new FileCacheStorager()); } @Test diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/WeixinProxyTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/WeixinProxyTest.java new file mode 100644 index 00000000..ea3522e6 --- /dev/null +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/WeixinProxyTest.java @@ -0,0 +1,37 @@ +package com.foxinmy.weixin4j.mp.test; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.mp.WeixinProxy; +import com.foxinmy.weixin4j.mp.model.Menu; + +/** + * 微信接口测试 + * + * @className WeixinProxyTest + * @author jinyu(foxinmy@gmail.com) + * @date 2016年8月18日 + * @since JDK 1.6 + * @see + */ +public class WeixinProxyTest { + private WeixinProxy weixinProxy; + + @Before + public void init() { + this.weixinProxy = new WeixinProxy(); + // Weixin4jSettings settings = new + // Weixin4jSettings(RediscacheStorager); + // this.weixinProxy= new WeixinProxy(settings); + } + + @Test + public void test() throws WeixinException{ + List buttons = weixinProxy.getAllMenu(); + System.err.println(buttons); + } +} 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 51ba4afe..2ef44100 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 @@ -3,9 +3,12 @@ package com.foxinmy.weixin4j.qy; import java.io.InputStream; import java.util.List; +import com.foxinmy.weixin4j.cache.CacheStorager; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.model.Button; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.media.MediaCounter; import com.foxinmy.weixin4j.model.media.MediaDownloadResult; @@ -20,6 +23,7 @@ import com.foxinmy.weixin4j.qy.api.HelperApi; 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.OauthApi; import com.foxinmy.weixin4j.qy.api.PartyApi; import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.UserApi; @@ -45,8 +49,8 @@ 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.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.PerTicketManager; +import com.foxinmy.weixin4j.token.TokenCreator; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.type.MediaType; @@ -63,7 +67,10 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; * @see api文档 */ public class WeixinProxy { - + /** + * 授权API + */ + private final OauthApi oauthApi; /** * 媒体素材API */ @@ -105,33 +112,48 @@ public class WeixinProxy { */ private final ChatApi chatApi; /** - * token实现 + * token管理 */ private final TokenManager tokenManager; /** - * 配置信息 + * 账号信息 */ - private Weixin4jSettings settings; + private final WeixinAccount weixinAccount; + /** + * token存储 + */ + private final CacheStorager cacheStorager; /** - * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 + * 微信接口实现(使用weixin4j.properties配置的account账号信息, + * 使用FileCacheStorager文件方式缓存TOKEN) */ public WeixinProxy() { - this(new Weixin4jSettings( - Weixin4jConfigUtil.getWeixinAccount())); + this(new FileCacheStorager()); } /** - * - * @param settings - * 微信配置信息 - * @see com.foxinmy.weixin4j.setting.Weixin4jSettings + * 微信接口实现(使用weixin4j.properties配置的account账号信息) + * + * @param cacheStorager + * token管理 */ - public WeixinProxy(Weixin4jSettings settings) { - this(new TokenManager(new WeixinTokenCreator(settings.getAccount() - .getId(), settings.getAccount().getSecret()), - settings.getCacheStorager0())); - this.settings = settings; + public WeixinProxy(CacheStorager cacheStorager) { + this(Weixin4jConfigUtil.getWeixinAccount(), cacheStorager); + } + + /** + * 微信接口实现 + * + * @param weixinAccount + * 账号信息 + * @param cacheStorager + * token管理 + */ + public WeixinProxy(WeixinAccount weixinAccount, + CacheStorager cacheStorager) { + this(weixinAccount, new WeixinTokenCreator(weixinAccount.getId(), + weixinAccount.getSecret()), cacheStorager); } /** @@ -148,21 +170,37 @@ public class WeixinProxy { */ public WeixinProxy(PerTicketManager perTicketManager, TokenManager suiteTokenManager) { - this(new TokenManager(new WeixinTokenSuiteCreator(perTicketManager, - suiteTokenManager), perTicketManager.getCacheStorager())); - this.settings = new Weixin4jSettings(new WeixinAccount( - perTicketManager.getAuthAppId(), null)); + this( + new WeixinAccount(perTicketManager.getThirdId(), + perTicketManager.getThirdSecret()), + new WeixinTokenSuiteCreator(perTicketManager, suiteTokenManager), + perTicketManager.getCacheStorager()); } /** - * 注意:TokenCreator 需为 WeixinTokenCreator或WeixinTokenSuiteCreator - * - * @see com.foxinmy.weixin4j.qy.token.WeixinTokenCreator + * 微信接口实现 + * + * @param settings + * 配置信息 * @param tokenManager + * token管理 */ - private WeixinProxy(TokenManager tokenManager) { - this.tokenManager = tokenManager; + private WeixinProxy(WeixinAccount weixinAccount, TokenCreator tokenCreator, + CacheStorager cacheStorager) { + if (weixinAccount == null) { + throw new IllegalArgumentException("settings must not be empty"); + } + if (tokenCreator == null) { + throw new IllegalArgumentException("tokenCreator must not be empty"); + } + if (cacheStorager == null) { + throw new IllegalArgumentException( + "cacheStorager must not be empty"); + } + this.tokenManager = new TokenManager(tokenCreator, cacheStorager); + this.weixinAccount = weixinAccount; + this.cacheStorager = cacheStorager; + this.oauthApi = new OauthApi(weixinAccount); this.partyApi = new PartyApi(tokenManager); this.userApi = new UserApi(tokenManager); this.tagApi = new TagApi(tokenManager); @@ -184,13 +222,23 @@ public class WeixinProxy { return this.tokenManager; } + /** + * 获取oauth授权API + * + * @see com.foxinmy.weixin4j.qy.api.OauthApi + * @return + */ + public OauthApi getOauthApi() { + return oauthApi; + } + /** * 获取微信账号信息 * * @return */ public WeixinAccount getWeixinAccount() { - return this.settings.getAccount(); + return weixinAccount; } /** @@ -201,9 +249,8 @@ public class WeixinProxy { * @return */ public TokenManager getTicketManager(TicketType ticketType) { - return new TokenManager(new WeixinTicketCreator(getWeixinAccount() - .getId(), ticketType, this.tokenManager), - this.settings.getCacheStorager0()); + return new TokenManager(new WeixinTicketCreator(weixinAccount.getId(), + ticketType, this.tokenManager), cacheStorager); } /** @@ -769,11 +816,11 @@ public class WeixinProxy { * 获取部门成员 * * @param partyId - * 部门ID 必须 + * 部门ID * @param fetchChild - * 是否递归获取子部门下面的成员 非必须 + * 是否递归获取子部门下面的成员 * @param userStatus - * 成员状态 status可叠加 非必须 未填写则默认为未关注(4) + * 成员状态 status可叠加 未填写则默认为未关注(4) * @param findDetail * 是否获取详细信息 * @see com.foxinmy.weixin4j.qy.model.User @@ -789,6 +836,21 @@ public class WeixinProxy { return userApi.listUser(partyId, fetchChild, userStatus, findDetail); } + /** + * 获取权限范围内的所有成员列表 + * + * @param userStatus + * 成员状态 未填写则默认为全部状态下的成员 + * @return 成员列表 + * @see com.foxinmy.weixin4j.qy.api.UserApi + * @see {@link #listUser(int, boolean, UserStatus,boolean)} + * @see {@link PartyApi#listParty(int)} + * @throws WeixinException + */ + public List listAllUser(UserStatus userStatus) throws WeixinException { + return userApi.listAllUser(userStatus); + } + /** * 获取部门下所有状态成员(不进行递归) * 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 4b733b2f..75340030 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 @@ -7,6 +7,8 @@ import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSON; +import com.foxinmy.weixin4j.cache.CacheStorager; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; @@ -17,7 +19,6 @@ import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator; import com.foxinmy.weixin4j.qy.type.LoginTargetType; import com.foxinmy.weixin4j.qy.type.URLConsts; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.TicketManager; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.util.Consts; @@ -47,40 +48,65 @@ public class WeixinSuiteProxy { */ private ProviderApi providerApi; /** - * 配置相关 + * 企业号账号信息 */ - private final Weixin4jSettings settings; + private final WeixinQyAccount weixinQyAccount; /** - * 默认使用文件方式保存token、使用weixin4j.properties配置的账号信息 + * 微信第三方套件接口实现(使用weixin4j.properties配置的account账号信息, + * 使用FileCacheStorager文件方式缓存TOKEN) */ public WeixinSuiteProxy() { - this(new Weixin4jSettings( - JSON.parseObject(Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class))); + this(new FileCacheStorager()); } /** - * - * @param settings - * 配置信息 + * 微信第三方套件接口实现(使用weixin4j.properties配置的account账号信息) + * + * @param cacheStorager + * token管理 */ - public WeixinSuiteProxy(Weixin4jSettings settings) { - this.settings = settings; - List suites = settings.getAccount().getSuites(); + public WeixinSuiteProxy(CacheStorager cacheStorager) { + this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), + WeixinQyAccount.class), cacheStorager); + } + + /** + * 微信第三方套件接口实现 + * + * @param weixinQyAccount + * 账号信息 + * @param cacheStorager + * token管理 + */ + public WeixinSuiteProxy(WeixinQyAccount weixinQyAccount, + CacheStorager cacheStorager) { + if (weixinQyAccount == null) { + throw new IllegalArgumentException( + "weixinQyAccount must not be empty"); + } + if (cacheStorager == null) { + throw new IllegalArgumentException( + "cacheStorager must not be empty"); + } + this.weixinQyAccount = weixinQyAccount; + List suites = weixinQyAccount.getSuites(); if (suites != null && !suites.isEmpty()) { this.suiteMap = new HashMap(suites.size()); for (WeixinAccount suite : suites) { this.suiteMap.put(suite.getId(), new SuiteApi( - new TicketManager(suite.getId(), suite.getSecret(), settings.getCacheStorager0()))); + new TicketManager(suite.getId(), suite.getSecret(), + cacheStorager))); } this.suiteMap.put(null, suiteMap.get(suites.get(0).getId())); } - if (StringUtil.isNotBlank(settings.getAccount().getId()) - && StringUtil.isNotBlank(settings.getAccount().getProviderSecret())) { + if (StringUtil.isNotBlank(weixinQyAccount.getId()) + && StringUtil.isNotBlank(weixinQyAccount.getProviderSecret())) { this.providerApi = new ProviderApi( - new TokenManager(new WeixinProviderTokenCreator(settings.getAccount().getId(), - settings.getAccount().getProviderSecret()), settings.getCacheStorager0()), - settings.getCacheStorager0()); + new TokenManager(new WeixinProviderTokenCreator( + weixinQyAccount.getId(), weixinQyAccount + .getProviderSecret()), cacheStorager), + cacheStorager); } } @@ -89,8 +115,8 @@ public class WeixinSuiteProxy { * * @return */ - public WeixinQyAccount getWeixinAccount() { - return this.settings.getAccount(); + public WeixinQyAccount getWeixinQyAccount() { + return weixinQyAccount; } /** @@ -121,17 +147,19 @@ public class WeixinSuiteProxy { * @param suiteId * 套件ID * @return 预授权码 + * @see #cacheSuiteTicket(String, String) * @see com.foxinmy.weixin4j.qy.api.SuiteApi * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getTicketManager() * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getPreCodeManager() * @throws WeixinException */ public String getPreSuiteTicket(String suiteId) throws WeixinException { - Token token = suite(suiteId).getTicketManager().getTicket(); + SuiteApi suite = suite(suiteId); + Token token = suite.getTicketManager().getTicket(); if (token == null || StringUtil.isBlank(token.getAccessToken())) { throw new WeixinException("maybe oauth first?"); } - return token.getAccessToken(); + return suite.getPreCodeManager().getAccessToken(); } /** @@ -146,27 +174,33 @@ public class WeixinSuiteProxy { * 推送suite_ticket协议 * @throws WeixinException */ - public void cacheSuiteTicket(String suiteId, String suiteTicket) throws WeixinException { + public void cacheSuiteTicket(String suiteId, String suiteTicket) + throws WeixinException { suite(suiteId).getTicketManager().cachingTicket(suiteTicket); } /** - * 应用套件授权 需先缓存ticket - * - * @see {@link #getSuiteAuthorizeURL(String, String,String)} + * 应用套件授权 需先缓存ticket
  • + * redirectUri默认填写weixin4j.properties#suite.oauth.redirect.uri
  • + * state默认填写state + * * @param suiteId * 套件ID - * @see {@link #cacheSuiteTicket(String, String)} + * @see {@link #getSuiteAuthorizationURL(String, String,String)} * @return 请求授权的URL * @throws WeixinException */ - public String getSuiteAuthorizeURL(String suiteId) throws WeixinException { - String redirectUri = Weixin4jConfigUtil.getValue("suite.oauth.redirect.uri"); - return getSuiteAuthorizeURL(suiteId, redirectUri, "state"); + public String getSuiteAuthorizationURL(String suiteId) + throws WeixinException { + String redirectUri = Weixin4jConfigUtil + .getValue("suite.oauth.redirect.uri"); + return getSuiteAuthorizationURL(suiteId, redirectUri, "state"); } /** - * 应用套件授权 需先缓存ticket + * 应用套件授权 需先缓存ticket,在授权完成之后需要调用SuiteApi#exchangeAuthInfo方法 + * ,否则无法缓存token相关导致后续的组件接口调用失败 * * @param suiteId * 套件ID @@ -174,16 +208,22 @@ public class WeixinSuiteProxy { * 授权后重定向url * @param state * 回调后原样返回 + * @see #cacheSuiteTicket(String, String) + * @see com.foxinmy.weixin4j.qy.api.SuiteApi + * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getTicketManager() + * @see com.foxinmy.weixin4j.qy.api.SuiteApi#getPreCodeManager() + * @see com.foxinmy.weixin4j.qy.api.SuiteApi#exchangeAuthInfo(String) * @see 企业号第三方应用套件授权 - * @see {@link SuiteApi#getPreCodeManager} * @return 请求授权的URL * @throws WeixinException */ - public String getSuiteAuthorizeURL(String suiteId, String redirectUri, String state) throws WeixinException { + public String getSuiteAuthorizationURL(String suiteId, String redirectUri, + String state) throws WeixinException { try { - return String.format(URLConsts.SUITE_OAUTH_URL, suiteId, getPreSuiteTicket(suiteId), + return String.format(URLConsts.SUITE_OAUTH_URL, suiteId, + getPreSuiteTicket(suiteId), URLEncoder.encode(redirectUri, Consts.UTF_8.name()), state); } catch (UnsupportedEncodingException e) { ; @@ -225,7 +265,8 @@ public class WeixinSuiteProxy { * 获取登录企业号官网的url * @throws WeixinException */ - public String getLoginUrl(String corpId, LoginTargetType targetType, int agentId) throws WeixinException { + public String getLoginUrl(String corpId, LoginTargetType targetType, + int agentId) throws WeixinException { return providerApi.getLoginUrl(corpId, targetType, agentId); } @@ -240,7 +281,8 @@ public class WeixinSuiteProxy { * @return */ public WeixinProxy getWeixinProxy(String suiteId, String authCorpId) { - return new WeixinProxy(suite(suiteId).getPerTicketManager(authCorpId), suite(suiteId).getTokenManager()); + return new WeixinProxy(suite(suiteId).getPerTicketManager(authCorpId), + suite(suiteId).getTokenManager()); } public final static String VERSION = "1.7.1"; 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 74523af9..7c8685ca 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 @@ -44,33 +44,34 @@ public class OauthApi extends QyApi { } /** - * 企业号用户身份授权:重定向URL使用weixin4j.properties#user.oauth.redirect.uri - * - * @see {@link #getUserAuthorizeURL(String,String)} + * 企业号成员身份授权
  • + * redirectUri默认填写weixin4j.properties#user.oauth.redirect.uri
  • + * state默认填写state + * + * @see {@link #getUserAuthorizationURL(String,String)} * * @return 请求授权的URL */ - public String getUserAuthorizeURL() { + public String getUserAuthorizationURL() { String redirectUri = Weixin4jConfigUtil .getValue("user.oauth.redirect.uri"); - return getUserAuthorizeURL(redirectUri, "state"); + return getUserAuthorizationURL(redirectUri, "state"); } /** - * 企业号用户身份授权 + * 企业号成员身份授权 * * @param redirectUri * 重定向地址 * @param state * 用于保持请求和回调的状态 * @return 请求授权的URL - * @see UserApi - * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#getUserByCode(String)} + * @see UserApi#getOUserInfoByCode(String, String) * @see * 企业号用户身份授权 */ - public String getUserAuthorizeURL(String redirectUri, String state) { + public String getUserAuthorizationURL(String redirectUri, String state) { String oauth_uri = getRequestUri("user_oauth_uri"); try { return String.format(oauth_uri, account.getId(), @@ -82,20 +83,22 @@ public class OauthApi extends QyApi { } /** - * 企业号第三方提供商授权:重定向URL使用weixin4j.properties#third.oauth.redirect.uri + * 企业号第三方提供商登陆授权
  • + * redirectUri默认填写weixin4j.properties#third.oauth.redirect.uri
  • + * state默认填写state * - * @see {@link #getThirdAuthorizeURL(String,String)} + * @see {@link #getThirdAuthorizationURL(String,String)} * * @return 请求授权的URL */ - public String getThirdAuthorizeURL() { + public String getThirdAuthorizationURL() { String redirectUri = Weixin4jConfigUtil .getValue("third.oauth.redirect.uri"); - return getThirdAuthorizeURL(redirectUri, "state"); + return getThirdAuthorizationURL(redirectUri, "state"); } /** - * 企业号登陆授权 + * 企业号第三方提供商登陆授权 * * @param corpId * 企业号(提供商)的corpid @@ -104,13 +107,12 @@ public class OauthApi extends QyApi { * @param state * 用于保持请求和回调的状态,授权请求后原样带回给第三方 * @return 请求授权的URL - * @see ProviderApi - * @see {@link com.foxinmy.weixin4j.qy.WeixinSuiteProxy#getOUserInfoByCode(String)} + * @see ProviderApi#getOUserInfoByCode(String) * @see * 企业号第三方提供商授权 */ - public String getThirdAuthorizeURL(String redirectUri, String state) { + public String getThirdAuthorizationURL(String redirectUri, String state) { String oauth_uri = getRequestUri("provider_oauth_uri"); try { return String.format(oauth_uri, account.getId(), diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java index 9f4940f2..ef4c670b 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java @@ -12,6 +12,7 @@ import com.foxinmy.weixin4j.http.weixin.ApiResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.qy.model.OUserInfo; +import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.type.InviteType; import com.foxinmy.weixin4j.qy.type.UserStatus; @@ -33,11 +34,13 @@ import com.foxinmy.weixin4j.util.StringUtil; */ public class UserApi extends QyApi { private final MediaApi mediaApi; + private final PartyApi partyApi; private final TokenManager tokenManager; public UserApi(TokenManager tokenManager) { this.tokenManager = tokenManager; this.mediaApi = new MediaApi(tokenManager); + this.partyApi = new PartyApi(tokenManager); } /** @@ -243,11 +246,11 @@ public class UserApi extends QyApi { * 获取部门成员 * * @param partyId - * 部门ID 必须 + * 部门ID * @param fetchChild - * 是否递归获取子部门下面的成员 非必须 + * 是否递归获取子部门下面的成员 * @param userStatus - * 成员状态 status可叠加 非必须 未填写则默认为未关注(4) + * 成员状态 status可叠加 未填写则默认为未关注(4) * @param findDetail * 是否获取详细信息 * @see com.foxinmy.weixin4j.qy.model.User @@ -303,6 +306,31 @@ public class UserApi extends QyApi { return listUser(partyId, false, UserStatus.BOTH, false); } + /** + * 获取权限范围内的所有成员列表 + * + * @param userStatus + * 成员状态 未填写则默认为全部状态下的成员 + * @return 成员列表 + * @see {@link #listUser(int, boolean, UserStatus,boolean)} + * @see {@link PartyApi#listParty(int)} + * @throws WeixinException + */ + public List listAllUser(UserStatus userStatus) throws WeixinException { + List users = null; + List parties = partyApi.listParty(0); + if (!parties.isEmpty()) { + if (userStatus == null) { + userStatus = UserStatus.BOTH; + } + users = new ArrayList(); + for (Party party : parties) { + users.addAll(listUser(party.getId(), true, userStatus, true)); + } + } + return users; + } + /** * 删除成员 * diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java index c9d56e5e..05b85841 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java @@ -230,6 +230,31 @@ public class User implements Serializable { this.status = status; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((userId == null) ? 0 : userId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + User other = (User) obj; + if (userId == null) { + if (other.userId != null) + return false; + } else if (!userId.equals(other.userId)) + return false; + return true; + } + @Override public String toString() { return "User [userId=" + userId + ", name=" + name + ", partyIds=" diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java index ac080288..7c17bd13 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTicketCreator.java @@ -60,6 +60,7 @@ public class WeixinTicketCreator extends TokenCreator { } JSONObject result = response.getAsJson(); return new Token(result.getString("ticket"), - result.getLong("expires_in") * 1000l); + result.getLong("expires_in") * 1000l).pushExtra("group_id", + result.getString("group_id")); } } diff --git a/weixin4j-qy/src/main/resources/weixin4j.properties b/weixin4j-qy/src/main/resources/weixin4j.properties index ddb46748..0c1523e3 100644 --- a/weixin4j-qy/src/main/resources/weixin4j.properties +++ b/weixin4j-qy/src/main/resources/weixin4j.properties @@ -1,29 +1,23 @@ # weixin4j\u7684\u914d\u7f6e\u6587\u4ef6:\u5982\u679c\u6ca1\u6709\u8bf7\u6784\u9020\u76f8\u5e94\u53c2\u6570\u4f20\u5165 \u5982\u679c\u6709\u8bf7\u4fdd\u8bc1\u5728classpath\u7684\u6839\u76ee\u5f55\u4e0b # \u4f01\u4e1a\u53f7\u4fe1\u606f \u8bf7\u6309\u9700\u586b\u5199 -weixin4j.account={"id":"wx5132afc5da26d661","secret":"GsnKLVDI1pWArdB60Ze4iP2cwFvcW5KCAs2vLJldipilmSYxtbkcAiBcGSHHvu_I",\ +weixin4j.account={"id":"wxb4a36f8a248475e9","secret":"iZ4Bk1gQN5S9lNoECH57krBwXgcN0fQk6wuPN2cE1talXQmjRT5UcKBpz-YHPRnI",\ "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)",\ "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",\ +"certificateFile":"\u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3(\u9000\u6b3e\u7b49)\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u8def\u5f84,classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199classpath:xxxxx.p12,\u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6",\ "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} -# weixin4j\u7684\u4e34\u65f6\u76ee\u5f55 -# \u53ef\u80fd\u5b58\u653etoken\u6587\u4ef6\u3001\u4e8c\u7ef4\u7801\u6587\u4ef6\u3001\u5a92\u4f53\u6587\u4ef6\u3001\u5bf9\u8d26\u5355\u6587\u4ef6\u7b49 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6java.io.tmpdir\u4e34\u65f6\u76ee\u5f55 -weixin4j.tmpdir= -# \u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 -# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199 -# weixin4j.certificate.file=classpath:xxxxx.p12 -# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6 -weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 - -# \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) +# \u4f01\u4e1a\u53f7\u6210\u5458\u8eab\u4efd\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttp://qydev.weixin.qq.com/wiki/index.php?title=%E8%BA%AB%E4%BB%BD%E9%AA%8C%E8%AF%81 weixin4j.user.oauth.redirect.uri= -# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) +# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttp://qydev.weixin.qq.com/wiki/index.php?title=%E6%88%90%E5%91%98%E7%99%BB%E5%BD%95%E6%8E%88%E6%9D%83 weixin4j.third.oauth.redirect.uri= -# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528SuiteApi\u65f6\u586b\u5199) +# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528SuiteApi\u65f6\u586b\u5199,\u4e5f\u53ef\u81ea\u5b9a\u4e49\u4f20\u5165) +# \u8be6\u89c1\uff1ahttp://qydev.weixin.qq.com/wiki/index.php?title=%E4%BC%81%E4%B8%9A%E5%8F%B7%E7%AE%A1%E7%90%86%E5%91%98%E6%8E%88%E6%9D%83%E5%BA%94%E7%94%A8 weixin4j.suite.oauth.redirect.uri= \ No newline at end of file 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 8f494800..ba8efef8 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 @@ -4,10 +4,11 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.foxinmy.weixin4j.cache.FileCacheStorager; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator; -import com.foxinmy.weixin4j.setting.Weixin4jSettings; import com.foxinmy.weixin4j.token.TokenManager; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; @@ -22,15 +23,14 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; public class TokenTest { protected TokenManager tokenManager; - protected Weixin4jSettings settings; + protected WeixinAccount weixinAccount; @Before public void setUp() { - this.settings = new Weixin4jSettings( - Weixin4jConfigUtil.getWeixinAccount()); - tokenManager = new TokenManager(new WeixinTokenCreator(settings - .getAccount().getId(), settings.getAccount().getSecret()), - settings.getCacheStorager0()); + weixinAccount = Weixin4jConfigUtil.getWeixinAccount(); + tokenManager = new TokenManager(new WeixinTokenCreator( + weixinAccount.getId(), weixinAccount.getSecret()), + new FileCacheStorager()); } @Test