#1079 小程序增加对转发客服消息功能的支持

This commit is contained in:
Binary Wang 2019-06-22 16:50:31 +08:00
parent a63321f712
commit 54c8ae5452
8 changed files with 179 additions and 90 deletions

View File

@ -8,13 +8,22 @@ import me.chanjar.weixin.common.session.WxSessionManager;
import java.util.Map; import java.util.Map;
/** /**
* 处理小程序推送消息的处理器接口 * 处理小程序推送消息的处理器接口.
* *
* @author <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
*/ */
public interface WxMaMessageHandler { public interface WxMaMessageHandler {
/**
void handle(WxMaMessage message, Map<String, Object> context, * 处理消息.
WxMaService service, WxSessionManager sessionManager) throws WxErrorException; *
* @param message 输入消息
* @param context 上下文
* @param service 服务类
* @param sessionManager session管理器
* @return 输出消息
* @throws WxErrorException 异常
*/
WxMaXmlOutMessage handle(WxMaMessage message, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) throws WxErrorException;
} }

View File

@ -8,17 +8,21 @@ import me.chanjar.weixin.common.session.WxSessionManager;
import java.util.Map; import java.util.Map;
/** /**
* 微信消息拦截器可以用来做验证 * 微信消息拦截器可以用来做验证.
* *
* @author <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
*/ */
public interface WxMaMessageInterceptor { public interface WxMaMessageInterceptor {
/** /**
* 拦截微信消息 * 拦截微信消息.
* *
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个 * @param wxMessage .
* @param context 上下文如果handler或interceptor之间有信息要传递可以用这个
* @param wxMaService .
* @param sessionManager .
* @return true代表OKfalse代表不OK * @return true代表OKfalse代表不OK
* @throws WxErrorException .
*/ */
boolean intercept(WxMaMessage wxMessage, boolean intercept(WxMaMessage wxMessage,
Map<String, Object> context, Map<String, Object> context,

View File

@ -3,14 +3,17 @@ package cn.binarywang.wx.miniapp.message;
import cn.binarywang.wx.miniapp.bean.WxMaMessage; import cn.binarywang.wx.miniapp.bean.WxMaMessage;
/** /**
* 消息匹配器用在消息路由的时候 * 消息匹配器用在消息路由的时候.
* *
* @author <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
*/ */
public interface WxMaMessageMatcher { public interface WxMaMessageMatcher {
/** /**
* 消息是否匹配某种模式 * 消息是否匹配某种模式.
*
* @param message 消息
* @return 是否匹配
*/ */
boolean match(WxMaMessage message); boolean match(WxMaMessage message);

View File

@ -32,8 +32,6 @@ public class WxMaMessageRouter {
private ExecutorService executorService; private ExecutorService executorService;
private WxMessageDuplicateChecker messageDuplicateChecker;
private WxSessionManager sessionManager; private WxSessionManager sessionManager;
private WxErrorExceptionHandler exceptionHandler; private WxErrorExceptionHandler exceptionHandler;
@ -43,7 +41,6 @@ public class WxMaMessageRouter {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxMaMessageRouter-pool-%d").build(); ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxMaMessageRouter-pool-%d").build();
this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE, this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), namedThreadFactory); 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), namedThreadFactory);
this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker();
this.sessionManager = new StandardSessionManager(); this.sessionManager = new StandardSessionManager();
this.exceptionHandler = new LogExceptionHandler(); this.exceptionHandler = new LogExceptionHandler();
} }
@ -58,16 +55,6 @@ public class WxMaMessageRouter {
this.executorService = executorService; this.executorService = executorService;
} }
/**
* <pre>
* 设置自定义的 {@link me.chanjar.weixin.common.api.WxMessageDuplicateChecker}
* 如果不调用该方法默认使用 {@link me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker}
* </pre>
*/
public void setMessageDuplicateChecker(WxMessageDuplicateChecker messageDuplicateChecker) {
this.messageDuplicateChecker = messageDuplicateChecker;
}
/** /**
* <pre> * <pre>
* 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager}
@ -93,16 +80,16 @@ public class WxMaMessageRouter {
} }
/** /**
* 开始一个新的Route规则 * 开始一个新的Route规则.
*/ */
public WxMaMessageRouterRule rule() { public WxMaMessageRouterRule rule() {
return new WxMaMessageRouterRule(this); return new WxMaMessageRouterRule(this);
} }
/** /**
* 处理微信消息 * 处理微信消息.
*/ */
public void route(final WxMaMessage wxMessage, final Map<String, Object> context) { private WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map<String, Object> context) {
final List<WxMaMessageRouterRule> matchRules = new ArrayList<>(); final List<WxMaMessageRouterRule> matchRules = new ArrayList<>();
// 收集匹配的规则 // 收集匹配的规则
for (final WxMaMessageRouterRule rule : this.rules) { for (final WxMaMessageRouterRule rule : this.rules) {
@ -115,10 +102,11 @@ public class WxMaMessageRouter {
} }
if (matchRules.size() == 0) { if (matchRules.size() == 0) {
return; return null;
} }
final List<Future<?>> futures = new ArrayList<>(); final List<Future<?>> futures = new ArrayList<>();
WxMaXmlOutMessage result = null;
for (final WxMaMessageRouterRule rule : matchRules) { for (final WxMaMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果 // 返回最后一个非异步的rule的执行结果
if (rule.isAsync()) { if (rule.isAsync()) {
@ -131,7 +119,7 @@ public class WxMaMessageRouter {
}) })
); );
} else { } else {
rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler); result = rule.service(wxMessage, context, this.wxMaService, this.sessionManager, this.exceptionHandler);
// 在同步操作结束session访问结束 // 在同步操作结束session访问结束
this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser()); this.log.debug("End session access: async=false, sessionId={}", wxMessage.getFromUser());
sessionEndAccess(wxMessage); sessionEndAccess(wxMessage);
@ -155,18 +143,17 @@ public class WxMaMessageRouter {
} }
}); });
} }
return result;
} }
public void route(final WxMaMessage wxMessage) { public WxMaXmlOutMessage route(final WxMaMessage wxMessage) {
this.route(wxMessage, new HashMap<String, Object>(2)); return this.route(wxMessage, new HashMap<String, Object>(2));
} }
/** /**
* 对session的访问结束 * 对session的访问结束.
*/ */
protected void sessionEndAccess(WxMaMessage wxMessage) { private void sessionEndAccess(WxMaMessage wxMessage) {
InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser()); InternalSession session = ((InternalSessionManager) this.sessionManager).findSession(wxMessage.getFromUser());
if (session != null) { if (session != null) {
session.endAccess(); session.endAccess();

View File

@ -16,7 +16,6 @@ import java.util.regex.Pattern;
* @author <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
*/ */
public class WxMaMessageRouterRule { public class WxMaMessageRouterRule {
private final WxMaMessageRouter routerBuilder; private final WxMaMessageRouter routerBuilder;
private boolean async = true; private boolean async = true;
@ -46,7 +45,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 设置是否异步执行默认是true * 设置是否异步执行默认是true.
*/ */
public WxMaMessageRouterRule async(boolean async) { public WxMaMessageRouterRule async(boolean async) {
this.async = async; this.async = async;
@ -54,7 +53,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果msgType等于某值 * 如果msgType等于某值.
*/ */
public WxMaMessageRouterRule msgType(String msgType) { public WxMaMessageRouterRule msgType(String msgType) {
this.msgType = msgType; this.msgType = msgType;
@ -62,7 +61,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果event等于某值 * 如果event等于某值.
*/ */
public WxMaMessageRouterRule event(String event) { public WxMaMessageRouterRule event(String event) {
this.event = event; this.event = event;
@ -70,7 +69,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果eventKey等于某值 * 如果eventKey等于某值.
*/ */
public WxMaMessageRouterRule eventKey(String eventKey) { public WxMaMessageRouterRule eventKey(String eventKey) {
this.eventKey = eventKey; this.eventKey = eventKey;
@ -78,7 +77,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果content等于某值 * 如果content等于某值.
*/ */
public WxMaMessageRouterRule content(String content) { public WxMaMessageRouterRule content(String content) {
this.content = content; this.content = content;
@ -86,7 +85,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果content匹配该正则表达式 * 如果content匹配该正则表达式.
*/ */
public WxMaMessageRouterRule rContent(String regex) { public WxMaMessageRouterRule rContent(String regex) {
this.rContent = regex; this.rContent = regex;
@ -94,7 +93,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果fromUser等于某值 * 如果fromUser等于某值.
*/ */
public WxMaMessageRouterRule fromUser(String fromUser) { public WxMaMessageRouterRule fromUser(String fromUser) {
this.fromUser = fromUser; this.fromUser = fromUser;
@ -102,7 +101,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 如果消息匹配某个matcher用在用户需要自定义更复杂的匹配规则的时候 * 如果消息匹配某个matcher用在用户需要自定义更复杂的匹配规则的时候.
*/ */
public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) { public WxMaMessageRouterRule matcher(WxMaMessageMatcher matcher) {
this.matcher = matcher; this.matcher = matcher;
@ -110,14 +109,14 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 设置微信消息拦截器 * 设置微信消息拦截器.
*/ */
public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) { public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor) {
return interceptor(interceptor, (WxMaMessageInterceptor[]) null); return interceptor(interceptor, (WxMaMessageInterceptor[]) null);
} }
/** /**
* 设置微信消息拦截器 * 设置微信消息拦截器.
*/ */
public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) { public WxMaMessageRouterRule interceptor(WxMaMessageInterceptor interceptor, WxMaMessageInterceptor... otherInterceptors) {
this.interceptors.add(interceptor); this.interceptors.add(interceptor);
@ -130,14 +129,14 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 设置微信消息处理器 * 设置微信消息处理器.
*/ */
public WxMaMessageRouterRule handler(WxMaMessageHandler handler) { public WxMaMessageRouterRule handler(WxMaMessageHandler handler) {
return handler(handler, (WxMaMessageHandler[]) null); return handler(handler, (WxMaMessageHandler[]) null);
} }
/** /**
* 设置微信消息处理器 * 设置微信消息处理器.
*/ */
public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) { public WxMaMessageRouterRule handler(WxMaMessageHandler handler, WxMaMessageHandler... otherHandlers) {
this.handlers.add(handler); this.handlers.add(handler);
@ -150,7 +149,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 规则结束代表如果一个消息匹配该规则那么它将不再会进入其他规则 * 规则结束代表如果一个消息匹配该规则那么它将不再会进入其他规则.
*/ */
public WxMaMessageRouter end() { public WxMaMessageRouter end() {
this.routerBuilder.getRules().add(this); this.routerBuilder.getRules().add(this);
@ -158,7 +157,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 规则结束但是消息还会进入其他规则 * 规则结束但是消息还会进入其他规则.
*/ */
public WxMaMessageRouter next() { public WxMaMessageRouter next() {
this.reEnter = true; this.reEnter = true;
@ -166,7 +165,7 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 将微信自定义的事件修正为不区分大小写, * 将微信自定义的事件修正为不区分大小写.
* 比如框架定义的事件常量为click但微信传递过来的却是CLICK * 比如框架定义的事件常量为click但微信传递过来的却是CLICK
*/ */
protected boolean test(WxMaMessage wxMessage) { protected boolean test(WxMaMessage wxMessage) {
@ -188,9 +187,9 @@ public class WxMaMessageRouterRule {
} }
/** /**
* 处理微信推送过来的消息 * 处理微信推送过来的消息.
*/ */
protected void service(WxMaMessage wxMessage, protected WxMaXmlOutMessage service(WxMaMessage wxMessage,
Map<String, Object> context, Map<String, Object> context,
WxMaService wxMaService, WxMaService wxMaService,
WxSessionManager sessionManager, WxSessionManager sessionManager,
@ -199,11 +198,12 @@ public class WxMaMessageRouterRule {
context = new HashMap<>(16); context = new HashMap<>(16);
} }
WxMaXmlOutMessage outMessage = null;
try { try {
// 如果拦截器不通过 // 如果拦截器不通过
for (WxMaMessageInterceptor interceptor : this.interceptors) { for (WxMaMessageInterceptor interceptor : this.interceptors) {
if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) { if (!interceptor.intercept(wxMessage, context, wxMaService, sessionManager)) {
return; return null;
} }
} }
@ -213,11 +213,13 @@ public class WxMaMessageRouterRule {
if (handler == null) { if (handler == null) {
continue; continue;
} }
handler.handle(wxMessage, context, wxMaService, sessionManager); outMessage = handler.handle(wxMessage, context, wxMaService, sessionManager);
} }
} catch (WxErrorException e) { } catch (WxErrorException e) {
exceptionHandler.handle(e); exceptionHandler.handle(e);
} }
return outMessage;
} }
public WxMaMessageRouter getRouterBuilder() { public WxMaMessageRouter getRouterBuilder() {

View File

@ -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 <a href="https://github.com/binarywang">Binary Wang</a>
* @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<WxMaXmlOutMessage>) this.getClass(), this);
}
/**
* 转换成加密的xml格式.
*/
public String toEncryptedXml(WxMaConfig config) {
String plainXml = toXml();
WxMaCryptUtils pc = new WxMaCryptUtils(config);
return pc.encrypt(plainXml);
}
}

View File

@ -1,15 +1,5 @@
package cn.binarywang.wx.miniapp.demo; 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.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; 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.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
import cn.binarywang.wx.miniapp.test.TestConfig; import cn.binarywang.wx.miniapp.test.TestConfig;
import com.google.common.collect.Lists; 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.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager; 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 <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
@ -33,29 +35,31 @@ public class WxMaDemoServer {
private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() { private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() {
@Override @Override
public void handle(WxMaMessage wxMessage, Map<String, Object> context, public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) throws WxErrorException { WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
System.out.println("收到消息:" + wxMessage.toString()); System.out.println("收到消息:" + wxMessage.toString());
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson()) service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
.toUser(wxMessage.getFromUser()).build()); .toUser(wxMessage.getFromUser()).build());
return null;
} }
}; };
private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() {
@Override @Override
public void handle(WxMaMessage wxMessage, Map<String, Object> context, public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) WxMaService service, WxSessionManager sessionManager)
throws WxErrorException { throws WxErrorException {
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息") service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
.toUser(wxMessage.getFromUser()).build()); .toUser(wxMessage.getFromUser()).build());
return null;
} }
}; };
private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() {
@Override @Override
public void handle(WxMaMessage wxMessage, Map<String, Object> context, public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) throws WxErrorException { WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
try { try {
WxMediaUploadResult uploadResult = service.getMediaService() WxMediaUploadResult uploadResult = service.getMediaService()
.uploadMedia(WxMaConstants.MediaType.IMAGE, "png", .uploadMedia(WxMaConstants.MediaType.IMAGE, "png",
@ -69,13 +73,14 @@ public class WxMaDemoServer {
} catch (WxErrorException e) { } catch (WxErrorException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null;
} }
}; };
private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() {
@Override @Override
public void handle(WxMaMessage wxMessage, Map<String, Object> context, public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) throws WxErrorException { WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
try { try {
final File file = service.getQrcodeService().createQrcode("123", 430); final File file = service.getQrcodeService().createQrcode("123", 430);
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file);
@ -88,13 +93,14 @@ public class WxMaDemoServer {
} catch (WxErrorException e) { } catch (WxErrorException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null;
} }
}; };
private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() { private static final WxMaMessageHandler templateMsgHandler = new WxMaMessageHandler() {
@Override @Override
public void handle(WxMaMessage wxMessage, Map<String, Object> context, public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map<String, Object> context,
WxMaService service, WxSessionManager sessionManager) WxMaService service, WxSessionManager sessionManager)
throws WxErrorException { throws WxErrorException {
service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder() service.getMsgService().sendTemplateMsg(WxMaTemplateMessage.builder()
.templateId(templateId).data(Lists.newArrayList( .templateId(templateId).data(Lists.newArrayList(
@ -102,10 +108,22 @@ public class WxMaDemoServer {
.toUser(wxMessage.getFromUser()) .toUser(wxMessage.getFromUser())
.formId("自己替换可用的formid") .formId("自己替换可用的formid")
.build()); .build());
return null;
} }
}; };
private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() {
@Override
public WxMaXmlOutMessage handle(WxMaMessage message, Map<String, Object> 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 WxMaConfig config;
private static WxMaService service; private static WxMaService service;
private static WxMaMessageRouter router; private static WxMaMessageRouter router;
@ -142,7 +160,8 @@ public class WxMaDemoServer {
.rule().async(false).content("模板").handler(templateMsgHandler).end() .rule().async(false).content("模板").handler(templateMsgHandler).end()
.rule().async(false).content("文本").handler(textHandler).end() .rule().async(false).content("文本").handler(textHandler).end()
.rule().async(false).content("图片").handler(picHandler).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) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -5,6 +5,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; 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.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -18,19 +20,13 @@ import java.util.Objects;
/** /**
* @author <a href="https://github.com/binarywang">Binary Wang</a> * @author <a href="https://github.com/binarywang">Binary Wang</a>
*/ */
@AllArgsConstructor
public class WxMaPortalServlet extends HttpServlet { public class WxMaPortalServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private WxMaConfig wxMaConfig; private WxMaConfig config;
private WxMaService wxMaService; private WxMaService service;
private WxMaMessageRouter wxMaMessageRouter; private WxMaMessageRouter messageRouter;
WxMaPortalServlet(WxMaConfig wxMaConfig, WxMaService wxMaService,
WxMaMessageRouter wxMaMessageRouter) {
this.wxMaConfig = wxMaConfig;
this.wxMaService = wxMaService;
this.wxMaMessageRouter = wxMaMessageRouter;
}
@Override @Override
protected void service(HttpServletRequest request, HttpServletResponse response) protected void service(HttpServletRequest request, HttpServletResponse response)
@ -42,7 +38,7 @@ public class WxMaPortalServlet extends HttpServlet {
String nonce = request.getParameter("nonce"); String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp"); String timestamp = request.getParameter("timestamp");
if (!this.wxMaService.checkSignature(timestamp, nonce, signature)) { if (!this.service.checkSignature(timestamp, nonce, signature)) {
// 消息签名不正确说明不是公众平台发过来的消息 // 消息签名不正确说明不是公众平台发过来的消息
response.getWriter().println("非法请求"); response.getWriter().println("非法请求");
return; return;
@ -56,7 +52,7 @@ public class WxMaPortalServlet extends HttpServlet {
} }
String encryptType = request.getParameter("encrypt_type"); 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)) { if (StringUtils.isBlank(encryptType)) {
// 明文传输的消息 // 明文传输的消息
WxMaMessage inMessage; WxMaMessage inMessage;
@ -66,7 +62,12 @@ public class WxMaPortalServlet extends HttpServlet {
inMessage = WxMaMessage.fromXml(request.getInputStream()); 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"); response.getWriter().write("success");
return; return;
} }
@ -76,12 +77,16 @@ public class WxMaPortalServlet extends HttpServlet {
String msgSignature = request.getParameter("msg_signature"); String msgSignature = request.getParameter("msg_signature");
WxMaMessage inMessage; WxMaMessage inMessage;
if (isJson) { if (isJson) {
inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.wxMaConfig); inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), this.config);
} else {//xml } 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"); response.getWriter().write("success");
return; return;
} }