mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-08-24 16:18:51 +08:00
#1079 小程序增加对转发客服消息功能的支持
This commit is contained in:
parent
a63321f712
commit
54c8ae5452
@ -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,
|
* 处理消息.
|
||||||
|
*
|
||||||
|
* @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;
|
WxMaService service, WxSessionManager sessionManager) throws WxErrorException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 wxMessage .
|
||||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
|
||||||
|
* @param wxMaService .
|
||||||
|
* @param sessionManager .
|
||||||
* @return true代表OK,false代表不OK
|
* @return true代表OK,false代表不OK
|
||||||
|
* @throws WxErrorException .
|
||||||
*/
|
*/
|
||||||
boolean intercept(WxMaMessage wxMessage,
|
boolean intercept(WxMaMessage wxMessage,
|
||||||
Map<String, Object> context,
|
Map<String, Object> context,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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() {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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,28 +35,30 @@ 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()
|
||||||
@ -69,12 +73,13 @@ 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);
|
||||||
@ -88,12 +93,13 @@ 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()
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user