@@ -1,7 +1,9 @@ | |||||
package me.chanjar.weixin.cp.api; | package me.chanjar.weixin.cp.api; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.session.*; | |||||
import me.chanjar.weixin.common.session.InternalSession; | |||||
import me.chanjar.weixin.common.session.InternalSessionManager; | |||||
import me.chanjar.weixin.common.session.StandardSessionManager; | |||||
import me.chanjar.weixin.common.session.WxSessionManager; | |||||
import me.chanjar.weixin.common.util.LogExceptionHandler; | import me.chanjar.weixin.common.util.LogExceptionHandler; | ||||
import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | ||||
import me.chanjar.weixin.common.util.WxMessageDuplicateChecker; | import me.chanjar.weixin.common.util.WxMessageDuplicateChecker; | ||||
@@ -12,14 +14,11 @@ import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.concurrent.ExecutionException; | import java.util.concurrent.ExecutionException; | ||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import java.util.concurrent.Future; | import java.util.concurrent.Future; | ||||
import java.util.regex.Pattern; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -27,8 +26,8 @@ import java.util.regex.Pattern; | |||||
* | * | ||||
* 说明: | * 说明: | ||||
* 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | ||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#next()} | |||||
* 3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效 | |||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()} | |||||
* 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效 | |||||
* | * | ||||
* 使用方法: | * 使用方法: | ||||
* WxCpMessageRouter router = new WxCpMessageRouter(); | * WxCpMessageRouter router = new WxCpMessageRouter(); | ||||
@@ -55,7 +54,7 @@ public class WxCpMessageRouter { | |||||
private static final int DEFAULT_THREAD_POOL_SIZE = 100; | private static final int DEFAULT_THREAD_POOL_SIZE = 100; | ||||
private final List<Rule> rules = new ArrayList<Rule>(); | |||||
private final List<WxCpMessageRouterRule> rules = new ArrayList<WxCpMessageRouterRule>(); | |||||
private final WxCpService wxCpService; | private final WxCpService wxCpService; | ||||
@@ -100,7 +99,7 @@ public class WxCpMessageRouter { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | ||||
* 如果不调用该方法,默认使用 {@linke SessionManagerImpl} | |||||
* 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} | |||||
* </pre> | * </pre> | ||||
* @param sessionManager | * @param sessionManager | ||||
*/ | */ | ||||
@@ -108,12 +107,27 @@ public class WxCpMessageRouter { | |||||
this.sessionManager = sessionManager; | this.sessionManager = sessionManager; | ||||
} | } | ||||
/** | |||||
* <pre> | |||||
* 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler} | |||||
* 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | |||||
* </pre> | |||||
* @param exceptionHandler | |||||
*/ | |||||
public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { | |||||
this.exceptionHandler = exceptionHandler; | |||||
} | |||||
List<WxCpMessageRouterRule> getRules() { | |||||
return this.rules; | |||||
} | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | * @return | ||||
*/ | */ | ||||
public Rule rule() { | |||||
return new Rule(this); | |||||
public WxCpMessageRouterRule rule() { | |||||
return new WxCpMessageRouterRule(this); | |||||
} | } | ||||
/** | /** | ||||
@@ -125,13 +139,13 @@ public class WxCpMessageRouter { | |||||
// 如果是重复消息,那么就不做处理 | // 如果是重复消息,那么就不做处理 | ||||
return null; | return null; | ||||
} | } | ||||
final List<Rule> matchRules = new ArrayList<Rule>(); | |||||
final List<WxCpMessageRouterRule> matchRules = new ArrayList<WxCpMessageRouterRule>(); | |||||
// 收集匹配的规则 | // 收集匹配的规则 | ||||
for (final Rule rule : rules) { | |||||
for (final WxCpMessageRouterRule rule : rules) { | |||||
if (rule.test(wxMessage)) { | if (rule.test(wxMessage)) { | ||||
matchRules.add(rule); | matchRules.add(rule); | ||||
if(!rule.reEnter) { | |||||
if(!rule.isReEnter()) { | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -143,9 +157,9 @@ public class WxCpMessageRouter { | |||||
WxCpXmlOutMessage res = null; | WxCpXmlOutMessage res = null; | ||||
final List<Future> futures = new ArrayList<Future>(); | final List<Future> futures = new ArrayList<Future>(); | ||||
for (final Rule rule : matchRules) { | |||||
for (final WxCpMessageRouterRule rule : matchRules) { | |||||
// 返回最后一个非异步的rule的执行结果 | // 返回最后一个非异步的rule的执行结果 | ||||
if(rule.async) { | |||||
if(rule.isAsync()) { | |||||
futures.add( | futures.add( | ||||
executorService.submit(new Runnable() { | executorService.submit(new Runnable() { | ||||
public void run() { | public void run() { | ||||
@@ -216,252 +230,5 @@ public class WxCpMessageRouter { | |||||
} | } | ||||
public static class Rule { | |||||
private final WxCpMessageRouter routerBuilder; | |||||
private boolean async = true; | |||||
private String fromUser; | |||||
private String msgType; | |||||
private String event; | |||||
private String eventKey; | |||||
private String content; | |||||
private String rContent; | |||||
private WxCpMessageMatcher matcher; | |||||
private boolean reEnter = false; | |||||
private Integer agentId; | |||||
private List<WxCpMessageHandler> handlers = new ArrayList<WxCpMessageHandler>(); | |||||
private List<WxCpMessageInterceptor> interceptors = new ArrayList<WxCpMessageInterceptor>(); | |||||
protected Rule(WxCpMessageRouter routerBuilder) { | |||||
this.routerBuilder = routerBuilder; | |||||
} | |||||
/** | |||||
* 设置是否异步执行,默认是true | |||||
* @param async | |||||
* @return | |||||
*/ | |||||
public Rule async(boolean async) { | |||||
this.async = async; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果agentId匹配 | |||||
* @param agentId | |||||
* @return | |||||
*/ | |||||
public Rule agentId(Integer agentId) { | |||||
this.agentId = agentId; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果msgType等于某值 | |||||
* @param msgType | |||||
* @return | |||||
*/ | |||||
public Rule msgType(String msgType) { | |||||
this.msgType = msgType; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果event等于某值 | |||||
* @param event | |||||
* @return | |||||
*/ | |||||
public Rule event(String event) { | |||||
this.event = event; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果eventKey等于某值 | |||||
* @param eventKey | |||||
* @return | |||||
*/ | |||||
public Rule eventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content等于某值 | |||||
* @param content | |||||
* @return | |||||
*/ | |||||
public Rule content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content匹配该正则表达式 | |||||
* @param regex | |||||
* @return | |||||
*/ | |||||
public Rule rContent(String regex) { | |||||
this.rContent = regex; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果fromUser等于某值 | |||||
* @param fromUser | |||||
* @return | |||||
*/ | |||||
public Rule fromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||||
* @param matcher | |||||
* @return | |||||
*/ | |||||
public Rule matcher(WxCpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* @param interceptor | |||||
* @return | |||||
*/ | |||||
public Rule interceptor(WxCpMessageInterceptor interceptor) { | |||||
return interceptor(interceptor, (WxCpMessageInterceptor[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* @param interceptor | |||||
* @param otherInterceptors | |||||
* @return | |||||
*/ | |||||
public Rule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { | |||||
this.interceptors.add(interceptor); | |||||
if (otherInterceptors != null && otherInterceptors.length > 0) { | |||||
for (WxCpMessageInterceptor i : otherInterceptors) { | |||||
this.interceptors.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* @param handler | |||||
* @return | |||||
*/ | |||||
public Rule handler(WxCpMessageHandler handler) { | |||||
return handler(handler, (WxCpMessageHandler[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* @param handler | |||||
* @param otherHandlers | |||||
* @return | |||||
*/ | |||||
public Rule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { | |||||
this.handlers.add(handler); | |||||
if (otherHandlers != null && otherHandlers.length > 0) { | |||||
for (WxCpMessageHandler i : otherHandlers) { | |||||
this.handlers.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouter end() { | |||||
this.routerBuilder.rules.add(this); | |||||
return this.routerBuilder; | |||||
} | |||||
/** | |||||
* 规则结束,但是消息还会进入其他规则 | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouter next() { | |||||
this.reEnter = true; | |||||
return end(); | |||||
} | |||||
protected boolean test(WxCpXmlMessage wxMessage) { | |||||
return | |||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) | |||||
&& | |||||
(this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) | |||||
&& | |||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) | |||||
&& | |||||
(this.event == null || this.event.equals(wxMessage.getEvent())) | |||||
&& | |||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) | |||||
&& | |||||
(this.content == null || this.content.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.rContent == null || Pattern.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.matcher == null || this.matcher.match(wxMessage)) | |||||
; | |||||
} | |||||
/** | |||||
* 处理微信推送过来的消息 | |||||
* @param wxMessage | |||||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||||
*/ | |||||
protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, | |||||
WxCpService wxCpService, | |||||
WxSessionManager sessionManager, | |||||
WxErrorExceptionHandler exceptionHandler) { | |||||
try { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | |||||
// 如果拦截器不通过 | |||||
for (WxCpMessageInterceptor interceptor : this.interceptors) { | |||||
if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { | |||||
return null; | |||||
} | |||||
} | |||||
// 交给handler处理 | |||||
WxCpXmlOutMessage res = null; | |||||
for (WxCpMessageHandler handler : this.handlers) { | |||||
// 返回最后handler的结果 | |||||
res = handler.handle(wxMessage, context, wxCpService, sessionManager); | |||||
} | |||||
return res; | |||||
} catch (WxErrorException e) { | |||||
exceptionHandler.handle(e); | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} | } |
@@ -0,0 +1,335 @@ | |||||
package me.chanjar.weixin.cp.api; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.session.WxSessionManager; | |||||
import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.regex.Pattern; | |||||
public class WxCpMessageRouterRule { | |||||
private final WxCpMessageRouter routerBuilder; | |||||
private boolean async = true; | |||||
private String fromUser; | |||||
private String msgType; | |||||
private String event; | |||||
private String eventKey; | |||||
private String content; | |||||
private String rContent; | |||||
private WxCpMessageMatcher matcher; | |||||
private boolean reEnter = false; | |||||
private Integer agentId; | |||||
private List<WxCpMessageHandler> handlers = new ArrayList<WxCpMessageHandler>(); | |||||
private List<WxCpMessageInterceptor> interceptors = new ArrayList<WxCpMessageInterceptor>(); | |||||
protected WxCpMessageRouterRule(WxCpMessageRouter routerBuilder) { | |||||
this.routerBuilder = routerBuilder; | |||||
} | |||||
/** | |||||
* 设置是否异步执行,默认是true | |||||
* | |||||
* @param async | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule async(boolean async) { | |||||
this.async = async; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果agentId匹配 | |||||
* | |||||
* @param agentId | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule agentId(Integer agentId) { | |||||
this.agentId = agentId; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果msgType等于某值 | |||||
* | |||||
* @param msgType | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule msgType(String msgType) { | |||||
this.msgType = msgType; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果event等于某值 | |||||
* | |||||
* @param event | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule event(String event) { | |||||
this.event = event; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果eventKey等于某值 | |||||
* | |||||
* @param eventKey | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule eventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content等于某值 | |||||
* | |||||
* @param content | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content匹配该正则表达式 | |||||
* | |||||
* @param regex | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule rContent(String regex) { | |||||
this.rContent = regex; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果fromUser等于某值 | |||||
* | |||||
* @param fromUser | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule fromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||||
* | |||||
* @param matcher | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* | |||||
* @param interceptor | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { | |||||
return interceptor(interceptor, (WxCpMessageInterceptor[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* | |||||
* @param interceptor | |||||
* @param otherInterceptors | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { | |||||
this.interceptors.add(interceptor); | |||||
if (otherInterceptors != null && otherInterceptors.length > 0) { | |||||
for (WxCpMessageInterceptor i : otherInterceptors) { | |||||
this.interceptors.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* | |||||
* @param handler | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { | |||||
return handler(handler, (WxCpMessageHandler[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* | |||||
* @param handler | |||||
* @param otherHandlers | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { | |||||
this.handlers.add(handler); | |||||
if (otherHandlers != null && otherHandlers.length > 0) { | |||||
for (WxCpMessageHandler i : otherHandlers) { | |||||
this.handlers.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||||
* | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouter end() { | |||||
this.routerBuilder.getRules().add(this); | |||||
return this.routerBuilder; | |||||
} | |||||
/** | |||||
* 规则结束,但是消息还会进入其他规则 | |||||
* | |||||
* @return | |||||
*/ | |||||
public WxCpMessageRouter next() { | |||||
this.reEnter = true; | |||||
return end(); | |||||
} | |||||
protected boolean test(WxCpXmlMessage wxMessage) { | |||||
return | |||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) | |||||
&& | |||||
(this.agentId == null || this.agentId.equals(wxMessage.getAgentId())) | |||||
&& | |||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) | |||||
&& | |||||
(this.event == null || this.event.equals(wxMessage.getEvent())) | |||||
&& | |||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) | |||||
&& | |||||
(this.content == null || this.content | |||||
.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.rContent == null || Pattern | |||||
.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.matcher == null || this.matcher.match(wxMessage)) | |||||
; | |||||
} | |||||
/** | |||||
* 处理微信推送过来的消息 | |||||
* | |||||
* @param wxMessage | |||||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||||
*/ | |||||
protected WxCpXmlOutMessage service(WxCpXmlMessage wxMessage, | |||||
WxCpService wxCpService, | |||||
WxSessionManager sessionManager, | |||||
WxErrorExceptionHandler exceptionHandler) { | |||||
try { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | |||||
// 如果拦截器不通过 | |||||
for (WxCpMessageInterceptor interceptor : this.interceptors) { | |||||
if (!interceptor.intercept(wxMessage, context, wxCpService, sessionManager)) { | |||||
return null; | |||||
} | |||||
} | |||||
// 交给handler处理 | |||||
WxCpXmlOutMessage res = null; | |||||
for (WxCpMessageHandler handler : this.handlers) { | |||||
// 返回最后handler的结果 | |||||
res = handler.handle(wxMessage, context, wxCpService, sessionManager); | |||||
} | |||||
return res; | |||||
} catch (WxErrorException e) { | |||||
exceptionHandler.handle(e); | |||||
} | |||||
return null; | |||||
} | |||||
public void setFromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
} | |||||
public void setMsgType(String msgType) { | |||||
this.msgType = msgType; | |||||
} | |||||
public void setEvent(String event) { | |||||
this.event = event; | |||||
} | |||||
public void setEventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
} | |||||
public void setContent(String content) { | |||||
this.content = content; | |||||
} | |||||
public void setrContent(String rContent) { | |||||
this.rContent = rContent; | |||||
} | |||||
public void setMatcher(WxCpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
} | |||||
public void setAgentId(Integer agentId) { | |||||
this.agentId = agentId; | |||||
} | |||||
public void setHandlers(List<WxCpMessageHandler> handlers) { | |||||
this.handlers = handlers; | |||||
} | |||||
public void setInterceptors(List<WxCpMessageInterceptor> interceptors) { | |||||
this.interceptors = interceptors; | |||||
} | |||||
public boolean isAsync() { | |||||
return async; | |||||
} | |||||
public void setAsync(boolean async) { | |||||
this.async = async; | |||||
} | |||||
public boolean isReEnter() { | |||||
return reEnter; | |||||
} | |||||
public void setReEnter(boolean reEnter) { | |||||
this.reEnter = reEnter; | |||||
} | |||||
} |
@@ -1,6 +1,5 @@ | |||||
package me.chanjar.weixin.mp.api; | package me.chanjar.weixin.mp.api; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.session.InternalSession; | import me.chanjar.weixin.common.session.InternalSession; | ||||
import me.chanjar.weixin.common.session.InternalSessionManager; | import me.chanjar.weixin.common.session.InternalSessionManager; | ||||
import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
@@ -15,14 +14,11 @@ import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.concurrent.ExecutionException; | import java.util.concurrent.ExecutionException; | ||||
import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||
import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||
import java.util.concurrent.Future; | import java.util.concurrent.Future; | ||||
import java.util.regex.Pattern; | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
@@ -30,8 +26,8 @@ import java.util.regex.Pattern; | |||||
* | * | ||||
* 说明: | * 说明: | ||||
* 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理 | ||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link Rule#next()} | |||||
* 3. 规则的结束必须用{@link Rule#end()}或者{@link Rule#next()},否则不会生效 | |||||
* 2. 默认情况下消息只会被处理一次,除非使用 {@link WxMpMessageRouterRule#next()} | |||||
* 3. 规则的结束必须用{@link WxMpMessageRouterRule#end()}或者{@link WxMpMessageRouterRule#next()},否则不会生效 | |||||
* | * | ||||
* 使用方法: | * 使用方法: | ||||
* WxMpMessageRouter router = new WxMpMessageRouter(); | * WxMpMessageRouter router = new WxMpMessageRouter(); | ||||
@@ -49,6 +45,8 @@ import java.util.regex.Pattern; | |||||
* router.route(message); | * router.route(message); | ||||
* | * | ||||
* </pre> | * </pre> | ||||
* @author Daniel Qian | |||||
* | |||||
*/ | */ | ||||
public class WxMpMessageRouter { | public class WxMpMessageRouter { | ||||
@@ -56,7 +54,7 @@ public class WxMpMessageRouter { | |||||
private static final int DEFAULT_THREAD_POOL_SIZE = 100; | private static final int DEFAULT_THREAD_POOL_SIZE = 100; | ||||
private final List<Rule> rules = new ArrayList<Rule>(); | |||||
private final List<WxMpMessageRouterRule> rules = new ArrayList<WxMpMessageRouterRule>(); | |||||
private final WxMpService wxMpService; | private final WxMpService wxMpService; | ||||
@@ -101,7 +99,7 @@ public class WxMpMessageRouter { | |||||
/** | /** | ||||
* <pre> | * <pre> | ||||
* 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | * 设置自定义的{@link me.chanjar.weixin.common.session.WxSessionManager} | ||||
* 如果不调用该方法,默认使用 {@linke SessionManagerImpl} | |||||
* 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.session.StandardSessionManager} | |||||
* </pre> | * </pre> | ||||
* @param sessionManager | * @param sessionManager | ||||
*/ | */ | ||||
@@ -109,12 +107,27 @@ public class WxMpMessageRouter { | |||||
this.sessionManager = sessionManager; | this.sessionManager = sessionManager; | ||||
} | } | ||||
/** | |||||
* <pre> | |||||
* 设置自定义的{@link me.chanjar.weixin.common.util.WxErrorExceptionHandler} | |||||
* 如果不调用该方法,默认使用 {@link me.chanjar.weixin.common.util.LogExceptionHandler} | |||||
* </pre> | |||||
* @param exceptionHandler | |||||
*/ | |||||
public void setExceptionHandler(WxErrorExceptionHandler exceptionHandler) { | |||||
this.exceptionHandler = exceptionHandler; | |||||
} | |||||
List<WxMpMessageRouterRule> getRules() { | |||||
return this.rules; | |||||
} | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | * @return | ||||
*/ | */ | ||||
public Rule rule() { | |||||
return new Rule(this); | |||||
public WxMpMessageRouterRule rule() { | |||||
return new WxMpMessageRouterRule(this); | |||||
} | } | ||||
/** | /** | ||||
@@ -127,12 +140,12 @@ public class WxMpMessageRouter { | |||||
return null; | return null; | ||||
} | } | ||||
final List<Rule> matchRules = new ArrayList<Rule>(); | |||||
final List<WxMpMessageRouterRule> matchRules = new ArrayList<WxMpMessageRouterRule>(); | |||||
// 收集匹配的规则 | // 收集匹配的规则 | ||||
for (final Rule rule : rules) { | |||||
for (final WxMpMessageRouterRule rule : rules) { | |||||
if (rule.test(wxMessage)) { | if (rule.test(wxMessage)) { | ||||
matchRules.add(rule); | matchRules.add(rule); | ||||
if(!rule.reEnter) { | |||||
if(!rule.isReEnter()) { | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -144,9 +157,9 @@ public class WxMpMessageRouter { | |||||
WxMpXmlOutMessage res = null; | WxMpXmlOutMessage res = null; | ||||
final List<Future> futures = new ArrayList<Future>(); | final List<Future> futures = new ArrayList<Future>(); | ||||
for (final Rule rule : matchRules) { | |||||
for (final WxMpMessageRouterRule rule : matchRules) { | |||||
// 返回最后一个非异步的rule的执行结果 | // 返回最后一个非异步的rule的执行结果 | ||||
if(rule.async) { | |||||
if(rule.isAsync()) { | |||||
futures.add( | futures.add( | ||||
executorService.submit(new Runnable() { | executorService.submit(new Runnable() { | ||||
public void run() { | public void run() { | ||||
@@ -215,237 +228,4 @@ public class WxMpMessageRouter { | |||||
} | } | ||||
} | } | ||||
public static class Rule { | |||||
private final WxMpMessageRouter routerBuilder; | |||||
private boolean async = true; | |||||
private String fromUser; | |||||
private String msgType; | |||||
private String event; | |||||
private String eventKey; | |||||
private String content; | |||||
private String rContent; | |||||
private WxMpMessageMatcher matcher; | |||||
private boolean reEnter = false; | |||||
private List<WxMpMessageHandler> handlers = new ArrayList<WxMpMessageHandler>(); | |||||
private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>(); | |||||
protected Rule(WxMpMessageRouter routerBuilder) { | |||||
this.routerBuilder = routerBuilder; | |||||
} | |||||
/** | |||||
* 设置是否异步执行,默认是true | |||||
* @param async | |||||
* @return | |||||
*/ | |||||
public Rule async(boolean async) { | |||||
this.async = async; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果msgType等于某值 | |||||
* @param msgType | |||||
* @return | |||||
*/ | |||||
public Rule msgType(String msgType) { | |||||
this.msgType = msgType; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果event等于某值 | |||||
* @param event | |||||
* @return | |||||
*/ | |||||
public Rule event(String event) { | |||||
this.event = event; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果eventKey等于某值 | |||||
* @param eventKey | |||||
* @return | |||||
*/ | |||||
public Rule eventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content等于某值 | |||||
* @param content | |||||
* @return | |||||
*/ | |||||
public Rule content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content匹配该正则表达式 | |||||
* @param regex | |||||
* @return | |||||
*/ | |||||
public Rule rContent(String regex) { | |||||
this.rContent = regex; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果fromUser等于某值 | |||||
* @param fromUser | |||||
* @return | |||||
*/ | |||||
public Rule fromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||||
* @param matcher | |||||
* @return | |||||
*/ | |||||
public Rule matcher(WxMpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* @param interceptor | |||||
* @return | |||||
*/ | |||||
public Rule interceptor(WxMpMessageInterceptor interceptor) { | |||||
return interceptor(interceptor, (WxMpMessageInterceptor[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* @param interceptor | |||||
* @param otherInterceptors | |||||
* @return | |||||
*/ | |||||
public Rule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { | |||||
this.interceptors.add(interceptor); | |||||
if (otherInterceptors != null && otherInterceptors.length > 0) { | |||||
for (WxMpMessageInterceptor i : otherInterceptors) { | |||||
this.interceptors.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* @param handler | |||||
* @return | |||||
*/ | |||||
public Rule handler(WxMpMessageHandler handler) { | |||||
return handler(handler, (WxMpMessageHandler[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* @param handler | |||||
* @param otherHandlers | |||||
* @return | |||||
*/ | |||||
public Rule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { | |||||
this.handlers.add(handler); | |||||
if (otherHandlers != null && otherHandlers.length > 0) { | |||||
for (WxMpMessageHandler i : otherHandlers) { | |||||
this.handlers.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouter end() { | |||||
this.routerBuilder.rules.add(this); | |||||
return this.routerBuilder; | |||||
} | |||||
/** | |||||
* 规则结束,但是消息还会进入其他规则 | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouter next() { | |||||
this.reEnter = true; | |||||
return end(); | |||||
} | |||||
protected boolean test(WxMpXmlMessage wxMessage) { | |||||
return | |||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) | |||||
&& | |||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) | |||||
&& | |||||
(this.event == null || this.event.equals(wxMessage.getEvent())) | |||||
&& | |||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) | |||||
&& | |||||
(this.content == null || this.content.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.rContent == null || Pattern.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.matcher == null || this.matcher.match(wxMessage)) | |||||
; | |||||
} | |||||
/** | |||||
* 处理微信推送过来的消息 | |||||
* @param wxMessage | |||||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||||
*/ | |||||
protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, | |||||
WxMpService wxMpService, | |||||
WxSessionManager sessionManager, | |||||
WxErrorExceptionHandler exceptionHandler) { | |||||
try { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | |||||
// 如果拦截器不通过 | |||||
for (WxMpMessageInterceptor interceptor : this.interceptors) { | |||||
if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { | |||||
return null; | |||||
} | |||||
} | |||||
// 交给handler处理 | |||||
WxMpXmlOutMessage res = null; | |||||
for (WxMpMessageHandler handler : this.handlers) { | |||||
// 返回最后handler的结果 | |||||
res = handler.handle(wxMessage, context, wxMpService, sessionManager); | |||||
} | |||||
return res; | |||||
} catch (WxErrorException e) { | |||||
exceptionHandler.handle(e); | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} | } |
@@ -0,0 +1,353 @@ | |||||
package me.chanjar.weixin.mp.api; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.session.WxSessionManager; | |||||
import me.chanjar.weixin.common.util.WxErrorExceptionHandler; | |||||
import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | |||||
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.regex.Pattern; | |||||
public class WxMpMessageRouterRule { | |||||
private final WxMpMessageRouter routerBuilder; | |||||
private boolean async = true; | |||||
private String fromUser; | |||||
private String msgType; | |||||
private String event; | |||||
private String eventKey; | |||||
private String content; | |||||
private String rContent; | |||||
private WxMpMessageMatcher matcher; | |||||
private boolean reEnter = false; | |||||
private List<WxMpMessageHandler> handlers = new ArrayList<WxMpMessageHandler>(); | |||||
private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>(); | |||||
public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) { | |||||
this.routerBuilder = routerBuilder; | |||||
} | |||||
/** | |||||
* 设置是否异步执行,默认是true | |||||
* | |||||
* @param async | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule async(boolean async) { | |||||
this.async = async; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果msgType等于某值 | |||||
* | |||||
* @param msgType | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule msgType(String msgType) { | |||||
this.msgType = msgType; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果event等于某值 | |||||
* | |||||
* @param event | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule event(String event) { | |||||
this.event = event; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果eventKey等于某值 | |||||
* | |||||
* @param eventKey | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule eventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content等于某值 | |||||
* | |||||
* @param content | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule content(String content) { | |||||
this.content = content; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果content匹配该正则表达式 | |||||
* | |||||
* @param regex | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule rContent(String regex) { | |||||
this.rContent = regex; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果fromUser等于某值 | |||||
* | |||||
* @param fromUser | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule fromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
return this; | |||||
} | |||||
/** | |||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||||
* | |||||
* @param matcher | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* | |||||
* @param interceptor | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { | |||||
return interceptor(interceptor, (WxMpMessageInterceptor[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息拦截器 | |||||
* | |||||
* @param interceptor | |||||
* @param otherInterceptors | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { | |||||
this.interceptors.add(interceptor); | |||||
if (otherInterceptors != null && otherInterceptors.length > 0) { | |||||
for (WxMpMessageInterceptor i : otherInterceptors) { | |||||
this.interceptors.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* | |||||
* @param handler | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { | |||||
return handler(handler, (WxMpMessageHandler[]) null); | |||||
} | |||||
/** | |||||
* 设置微信消息处理器 | |||||
* | |||||
* @param handler | |||||
* @param otherHandlers | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { | |||||
this.handlers.add(handler); | |||||
if (otherHandlers != null && otherHandlers.length > 0) { | |||||
for (WxMpMessageHandler i : otherHandlers) { | |||||
this.handlers.add(i); | |||||
} | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||||
* | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouter end() { | |||||
this.routerBuilder.getRules().add(this); | |||||
return this.routerBuilder; | |||||
} | |||||
/** | |||||
* 规则结束,但是消息还会进入其他规则 | |||||
* | |||||
* @return | |||||
*/ | |||||
public WxMpMessageRouter next() { | |||||
this.reEnter = true; | |||||
return end(); | |||||
} | |||||
protected boolean test(WxMpXmlMessage wxMessage) { | |||||
return | |||||
(this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName())) | |||||
&& | |||||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) | |||||
&& | |||||
(this.event == null || this.event.equals(wxMessage.getEvent())) | |||||
&& | |||||
(this.eventKey == null || this.eventKey.equals(wxMessage.getEventKey())) | |||||
&& | |||||
(this.content == null || this.content | |||||
.equals(wxMessage.getContent() == null ? null : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.rContent == null || Pattern | |||||
.matches(this.rContent, wxMessage.getContent() == null ? "" : wxMessage.getContent().trim())) | |||||
&& | |||||
(this.matcher == null || this.matcher.match(wxMessage)) | |||||
; | |||||
} | |||||
/** | |||||
* 处理微信推送过来的消息 | |||||
* | |||||
* @param wxMessage | |||||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||||
*/ | |||||
protected WxMpXmlOutMessage service(WxMpXmlMessage wxMessage, | |||||
WxMpService wxMpService, | |||||
WxSessionManager sessionManager, | |||||
WxErrorExceptionHandler exceptionHandler) { | |||||
try { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | |||||
// 如果拦截器不通过 | |||||
for (WxMpMessageInterceptor interceptor : this.interceptors) { | |||||
if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { | |||||
return null; | |||||
} | |||||
} | |||||
// 交给handler处理 | |||||
WxMpXmlOutMessage res = null; | |||||
for (WxMpMessageHandler handler : this.handlers) { | |||||
// 返回最后handler的结果 | |||||
res = handler.handle(wxMessage, context, wxMpService, sessionManager); | |||||
} | |||||
return res; | |||||
} catch (WxErrorException e) { | |||||
exceptionHandler.handle(e); | |||||
} | |||||
return null; | |||||
} | |||||
public WxMpMessageRouter getRouterBuilder() { | |||||
return routerBuilder; | |||||
} | |||||
public boolean isAsync() { | |||||
return async; | |||||
} | |||||
public void setAsync(boolean async) { | |||||
this.async = async; | |||||
} | |||||
public String getFromUser() { | |||||
return fromUser; | |||||
} | |||||
public void setFromUser(String fromUser) { | |||||
this.fromUser = fromUser; | |||||
} | |||||
public String getMsgType() { | |||||
return msgType; | |||||
} | |||||
public void setMsgType(String msgType) { | |||||
this.msgType = msgType; | |||||
} | |||||
public String getEvent() { | |||||
return event; | |||||
} | |||||
public void setEvent(String event) { | |||||
this.event = event; | |||||
} | |||||
public String getEventKey() { | |||||
return eventKey; | |||||
} | |||||
public void setEventKey(String eventKey) { | |||||
this.eventKey = eventKey; | |||||
} | |||||
public String getContent() { | |||||
return content; | |||||
} | |||||
public void setContent(String content) { | |||||
this.content = content; | |||||
} | |||||
public String getrContent() { | |||||
return rContent; | |||||
} | |||||
public void setrContent(String rContent) { | |||||
this.rContent = rContent; | |||||
} | |||||
public WxMpMessageMatcher getMatcher() { | |||||
return matcher; | |||||
} | |||||
public void setMatcher(WxMpMessageMatcher matcher) { | |||||
this.matcher = matcher; | |||||
} | |||||
public boolean isReEnter() { | |||||
return reEnter; | |||||
} | |||||
public void setReEnter(boolean reEnter) { | |||||
this.reEnter = reEnter; | |||||
} | |||||
public List<WxMpMessageHandler> getHandlers() { | |||||
return handlers; | |||||
} | |||||
public void setHandlers(List<WxMpMessageHandler> handlers) { | |||||
this.handlers = handlers; | |||||
} | |||||
public List<WxMpMessageInterceptor> getInterceptors() { | |||||
return interceptors; | |||||
} | |||||
public void setInterceptors(List<WxMpMessageInterceptor> interceptors) { | |||||
this.interceptors = interceptors; | |||||
} | |||||
} |