新增企业付款查询接口 & 对多个公众号的接入支持
This commit is contained in:
parent
37503acac6
commit
bb79042d4e
@ -341,4 +341,10 @@
|
|||||||
|
|
||||||
* 2015-06-22
|
* 2015-06-22
|
||||||
|
|
||||||
+ **weixin4j-qy**: 新增企业号[第三方应用代理](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinSuiteProxy.java)。
|
+ **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>
|
</plugins>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<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>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
|||||||
@ -112,4 +112,8 @@
|
|||||||
|
|
||||||
* 2015-06-04
|
* 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.coupon.CouponStock;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
|
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.MPPayment;
|
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.MPPaymentResult;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.Redpacket;
|
import com.foxinmy.weixin4j.mp.payment.v3.Redpacket;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.RedpacketRecord;
|
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.mp.type.RefundType;
|
||||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||||
import com.foxinmy.weixin4j.token.TokenStorager;
|
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,
|
IdQuery idQuery, String outRefundNo, double totalFee,
|
||||||
double refundFee, String opUserId, String opUserPasswd)
|
double refundFee, String opUserId, String opUserPasswd)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return refundV2(PayApi.DEFAULT_CA_FILE, idQuery, outRefundNo, totalFee,
|
||||||
return refundV2(caFile, idQuery, outRefundNo, totalFee, refundFee,
|
refundFee, opUserId, opUserPasswd);
|
||||||
opUserId, opUserPasswd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -358,9 +357,8 @@ public class WeixinPayProxy {
|
|||||||
public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3(
|
public com.foxinmy.weixin4j.mp.payment.v3.RefundResult refundV3(
|
||||||
IdQuery idQuery, String outRefundNo, double totalFee,
|
IdQuery idQuery, String outRefundNo, double totalFee,
|
||||||
double refundFee, String opUserId) throws WeixinException {
|
double refundFee, String opUserId) throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return pay3Api.refund(PayApi.DEFAULT_CA_FILE, idQuery, outRefundNo,
|
||||||
return pay3Api.refund(caFile, idQuery, outRefundNo, totalFee,
|
totalFee, refundFee, CurrencyType.CNY, opUserId);
|
||||||
refundFee, CurrencyType.CNY, opUserId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -444,8 +442,7 @@ public class WeixinPayProxy {
|
|||||||
* @throws WeixinException
|
* @throws WeixinException
|
||||||
*/
|
*/
|
||||||
public ApiResult reverse(IdQuery idQuery) throws WeixinException {
|
public ApiResult reverse(IdQuery idQuery) throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return payApi.reverse(PayApi.DEFAULT_CA_FILE, idQuery);
|
||||||
return payApi.reverse(caFile, idQuery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -552,9 +549,8 @@ public class WeixinPayProxy {
|
|||||||
*/
|
*/
|
||||||
public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
|
public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
|
||||||
String openId) throws WeixinException {
|
String openId) throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return couponApi.sendCoupon(PayApi.DEFAULT_CA_FILE, couponStockId,
|
||||||
return couponApi.sendCoupon(caFile, couponStockId, partnerTradeNo,
|
partnerTradeNo, openId, null);
|
||||||
openId, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -618,8 +614,7 @@ public class WeixinPayProxy {
|
|||||||
*/
|
*/
|
||||||
public RedpacketSendResult sendRedpack(Redpacket redpacket)
|
public RedpacketSendResult sendRedpack(Redpacket redpacket)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return cashApi.sendRedpack(PayApi.DEFAULT_CA_FILE, redpacket);
|
||||||
return cashApi.sendRedpack(caFile, redpacket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -648,8 +643,7 @@ public class WeixinPayProxy {
|
|||||||
*/
|
*/
|
||||||
public RedpacketRecord queryRedpack(String outTradeNo)
|
public RedpacketRecord queryRedpack(String outTradeNo)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return cashApi.queryRedpack(PayApi.DEFAULT_CA_FILE, outTradeNo);
|
||||||
return cashApi.queryRedpack(caFile, outTradeNo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -679,7 +673,35 @@ public class WeixinPayProxy {
|
|||||||
*/
|
*/
|
||||||
public MPPaymentResult mpPayment(MPPayment mpPayment)
|
public MPPaymentResult mpPayment(MPPayment mpPayment)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
File caFile = new File(ConfigUtil.getClassPathValue("ca_file"));
|
return cashApi.mpPayment(PayApi.DEFAULT_CA_FILE, mpPayment);
|
||||||
return cashApi.mpPayment(caFile, 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.model.WeixinMpAccount;
|
||||||
import com.foxinmy.weixin4j.mp.payment.PayUtil;
|
import com.foxinmy.weixin4j.mp.payment.PayUtil;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.MPPayment;
|
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.MPPaymentResult;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.Redpacket;
|
import com.foxinmy.weixin4j.mp.payment.v3.Redpacket;
|
||||||
import com.foxinmy.weixin4j.mp.payment.v3.RedpacketRecord;
|
import com.foxinmy.weixin4j.mp.payment.v3.RedpacketRecord;
|
||||||
@ -194,4 +195,52 @@ public class CashApi extends MpApi {
|
|||||||
.replaceFirst("</mchid>", "</mch_id>");
|
.replaceFirst("</mchid>", "</mch_id>");
|
||||||
return XmlStream.fromXML(text, MPPaymentResult.class);
|
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>() {
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,13 +18,13 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
|
|||||||
* @see <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
|
* @see <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
|
||||||
*/
|
*/
|
||||||
public class MpApi extends BaseApi {
|
public class MpApi extends BaseApi {
|
||||||
|
|
||||||
private final static ResourceBundle WEIXIN_BUNDLE;
|
private final static ResourceBundle WEIXIN_BUNDLE;
|
||||||
/**
|
/**
|
||||||
* 默认使用weixin4j.properties文件中的公众号信息
|
* 默认使用weixin4j.properties文件中的公众号信息
|
||||||
*/
|
*/
|
||||||
public final static WeixinMpAccount DEFAULT_WEIXIN_ACCOUNT;
|
public final static WeixinMpAccount DEFAULT_WEIXIN_ACCOUNT;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
WEIXIN_BUNDLE = ResourceBundle
|
WEIXIN_BUNDLE = ResourceBundle
|
||||||
.getBundle("com/foxinmy/weixin4j/mp/api/weixin");
|
.getBundle("com/foxinmy/weixin4j/mp/api/weixin");
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import com.foxinmy.weixin4j.mp.type.BillType;
|
|||||||
import com.foxinmy.weixin4j.mp.type.IdQuery;
|
import com.foxinmy.weixin4j.mp.type.IdQuery;
|
||||||
import com.foxinmy.weixin4j.mp.type.SignType;
|
import com.foxinmy.weixin4j.mp.type.SignType;
|
||||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||||
|
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||||
import com.foxinmy.weixin4j.util.DateUtil;
|
import com.foxinmy.weixin4j.util.DateUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,6 +32,12 @@ import com.foxinmy.weixin4j.util.DateUtil;
|
|||||||
*/
|
*/
|
||||||
public abstract class PayApi extends MpApi {
|
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 WeixinMpAccount weixinAccount;
|
||||||
protected final TokenHolder tokenHolder;
|
protected final TokenHolder tokenHolder;
|
||||||
|
|
||||||
@ -93,8 +100,9 @@ public abstract class PayApi extends MpApi {
|
|||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
String payfeedback_update_uri = getRequestUri("payfeedback_update_uri");
|
String payfeedback_update_uri = getRequestUri("payfeedback_update_uri");
|
||||||
Token token = tokenHolder.getToken();
|
Token token = tokenHolder.getToken();
|
||||||
WeixinResponse response = weixinClient.get(String.format(payfeedback_update_uri,
|
WeixinResponse response = weixinClient.get(String.format(
|
||||||
token.getAccessToken(), openId, feedbackId));
|
payfeedback_update_uri, token.getAccessToken(), openId,
|
||||||
|
feedbackId));
|
||||||
return response.getAsJsonResult();
|
return response.getAsJsonResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -180,4 +180,6 @@ redpack_send_uri={mch_base_url}/mmpaymkttransfers/sendredpack
|
|||||||
# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
|
# \u67e5\u8be2\u73b0\u91d1\u7ea2\u5305
|
||||||
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
|
redpack_query_uri={mch_base_url}/mmpaymkttransfers/gethbinfo
|
||||||
# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e
|
# \u4f01\u4e1a\u5411\u4e2a\u4eba\u4ed8\u6b3e
|
||||||
mp_payment_uri={mch_base_url}/mmpaymkttransfers/promotion/transfers
|
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
|
* @param suiteTicket
|
||||||
* @throws WeixinException
|
* @throws WeixinException
|
||||||
*/
|
*/
|
||||||
public void cachingTicket(SuiteTicketMessage suiteTicket)
|
public void cachingTicket(WeixinSuiteMessage suiteTicket)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
Token token = new Token(suiteTicket.getSuiteTicket());
|
Token token = new Token(suiteTicket.getSuiteTicket());
|
||||||
token.setExpiresIn(-1);
|
token.setExpiresIn(-1);
|
||||||
|
|||||||
@ -7,9 +7,18 @@ import javax.xml.bind.annotation.XmlAccessorType;
|
|||||||
import javax.xml.bind.annotation.XmlElement;
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 套件消息
|
||||||
|
*
|
||||||
|
* @className WeixinSuiteMessage
|
||||||
|
* @author jy
|
||||||
|
* @date 2015年6月23日
|
||||||
|
* @since JDK 1.7
|
||||||
|
* @see
|
||||||
|
*/
|
||||||
@XmlRootElement(name = "xml")
|
@XmlRootElement(name = "xml")
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public class SuiteTicketMessage implements Serializable {
|
public class WeixinSuiteMessage implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 6457919241019021514L;
|
private static final long serialVersionUID = 6457919241019021514L;
|
||||||
/**
|
/**
|
||||||
@ -60,7 +69,7 @@ public class SuiteTicketMessage implements Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SuiteTicketMessage [suiteId=" + suiteId + ", eventType="
|
return "WeixinSuiteMessage [suiteId=" + suiteId + ", eventType="
|
||||||
+ eventType + ", timeStamp=" + timeStamp + ", SuiteTicket="
|
+ eventType + ", timeStamp=" + timeStamp + ", SuiteTicket="
|
||||||
+ SuiteTicket + ", authCorpId=" + authCorpId + "]";
|
+ SuiteTicket + ", authCorpId=" + authCorpId + "]";
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ package com.foxinmy.weixin4j.request;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import com.foxinmy.weixin4j.type.EncryptType;
|
import com.foxinmy.weixin4j.type.EncryptType;
|
||||||
|
import com.foxinmy.weixin4j.util.AesToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信请求
|
* 微信请求
|
||||||
@ -60,10 +61,15 @@ public class WeixinRequest implements Serializable, Cloneable {
|
|||||||
* xml消息密文主体(AES时存在)
|
* xml消息密文主体(AES时存在)
|
||||||
*/
|
*/
|
||||||
private String encryptContent;
|
private String encryptContent;
|
||||||
|
/**
|
||||||
|
* aes & token
|
||||||
|
*/
|
||||||
|
private AesToken aesToken;
|
||||||
|
|
||||||
public WeixinRequest(String method, EncryptType encryptType,
|
public WeixinRequest(String method, EncryptType encryptType,
|
||||||
String echoStr, String timeStamp, String nonce, String signature,
|
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.method = method;
|
||||||
this.encryptType = encryptType;
|
this.encryptType = encryptType;
|
||||||
this.echoStr = echoStr;
|
this.echoStr = echoStr;
|
||||||
@ -73,6 +79,7 @@ public class WeixinRequest implements Serializable, Cloneable {
|
|||||||
this.msgSignature = msgSignature;
|
this.msgSignature = msgSignature;
|
||||||
this.originalContent = originalContent;
|
this.originalContent = originalContent;
|
||||||
this.encryptContent = encryptContent;
|
this.encryptContent = encryptContent;
|
||||||
|
this.aesToken = aesToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethod() {
|
public String getMethod() {
|
||||||
@ -111,12 +118,17 @@ public class WeixinRequest implements Serializable, Cloneable {
|
|||||||
return encryptContent;
|
return encryptContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AesToken getAesToken() {
|
||||||
|
return aesToken;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "WeixinRequest [encryptContent=" + encryptContent
|
return "WeixinRequest [encryptContent=" + encryptContent
|
||||||
+ ", encryptType=" + encryptType + ", echoStr=" + echoStr
|
+ ", encryptType=" + encryptType + ", echoStr=" + echoStr
|
||||||
+ ", timeStamp=" + timeStamp + ", nonce=" + nonce
|
+ ", timeStamp=" + timeStamp + ", nonce=" + nonce
|
||||||
+ ", signature=" + signature + ", originalContent="
|
+ ", 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;
|
package com.foxinmy.weixin4j.response;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信被动消息回复
|
* 微信被动消息回复
|
||||||
*
|
*
|
||||||
@ -20,18 +21,11 @@ package com.foxinmy.weixin4j.response;
|
|||||||
* @see <a
|
* @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>
|
* 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
|
* @return
|
||||||
*/
|
*/
|
||||||
public String getMsgType();
|
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
|
private final InternalLogger logger = InternalLoggerFactory
|
||||||
.getInstance(getClass());
|
.getInstance(getClass());
|
||||||
|
|
||||||
private AesToken aesToken;
|
private Map<String, AesToken> aesTokenMap;
|
||||||
|
|
||||||
public WeixinMessageDecoder(AesToken aesToken) {
|
public WeixinMessageDecoder(Map<String, AesToken> aesTokenMap) {
|
||||||
this.aesToken = aesToken;
|
this.aesTokenMap = aesTokenMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -47,8 +47,9 @@ public class WeixinMessageDecoder extends
|
|||||||
String content = req.content().toString(Consts.UTF_8);
|
String content = req.content().toString(Consts.UTF_8);
|
||||||
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(),
|
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri(),
|
||||||
true);
|
true);
|
||||||
|
String methodName = req.getMethod().name();
|
||||||
logger.info("decode request:{} use {} method invoking", req.getUri(),
|
logger.info("decode request:{} use {} method invoking", req.getUri(),
|
||||||
req.getMethod().name());
|
methodName);
|
||||||
Map<String, List<String>> parameters = queryDecoder.parameters();
|
Map<String, List<String>> parameters = queryDecoder.parameters();
|
||||||
EncryptType encryptType = parameters.containsKey("encrypt_type") ? EncryptType
|
EncryptType encryptType = parameters.containsKey("encrypt_type") ? EncryptType
|
||||||
.valueOf(parameters.get("encrypt_type").get(0).toUpperCase())
|
.valueOf(parameters.get("encrypt_type").get(0).toUpperCase())
|
||||||
@ -63,22 +64,23 @@ public class WeixinMessageDecoder extends
|
|||||||
.get("signature").get(0) : "";
|
.get("signature").get(0) : "";
|
||||||
String msgSignature = parameters.containsKey("msg_signature") ? parameters
|
String msgSignature = parameters.containsKey("msg_signature") ? parameters
|
||||||
.get("msg_signature").get(0) : "";
|
.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 originalContent = content;
|
||||||
String encryptContent = null;
|
String encryptContent = null;
|
||||||
if (!content.isEmpty()) {
|
if (!content.isEmpty() && encryptType == EncryptType.AES) {
|
||||||
if (encryptType == EncryptType.AES) {
|
if (StringUtil.isBlank(aesToken.getAesKey())
|
||||||
if (StringUtil.isBlank(aesToken.getAesKey())
|
|| StringUtil.isBlank(aesToken.getWeixinId())) {
|
||||||
|| StringUtil.isBlank(aesToken.getAppid())) {
|
throw new WeixinException(
|
||||||
throw new WeixinException(
|
"AESEncodingKey or WeixinId not be null in AES mode");
|
||||||
"AESEncodingKey or AppId not be null in AES mode");
|
|
||||||
}
|
|
||||||
encryptContent = EncryptMessageHandler.parser(content);
|
|
||||||
originalContent = MessageUtil.aesDecrypt(aesToken.getAppid(),
|
|
||||||
aesToken.getAesKey(), encryptContent);
|
|
||||||
}
|
}
|
||||||
|
encryptContent = EncryptMessageHandler.parser(content);
|
||||||
|
originalContent = MessageUtil.aesDecrypt(aesToken.getWeixinId(),
|
||||||
|
aesToken.getAesKey(), encryptContent);
|
||||||
}
|
}
|
||||||
out.add(new WeixinRequest(req.getMethod().name(), encryptType, echoStr,
|
out.add(new WeixinRequest(methodName, encryptType, echoStr, timeStamp,
|
||||||
timeStamp, nonce, signature, msgSignature, originalContent,
|
nonce, signature, msgSignature, originalContent,
|
||||||
encryptContent));
|
encryptContent, aesToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import com.foxinmy.weixin4j.util.AesToken;
|
|||||||
import com.foxinmy.weixin4j.util.Consts;
|
import com.foxinmy.weixin4j.util.Consts;
|
||||||
import com.foxinmy.weixin4j.util.HttpUtil;
|
import com.foxinmy.weixin4j.util.HttpUtil;
|
||||||
import com.foxinmy.weixin4j.util.MessageUtil;
|
import com.foxinmy.weixin4j.util.MessageUtil;
|
||||||
import com.foxinmy.weixin4j.util.StringUtil;
|
|
||||||
import com.foxinmy.weixin4j.xml.CruxMessageHandler;
|
import com.foxinmy.weixin4j.xml.CruxMessageHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,12 +33,11 @@ public class WeixinRequestHandler extends
|
|||||||
SimpleChannelInboundHandler<WeixinRequest> {
|
SimpleChannelInboundHandler<WeixinRequest> {
|
||||||
private final InternalLogger logger = InternalLoggerFactory
|
private final InternalLogger logger = InternalLoggerFactory
|
||||||
.getInstance(getClass());
|
.getInstance(getClass());
|
||||||
private final AesToken aesToken;
|
|
||||||
private final WeixinMessageDispatcher messageDispatcher;
|
private final WeixinMessageDispatcher messageDispatcher;
|
||||||
|
|
||||||
public WeixinRequestHandler(AesToken aesToken,
|
public WeixinRequestHandler(WeixinMessageDispatcher messageDispatcher)
|
||||||
WeixinMessageDispatcher messageDispatcher) throws WeixinException {
|
throws WeixinException {
|
||||||
this.aesToken = aesToken;
|
|
||||||
this.messageDispatcher = messageDispatcher;
|
this.messageDispatcher = messageDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +54,7 @@ public class WeixinRequestHandler extends
|
|||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request)
|
protected void channelRead0(ChannelHandlerContext ctx, WeixinRequest request)
|
||||||
throws WeixinException {
|
throws WeixinException {
|
||||||
|
final AesToken aesToken = request.getAesToken();
|
||||||
if (request.getMethod().equals(HttpMethod.GET.name())) {
|
if (request.getMethod().equals(HttpMethod.GET.name())) {
|
||||||
if (MessageUtil.signature(aesToken.getToken(),
|
if (MessageUtil.signature(aesToken.getToken(),
|
||||||
request.getTimeStamp(), request.getNonce()).equals(
|
request.getTimeStamp(), request.getNonce()).equals(
|
||||||
@ -98,14 +97,10 @@ public class WeixinRequestHandler extends
|
|||||||
}
|
}
|
||||||
CruxMessageHandler cruxMessage = CruxMessageHandler.parser(request
|
CruxMessageHandler cruxMessage = CruxMessageHandler.parser(request
|
||||||
.getOriginalContent());
|
.getOriginalContent());
|
||||||
ctx.channel().attr(Consts.ENCRYPTTYPE_KEY)
|
MessageTransfer messageTransfer = new MessageTransfer(aesToken,
|
||||||
.set(request.getEncryptType());
|
request.getEncryptType(), cruxMessage.getToUserName(),
|
||||||
ctx.channel().attr(Consts.USEROPENID_KEY)
|
cruxMessage.getFromUserName());
|
||||||
.set(cruxMessage.getFromUserName());
|
ctx.channel().attr(Consts.MESSAGE_TRANSFER_KEY).set(messageTransfer);
|
||||||
if (StringUtil.isBlank(aesToken.getAppid())) {
|
|
||||||
ctx.channel().attr(Consts.ACCOUNTOPENID_KEY)
|
|
||||||
.set(cruxMessage.getToUserName());
|
|
||||||
}
|
|
||||||
messageDispatcher.doDispatch(ctx, request, cruxMessage);
|
messageDispatcher.doDispatch(ctx, request, cruxMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,22 +36,16 @@ public class WeixinResponseEncoder extends
|
|||||||
private final InternalLogger logger = InternalLoggerFactory
|
private final InternalLogger logger = InternalLoggerFactory
|
||||||
.getInstance(getClass());
|
.getInstance(getClass());
|
||||||
|
|
||||||
private final AesToken aesToken;
|
|
||||||
|
|
||||||
public WeixinResponseEncoder(AesToken aesToken) {
|
|
||||||
this.aesToken = aesToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, WeixinResponse response,
|
protected void encode(ChannelHandlerContext ctx, WeixinResponse response,
|
||||||
List<Object> out) throws WeixinException {
|
List<Object> out) throws WeixinException {
|
||||||
EncryptType encryptType = ctx.channel().attr(Consts.ENCRYPTTYPE_KEY)
|
MessageTransfer messageTransfer = ctx.channel()
|
||||||
.get();
|
.attr(Consts.MESSAGE_TRANSFER_KEY).get();
|
||||||
String userOpenId = ctx.channel().attr(Consts.USEROPENID_KEY).get();
|
AesToken aesToken = messageTransfer.getAesToken();
|
||||||
String accountOpenId = ctx.channel().attr(Consts.ACCOUNTOPENID_KEY)
|
EncryptType encryptType = messageTransfer.getEncryptType();
|
||||||
.get();
|
String weixinId = aesToken.getWeixinId();
|
||||||
if (StringUtil.isBlank(accountOpenId)) {
|
if (StringUtil.isBlank(weixinId)) {
|
||||||
accountOpenId = aesToken.getAppid();
|
weixinId = messageTransfer.getToUserName();
|
||||||
}
|
}
|
||||||
StringBuilder content = new StringBuilder();
|
StringBuilder content = new StringBuilder();
|
||||||
if (response instanceof BlankResponse) {
|
if (response instanceof BlankResponse) {
|
||||||
@ -59,10 +53,10 @@ public class WeixinResponseEncoder extends
|
|||||||
} else {
|
} else {
|
||||||
content.append("<xml>");
|
content.append("<xml>");
|
||||||
content.append(String.format(
|
content.append(String.format(
|
||||||
"<ToUserName><![CDATA[%s]]></ToUserName>", userOpenId));
|
"<ToUserName><![CDATA[%s]]></ToUserName>",
|
||||||
|
messageTransfer.getFromUserName()));
|
||||||
content.append(String.format(
|
content.append(String.format(
|
||||||
"<FromUserName><![CDATA[%s]]></FromUserName>",
|
"<FromUserName><![CDATA[%s]]></FromUserName>", weixinId));
|
||||||
accountOpenId));
|
|
||||||
content.append(String.format(
|
content.append(String.format(
|
||||||
"<CreateTime><![CDATA[%d]]></CreateTime>",
|
"<CreateTime><![CDATA[%d]]></CreateTime>",
|
||||||
System.currentTimeMillis() / 1000l));
|
System.currentTimeMillis() / 1000l));
|
||||||
@ -74,7 +68,7 @@ public class WeixinResponseEncoder extends
|
|||||||
String nonce = RandomUtil.generateString(32);
|
String nonce = RandomUtil.generateString(32);
|
||||||
String timestamp = String
|
String timestamp = String
|
||||||
.valueOf(System.currentTimeMillis() / 1000l);
|
.valueOf(System.currentTimeMillis() / 1000l);
|
||||||
String encrtypt = MessageUtil.aesEncrypt(accountOpenId,
|
String encrtypt = MessageUtil.aesEncrypt(weixinId,
|
||||||
aesToken.getAesKey(), content.toString());
|
aesToken.getAesKey(), content.toString());
|
||||||
String msgSignature = MessageUtil.signature(
|
String msgSignature = MessageUtil.signature(
|
||||||
aesToken.getToken(), nonce, timestamp, encrtypt);
|
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.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
|
import com.foxinmy.weixin4j.dispatcher.WeixinMessageDispatcher;
|
||||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||||
import com.foxinmy.weixin4j.util.AesToken;
|
import com.foxinmy.weixin4j.util.AesToken;
|
||||||
@ -21,15 +23,15 @@ import com.foxinmy.weixin4j.util.AesToken;
|
|||||||
*/
|
*/
|
||||||
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
|
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
private final AesToken aesToken;
|
private final Map<String, AesToken> aesTokenMap;
|
||||||
private final WeixinMessageDispatcher messageDispatcher;
|
private final WeixinMessageDispatcher messageDispatcher;
|
||||||
|
|
||||||
public WeixinServerInitializer(AesToken aesToken,
|
public WeixinServerInitializer(Map<String, AesToken> aesTokenMap,
|
||||||
WeixinMessageDispatcher messageDispatcher) throws WeixinException {
|
WeixinMessageDispatcher messageDispatcher) throws WeixinException {
|
||||||
if (aesToken == null) {
|
if (aesTokenMap.isEmpty()) {
|
||||||
throw new WeixinException("AesToken not be null.");
|
throw new WeixinException("AesToken not be null.");
|
||||||
}
|
}
|
||||||
this.aesToken = aesToken;
|
this.aesTokenMap = aesTokenMap;
|
||||||
this.messageDispatcher = messageDispatcher;
|
this.messageDispatcher = messageDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +40,8 @@ public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
ChannelPipeline pipeline = channel.pipeline();
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
pipeline.addLast(new HttpServerCodec());
|
pipeline.addLast(new HttpServerCodec());
|
||||||
pipeline.addLast(new HttpObjectAggregator(65536));
|
pipeline.addLast(new HttpObjectAggregator(65536));
|
||||||
pipeline.addLast(new WeixinMessageDecoder(aesToken));
|
pipeline.addLast(new WeixinMessageDecoder(aesTokenMap));
|
||||||
pipeline.addLast(new WeixinResponseEncoder(aesToken));
|
pipeline.addLast(new WeixinResponseEncoder());
|
||||||
pipeline.addLast(new WeixinRequestHandler(aesToken, messageDispatcher));
|
pipeline.addLast(new WeixinRequestHandler(messageDispatcher));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,10 @@ import io.netty.util.internal.logging.InternalLogger;
|
|||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.foxinmy.weixin4j.dispatcher.BeanFactory;
|
import com.foxinmy.weixin4j.dispatcher.BeanFactory;
|
||||||
import com.foxinmy.weixin4j.dispatcher.DefaultMessageMatcher;
|
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
|
* 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) {
|
public WeixinServerBootstrap(String openid, String token) {
|
||||||
this(new AesToken(token));
|
this(openid, token, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,12 +110,32 @@ public final class WeixinServerBootstrap {
|
|||||||
|
|
||||||
public WeixinServerBootstrap(AesToken aesToken,
|
public WeixinServerBootstrap(AesToken aesToken,
|
||||||
WeixinMessageMatcher messageMatcher) {
|
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.messageHandlerList = new LinkedList<WeixinMessageHandler>();
|
||||||
this.messageInterceptorList = new LinkedList<WeixinMessageInterceptor>();
|
this.messageInterceptorList = new LinkedList<WeixinMessageInterceptor>();
|
||||||
this.messageDispatcher = new WeixinMessageDispatcher(messageMatcher);
|
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)
|
.channel(NioServerSocketChannel.class)
|
||||||
.handler(new LoggingHandler())
|
.handler(new LoggingHandler())
|
||||||
.childHandler(
|
.childHandler(
|
||||||
new WeixinServerInitializer(aesToken,
|
new WeixinServerInitializer(aesTokenMap,
|
||||||
messageDispatcher));
|
messageDispatcher));
|
||||||
Channel ch = b.bind(serverPort).sync().channel();
|
Channel ch = b.bind(serverPort).sync().channel();
|
||||||
logger.info("weixin4j server startup OK:{}", serverPort);
|
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;
|
private static final long serialVersionUID = -6001008896414323534L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号ID
|
* 账号ID(原始ID或者appid)
|
||||||
*/
|
*/
|
||||||
private String appid;
|
private String weixinId;
|
||||||
/**
|
/**
|
||||||
* 开发者的token
|
* 开发者的token
|
||||||
*/
|
*/
|
||||||
@ -28,18 +28,36 @@ public class AesToken implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String aesKey;
|
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) {
|
public AesToken(String appid, String token, String aesKey) {
|
||||||
this.appid = appid;
|
this.weixinId = appid;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.aesKey = aesKey;
|
this.aesKey = aesKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAppid() {
|
public String getWeixinId() {
|
||||||
return appid;
|
return weixinId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import io.netty.util.AttributeKey;
|
|||||||
|
|
||||||
import java.nio.charset.Charset;
|
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$APPLICATION_XML = "application/xml";
|
||||||
public static final String CONTENTTYPE$TEXT_PLAIN = "text/plain";
|
public static final String CONTENTTYPE$TEXT_PLAIN = "text/plain";
|
||||||
|
|
||||||
public static final AttributeKey<EncryptType> ENCRYPTTYPE_KEY = AttributeKey
|
public static final AttributeKey<MessageTransfer> MESSAGE_TRANSFER_KEY = AttributeKey
|
||||||
.valueOf("ENCRYPTTYPE");
|
.valueOf("$_MESSAGETRANSFER");
|
||||||
public static final AttributeKey<String> ACCOUNTOPENID_KEY = AttributeKey
|
|
||||||
.valueOf("ACCOUNTOPENID");
|
|
||||||
public static final AttributeKey<String> USEROPENID_KEY = AttributeKey
|
|
||||||
.valueOf("USEROPENID");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,11 +23,13 @@ import com.foxinmy.weixin4j.util.Consts;
|
|||||||
*/
|
*/
|
||||||
public class EncryptMessageHandler extends DefaultHandler {
|
public class EncryptMessageHandler extends DefaultHandler {
|
||||||
|
|
||||||
|
private String toUserName;
|
||||||
private String encryptContent;
|
private String encryptContent;
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startDocument() throws SAXException {
|
public void startDocument() throws SAXException {
|
||||||
|
toUserName = null;
|
||||||
encryptContent = null;
|
encryptContent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +44,8 @@ public class EncryptMessageHandler extends DefaultHandler {
|
|||||||
throws SAXException {
|
throws SAXException {
|
||||||
if (localName.equalsIgnoreCase("encrypt")) {
|
if (localName.equalsIgnoreCase("encrypt")) {
|
||||||
encryptContent = content;
|
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);
|
this.content = new String(ch, start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getToUserName() {
|
||||||
|
return toUserName;
|
||||||
|
}
|
||||||
|
|
||||||
public String getEncryptContent() {
|
public String getEncryptContent() {
|
||||||
return encryptContent;
|
return encryptContent;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,6 @@ package com.foxinmy.weixin4j.server.test;
|
|||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||||
import com.foxinmy.weixin4j.handler.BlankMessageHandler;
|
import com.foxinmy.weixin4j.handler.BlankMessageHandler;
|
||||||
import com.foxinmy.weixin4j.handler.DebugMessageHandler;
|
import com.foxinmy.weixin4j.handler.DebugMessageHandler;
|
||||||
@ -27,6 +25,8 @@ import com.foxinmy.weixin4j.startup.WeixinServerBootstrap;
|
|||||||
*/
|
*/
|
||||||
public class MessageServerStartup {
|
public class MessageServerStartup {
|
||||||
|
|
||||||
|
// 微信号(原始ID)
|
||||||
|
final String openid = "gh_22b350df957b";
|
||||||
// 应用ID
|
// 应用ID
|
||||||
final String appid = "wx4ab8f8de58159a57";
|
final String appid = "wx4ab8f8de58159a57";
|
||||||
// 开发者token
|
// 开发者token
|
||||||
@ -41,8 +41,8 @@ public class MessageServerStartup {
|
|||||||
*/
|
*/
|
||||||
public void test1() throws WeixinException {
|
public void test1() throws WeixinException {
|
||||||
// 所有请求都回复调试的文本消息
|
// 所有请求都回复调试的文本消息
|
||||||
new WeixinServerBootstrap(token).addHandler(DebugMessageHandler.global)
|
new WeixinServerBootstrap(openid, token).addHandler(
|
||||||
.startup();
|
DebugMessageHandler.global).startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,8 +78,8 @@ public class MessageServerStartup {
|
|||||||
public void test4() throws WeixinException {
|
public void test4() throws WeixinException {
|
||||||
// 扫描包加载消息处理器
|
// 扫描包加载消息处理器
|
||||||
String packageToScan = "com.foxinmy.weixin4j.handler";
|
String packageToScan = "com.foxinmy.weixin4j.handler";
|
||||||
new WeixinServerBootstrap(token).handlerPackagesToScan(packageToScan)
|
new WeixinServerBootstrap(openid, token).handlerPackagesToScan(
|
||||||
.startup();
|
packageToScan).startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void test5() throws WeixinException {
|
public void test5() throws WeixinException {
|
||||||
@ -109,14 +109,11 @@ public class MessageServerStartup {
|
|||||||
System.err.println("请求处理完毕");
|
System.err.println("请求处理完毕");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
new WeixinServerBootstrap(token).addInterceptor(interceptor)
|
new WeixinServerBootstrap(openid, token).addInterceptor(interceptor)
|
||||||
.addHandler(BlankMessageHandler.global).startup();
|
.addHandler(BlankMessageHandler.global).startup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
new MessageServerStartup().test1();
|
||||||
System.err.println(new BigDecimal(new Long(14212345l)).divide(
|
|
||||||
new BigDecimal("100000"))
|
|
||||||
.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user