@@ -70,11 +70,6 @@ | |||||
<artifactId>gson</artifactId> | <artifactId>gson</artifactId> | ||||
<version>2.2.2</version> | <version>2.2.2</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.apache.commons</groupId> | |||||
<artifactId>commons-lang3</artifactId> | |||||
<version>3.1</version> | |||||
</dependency> | |||||
<dependency> | <dependency> | ||||
<groupId>commons-codec</groupId> | <groupId>commons-codec</groupId> | ||||
<artifactId>commons-codec</artifactId> | <artifactId>commons-codec</artifactId> | ||||
@@ -0,0 +1,100 @@ | |||||
package me.chanjar.weixin.common.util; | |||||
/** | |||||
* copy from apache-commons-lang3 | |||||
*/ | |||||
public class StringUtils { | |||||
/** | |||||
* <p>Checks if a CharSequence is whitespace, empty ("") or null.</p> | |||||
* | |||||
* <pre> | |||||
* StringUtils.isBlank(null) = true | |||||
* StringUtils.isBlank("") = true | |||||
* StringUtils.isBlank(" ") = true | |||||
* StringUtils.isBlank("bob") = false | |||||
* StringUtils.isBlank(" bob ") = false | |||||
* </pre> | |||||
* | |||||
* @param cs the CharSequence to check, may be null | |||||
* @return {@code true} if the CharSequence is null, empty or whitespace | |||||
* @since 2.0 | |||||
* @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence) | |||||
*/ | |||||
public static boolean isBlank(CharSequence cs) { | |||||
int strLen; | |||||
if (cs == null || (strLen = cs.length()) == 0) { | |||||
return true; | |||||
} | |||||
for (int i = 0; i < strLen; i++) { | |||||
if (Character.isWhitespace(cs.charAt(i)) == false) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p> | |||||
* | |||||
* <pre> | |||||
* StringUtils.isNotBlank(null) = false | |||||
* StringUtils.isNotBlank("") = false | |||||
* StringUtils.isNotBlank(" ") = false | |||||
* StringUtils.isNotBlank("bob") = true | |||||
* StringUtils.isNotBlank(" bob ") = true | |||||
* </pre> | |||||
* | |||||
* @param cs the CharSequence to check, may be null | |||||
* @return {@code true} if the CharSequence is | |||||
* not empty and not null and not whitespace | |||||
* @since 2.0 | |||||
* @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) | |||||
*/ | |||||
public static boolean isNotBlank(CharSequence cs) { | |||||
return !StringUtils.isBlank(cs); | |||||
} | |||||
/** | |||||
* <p>Checks if a CharSequence is empty ("") or null.</p> | |||||
* | |||||
* <pre> | |||||
* StringUtils.isEmpty(null) = true | |||||
* StringUtils.isEmpty("") = true | |||||
* StringUtils.isEmpty(" ") = false | |||||
* StringUtils.isEmpty("bob") = false | |||||
* StringUtils.isEmpty(" bob ") = false | |||||
* </pre> | |||||
* | |||||
* <p>NOTE: This method changed in Lang version 2.0. | |||||
* It no longer trims the CharSequence. | |||||
* That functionality is available in isBlank().</p> | |||||
* | |||||
* @param cs the CharSequence to check, may be null | |||||
* @return {@code true} if the CharSequence is empty or null | |||||
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) | |||||
*/ | |||||
public static boolean isEmpty(CharSequence cs) { | |||||
return cs == null || cs.length() == 0; | |||||
} | |||||
/** | |||||
* <p>Checks if a CharSequence is not empty ("") and not null.</p> | |||||
* | |||||
* <pre> | |||||
* StringUtils.isNotEmpty(null) = false | |||||
* StringUtils.isNotEmpty("") = false | |||||
* StringUtils.isNotEmpty(" ") = true | |||||
* StringUtils.isNotEmpty("bob") = true | |||||
* StringUtils.isNotEmpty(" bob ") = true | |||||
* </pre> | |||||
* | |||||
* @param cs the CharSequence to check, may be null | |||||
* @return {@code true} if the CharSequence is not empty and not null | |||||
* @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence) | |||||
*/ | |||||
public static boolean isNotEmpty(CharSequence cs) { | |||||
return !StringUtils.isEmpty(cs); | |||||
} | |||||
} |
@@ -1,12 +1,9 @@ | |||||
package me.chanjar.weixin.common.util.http; | package me.chanjar.weixin.common.util.http; | ||||
import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.common.util.http.InputStreamResponseHandler; | |||||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.Utf8ResponseHandler; | |||||
import org.apache.commons.lang3.StringUtils; | |||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||||
import org.apache.http.Header; | import org.apache.http.Header; | ||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.client.ClientProtocolException; | import org.apache.http.client.ClientProtocolException; | ||||
@@ -16,8 +16,9 @@ public interface WxCpMessageHandler { | |||||
* | * | ||||
* @param wxMessage | * @param wxMessage | ||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | ||||
* @param wxCpService | |||||
* @return xml格式的消息,如果在异步规则里处理的话,可以返回null | * @return xml格式的消息,如果在异步规则里处理的话,可以返回null | ||||
*/ | */ | ||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context); | |||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService); | |||||
} | } |
@@ -15,8 +15,9 @@ public interface WxCpMessageInterceptor { | |||||
* 拦截微信消息 | * 拦截微信消息 | ||||
* @param wxMessage | * @param wxMessage | ||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | ||||
* @param wxCpService | |||||
* @return true代表OK,false代表不OK | * @return true代表OK,false代表不OK | ||||
*/ | */ | ||||
public boolean intercept(WxCpXmlMessage wxMessage, Map<String, Object> context); | |||||
public boolean intercept(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService); | |||||
} | } |
@@ -45,12 +45,18 @@ public class WxCpMessageRouter { | |||||
private final ExecutorService es = Executors.newCachedThreadPool(); | private final ExecutorService es = Executors.newCachedThreadPool(); | ||||
private final WxCpService wxCpService; | |||||
public WxCpMessageRouter(WxCpService wxCpService) { | |||||
this.wxCpService = wxCpService; | |||||
} | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | * @return | ||||
*/ | */ | ||||
public Rule rule() { | public Rule rule() { | ||||
return new Rule(this); | |||||
return new Rule(this, wxCpService); | |||||
} | } | ||||
/** | /** | ||||
@@ -101,6 +107,8 @@ public class WxCpMessageRouter { | |||||
private final WxCpMessageRouter routerBuilder; | private final WxCpMessageRouter routerBuilder; | ||||
private final WxCpService wxCpService; | |||||
private boolean async = true; | private boolean async = true; | ||||
private String msgType; | private String msgType; | ||||
@@ -121,8 +129,9 @@ public class WxCpMessageRouter { | |||||
private List<WxCpMessageInterceptor> interceptors = new ArrayList<WxCpMessageInterceptor>(); | private List<WxCpMessageInterceptor> interceptors = new ArrayList<WxCpMessageInterceptor>(); | ||||
protected Rule(WxCpMessageRouter routerBuilder) { | |||||
protected Rule(WxCpMessageRouter routerBuilder, WxCpService wxCpService) { | |||||
this.routerBuilder = routerBuilder; | this.routerBuilder = routerBuilder; | ||||
this.wxCpService = wxCpService; | |||||
} | } | ||||
/** | /** | ||||
@@ -288,7 +297,7 @@ public class WxCpMessageRouter { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | Map<String, Object> context = new HashMap<String, Object>(); | ||||
// 如果拦截器不通过 | // 如果拦截器不通过 | ||||
for (WxCpMessageInterceptor interceptor : this.interceptors) { | for (WxCpMessageInterceptor interceptor : this.interceptors) { | ||||
if (!interceptor.intercept(wxMessage, context)) { | |||||
if (!interceptor.intercept(wxMessage, context, wxCpService)) { | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@@ -297,7 +306,7 @@ public class WxCpMessageRouter { | |||||
WxCpXmlOutMessage res = null; | WxCpXmlOutMessage res = null; | ||||
for (WxCpMessageHandler handler : this.handlers) { | for (WxCpMessageHandler handler : this.handlers) { | ||||
// 返回最后handler的结果 | // 返回最后handler的结果 | ||||
res = handler.handle(wxMessage, context); | |||||
res = handler.handle(wxMessage, context, wxCpService); | |||||
} | } | ||||
return res; | return res; | ||||
} | } | ||||
@@ -1,25 +1,27 @@ | |||||
package me.chanjar.weixin.cp.api; | package me.chanjar.weixin.cp.api; | ||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.StringReader; | |||||
import java.util.List; | |||||
import java.util.UUID; | |||||
import java.util.concurrent.atomic.AtomicBoolean; | |||||
import com.google.gson.JsonArray; | import com.google.gson.JsonArray; | ||||
import com.google.gson.JsonElement; | |||||
import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||
import com.google.gson.JsonPrimitive; | import com.google.gson.JsonPrimitive; | ||||
import com.google.gson.internal.Streams; | |||||
import com.google.gson.reflect.TypeToken; | |||||
import com.google.gson.stream.JsonReader; | |||||
import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||
import me.chanjar.weixin.common.bean.WxMenu; | import me.chanjar.weixin.common.bean.WxMenu; | ||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.cp.bean.*; | |||||
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||||
import me.chanjar.weixin.common.util.http.*; | |||||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||||
import me.chanjar.weixin.cp.bean.WxCpDepart; | |||||
import me.chanjar.weixin.cp.bean.WxCpMessage; | |||||
import me.chanjar.weixin.cp.bean.WxCpTag; | |||||
import me.chanjar.weixin.cp.bean.WxCpUser; | |||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.auth.AuthScope; | import org.apache.http.auth.AuthScope; | ||||
import org.apache.http.auth.UsernamePasswordCredentials; | import org.apache.http.auth.UsernamePasswordCredentials; | ||||
@@ -33,20 +35,13 @@ import org.apache.http.impl.client.BasicResponseHandler; | |||||
import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||
import org.apache.http.impl.client.HttpClients; | import org.apache.http.impl.client.HttpClients; | ||||
import me.chanjar.weixin.cp.bean.WxCpDepart; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | |||||
import me.chanjar.weixin.cp.bean.WxCpUser; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | |||||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||||
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.RequestExecutor; | |||||
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||||
import com.google.gson.JsonElement; | |||||
import com.google.gson.internal.Streams; | |||||
import com.google.gson.reflect.TypeToken; | |||||
import com.google.gson.stream.JsonReader; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.io.StringReader; | |||||
import java.util.List; | |||||
import java.util.UUID; | |||||
import java.util.concurrent.atomic.AtomicBoolean; | |||||
public class WxCpServiceImpl implements WxCpService { | public class WxCpServiceImpl implements WxCpService { | ||||
@@ -8,17 +8,12 @@ | |||||
*/ | */ | ||||
package me.chanjar.weixin.cp.util.json; | package me.chanjar.weixin.cp.util.json; | ||||
import java.lang.reflect.Type; | |||||
import com.google.gson.*; | |||||
import me.chanjar.weixin.common.api.WxConsts; | import me.chanjar.weixin.common.api.WxConsts; | ||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.cp.bean.WxCpMessage; | import me.chanjar.weixin.cp.bean.WxCpMessage; | ||||
import com.google.gson.JsonArray; | |||||
import com.google.gson.JsonElement; | |||||
import com.google.gson.JsonObject; | |||||
import com.google.gson.JsonSerializationContext; | |||||
import com.google.gson.JsonSerializer; | |||||
import org.apache.commons.lang3.StringUtils; | |||||
import java.lang.reflect.Type; | |||||
/** | /** | ||||
* | * | ||||
@@ -1,6 +1,6 @@ | |||||
package me.chanjar.weixin.cp.api; | package me.chanjar.weixin.cp.api; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import org.testng.Assert; | import org.testng.Assert; | ||||
import org.testng.annotations.Guice; | import org.testng.annotations.Guice; | ||||
import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
@@ -47,7 +47,7 @@ public class WxCpMessageRouterTest { | |||||
@Test(dataProvider="messages-1") | @Test(dataProvider="messages-1") | ||||
public void testSync(WxCpXmlMessage message, String expected) { | public void testSync(WxCpXmlMessage message, String expected) { | ||||
StringBuffer sb = new StringBuffer(); | StringBuffer sb = new StringBuffer(); | ||||
WxCpMessageRouter router = new WxCpMessageRouter(); | |||||
WxCpMessageRouter router = new WxCpMessageRouter(null); | |||||
prepare(false, sb, router); | prepare(false, sb, router); | ||||
router.route(message); | router.route(message); | ||||
Assert.assertEquals(sb.toString(), expected); | Assert.assertEquals(sb.toString(), expected); | ||||
@@ -56,7 +56,7 @@ public class WxCpMessageRouterTest { | |||||
@Test(dataProvider="messages-1") | @Test(dataProvider="messages-1") | ||||
public void testAsync(WxCpXmlMessage message, String expected) throws InterruptedException { | public void testAsync(WxCpXmlMessage message, String expected) throws InterruptedException { | ||||
StringBuffer sb = new StringBuffer(); | StringBuffer sb = new StringBuffer(); | ||||
WxCpMessageRouter router = new WxCpMessageRouter(); | |||||
WxCpMessageRouter router = new WxCpMessageRouter(null); | |||||
prepare(true, sb, router); | prepare(true, sb, router); | ||||
router.route(message); | router.route(message); | ||||
Thread.sleep(500l); | Thread.sleep(500l); | ||||
@@ -64,10 +64,10 @@ public class WxCpMessageRouterTest { | |||||
} | } | ||||
public void testConcurrency() throws InterruptedException { | public void testConcurrency() throws InterruptedException { | ||||
final WxCpMessageRouter router = new WxCpMessageRouter(); | |||||
final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||||
router.rule().handler(new WxCpMessageHandler() { | router.rule().handler(new WxCpMessageHandler() { | ||||
@Override | @Override | ||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService) { | |||||
return null; | return null; | ||||
} | } | ||||
}).end(); | }).end(); | ||||
@@ -149,7 +149,7 @@ public class WxCpMessageRouterTest { | |||||
} | } | ||||
@Override | @Override | ||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService) { | |||||
sb.append(this.echoStr).append(','); | sb.append(this.echoStr).append(','); | ||||
return null; | return null; | ||||
} | } | ||||
@@ -1,11 +1,11 @@ | |||||
package me.chanjar.weixin.cp.demo; | package me.chanjar.weixin.cp.demo; | ||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.cp.api.*; | import me.chanjar.weixin.cp.api.*; | ||||
import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | ||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | ||||
import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; | import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; | ||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import javax.servlet.ServletException; | import javax.servlet.ServletException; | ||||
import javax.servlet.http.HttpServlet; | import javax.servlet.http.HttpServlet; | ||||
@@ -21,8 +21,8 @@ import java.util.Map; | |||||
*/ | */ | ||||
public class WxCpDemoServlet extends HttpServlet { | public class WxCpDemoServlet extends HttpServlet { | ||||
protected WxCpService wxCpService; | |||||
protected WxCpConfigStorage wxCpConfigStorage; | protected WxCpConfigStorage wxCpConfigStorage; | ||||
protected WxCpService wxCpService; | |||||
protected WxCpMessageRouter wxCpMessageRouter; | protected WxCpMessageRouter wxCpMessageRouter; | ||||
@Override public void init() throws ServletException { | @Override public void init() throws ServletException { | ||||
@@ -37,7 +37,7 @@ public class WxCpDemoServlet extends HttpServlet { | |||||
wxCpService.setWxCpConfigStorage(config); | wxCpService.setWxCpConfigStorage(config); | ||||
WxCpMessageHandler handler = new WxCpMessageHandler() { | WxCpMessageHandler handler = new WxCpMessageHandler() { | ||||
@Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context) { | |||||
@Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService) { | |||||
WxCpXmlOutTextMessage m = WxCpXmlOutMessage | WxCpXmlOutTextMessage m = WxCpXmlOutMessage | ||||
.TEXT() | .TEXT() | ||||
.content("测试加密消息") | .content("测试加密消息") | ||||
@@ -48,7 +48,7 @@ public class WxCpDemoServlet extends HttpServlet { | |||||
} | } | ||||
}; | }; | ||||
wxCpMessageRouter = new WxCpMessageRouter(); | |||||
wxCpMessageRouter = new WxCpMessageRouter(wxCpService); | |||||
wxCpMessageRouter | wxCpMessageRouter | ||||
.rule() | .rule() | ||||
.async(false) | .async(false) | ||||
@@ -64,13 +64,14 @@ public class WxCpDemoServlet extends HttpServlet { | |||||
@Override protected void service(HttpServletRequest request, HttpServletResponse response) | @Override protected void service(HttpServletRequest request, HttpServletResponse response) | ||||
throws ServletException, IOException { | throws ServletException, IOException { | ||||
response.setContentType("text/html;charset=utf-8"); | |||||
response.setStatus(HttpServletResponse.SC_OK); | |||||
String msgSignature = request.getParameter("msg_signature"); | String msgSignature = request.getParameter("msg_signature"); | ||||
String nonce = request.getParameter("nonce"); | String nonce = request.getParameter("nonce"); | ||||
String timestamp = request.getParameter("timestamp"); | String timestamp = request.getParameter("timestamp"); | ||||
String echostr = request.getParameter("echostr"); | String echostr = request.getParameter("echostr"); | ||||
response.setContentType("text/html;charset=utf-8"); | |||||
response.setStatus(HttpServletResponse.SC_OK); | |||||
if (StringUtils.isNotBlank(echostr)) { | if (StringUtils.isNotBlank(echostr)) { | ||||
if (!wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) { | if (!wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) { | ||||
// 消息签名不正确,说明不是公众平台发过来的消息 | // 消息签名不正确,说明不是公众平台发过来的消息 | ||||
@@ -84,11 +85,8 @@ public class WxCpDemoServlet extends HttpServlet { | |||||
return; | return; | ||||
} | } | ||||
WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(request.getInputStream(), wxCpConfigStorage, timestamp, nonce, msgSignature); | WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(request.getInputStream(), wxCpConfigStorage, timestamp, nonce, msgSignature); | ||||
WxCpXmlOutMessage outMessage = wxCpMessageRouter.route(inMessage); | WxCpXmlOutMessage outMessage = wxCpMessageRouter.route(inMessage); | ||||
if (outMessage != null) { | if (outMessage != null) { | ||||
response.getWriter().write(outMessage.toEncryptedXml(wxCpConfigStorage)); | response.getWriter().write(outMessage.toEncryptedXml(wxCpConfigStorage)); | ||||
} | } | ||||
@@ -16,8 +16,9 @@ public interface WxMpMessageHandler { | |||||
* | * | ||||
* @param wxMessage | * @param wxMessage | ||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | ||||
* @param wxMpService | |||||
* @return xml格式的消息,如果在异步规则里处理的话,可以返回null | * @return xml格式的消息,如果在异步规则里处理的话,可以返回null | ||||
*/ | */ | ||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context); | |||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService); | |||||
} | } |
@@ -15,8 +15,9 @@ public interface WxMpMessageInterceptor { | |||||
* 拦截微信消息 | * 拦截微信消息 | ||||
* @param wxMessage | * @param wxMessage | ||||
* @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 | ||||
* @param wxMpService | |||||
* @return true代表OK,false代表不OK | * @return true代表OK,false代表不OK | ||||
*/ | */ | ||||
public boolean intercept(WxMpXmlMessage wxMessage, Map<String, Object> context); | |||||
public boolean intercept(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService); | |||||
} | } |
@@ -43,14 +43,20 @@ public class WxMpMessageRouter { | |||||
private final List<Rule> rules = new ArrayList<Rule>(); | private final List<Rule> rules = new ArrayList<Rule>(); | ||||
private final ExecutorService es = Executors.newCachedThreadPool(); | |||||
private final ExecutorService executorService = Executors.newCachedThreadPool(); | |||||
private final WxMpService wxMpService; | |||||
public WxMpMessageRouter(WxMpService wxMpService) { | |||||
this.wxMpService = wxMpService; | |||||
} | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | * @return | ||||
*/ | */ | ||||
public Rule rule() { | public Rule rule() { | ||||
return new Rule(this); | |||||
return new Rule(this, wxMpService); | |||||
} | } | ||||
/** | /** | ||||
@@ -73,7 +79,7 @@ public class WxMpMessageRouter { | |||||
if (matchRules.get(0).async) { | if (matchRules.get(0).async) { | ||||
// 只要第一个是异步的,那就异步执行 | // 只要第一个是异步的,那就异步执行 | ||||
// 在另一个线程里执行 | // 在另一个线程里执行 | ||||
es.submit(new Runnable() { | |||||
executorService.submit(new Runnable() { | |||||
public void run() { | public void run() { | ||||
for (final Rule rule : matchRules) { | for (final Rule rule : matchRules) { | ||||
rule.service(wxMessage); | rule.service(wxMessage); | ||||
@@ -101,6 +107,8 @@ public class WxMpMessageRouter { | |||||
private final WxMpMessageRouter routerBuilder; | private final WxMpMessageRouter routerBuilder; | ||||
private final WxMpService wxMpService; | |||||
private boolean async = true; | private boolean async = true; | ||||
private String msgType; | private String msgType; | ||||
@@ -119,8 +127,9 @@ public class WxMpMessageRouter { | |||||
private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>(); | private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>(); | ||||
protected Rule(WxMpMessageRouter routerBuilder) { | |||||
protected Rule(WxMpMessageRouter routerBuilder, WxMpService wxMpService) { | |||||
this.routerBuilder = routerBuilder; | this.routerBuilder = routerBuilder; | ||||
this.wxMpService = wxMpService; | |||||
} | } | ||||
/** | /** | ||||
@@ -274,7 +283,7 @@ public class WxMpMessageRouter { | |||||
Map<String, Object> context = new HashMap<String, Object>(); | Map<String, Object> context = new HashMap<String, Object>(); | ||||
// 如果拦截器不通过 | // 如果拦截器不通过 | ||||
for (WxMpMessageInterceptor interceptor : this.interceptors) { | for (WxMpMessageInterceptor interceptor : this.interceptors) { | ||||
if (!interceptor.intercept(wxMessage, context)) { | |||||
if (!interceptor.intercept(wxMessage, context, wxMpService)) { | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@@ -283,7 +292,7 @@ public class WxMpMessageRouter { | |||||
WxMpXmlOutMessage res = null; | WxMpXmlOutMessage res = null; | ||||
for (WxMpMessageHandler handler : this.handlers) { | for (WxMpMessageHandler handler : this.handlers) { | ||||
// 返回最后handler的结果 | // 返回最后handler的结果 | ||||
res = handler.handle(wxMessage, context); | |||||
res = handler.handle(wxMessage, context, wxMpService); | |||||
} | } | ||||
return res; | return res; | ||||
} | } | ||||
@@ -10,6 +10,7 @@ import me.chanjar.weixin.common.bean.WxMenu; | |||||
import me.chanjar.weixin.common.bean.result.WxError; | import me.chanjar.weixin.common.bean.result.WxError; | ||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | ||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
import me.chanjar.weixin.common.util.fs.FileUtils; | import me.chanjar.weixin.common.util.fs.FileUtils; | ||||
import me.chanjar.weixin.common.util.http.*; | import me.chanjar.weixin.common.util.http.*; | ||||
@@ -18,7 +19,6 @@ import me.chanjar.weixin.mp.bean.*; | |||||
import me.chanjar.weixin.mp.bean.result.*; | import me.chanjar.weixin.mp.bean.result.*; | ||||
import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; | import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor; | ||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.auth.AuthScope; | import org.apache.http.auth.AuthScope; | ||||
import org.apache.http.auth.UsernamePasswordCredentials; | import org.apache.http.auth.UsernamePasswordCredentials; | ||||
@@ -27,7 +27,6 @@ import org.apache.http.client.CredentialsProvider; | |||||
import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
import org.apache.http.client.methods.CloseableHttpResponse; | import org.apache.http.client.methods.CloseableHttpResponse; | ||||
import org.apache.http.client.methods.HttpGet; | import org.apache.http.client.methods.HttpGet; | ||||
import org.apache.http.client.methods.HttpPost; | |||||
import org.apache.http.impl.client.BasicCredentialsProvider; | import org.apache.http.impl.client.BasicCredentialsProvider; | ||||
import org.apache.http.impl.client.BasicResponseHandler; | import org.apache.http.impl.client.BasicResponseHandler; | ||||
import org.apache.http.impl.client.CloseableHttpClient; | import org.apache.http.impl.client.CloseableHttpClient; | ||||
@@ -38,7 +37,6 @@ import java.io.IOException; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.StringReader; | import java.io.StringReader; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.UUID; | import java.util.UUID; | ||||
import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||
@@ -1,6 +1,6 @@ | |||||
package me.chanjar.weixin.mp.api; | package me.chanjar.weixin.mp.api; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import org.testng.Assert; | import org.testng.Assert; | ||||
import org.testng.annotations.Guice; | import org.testng.annotations.Guice; | ||||
import org.testng.annotations.Test; | import org.testng.annotations.Test; | ||||
@@ -47,7 +47,7 @@ public class WxMpMessageRouterTest { | |||||
@Test(dataProvider="messages-1") | @Test(dataProvider="messages-1") | ||||
public void testSync(WxMpXmlMessage message, String expected) { | public void testSync(WxMpXmlMessage message, String expected) { | ||||
StringBuffer sb = new StringBuffer(); | StringBuffer sb = new StringBuffer(); | ||||
WxMpMessageRouter router = new WxMpMessageRouter(); | |||||
WxMpMessageRouter router = new WxMpMessageRouter(null); | |||||
prepare(false, sb, router); | prepare(false, sb, router); | ||||
router.route(message); | router.route(message); | ||||
Assert.assertEquals(sb.toString(), expected); | Assert.assertEquals(sb.toString(), expected); | ||||
@@ -56,7 +56,7 @@ public class WxMpMessageRouterTest { | |||||
@Test(dataProvider="messages-1") | @Test(dataProvider="messages-1") | ||||
public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException { | public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException { | ||||
StringBuffer sb = new StringBuffer(); | StringBuffer sb = new StringBuffer(); | ||||
WxMpMessageRouter router = new WxMpMessageRouter(); | |||||
WxMpMessageRouter router = new WxMpMessageRouter(null); | |||||
prepare(true, sb, router); | prepare(true, sb, router); | ||||
router.route(message); | router.route(message); | ||||
Thread.sleep(500l); | Thread.sleep(500l); | ||||
@@ -64,10 +64,10 @@ public class WxMpMessageRouterTest { | |||||
} | } | ||||
public void testConcurrency() throws InterruptedException { | public void testConcurrency() throws InterruptedException { | ||||
final WxMpMessageRouter router = new WxMpMessageRouter(); | |||||
final WxMpMessageRouter router = new WxMpMessageRouter(null); | |||||
router.rule().handler(new WxMpMessageHandler() { | router.rule().handler(new WxMpMessageHandler() { | ||||
@Override | @Override | ||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService) { | |||||
return null; | return null; | ||||
} | } | ||||
}).end(); | }).end(); | ||||
@@ -149,7 +149,7 @@ public class WxMpMessageRouterTest { | |||||
} | } | ||||
@Override | @Override | ||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context) { | |||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService) { | |||||
sb.append(this.echoStr).append(','); | sb.append(this.echoStr).append(','); | ||||
return null; | return null; | ||||
} | } | ||||
@@ -1,10 +1,10 @@ | |||||
package me.chanjar.weixin.mp.demo; | package me.chanjar.weixin.mp.demo; | ||||
import me.chanjar.weixin.common.util.StringUtils; | |||||
import me.chanjar.weixin.mp.api.*; | import me.chanjar.weixin.mp.api.*; | ||||
import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlMessage; | ||||
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; | ||||
import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; | import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; | ||||
import org.apache.commons.lang3.StringUtils; | |||||
import javax.servlet.ServletException; | import javax.servlet.ServletException; | ||||
import javax.servlet.http.HttpServlet; | import javax.servlet.http.HttpServlet; | ||||
@@ -20,8 +20,8 @@ import java.util.Map; | |||||
*/ | */ | ||||
public class WxMpDemoServlet extends HttpServlet { | public class WxMpDemoServlet extends HttpServlet { | ||||
protected WxMpService wxMpService; | |||||
protected WxMpConfigStorage wxMpConfigStorage; | protected WxMpConfigStorage wxMpConfigStorage; | ||||
protected WxMpService wxMpService; | |||||
protected WxMpMessageRouter wxMpMessageRouter; | protected WxMpMessageRouter wxMpMessageRouter; | ||||
@Override public void init() throws ServletException { | @Override public void init() throws ServletException { | ||||
@@ -36,7 +36,7 @@ public class WxMpDemoServlet extends HttpServlet { | |||||
wxMpService.setWxMpConfigStorage(config); | wxMpService.setWxMpConfigStorage(config); | ||||
WxMpMessageHandler handler = new WxMpMessageHandler() { | WxMpMessageHandler handler = new WxMpMessageHandler() { | ||||
@Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context) { | |||||
@Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService) { | |||||
WxMpXmlOutTextMessage m | WxMpXmlOutTextMessage m | ||||
= WxMpXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) | = WxMpXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) | ||||
.toUser(wxMessage.getFromUserName()).build(); | .toUser(wxMessage.getFromUserName()).build(); | ||||
@@ -44,7 +44,7 @@ public class WxMpDemoServlet extends HttpServlet { | |||||
} | } | ||||
}; | }; | ||||
wxMpMessageRouter = new WxMpMessageRouter(); | |||||
wxMpMessageRouter = new WxMpMessageRouter(wxMpService); | |||||
wxMpMessageRouter | wxMpMessageRouter | ||||
.rule() | .rule() | ||||
.async(false) | .async(false) | ||||
@@ -60,13 +60,13 @@ public class WxMpDemoServlet extends HttpServlet { | |||||
@Override protected void service(HttpServletRequest request, HttpServletResponse response) | @Override protected void service(HttpServletRequest request, HttpServletResponse response) | ||||
throws ServletException, IOException { | throws ServletException, IOException { | ||||
response.setContentType("text/html;charset=utf-8"); | |||||
response.setStatus(HttpServletResponse.SC_OK); | |||||
String signature = request.getParameter("signature"); | String signature = request.getParameter("signature"); | ||||
String nonce = request.getParameter("nonce"); | String nonce = request.getParameter("nonce"); | ||||
String timestamp = request.getParameter("timestamp"); | String timestamp = request.getParameter("timestamp"); | ||||
response.setContentType("text/html;charset=utf-8"); | |||||
response.setStatus(HttpServletResponse.SC_OK); | |||||
if (!wxMpService.checkSignature(timestamp, nonce, signature)) { | if (!wxMpService.checkSignature(timestamp, nonce, signature)) { | ||||
// 消息签名不正确,说明不是公众平台发过来的消息 | // 消息签名不正确,说明不是公众平台发过来的消息 | ||||
response.getWriter().println("非法请求"); | response.getWriter().println("非法请求"); | ||||
@@ -84,31 +84,25 @@ public class WxMpDemoServlet extends HttpServlet { | |||||
"raw" : | "raw" : | ||||
request.getParameter("encrypt_type"); | request.getParameter("encrypt_type"); | ||||
WxMpXmlMessage inMessage = null; | |||||
if ("raw".equals(encryptType)) { | if ("raw".equals(encryptType)) { | ||||
// 明文传输的消息 | // 明文传输的消息 | ||||
inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); | |||||
} else if ("aes".equals(encryptType)) { | |||||
// 是aes加密的消息 | |||||
String msgSignature = request.getParameter("msg_signature"); | |||||
inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), wxMpConfigStorage, timestamp, nonce, msgSignature); | |||||
} else { | |||||
response.getWriter().println("不可识别的加密类型"); | |||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); | |||||
WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); | |||||
response.getWriter().write(outMessage.toXml()); | |||||
return; | return; | ||||
} | } | ||||
WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); | |||||
if (outMessage != null) { | |||||
if ("raw".equals(encryptType)) { | |||||
response.getWriter().write(outMessage.toXml()); | |||||
} else if ("aes".equals(encryptType)) { | |||||
response.getWriter().write(outMessage.toEncryptedXml(wxMpConfigStorage)); | |||||
} | |||||
if ("aes".equals(encryptType)) { | |||||
// 是aes加密的消息 | |||||
String msgSignature = request.getParameter("msg_signature"); | |||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), wxMpConfigStorage, timestamp, nonce, msgSignature); | |||||
WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); | |||||
response.getWriter().write(outMessage.toEncryptedXml(wxMpConfigStorage)); | |||||
return; | return; | ||||
} | } | ||||
response.getWriter().println("不可识别的加密类型"); | |||||
return; | |||||
} | } | ||||
} | } |