From bb79042d4e57a3eea2b4a0e8cb9278a595fc4a63 Mon Sep 17 00:00:00 2001 From: jinyu Date: Tue, 23 Jun 2015 22:20:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BC=81=E4=B8=9A=E4=BB=98?= =?UTF-8?q?=E6=AC=BE=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3=20&=20=E5=AF=B9?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E5=85=AC=E4=BC=97=E5=8F=B7=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 8 +- pom.xml | 11 - weixin4j-mp/CHANGE.md | 6 +- .../foxinmy/weixin4j/mp/WeixinPayProxy.java | 58 ++++-- .../com/foxinmy/weixin4j/mp/api/CashApi.java | 49 +++++ .../com/foxinmy/weixin4j/mp/api/MpApi.java | 4 +- .../com/foxinmy/weixin4j/mp/api/PayApi.java | 12 +- .../foxinmy/weixin4j/mp/api/weixin.properties | 4 +- .../mp/payment/v3/MPPaymentRecord.java | 193 ++++++++++++++++++ .../weixin4j/qy/suite/SuiteTicketHolder.java | 2 +- ...etMessage.java => WeixinSuiteMessage.java} | 13 +- .../weixin4j/request/WeixinRequest.java | 16 +- .../weixin4j/response/SingleResponse.java | 19 ++ .../weixin4j/response/WeixinResponse.java | 12 +- .../weixin4j/socket/MessageTransfer.java | 62 ++++++ .../weixin4j/socket/WeixinMessageDecoder.java | 36 ++-- .../weixin4j/socket/WeixinRequestHandler.java | 21 +- .../socket/WeixinResponseEncoder.java | 28 +-- .../socket/WeixinServerInitializer.java | 16 +- .../startup/WeixinServerBootstrap.java | 39 +++- .../weixin4j/suite/SuiteEventType.java | 26 +++ .../weixin4j/suite/SuiteMessageHandler.java | 23 +++ .../weixin4j/suite/WeixinSuiteMessage.java | 76 +++++++ .../com/foxinmy/weixin4j/util/AesToken.java | 32 ++- .../com/foxinmy/weixin4j/util/Consts.java | 10 +- .../weixin4j/xml/EncryptMessageHandler.java | 8 + .../server/test/MessageServerStartup.java | 19 +- 27 files changed, 667 insertions(+), 136 deletions(-) create mode 100644 weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentRecord.java rename weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/{SuiteTicketMessage.java => WeixinSuiteMessage.java} (84%) create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/SingleResponse.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/MessageTransfer.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteEventType.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteMessageHandler.java create mode 100644 weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/WeixinSuiteMessage.java diff --git a/CHANGE.md b/CHANGE.md index 1cda3edc..d8689ad3 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -341,4 +341,10 @@ * 2015-06-22 - + **weixin4j-qy**: 新增企业号[第三方应用代理](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java)。 \ No newline at end of file + + **weixin4j-qy**: 新增企业号[第三方应用代理](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java)。 + +* 2015-06-23 + + + **weixin4j-mp**: 新增企业付款查询接口 + + + **weixin4j-server**: 对多个公众号的接入支持 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 211d25a2..2797bc6f 100644 --- a/pom.xml +++ b/pom.xml @@ -110,17 +110,6 @@ - org.apache.maven.plugins maven-source-plugin diff --git a/weixin4j-mp/CHANGE.md b/weixin4j-mp/CHANGE.md index 5224ad67..af6b475f 100644 --- a/weixin4j-mp/CHANGE.md +++ b/weixin4j-mp/CHANGE.md @@ -112,4 +112,8 @@ * 2015-06-04 - + 新增查询红包接口 \ No newline at end of file + + 新增查询红包接口 + +* 2015-06-23 + + + 新增企业付款查询接口 \ No newline at end of file diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java index c5643329..9a38d1ca 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinPayProxy.java @@ -18,6 +18,7 @@ import com.foxinmy.weixin4j.mp.payment.coupon.CouponResult; import com.foxinmy.weixin4j.mp.payment.coupon.CouponStock; import com.foxinmy.weixin4j.mp.payment.v3.ApiResult; import com.foxinmy.weixin4j.mp.payment.v3.MPPayment; +import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentRecord; import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult; import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; import com.foxinmy.weixin4j.mp.payment.v3.RedpacketRecord; @@ -30,7 +31,6 @@ import com.foxinmy.weixin4j.mp.type.IdType; import com.foxinmy.weixin4j.mp.type.RefundType; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; -import com.foxinmy.weixin4j.util.ConfigUtil; /** * 微信支付接口实现 @@ -239,9 +239,8 @@ public class WeixinPayProxy { IdQuery idQuery, String outRefundNo, double totalFee, double refundFee, String opUserId, String opUserPasswd) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return refundV2(caFile, idQuery, outRefundNo, totalFee, refundFee, - opUserId, opUserPasswd); + return refundV2(PayApi.DEFAULT_CA_FILE, idQuery, outRefundNo, totalFee, + refundFee, opUserId, opUserPasswd); } /** @@ -358,9 +357,8 @@ public class WeixinPayProxy { public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3( IdQuery idQuery, String outRefundNo, double totalFee, double refundFee, String opUserId) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return pay3Api.refund(caFile, idQuery, outRefundNo, totalFee, - refundFee, CurrencyType.CNY, opUserId); + return pay3Api.refund(PayApi.DEFAULT_CA_FILE, idQuery, outRefundNo, + totalFee, refundFee, CurrencyType.CNY, opUserId); } /** @@ -444,8 +442,7 @@ public class WeixinPayProxy { * @throws WeixinException */ public ApiResult reverse(IdQuery idQuery) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return payApi.reverse(caFile, idQuery); + return payApi.reverse(PayApi.DEFAULT_CA_FILE, idQuery); } /** @@ -552,9 +549,8 @@ public class WeixinPayProxy { */ public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, String openId) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return couponApi.sendCoupon(caFile, couponStockId, partnerTradeNo, - openId, null); + return couponApi.sendCoupon(PayApi.DEFAULT_CA_FILE, couponStockId, + partnerTradeNo, openId, null); } /** @@ -618,8 +614,7 @@ public class WeixinPayProxy { */ public RedpacketSendResult sendRedpack(Redpacket redpacket) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return cashApi.sendRedpack(caFile, redpacket); + return cashApi.sendRedpack(PayApi.DEFAULT_CA_FILE, redpacket); } /** @@ -648,8 +643,7 @@ public class WeixinPayProxy { */ public RedpacketRecord queryRedpack(String outTradeNo) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return cashApi.queryRedpack(caFile, outTradeNo); + return cashApi.queryRedpack(PayApi.DEFAULT_CA_FILE, outTradeNo); } /** @@ -679,7 +673,35 @@ public class WeixinPayProxy { */ public MPPaymentResult mpPayment(MPPayment mpPayment) throws WeixinException { - File caFile = new File(ConfigUtil.getClassPathValue("ca_file")); - return cashApi.mpPayment(caFile, mpPayment); + return cashApi.mpPayment(PayApi.DEFAULT_CA_FILE, mpPayment); + } + + /** + * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param outTradeNo + * 商户调用企业付款API时使用的商户订单号 + * @return 付款记录 + * @see com.foxinmy.weixin4j.mp.api.CashApi + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPaymentRecord + * @see 企业付款查询 + * @throws WeixinException + */ + public MPPaymentRecord mpPaymentQuery(File caFile, String outTradeNo) + throws WeixinException { + return cashApi.mpPaymentQuery(caFile, outTradeNo); + } + + /** + * 企业付款查询采用properties中配置的ca文件 + * + * @see {@link com.foxinmy.weixin4j.mp.WeixinPayProxy#mpPaymentQuery(File, String)} + */ + public MPPaymentRecord mpPaymentQuery(String outTradeNo) + throws WeixinException { + return cashApi.mpPaymentQuery(PayApi.DEFAULT_CA_FILE, outTradeNo); } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java index e6de86f6..155790c0 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/CashApi.java @@ -16,6 +16,7 @@ import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.mp.model.WeixinMpAccount; import com.foxinmy.weixin4j.mp.payment.PayUtil; import com.foxinmy.weixin4j.mp.payment.v3.MPPayment; +import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentRecord; import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult; import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; import com.foxinmy.weixin4j.mp.payment.v3.RedpacketRecord; @@ -194,4 +195,52 @@ public class CashApi extends MpApi { .replaceFirst("", ""); return XmlStream.fromXML(text, MPPaymentResult.class); } + + /** + * 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果 + * + * @param caFile + * 证书文件(V3版本后缀为*.p12) + * @param outTradeNo + * 商户调用企业付款API时使用的商户订单号 + * @return 付款记录 + * @see com.foxinmy.weixin4j.mp.payment.v3.MPPaymentRecord + * @see 企业付款查询 + * @throws WeixinException + */ + public MPPaymentRecord mpPaymentQuery(File caFile, String outTradeNo) + throws WeixinException { + JSONObject obj = new JSONObject(); + obj.put("nonce_str", RandomUtil.generateString(16)); + obj.put("mch_id", weixinAccount.getMchId()); + obj.put("appid", weixinAccount.getId()); + obj.put("partner_trade_no", outTradeNo); + String sign = PayUtil.paysignMd5(obj, weixinAccount.getPaySignKey()); + obj.put("sign", sign); + String param = XmlStream.map2xml(obj); + String mp_payquery_uri = getRequestUri("mp_payquery_uri"); + WeixinResponse response = null; + InputStream ca = null; + try { + ca = new FileInputStream(caFile); + SSLHttpClinet request = new SSLHttpClinet(weixinAccount.getMchId(), + ca); + response = request.post(mp_payquery_uri, param); + } catch (WeixinException e) { + throw e; + } catch (IOException e) { + throw new WeixinException(e.getMessage()); + } finally { + if (ca != null) { + try { + ca.close(); + } catch (IOException e) { + ; + } + } + } + return response.getAsObject(new TypeReference() { + }); + } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java index 98cfd9d9..8801e67c 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java @@ -18,13 +18,13 @@ import com.foxinmy.weixin4j.util.ConfigUtil; * @see api文档 */ public class MpApi extends BaseApi { - + private final static ResourceBundle WEIXIN_BUNDLE; /** * 默认使用weixin4j.properties文件中的公众号信息 */ public final static WeixinMpAccount DEFAULT_WEIXIN_ACCOUNT; - + static { WEIXIN_BUNDLE = ResourceBundle .getBundle("com/foxinmy/weixin4j/mp/api/weixin"); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java index 1fac0d2e..00ed55e9 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/PayApi.java @@ -17,6 +17,7 @@ import com.foxinmy.weixin4j.mp.type.BillType; import com.foxinmy.weixin4j.mp.type.IdQuery; import com.foxinmy.weixin4j.mp.type.SignType; import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.DateUtil; /** @@ -31,6 +32,12 @@ import com.foxinmy.weixin4j.util.DateUtil; */ public abstract class PayApi extends MpApi { + /** + * 默认的证书文件 + */ + public final static File DEFAULT_CA_FILE = new File( + ConfigUtil.getClassPathValue("ca_file")); + protected final WeixinMpAccount weixinAccount; protected final TokenHolder tokenHolder; @@ -93,8 +100,9 @@ public abstract class PayApi extends MpApi { throws WeixinException { String payfeedback_update_uri = getRequestUri("payfeedback_update_uri"); Token token = tokenHolder.getToken(); - WeixinResponse response = weixinClient.get(String.format(payfeedback_update_uri, - token.getAccessToken(), openId, feedbackId)); + WeixinResponse response = weixinClient.get(String.format( + payfeedback_update_uri, token.getAccessToken(), openId, + feedbackId)); return response.getAsJsonResult(); } 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 8863efea..a36fb0ac 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 @@ -180,4 +180,6 @@ redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack # \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305 redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo # \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e -mp_payment_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers \ No newline at end of file +mp_payment_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers +# \u4f01\u4e1a\u4ed8\u6b3e\u67e5\u8be2 +mp_payquery_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo \ No newline at end of file diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentRecord.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentRecord.java new file mode 100644 index 00000000..c5d4c0d1 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/payment/v3/MPPaymentRecord.java @@ -0,0 +1,193 @@ +package com.foxinmy.weixin4j.mp.payment.v3; + +import java.util.Date; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.mp.type.MPPaymentCheckNameType; +import com.foxinmy.weixin4j.util.DateUtil; + +/** + * 企业付款记录 + * + * @className MPPaymentRecord + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class MPPaymentRecord extends ApiResult { + + private static final long serialVersionUID = -1926873539419750498L; + + /** + * 微信订单订单号 + */ + @JSONField(name = "detail_id") + @XmlElement(name = "detail_id") + private String transactionId; + /** + * 商户订单号 + */ + @JSONField(name = "partner_trade_no") + @XmlElement(name = "partner_trade_no") + private String outTradeNo; + /** + * 交易状态 SUCCESS:转账成功 FAILED:转账失败 + */ + @JSONField(name = "status") + @XmlElement(name = "status") + private String transactionStatus; + /** + * 如果失败则应该有原因 + */ + @JSONField(name = "reason") + @XmlElement(name = "reason") + private String failureReason; + /** + * 收款用户openid + */ + private String openid; + /** + * 收款用户姓名 + */ + @JSONField(name = "transfer_name") + @XmlElement(name = "transfer_name") + private String transferName; + /** + * 付款金额(单位为分) + */ + @JSONField(name = "payment_amount") + @XmlElement(name = "payment_amount") + private int paymentAmount; + /** + * 转账时间 + */ + @JSONField(name = "transfer_time") + @XmlElement(name = "transfer_time") + private String transferTime; + /** + * 校验用户姓名选项 + * + * @see com.foxinmy.weixin4j.mp.type.MPPaymentCheckNameType + */ + @XmlElement(name = "check_name") + @JSONField(name = "check_name") + private MPPaymentCheckNameType checkNameType; + /** + * 企业付款描述信息 + */ + private String desc; + /** + * 实名验证结果 PASS:通过 FAILED:不通过 + */ + @JSONField(name = "check_name_result") + @XmlElement(name = "check_name_result") + private String checkNameResult; + + protected MPPaymentRecord() { + // jaxb required + } + + public String getTransactionId() { + return transactionId; + } + + public String getOutTradeNo() { + return outTradeNo; + } + + public String getTransactionStatus() { + return transactionStatus; + } + + /** + * 格式化交易状态 + * + * @return + */ + @JSONField(serialize = false) + public boolean getFormatTransactionStatus() { + return "success".equalsIgnoreCase(transactionStatus); + } + + public String getFailureReason() { + return failureReason; + } + + public String getOpenid() { + return openid; + } + + public String getTransferName() { + return transferName; + } + + public int getPaymentAmount() { + return paymentAmount; + } + + /** + * 调用接口获取单位为分,get方法转换为元方便使用 + * + * @return 元单位 + */ + @JSONField(serialize = false) + public double getFormatPaymentAmount() { + return paymentAmount / 100d; + } + + public String getTransferTime() { + return transferTime; + } + + /** + * 格式化转账时间 + * + * @return + */ + @JSONField(serialize = false) + public Date getFormatTransferTime() { + return DateUtil.parse2yyyyMMddHHmmss(transferTime); + } + + public MPPaymentCheckNameType getCheckNameType() { + return checkNameType; + } + + public String getDesc() { + return desc; + } + + public String getCheckNameResult() { + return checkNameResult; + } + + /** + * 格式化交易状态 + * + * @return + */ + @JSONField(serialize = false) + public boolean getFormatCheckNameResult() { + return "pass".equalsIgnoreCase(checkNameResult); + } + + @Override + public String toString() { + return "MPPaymentRecord [transactionId=" + transactionId + + ", outTradeNo=" + outTradeNo + ", transactionStatus=" + + getFormatTransactionStatus() + ", failureReason=" + + failureReason + ", openid=" + openid + ", transferName=" + + transferName + ", paymentAmount=" + getFormatPaymentAmount() + + ", transferTime=" + transferTime + ", checkNameType=" + + checkNameType + ", desc=" + desc + ", checkNameResult=" + + getFormatCheckNameResult() + ", " + super.toString() + "]"; + } +} diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java index 6d22372f..9cb2f87f 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketHolder.java @@ -48,7 +48,7 @@ public class SuiteTicketHolder { * @param suiteTicket * @throws WeixinException */ - public void cachingTicket(SuiteTicketMessage suiteTicket) + public void cachingTicket(WeixinSuiteMessage suiteTicket) throws WeixinException { Token token = new Token(suiteTicket.getSuiteTicket()); token.setExpiresIn(-1); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteMessage.java similarity index 84% rename from weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java rename to weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteMessage.java index 767bb5e9..778c415d 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/SuiteTicketMessage.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/suite/WeixinSuiteMessage.java @@ -7,9 +7,18 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +/** + * 套件消息 + * + * @className WeixinSuiteMessage + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see + */ @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class SuiteTicketMessage implements Serializable { +public class WeixinSuiteMessage implements Serializable { private static final long serialVersionUID = 6457919241019021514L; /** @@ -60,7 +69,7 @@ public class SuiteTicketMessage implements Serializable { @Override public String toString() { - return "SuiteTicketMessage [suiteId=" + suiteId + ", eventType=" + return "WeixinSuiteMessage [suiteId=" + suiteId + ", eventType=" + eventType + ", timeStamp=" + timeStamp + ", SuiteTicket=" + SuiteTicket + ", authCorpId=" + authCorpId + "]"; } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/request/WeixinRequest.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/request/WeixinRequest.java index ed180e18..57191f91 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/request/WeixinRequest.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/request/WeixinRequest.java @@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.request; import java.io.Serializable; import com.foxinmy.weixin4j.type.EncryptType; +import com.foxinmy.weixin4j.util.AesToken; /** * 微信请求 @@ -60,10 +61,15 @@ public class WeixinRequest implements Serializable, Cloneable { * xml消息密文主体(AES时存在) */ private String encryptContent; + /** + * aes & token + */ + private AesToken aesToken; public WeixinRequest(String method, EncryptType encryptType, String echoStr, String timeStamp, String nonce, String signature, - String msgSignature, String originalContent, String encryptContent) { + String msgSignature, String originalContent, String encryptContent, + AesToken aesToken) { this.method = method; this.encryptType = encryptType; this.echoStr = echoStr; @@ -73,6 +79,7 @@ public class WeixinRequest implements Serializable, Cloneable { this.msgSignature = msgSignature; this.originalContent = originalContent; this.encryptContent = encryptContent; + this.aesToken = aesToken; } public String getMethod() { @@ -111,12 +118,17 @@ public class WeixinRequest implements Serializable, Cloneable { return encryptContent; } + public AesToken getAesToken() { + return aesToken; + } + @Override public String toString() { return "WeixinRequest [encryptContent=" + encryptContent + ", encryptType=" + encryptType + ", echoStr=" + echoStr + ", timeStamp=" + timeStamp + ", nonce=" + nonce + ", signature=" + signature + ", originalContent=" - + originalContent + ", method=" + method + "]"; + + originalContent + ", method=" + method + ", aesToken=" + + aesToken + "]"; } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/SingleResponse.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/SingleResponse.java new file mode 100644 index 00000000..a58ff098 --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/SingleResponse.java @@ -0,0 +1,19 @@ +package com.foxinmy.weixin4j.response; + +/** + * 单一的字符串回复,如回复SUCCESS + * + * @className SingleResponse + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see + */ +public interface SingleResponse { + /** + * 回复内容 + * + * @return + */ + public String toContent(); +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/WeixinResponse.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/WeixinResponse.java index 189496b7..c4a1ed21 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/WeixinResponse.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/response/WeixinResponse.java @@ -1,5 +1,6 @@ package com.foxinmy.weixin4j.response; + /** * 微信被动消息回复 * @@ -20,18 +21,11 @@ package com.foxinmy.weixin4j.response; * @see 企业号的被动响应消息 */ -public interface WeixinResponse { +public interface WeixinResponse extends SingleResponse { /** - * 消息类型 + * 回复的消息类型 * * @return */ public String getMsgType(); - - /** - * 消息内容 - * - * @return - */ - public String toContent(); } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/MessageTransfer.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/MessageTransfer.java new file mode 100644 index 00000000..a4d1d924 --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/MessageTransfer.java @@ -0,0 +1,62 @@ +package com.foxinmy.weixin4j.socket; + +import java.io.Serializable; + +import com.foxinmy.weixin4j.type.EncryptType; +import com.foxinmy.weixin4j.util.AesToken; + +/** + * 消息传递 + * + * @className MessageTransfer + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see + */ +public class MessageTransfer implements Serializable { + + private static final long serialVersionUID = 7779948135156353261L; + + /** + * aes & token + */ + private AesToken aesToken; + /** + * 加密类型 + */ + private EncryptType encryptType; + + /** + * 消息接收方 + */ + private String toUserName; + /** + * 消息发送方 + */ + private String fromUserName; + + public MessageTransfer(AesToken aesToken, EncryptType encryptType, + String toUserName, String fromUserName) { + this.aesToken = aesToken; + this.encryptType = encryptType; + this.toUserName = toUserName; + this.fromUserName = fromUserName; + } + + public AesToken getAesToken() { + return aesToken; + } + + public EncryptType getEncryptType() { + return encryptType; + } + + public String getToUserName() { + return toUserName; + } + + public String getFromUserName() { + return fromUserName; + } +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java index 0d77baed..5d7d3642 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinMessageDecoder.java @@ -35,10 +35,10 @@ public class WeixinMessageDecoder extends private final InternalLogger logger = InternalLoggerFactory .getInstance(getClass()); - private AesToken aesToken; + private Map aesTokenMap; - public WeixinMessageDecoder(AesToken aesToken) { - this.aesToken = aesToken; + public WeixinMessageDecoder(Map aesTokenMap) { + this.aesTokenMap = aesTokenMap; } @Override @@ -47,8 +47,9 @@ public class WeixinMessageDecoder extends String content = req.content().toString(Consts.UTF_8); QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(), true); + String methodName = req.getMethod().name(); logger.info("decode request:{} use {} method invoking", req.getUri(), - req.getMethod().name()); + methodName); Map> parameters = queryDecoder.parameters(); EncryptType encryptType = parameters.containsKey("encrypt_type") ? EncryptType .valueOf(parameters.get("encrypt_type").get(0).toUpperCase()) @@ -63,22 +64,23 @@ public class WeixinMessageDecoder extends .get("signature").get(0) : ""; String msgSignature = parameters.containsKey("msg_signature") ? parameters .get("msg_signature").get(0) : ""; + String weixinId = parameters.containsKey("weixin_id") ? parameters.get( + "weixin_id").get(0) : null; + AesToken aesToken = aesTokenMap.get(weixinId); String originalContent = content; String encryptContent = null; - if (!content.isEmpty()) { - if (encryptType == EncryptType.AES) { - if (StringUtil.isBlank(aesToken.getAesKey()) - || StringUtil.isBlank(aesToken.getAppid())) { - throw new WeixinException( - "AESEncodingKey or AppId not be null in AES mode"); - } - encryptContent = EncryptMessageHandler.parser(content); - originalContent = MessageUtil.aesDecrypt(aesToken.getAppid(), - aesToken.getAesKey(), encryptContent); + if (!content.isEmpty() && encryptType == EncryptType.AES) { + if (StringUtil.isBlank(aesToken.getAesKey()) + || StringUtil.isBlank(aesToken.getWeixinId())) { + throw new WeixinException( + "AESEncodingKey or WeixinId not be null in AES mode"); } + encryptContent = EncryptMessageHandler.parser(content); + originalContent = MessageUtil.aesDecrypt(aesToken.getWeixinId(), + aesToken.getAesKey(), encryptContent); } - out.add(new WeixinRequest(req.getMethod().name(), encryptType, echoStr, - timeStamp, nonce, signature, msgSignature, originalContent, - encryptContent)); + out.add(new WeixinRequest(methodName, encryptType, echoStr, timeStamp, + nonce, signature, msgSignature, originalContent, + encryptContent, aesToken)); } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java index 0a9a1eef..b99c9d8d 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinRequestHandler.java @@ -18,7 +18,6 @@ import com.foxinmy.weixin4j.util.AesToken; import com.foxinmy.weixin4j.util.Consts; import com.foxinmy.weixin4j.util.HttpUtil; import com.foxinmy.weixin4j.util.MessageUtil; -import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.xml.CruxMessageHandler; /** @@ -34,12 +33,11 @@ public class WeixinRequestHandler extends SimpleChannelInboundHandler { private final InternalLogger logger = InternalLoggerFactory .getInstance(getClass()); - private final AesToken aesToken; + private final WeixinMessageDispatcher messageDispatcher; - public WeixinRequestHandler(AesToken aesToken, - WeixinMessageDispatcher messageDispatcher) throws WeixinException { - this.aesToken = aesToken; + public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher) + throws WeixinException { this.messageDispatcher = messageDispatcher; } @@ -56,6 +54,7 @@ public class WeixinRequestHandler extends @Override protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request) throws WeixinException { + final AesToken aesToken = request.getAesToken(); if (request.getMethod().equals(HttpMethod.GET.name())) { if (MessageUtil.signature(aesToken.getToken(), request.getTimeStamp(), request.getNonce()).equals( @@ -98,14 +97,10 @@ public class WeixinRequestHandler extends } CruxMessageHandler cruxMessage = CruxMessageHandler.parser(request .getOriginalContent()); - ctx.channel().attr(Consts.ENCRYPTTYPE_KEY) - .set(request.getEncryptType()); - ctx.channel().attr(Consts.USEROPENID_KEY) - .set(cruxMessage.getFromUserName()); - if (StringUtil.isBlank(aesToken.getAppid())) { - ctx.channel().attr(Consts.ACCOUNTOPENID_KEY) - .set(cruxMessage.getToUserName()); - } + MessageTransfer messageTransfer = new MessageTransfer(aesToken, + request.getEncryptType(), cruxMessage.getToUserName(), + cruxMessage.getFromUserName()); + ctx.channel().attr(Consts.MESSAGE_TRANSFER_KEY).set(messageTransfer); messageDispatcher.doDispatch(ctx, request, cruxMessage); } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java index 032646f7..8343aa90 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinResponseEncoder.java @@ -36,22 +36,16 @@ public class WeixinResponseEncoder extends private final InternalLogger logger = InternalLoggerFactory .getInstance(getClass()); - private final AesToken aesToken; - - public WeixinResponseEncoder(AesToken aesToken) { - this.aesToken = aesToken; - } - @Override protected void encode(ChannelHandlerContext ctx, WeixinResponse response, List out) throws WeixinException { - EncryptType encryptType = ctx.channel().attr(Consts.ENCRYPTTYPE_KEY) - .get(); - String userOpenId = ctx.channel().attr(Consts.USEROPENID_KEY).get(); - String accountOpenId = ctx.channel().attr(Consts.ACCOUNTOPENID_KEY) - .get(); - if (StringUtil.isBlank(accountOpenId)) { - accountOpenId = aesToken.getAppid(); + MessageTransfer messageTransfer = ctx.channel() + .attr(Consts.MESSAGE_TRANSFER_KEY).get(); + AesToken aesToken = messageTransfer.getAesToken(); + EncryptType encryptType = messageTransfer.getEncryptType(); + String weixinId = aesToken.getWeixinId(); + if (StringUtil.isBlank(weixinId)) { + weixinId = messageTransfer.getToUserName(); } StringBuilder content = new StringBuilder(); if (response instanceof BlankResponse) { @@ -59,10 +53,10 @@ public class WeixinResponseEncoder extends } else { content.append(""); content.append(String.format( - "", userOpenId)); + "", + messageTransfer.getFromUserName())); content.append(String.format( - "", - accountOpenId)); + "", weixinId)); content.append(String.format( "", System.currentTimeMillis() / 1000l)); @@ -74,7 +68,7 @@ public class WeixinResponseEncoder extends String nonce = RandomUtil.generateString(32); String timestamp = String .valueOf(System.currentTimeMillis() / 1000l); - String encrtypt = MessageUtil.aesEncrypt(accountOpenId, + String encrtypt = MessageUtil.aesEncrypt(weixinId, aesToken.getAesKey(), content.toString()); String msgSignature = MessageUtil.signature( aesToken.getToken(), nonce, timestamp, encrtypt); diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinServerInitializer.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinServerInitializer.java index 269b1f05..386af7be 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinServerInitializer.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/socket/WeixinServerInitializer.java @@ -6,6 +6,8 @@ import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; +import java.util.Map; + import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.util.AesToken; @@ -21,15 +23,15 @@ import com.foxinmy.weixin4j.util.AesToken; */ public class WeixinServerInitializer extends ChannelInitializer { - private final AesToken aesToken; + private final Map aesTokenMap; private final WeixinMessageDispatcher messageDispatcher; - public WeixinServerInitializer(AesToken aesToken, + public WeixinServerInitializer(Map aesTokenMap, WeixinMessageDispatcher messageDispatcher) throws WeixinException { - if (aesToken == null) { + if (aesTokenMap.isEmpty()) { throw new WeixinException("AesToken not be null."); } - this.aesToken = aesToken; + this.aesTokenMap = aesTokenMap; this.messageDispatcher = messageDispatcher; } @@ -38,8 +40,8 @@ public class WeixinServerInitializer extends ChannelInitializer { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(65536)); - pipeline.addLast(new WeixinMessageDecoder(aesToken)); - pipeline.addLast(new WeixinResponseEncoder(aesToken)); - pipeline.addLast(new WeixinRequestHandler(aesToken, messageDispatcher)); + pipeline.addLast(new WeixinMessageDecoder(aesTokenMap)); + pipeline.addLast(new WeixinResponseEncoder()); + pipeline.addLast(new WeixinRequestHandler(messageDispatcher)); } } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java index d7e14a79..7084715c 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java @@ -11,8 +11,10 @@ import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import com.foxinmy.weixin4j.dispatcher.BeanFactory; import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher; @@ -54,7 +56,7 @@ public final class WeixinServerBootstrap { /** * 服务启动的默认端口 */ - public final static int DEFAULT_SERVERPORT = 30000; + public final static int DEFAULT_SERVERPORT = 80; /** * 消息分发器 */ @@ -73,16 +75,19 @@ public final class WeixinServerBootstrap { * aes and token * */ - private final AesToken aesToken; + private final Map aesTokenMap; /** * 明文模式 * - * * @param token 开发者token + * @param openid + * 微信号(原始ID) + * @param token + * 开发者token * */ - public WeixinServerBootstrap(String token) { - this(new AesToken(token)); + public WeixinServerBootstrap(String openid, String token) { + this(openid, token, null); } /** @@ -105,12 +110,32 @@ public final class WeixinServerBootstrap { public WeixinServerBootstrap(AesToken aesToken, WeixinMessageMatcher messageMatcher) { - this.aesToken = aesToken; + this.aesTokenMap = new HashMap(); + this.aesTokenMap.put(aesToken.getWeixinId(), aesToken); + this.aesTokenMap.put(null, aesToken); this.messageHandlerList = new LinkedList(); this.messageInterceptorList = new LinkedList(); this.messageDispatcher = new WeixinMessageDispatcher(messageMatcher); } + /** + * 多个公众号的支持 + *

+ * 请注意:需在服务接收事件的URL中附加一个名为wexin_id的参数,其值视加密模式而定, + * 如为明文模式weixin_id则填写公众号的微信号(即原始ID),如为AES加密模式weixin_id则填写公众号的应用ID(即appid) + * + *

+ * + * @param aesTokens + * @return + */ + public WeixinServerBootstrap multAesToken(AesToken... aesTokens) { + for (AesToken aesToken : aesTokens) { + this.aesTokenMap.put(aesToken.getWeixinId(), aesToken); + } + return this; + } + /** * 默认端口启动服务 * @@ -144,7 +169,7 @@ public final class WeixinServerBootstrap { .channel(NioServerSocketChannel.class) .handler(new LoggingHandler()) .childHandler( - new WeixinServerInitializer(aesToken, + new WeixinServerInitializer(aesTokenMap, messageDispatcher)); Channel ch = b.bind(serverPort).sync().channel(); logger.info("weixin4j server startup OK:{}", serverPort); diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteEventType.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteEventType.java new file mode 100644 index 00000000..0e57bc6a --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteEventType.java @@ -0,0 +1,26 @@ +package com.foxinmy.weixin4j.suite; + +/** + * 应用套件回调事件 + * + * @className SuiteEventType + * @author jy + * @date 2015年6月21日 + * @since JDK 1.7 + * @see 第三方回调协议 + */ +public enum SuiteEventType { + /** + * 推送ticket + */ + suite_ticket, + /** + * 变更授权 + */ + change_auth, + /** + * 取消授权 + */ + cancel_auth; +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteMessageHandler.java new file mode 100644 index 00000000..1fa269c9 --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/SuiteMessageHandler.java @@ -0,0 +1,23 @@ +package com.foxinmy.weixin4j.suite; + +import com.foxinmy.weixin4j.response.SingleResponse; + +/** + * 处理第三方应用套件请求 + * + * @className SuiteMessageHandler + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see 套件回调协议 + */ +public interface SuiteMessageHandler { + /** + * 处理套件消息 + * + * @param suiteMessage + * @return + */ + public SingleResponse handle(WeixinSuiteMessage suiteMessage); +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/WeixinSuiteMessage.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/WeixinSuiteMessage.java new file mode 100644 index 00000000..7bcf9451 --- /dev/null +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/suite/WeixinSuiteMessage.java @@ -0,0 +1,76 @@ +package com.foxinmy.weixin4j.suite; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * 套件消息 + * + * @className WeixinSuiteMessage + * @author jy + * @date 2015年6月23日 + * @since JDK 1.7 + * @see + */ +@XmlRootElement(name = "xml") +@XmlAccessorType(XmlAccessType.FIELD) +public class WeixinSuiteMessage implements Serializable { + + private static final long serialVersionUID = 6457919241019021514L; + /** + * 应用套件的SuiteId + */ + @XmlElement(name = "SuiteId") + private String suiteId; + /** + * 事件类型 + */ + @XmlElement(name = "InfoType") + private SuiteEventType eventType; + /** + * 时间戳 + */ + @XmlElement(name = "TimeStamp") + private long timeStamp; + /** + * Ticket内容 + */ + @XmlElement(name = "SuiteTicket") + private String SuiteTicket; + /** + * 授权方企业号的corpid + */ + @XmlElement(name = "AuthCorpId") + private String authCorpId; + + public String getSuiteId() { + return suiteId; + } + + public SuiteEventType getEventType() { + return eventType; + } + + public long getTimeStamp() { + return timeStamp; + } + + public String getSuiteTicket() { + return SuiteTicket; + } + + public String getAuthCorpId() { + return authCorpId; + } + + @Override + public String toString() { + return "WeixinSuiteMessage [suiteId=" + suiteId + ", eventType=" + + eventType + ", timeStamp=" + timeStamp + ", SuiteTicket=" + + SuiteTicket + ", authCorpId=" + authCorpId + "]"; + } +} diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/AesToken.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/AesToken.java index d2f119d0..d05c1f43 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/AesToken.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/AesToken.java @@ -16,9 +16,9 @@ public class AesToken implements Serializable { private static final long serialVersionUID = -6001008896414323534L; /** - * 账号ID + * 账号ID(原始ID或者appid) */ - private String appid; + private String weixinId; /** * 开发者的token */ @@ -28,18 +28,36 @@ public class AesToken implements Serializable { */ private String aesKey; - public AesToken(String token) { - this.token = token; + /** + * 一般为明文模式 + * + * @param openid + * 微信号(原始ID) + * @param token + * 开发者的Token + */ + public AesToken(String openid, String token) { + this(openid, token, null); } + /** + * 一般为AES加密模式 + * + * @param appid + * 应用ID + * @param token + * 开发者Token + * @param aesKey + * 解密的EncodingAESKey + */ public AesToken(String appid, String token, String aesKey) { - this.appid = appid; + this.weixinId = appid; this.token = token; this.aesKey = aesKey; } - public String getAppid() { - return appid; + public String getWeixinId() { + return weixinId; } public String getToken() { diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/Consts.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/Consts.java index 78a76cd3..e1bded87 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/Consts.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/util/Consts.java @@ -4,7 +4,7 @@ import io.netty.util.AttributeKey; import java.nio.charset.Charset; -import com.foxinmy.weixin4j.type.EncryptType; +import com.foxinmy.weixin4j.socket.MessageTransfer; /** * 常量类 @@ -35,10 +35,6 @@ public final class Consts { public static final String CONTENTTYPE$APPLICATION_XML = "application/xml"; public static final String CONTENTTYPE$TEXT_PLAIN = "text/plain"; - public static final AttributeKey ENCRYPTTYPE_KEY = AttributeKey - .valueOf("ENCRYPTTYPE"); - public static final AttributeKey ACCOUNTOPENID_KEY = AttributeKey - .valueOf("ACCOUNTOPENID"); - public static final AttributeKey USEROPENID_KEY = AttributeKey - .valueOf("USEROPENID"); + public static final AttributeKey MESSAGE_TRANSFER_KEY = AttributeKey + .valueOf("$_MESSAGETRANSFER"); } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java index 3237394e..8c20e05a 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/xml/EncryptMessageHandler.java @@ -23,11 +23,13 @@ import com.foxinmy.weixin4j.util.Consts; */ public class EncryptMessageHandler extends DefaultHandler { + private String toUserName; private String encryptContent; private String content; @Override public void startDocument() throws SAXException { + toUserName = null; encryptContent = null; } @@ -42,6 +44,8 @@ public class EncryptMessageHandler extends DefaultHandler { throws SAXException { if (localName.equalsIgnoreCase("encrypt")) { encryptContent = content; + } else if (localName.equalsIgnoreCase("tousername")) { + toUserName = content; } } @@ -51,6 +55,10 @@ public class EncryptMessageHandler extends DefaultHandler { this.content = new String(ch, start, length); } + public String getToUserName() { + return toUserName; + } + public String getEncryptContent() { return encryptContent; } diff --git a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java index 940a1c30..20043800 100644 --- a/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java +++ b/weixin4j-server/src/test/java/com/foxinmy/weixin4j/server/test/MessageServerStartup.java @@ -2,8 +2,6 @@ package com.foxinmy.weixin4j.server.test; import io.netty.channel.ChannelHandlerContext; -import java.math.BigDecimal; - import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.handler.BlankMessageHandler; import com.foxinmy.weixin4j.handler.DebugMessageHandler; @@ -27,6 +25,8 @@ import com.foxinmy.weixin4j.startup.WeixinServerBootstrap; */ public class MessageServerStartup { + // 微信号(原始ID) + final String openid = "gh_22b350df957b"; // 应用ID final String appid = "wx4ab8f8de58159a57"; // 开发者token @@ -41,8 +41,8 @@ public class MessageServerStartup { */ public void test1() throws WeixinException { // 所有请求都回复调试的文本消息 - new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global) - .startup(); + new WeixinServerBootstrap(openid, token).addHandler( + DebugMessageHandler.global).startup(); } /** @@ -78,8 +78,8 @@ public class MessageServerStartup { public void test4() throws WeixinException { // 扫描包加载消息处理器 String packageToScan = "com.foxinmy.weixin4j.handler"; - new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan) - .startup(); + new WeixinServerBootstrap(openid, token).handlerPackagesToScan( + packageToScan).startup(); } public void test5() throws WeixinException { @@ -109,14 +109,11 @@ public class MessageServerStartup { System.err.println("请求处理完毕"); } }; - new WeixinServerBootstrap(token).addInterceptor(interceptor) + new WeixinServerBootstrap(openid, token).addInterceptor(interceptor) .addHandler(BlankMessageHandler.global).startup(); } public static void main(String[] args) throws Exception { - - System.err.println(new BigDecimal(new Long(14212345l)).divide( - new BigDecimal("100000")) - .toString()); + new MessageServerStartup().test1(); } }