新增企业付款查询接口 & 对多个公众号的接入支持
This commit is contained in:
parent
37503acac6
commit
bb79042d4e
@ -342,3 +342,9 @@
|
||||
* 2015-06-22
|
||||
|
||||
+ **weixin4j-qy**: 新增企业号[第三方应用代理](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java)。
|
||||
|
||||
* 2015-06-23
|
||||
|
||||
+ **weixin4j-mp**: 新增企业付款查询接口
|
||||
|
||||
+ **weixin4j-server**: 对多个公众号的接入支持
|
||||
11
pom.xml
11
pom.xml
@ -110,17 +110,6 @@
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version> <executions> <execution> <id>standard</id> <phase>package</phase>
|
||||
<goals> <goal>shade</goal> </goals> <configuration> <createSourcesJar>false</createSourcesJar>
|
||||
<artifactSet> <includes> <include>com.foxinmy:weixin4j-base</include> </includes>
|
||||
</artifactSet> <createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration> </execution> <execution> <id>full</id> <phase>package</phase>
|
||||
<goals> <goal>shade</goal> </goals> <configuration> <createSourcesJar>false</createSourcesJar>
|
||||
<artifactSet> <includes> <include>com.foxinmy:weixin4j-base</include> <include>com.alibaba:fastjson</include>
|
||||
</includes> </artifactSet> <finalName>${project.artifactId}-${project.version}-full</finalName>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom> </configuration>
|
||||
</execution> </executions> </plugin> -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
|
||||
@ -113,3 +113,7 @@
|
||||
* 2015-06-04
|
||||
|
||||
+ 新增查询红包接口
|
||||
|
||||
* 2015-06-23
|
||||
|
||||
+ 新增企业付款查询接口
|
||||
@ -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 <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/mch_pay.php?chapter=14_3">企业付款查询</a>
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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("</mchid>", "</mch_id>");
|
||||
return XmlStream.fromXML(text, MPPaymentResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业付款查询 用于商户的企业付款操作进行结果查询,返回付款操作详细结果
|
||||
*
|
||||
* @param caFile
|
||||
* 证书文件(V3版本后缀为*.p12)
|
||||
* @param outTradeNo
|
||||
* 商户调用企业付款API时使用的商户订单号
|
||||
* @return 付款记录
|
||||
* @see com.foxinmy.weixin4j.mp.payment.v3.MPPaymentRecord
|
||||
* @see <a
|
||||
* href="http://pay.weixin.qq.com/wiki/doc/api/mch_pay.php?chapter=14_3">企业付款查询</a>
|
||||
* @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<MPPaymentRecord>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -181,3 +181,5 @@ redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
|
||||
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
|
||||
# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e
|
||||
mp_payment_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers
|
||||
# \u4f01\u4e1a\u4ed8\u6b3e\u67e5\u8be2
|
||||
mp_payquery_uri={mch_base_url}/mmpaymkttransfers/gettransferinfo
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <font color="red">调用接口获取单位为分,get方法转换为元方便使用</font>
|
||||
*
|
||||
* @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() + "]";
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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 + "]";
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.foxinmy.weixin4j.response;
|
||||
|
||||
|
||||
/**
|
||||
* 微信被动消息回复
|
||||
*
|
||||
@ -20,18 +21,11 @@ package com.foxinmy.weixin4j.response;
|
||||
* @see <a
|
||||
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF">企业号的被动响应消息</a>
|
||||
*/
|
||||
public interface WeixinResponse {
|
||||
public interface WeixinResponse extends SingleResponse {
|
||||
/**
|
||||
* 消息类型
|
||||
* 回复的消息类型
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getMsgType();
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String toContent();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -35,10 +35,10 @@ public class WeixinMessageDecoder extends
|
||||
private final InternalLogger logger = InternalLoggerFactory
|
||||
.getInstance(getClass());
|
||||
|
||||
private AesToken aesToken;
|
||||
private Map<String, AesToken> aesTokenMap;
|
||||
|
||||
public WeixinMessageDecoder(AesToken aesToken) {
|
||||
this.aesToken = aesToken;
|
||||
public WeixinMessageDecoder(Map<String, AesToken> 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<String, List<String>> 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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<WeixinRequest> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Object> 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("<xml>");
|
||||
content.append(String.format(
|
||||
"<ToUserName><![CDATA[%s]]></ToUserName>", userOpenId));
|
||||
"<ToUserName><![CDATA[%s]]></ToUserName>",
|
||||
messageTransfer.getFromUserName()));
|
||||
content.append(String.format(
|
||||
"<FromUserName><![CDATA[%s]]></FromUserName>",
|
||||
accountOpenId));
|
||||
"<FromUserName><![CDATA[%s]]></FromUserName>", weixinId));
|
||||
content.append(String.format(
|
||||
"<CreateTime><![CDATA[%d]]></CreateTime>",
|
||||
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);
|
||||
|
||||
@ -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<SocketChannel> {
|
||||
|
||||
private final AesToken aesToken;
|
||||
private final Map<String, AesToken> aesTokenMap;
|
||||
private final WeixinMessageDispatcher messageDispatcher;
|
||||
|
||||
public WeixinServerInitializer(AesToken aesToken,
|
||||
public WeixinServerInitializer(Map<String, AesToken> 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<SocketChannel> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String, AesToken> 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<String, AesToken>();
|
||||
this.aesTokenMap.put(aesToken.getWeixinId(), aesToken);
|
||||
this.aesTokenMap.put(null, aesToken);
|
||||
this.messageHandlerList = new LinkedList<WeixinMessageHandler>();
|
||||
this.messageInterceptorList = new LinkedList<WeixinMessageInterceptor>();
|
||||
this.messageDispatcher = new WeixinMessageDispatcher(messageMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个公众号的支持
|
||||
* <p>
|
||||
* <font color="red">请注意:需在服务接收事件的URL中附加一个名为wexin_id的参数,其值视加密模式而定,
|
||||
* 如为明文模式weixin_id则填写公众号的微信号(即原始ID),如为AES加密模式weixin_id则填写公众号的应用ID(即appid)
|
||||
* </font>
|
||||
* <p>
|
||||
*
|
||||
* @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);
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package com.foxinmy.weixin4j.suite;
|
||||
|
||||
/**
|
||||
* 应用套件回调事件
|
||||
*
|
||||
* @className SuiteEventType
|
||||
* @author jy
|
||||
* @date 2015年6月21日
|
||||
* @since JDK 1.7
|
||||
* @see <a
|
||||
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%9B%9E%E8%B0%83%E5%8D%8F%E8%AE%AE">第三方回调协议</a>
|
||||
*/
|
||||
public enum SuiteEventType {
|
||||
/**
|
||||
* 推送ticket
|
||||
*/
|
||||
suite_ticket,
|
||||
/**
|
||||
* 变更授权
|
||||
*/
|
||||
change_auth,
|
||||
/**
|
||||
* 取消授权
|
||||
*/
|
||||
cancel_auth;
|
||||
}
|
||||
@ -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 <a
|
||||
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%9B%9E%E8%B0%83%E5%8D%8F%E8%AE%AE">套件回调协议</a>
|
||||
*/
|
||||
public interface SuiteMessageHandler {
|
||||
/**
|
||||
* 处理套件消息
|
||||
*
|
||||
* @param suiteMessage
|
||||
* @return
|
||||
*/
|
||||
public SingleResponse handle(WeixinSuiteMessage suiteMessage);
|
||||
}
|
||||
@ -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 + "]";
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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> ENCRYPTTYPE_KEY = AttributeKey
|
||||
.valueOf("ENCRYPTTYPE");
|
||||
public static final AttributeKey<String> ACCOUNTOPENID_KEY = AttributeKey
|
||||
.valueOf("ACCOUNTOPENID");
|
||||
public static final AttributeKey<String> USEROPENID_KEY = AttributeKey
|
||||
.valueOf("USEROPENID");
|
||||
public static final AttributeKey<MessageTransfer> MESSAGE_TRANSFER_KEY = AttributeKey
|
||||
.valueOf("$_MESSAGETRANSFER");
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user