(), namedThreadFactory);
- this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker();
this.sessionManager = new StandardSessionManager();
this.exceptionHandler = new LogExceptionHandler();
}
@@ -58,16 +55,6 @@ public class WxMaMessageRouter {
this.executorService = executorService;
}
- /**
- *
- * 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
- * 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
- *
- */
- public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) {
- this.messageDuplicateChecker = messageDuplicateChecker;
- }
-
/**
*
* 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
@@ -93,16 +80,16 @@ public class WxMaMessageRouter {
}
/**
- * 开始一个新的Route规则
+ * 开始一个新的Route规则.
*/
public WxMaMessageRouterRule rule() {
return new WxMaMessageRouterRule(this);
}
/**
- * 处理微信消息
+ * 处理微信消息.
*/
- public void route(final WxMaMessage wxMessage, final Map context) {
+ private WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map context) {
final List matchRules = new ArrayList<>();
// 收集匹配的规则
for (final WxMaMessageRouterRule rule : this.rules) {
@@ -115,10 +102,11 @@ public class WxMaMessageRouter {
}
if (matchRules.size() == 0) {
- return;
+ return null;
}
final List> futures = new ArrayList<>();
+ WxMaXmlOutMessage result = null;
for (final WxMaMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if (rule.isAsync()) {
@@ -131,7 +119,7 @@ public class WxMaMessageRouter {
})
);
} else {
- rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler);
+ result = rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler);
// 在同步操作结束,session访问结束
this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
sessionEndAccess(wxMessage);
@@ -155,18 +143,17 @@ public class WxMaMessageRouter {
}
});
}
-
+ return result;
}
- public void route(final WxMaMessage wxMessage) {
- this.route(wxMessage, new HashMap(2));
+ public WxMaXmlOutMessage route(final WxMaMessage wxMessage) {
+ return this.route(wxMessage, new HashMap(2));
}
/**
- * 对session的访问结束
+ * 对session的访问结束.
*/
- protected void sessionEndAccess(WxMaMessage wxMessage) {
-
+ private void sessionEndAccess(WxMaMessage wxMessage) {
InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser());
if (session != null) {
session.endAccess();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
index 2e4906eb..5ea3fb8a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java
@@ -16,7 +16,6 @@ import java.util.regex.Pattern;
* @author Binary Wang
*/
public class WxMaMessageRouterRule {
-
private final WxMaMessageRouter routerBuilder;
private boolean async = true;
@@ -46,7 +45,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 设置是否异步执行,默认是true
+ * 设置是否异步执行,默认是true.
*/
public WxMaMessageRouterRule async(boolean async) {
this.async = async;
@@ -54,7 +53,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果msgType等于某值
+ * 如果msgType等于某值.
*/
public WxMaMessageRouterRule msgType(String msgType) {
this.msgType = msgType;
@@ -62,7 +61,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果event等于某值
+ * 如果event等于某值.
*/
public WxMaMessageRouterRule event(String event) {
this.event = event;
@@ -70,7 +69,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果eventKey等于某值
+ * 如果eventKey等于某值.
*/
public WxMaMessageRouterRule eventKey(String eventKey) {
this.eventKey = eventKey;
@@ -78,7 +77,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果content等于某值
+ * 如果content等于某值.
*/
public WxMaMessageRouterRule content(String content) {
this.content = content;
@@ -86,7 +85,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果content匹配该正则表达式
+ * 如果content匹配该正则表达式.
*/
public WxMaMessageRouterRule rContent(String regex) {
this.rContent = regex;
@@ -94,7 +93,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果fromUser等于某值
+ * 如果fromUser等于某值.
*/
public WxMaMessageRouterRule fromUser(String fromUser) {
this.fromUser = fromUser;
@@ -102,7 +101,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
+ * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候.
*/
public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) {
this.matcher = matcher;
@@ -110,14 +109,14 @@ public class WxMaMessageRouterRule {
}
/**
- * 设置微信消息拦截器
+ * 设置微信消息拦截器.
*/
public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) {
return interceptor(interceptor, (WxMaMessageInterceptor[]) null);
}
/**
- * 设置微信消息拦截器
+ * 设置微信消息拦截器.
*/
public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) {
this.interceptors.add(interceptor);
@@ -130,14 +129,14 @@ public class WxMaMessageRouterRule {
}
/**
- * 设置微信消息处理器
+ * 设置微信消息处理器.
*/
public WxMaMessageRouterRule handler(WxMaMessageHandler handler) {
return handler(handler, (WxMaMessageHandler[]) null);
}
/**
- * 设置微信消息处理器
+ * 设置微信消息处理器.
*/
public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) {
this.handlers.add(handler);
@@ -150,7 +149,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
+ * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则.
*/
public WxMaMessageRouter end() {
this.routerBuilder.getRules().add(this);
@@ -158,7 +157,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 规则结束,但是消息还会进入其他规则
+ * 规则结束,但是消息还会进入其他规则.
*/
public WxMaMessageRouter next() {
this.reEnter = true;
@@ -166,7 +165,7 @@ public class WxMaMessageRouterRule {
}
/**
- * 将微信自定义的事件修正为不区分大小写,
+ * 将微信自定义的事件修正为不区分大小写.
* 比如框架定义的事件常量为click,但微信传递过来的却是CLICK
*/
protected boolean test(WxMaMessage wxMessage) {
@@ -188,9 +187,9 @@ public class WxMaMessageRouterRule {
}
/**
- * 处理微信推送过来的消息
+ * 处理微信推送过来的消息.
*/
- protected void service(WxMaMessage wxMessage,
+ protected WxMaXmlOutMessage service(WxMaMessage wxMessage,
Map context,
WxMaService wxMaService,
WxSessionManager sessionManager,
@@ -199,11 +198,12 @@ public class WxMaMessageRouterRule {
context = new HashMap<>(16);
}
+ WxMaXmlOutMessage outMessage = null;
try {
// 如果拦截器不通过
for (WxMaMessageInterceptor interceptor : this.interceptors) {
if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) {
- return;
+ return null;
}
}
@@ -213,11 +213,13 @@ public class WxMaMessageRouterRule {
if (handler == null) {
continue;
}
- handler.handle(wxMessage, context, wxMaService, sessionManager);
+ outMessage = handler.handle(wxMessage, context, wxMaService, sessionManager);
}
} catch (WxErrorException e) {
exceptionHandler.handle(e);
}
+
+ return outMessage;
}
public WxMaMessageRouter getRouterBuilder() {
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java
new file mode 100644
index 00000000..7211e053
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java
@@ -0,0 +1,60 @@
+package cn.binarywang.wx.miniapp.message;
+
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
+import cn.binarywang.wx.miniapp.util.xml.XStreamTransformer;
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamConverter;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
+
+import java.io.Serializable;
+
+/**
+ * 微信小程序输出给微信服务器的消息.
+ *
+ * @author Binary Wang
+ * @date 2019-06-22
+ */
+@Data
+@XStreamAlias("xml")
+@Accessors(chain = true)
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class WxMaXmlOutMessage implements Serializable {
+ private static final long serialVersionUID = 4241135225946919153L;
+
+ @XStreamAlias("ToUserName")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ protected String toUserName;
+
+ @XStreamAlias("FromUserName")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ protected String fromUserName;
+
+ @XStreamAlias("CreateTime")
+ protected Long createTime;
+
+ @XStreamAlias("MsgType")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ protected String msgType;
+
+ @SuppressWarnings("unchecked")
+ public String toXml() {
+ return XStreamTransformer.toXml((Class) this.getClass(), this);
+ }
+
+ /**
+ * 转换成加密的xml格式.
+ */
+ public String toEncryptedXml(WxMaConfig config) {
+ String plainXml = toXml();
+ WxMaCryptUtils pc = new WxMaCryptUtils(config);
+ return pc.encrypt(plainXml);
+ }
+}
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java
index fe886f4b..89df2444 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java
@@ -1,15 +1,5 @@
package cn.binarywang.wx.miniapp.demo;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
@@ -20,11 +10,23 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
import cn.binarywang.wx.miniapp.test.TestConfig;
import com.google.common.collect.Lists;
+import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
/**
* @author Binary Wang
@@ -33,29 +35,31 @@ public class WxMaDemoServer {
private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() {
@Override
- public void handle(WxMaMessage wxMessage, Map context,
- WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+ public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+ WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
System.out.println("收到消息:" + wxMessage.toString());
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
.toUser(wxMessage.getFromUser()).build());
+ return null;
}
};
private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() {
@Override
- public void handle(WxMaMessage wxMessage, Map context,
- WxMaService service, WxSessionManager sessionManager)
+ public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+ WxMaService service, WxSessionManager sessionManager)
throws WxErrorException {
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
.toUser(wxMessage.getFromUser()).build());
+ return null;
}
};
private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() {
@Override
- public void handle(WxMaMessage wxMessage, Map context,
- WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+ public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+ WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
try {
WxMediaUploadResult uploadResult = service.getMediaService()
.uploadMedia(WxMaConstants.MediaType.IMAGE, "png",
@@ -69,13 +73,14 @@ public class WxMaDemoServer {
} catch (WxErrorException e) {
e.printStackTrace();
}
+ return null;
}
};
private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() {
@Override
- public void handle(WxMaMessage wxMessage, Map context,
- WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+ public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+ WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
try {
final File file = service.getQrcodeService().createQrcode("123", 430);
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file);
@@ -88,13 +93,14 @@ public class WxMaDemoServer {
} catch (WxErrorException e) {
e.printStackTrace();
}
+ return null;
}
};
private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() {
@Override
- public void handle(WxMaMessage wxMessage, Map context,
- WxMaService service, WxSessionManager sessionManager)
+ public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context,
+ WxMaService service, WxSessionManager sessionManager)
throws WxErrorException {
service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
.templateId(templateId).data(Lists.newArrayList(
@@ -102,10 +108,22 @@ public class WxMaDemoServer {
.toUser(wxMessage.getFromUser())
.formId("自己替换可用的formid")
.build());
+ return null;
}
};
+ private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() {
+ @Override
+ public WxMaXmlOutMessage handle(WxMaMessage message, Map context, WxMaService service, WxSessionManager sessionManager) {
+ return new WxMaXmlOutMessage()
+ .setMsgType(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE)
+ .setFromUserName(message.getToUser())
+ .setCreateTime(Calendar.getInstance().getTimeInMillis() / 1000)
+ .setToUserName(message.getFromUser());
+ }
+ };
+
private static WxMaConfig config;
private static WxMaService service;
private static WxMaMessageRouter router;
@@ -142,7 +160,8 @@ public class WxMaDemoServer {
.rule().async(false).content("模板").handler(templateMsgHandler).end()
.rule().async(false).content("文本").handler(textHandler).end()
.rule().async(false).content("图片").handler(picHandler).end()
- .rule().async(false).content("二维码").handler(qrcodeHandler).end();
+ .rule().async(false).content("二维码").handler(qrcodeHandler).end()
+ .rule().async(false).content("转发客服").handler(customerServiceMessageHandler).end();
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
index 5cadb689..c209082d 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java
@@ -5,6 +5,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
+import lombok.AllArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -18,19 +20,13 @@ import java.util.Objects;
/**
* @author Binary Wang
*/
+@AllArgsConstructor
public class WxMaPortalServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- private WxMaConfig wxMaConfig;
- private WxMaService wxMaService;
- private WxMaMessageRouter wxMaMessageRouter;
-
- WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService,
- WxMaMessageRouter wxMaMessageRouter) {
- this.wxMaConfig = wxMaConfig;
- this.wxMaService = wxMaService;
- this.wxMaMessageRouter = wxMaMessageRouter;
- }
+ private WxMaConfig config;
+ private WxMaService service;
+ private WxMaMessageRouter messageRouter;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
@@ -42,7 +38,7 @@ public class WxMaPortalServlet extends HttpServlet {
String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp");
- if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) {
+ if (!this.service.checkSignature(timestamp, nonce, signature)) {
// 消息签名不正确,说明不是公众平台发过来的消息
response.getWriter().println("非法请求");
return;
@@ -56,7 +52,7 @@ public class WxMaPortalServlet extends HttpServlet {
}
String encryptType = request.getParameter("encrypt_type");
- final boolean isJson = Objects.equals(this.wxMaConfig.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON);
+ final boolean isJson = Objects.equals(this.config.getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON);
if (StringUtils.isBlank(encryptType)) {
// 明文传输的消息
WxMaMessage inMessage;
@@ -66,7 +62,12 @@ public class WxMaPortalServlet extends HttpServlet {
inMessage = WxMaMessage.fromXml(request.getInputStream());
}
- this.wxMaMessageRouter.route(inMessage);
+ final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage);
+ if (outMessage != null) {
+ response.getWriter().write(outMessage.toXml());
+ return;
+ }
+
response.getWriter().write("success");
return;
}
@@ -76,12 +77,16 @@ public class WxMaPortalServlet extends HttpServlet {
String msgSignature = request.getParameter("msg_signature");
WxMaMessage inMessage;
if (isJson) {
- inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig);
+ inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.config);
} else {//xml
- inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.wxMaConfig, timestamp, nonce, msgSignature);
+ inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.config, timestamp, nonce, msgSignature);
}
- this.wxMaMessageRouter.route(inMessage);
+ final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage);
+ if (outMessage != null) {
+ response.getWriter().write(outMessage.toEncryptedXml(this.config));
+ return;
+ }
response.getWriter().write("success");
return;
}