diff --git a/README.md b/README.md index 61751e9c..9b435d6b 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ weixin-java-tools me.chanjar weixin-java-mp - 1.0.4 + 1.0.5 ``` @@ -29,7 +29,7 @@ weixin-java-tools me.chanjar weixin-java-cp - 1.0.4 + 1.0.5 ``` diff --git a/pom.xml b/pom.xml index 9ff35595..96267689 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 me.chanjar weixin-java-parent - 1.0.4 + 1.0.5 pom WeiXin Java Tools - Parent 微信公众号、企业号上级POM @@ -70,11 +70,6 @@ gson 2.2.2 - - org.apache.commons - commons-lang3 - 3.1 - commons-codec commons-codec diff --git a/pom.xml.versionsBackup b/pom.xml.versionsBackup new file mode 100644 index 00000000..3e038387 --- /dev/null +++ b/pom.xml.versionsBackup @@ -0,0 +1,229 @@ + + + 4.0.0 + me.chanjar + weixin-java-parent + 1.0.5-SNAPSHOT + pom + WeiXin Java Tools - Parent + 微信公众号、企业号上级POM + https://github.com/chanjarster/weixin-java-tools + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + Daniel Qian + chanjarster@gmail.com + + + + + scm:git:https://github.com/chanjarster/weixin-java-tools.git + scm:git:git@github.com:chanjarster/weixin-java-tools.git + https://github.com/chanjarster/weixin-java-tools + + + + weixin-java-common + weixin-java-cp + weixin-java-mp + + + + UTF-8 + true + true + 4.3.5 + + + + + org.apache.httpcomponents + fluent-hc + ${httpclient.version} + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + + + javax.xml.bind + jaxb-api + 2.2.7 + + + com.sun.xml.bind + jaxb-impl + 2.2.7 + + + com.google.code.gson + gson + 2.2.2 + + + commons-codec + commons-codec + 1.9 + + + commons-io + commons-io + 2.4 + + + + + + + junit + junit + 4.11 + test + + + com.google.inject + guice + 3.0 + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + UTF-8 + zh_CN + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.17 + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.3 + true + + ossrh + https://oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-release-plugin + 2.5 + + true + false + release + deploy + + + + + + + diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index 1d9c3ebc..a1365add 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.0.4 + 1.0.5 weixin-java-common diff --git a/weixin-java-common/pom.xml.versionsBackup b/weixin-java-common/pom.xml.versionsBackup new file mode 100644 index 00000000..47e4ec22 --- /dev/null +++ b/weixin-java-common/pom.xml.versionsBackup @@ -0,0 +1,68 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.5-SNAPSHOT + + + weixin-java-common + WeiXin Java Tools - Common + 微信公众号、企业号Java SDK Common + + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java index 8a843e94..18260295 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java @@ -128,4 +128,12 @@ public class WxConsts { /** 弹出地理位置选择器 */ public static final String LOCATION_SELECT = "location_select"; + /////////////////////// + // oauth2网页授权的scope + /////////////////////// + /** 不弹出授权页面,直接跳转,只能获取用户openid */ + public static final String OAUTH2_SCOPE_BASE = "snsapi_base"; + /** 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息 */ + public static final String OAUTH2_SCOPE_USER_INFO = "snsapi_userinfo"; + } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/StringUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/StringUtils.java new file mode 100644 index 00000000..4234a8c8 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/StringUtils.java @@ -0,0 +1,100 @@ +package me.chanjar.weixin.common.util; + +/** + * copy from apache-commons-lang3 + */ +public class StringUtils { + + /** + *

Checks if a CharSequence is whitespace, empty ("") or null.

+ * + *
+   * StringUtils.isBlank(null)      = true
+   * StringUtils.isBlank("")        = true
+   * StringUtils.isBlank(" ")       = true
+   * StringUtils.isBlank("bob")     = false
+   * StringUtils.isBlank("  bob  ") = false
+   * 
+ * + * @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; + } + + /** + *

Checks if a CharSequence is not empty (""), not null and not whitespace only.

+ * + *
+   * StringUtils.isNotBlank(null)      = false
+   * StringUtils.isNotBlank("")        = false
+   * StringUtils.isNotBlank(" ")       = false
+   * StringUtils.isNotBlank("bob")     = true
+   * StringUtils.isNotBlank("  bob  ") = true
+   * 
+ * + * @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); + } + + /** + *

Checks if a CharSequence is empty ("") or null.

+ * + *
+   * StringUtils.isEmpty(null)      = true
+   * StringUtils.isEmpty("")        = true
+   * StringUtils.isEmpty(" ")       = false
+   * StringUtils.isEmpty("bob")     = false
+   * StringUtils.isEmpty("  bob  ") = false
+   * 
+ * + *

NOTE: This method changed in Lang version 2.0. + * It no longer trims the CharSequence. + * That functionality is available in isBlank().

+ * + * @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; + } + + /** + *

Checks if a CharSequence is not empty ("") and not null.

+ * + *
+   * StringUtils.isNotEmpty(null)      = false
+   * StringUtils.isNotEmpty("")        = false
+   * StringUtils.isNotEmpty(" ")       = true
+   * StringUtils.isNotEmpty("bob")     = true
+   * StringUtils.isNotEmpty("  bob  ") = true
+   * 
+ * + * @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); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java index 7fc05d94..dc7f28b4 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaDownloadRequestExecutor.java @@ -1,12 +1,9 @@ package me.chanjar.weixin.common.util.http; 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.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.HttpHost; import org.apache.http.client.ClientProtocolException; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java new file mode 100644 index 00000000..bb671eb1 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/URIUtil.java @@ -0,0 +1,47 @@ +package me.chanjar.weixin.common.util.http; + +import me.chanjar.weixin.common.util.StringUtils; + +import java.io.UnsupportedEncodingException; + +public class URIUtil { + + private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; + + public static String encodeURIComponent(String input) { + if (StringUtils.isEmpty(input)) { + return input; + } + + int l = input.length(); + StringBuilder o = new StringBuilder(l * 3); + try { + for (int i = 0; i < l; i++) { + String e = input.substring(i, i + 1); + if (ALLOWED_CHARS.indexOf(e) == -1) { + byte[] b = e.getBytes("utf-8"); + o.append(getHex(b)); + continue; + } + o.append(e); + } + return o.toString(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return input; + } + + private static String getHex(byte buf[]) { + StringBuilder o = new StringBuilder(buf.length * 3); + for (int i = 0; i < buf.length; i++) { + int n = (int) buf[i] & 0xff; + o.append("%"); + if (n < 0x10) { + o.append("0"); + } + o.append(Long.toString(n, 16).toUpperCase()); + } + return o.toString(); + } +} diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 7f96ee7a..e0f1d49a 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.0.4 + 1.0.5 weixin-java-cp diff --git a/weixin-java-cp/pom.xml.versionsBackup b/weixin-java-cp/pom.xml.versionsBackup new file mode 100644 index 00000000..fe491f91 --- /dev/null +++ b/weixin-java-cp/pom.xml.versionsBackup @@ -0,0 +1,73 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.5-SNAPSHOT + + + weixin-java-cp + WeiXin Java Tools - CP + 微信企业号Java SDK + + + + me.chanjar + weixin-java-common + ${project.version} + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java index 7837a6f4..36c9cfba 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpConfigStorage.java @@ -27,6 +27,8 @@ public interface WxCpConfigStorage { public int getExpiresIn(); + public String getOauth2redirectUri(); + public String getHttp_proxy_host(); public int getHttp_proxy_port(); diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java index 49e5f392..9ff1f187 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpInMemoryConfigStorage.java @@ -18,6 +18,8 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { protected String agentId; protected int expiresIn; + protected String oauth2redirectUri; + protected String http_proxy_host; protected int http_proxy_port; protected String http_proxy_username; @@ -88,6 +90,15 @@ public class WxCpInMemoryConfigStorage implements WxCpConfigStorage { this.agentId = agentId; } + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + public String getHttp_proxy_host() { return http_proxy_host; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java index b82dddeb..861c610d 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageHandler.java @@ -16,8 +16,9 @@ public interface WxCpMessageHandler { * * @param wxMessage * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService * @return xml格式的消息,如果在异步规则里处理的话,可以返回null */ - public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context); + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, WxCpService wxCpService); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java index 7a09dacd..c1e7ee9d 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageInterceptor.java @@ -15,8 +15,9 @@ public interface WxCpMessageInterceptor { * 拦截微信消息 * @param wxMessage * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxCpService * @return true代表OK,false代表不OK */ - public boolean intercept(WxCpXmlMessage wxMessage, Map context); + public boolean intercept(WxCpXmlMessage wxMessage, Map context, WxCpService wxCpService); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java index 333fca9a..5d5828e5 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java @@ -41,16 +41,30 @@ import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; */ public class WxCpMessageRouter { + private static final int DEFAULT_THREAD_POOL_SIZE = 20; + private final List rules = new ArrayList(); - private final ExecutorService es = Executors.newCachedThreadPool(); + private final ExecutorService executorService; + + private final WxCpService wxCpService; + + public WxCpMessageRouter(WxCpService wxCpService) { + this.wxCpService = wxCpService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + } + + public WxCpMessageRouter(WxCpService wxMpService, int threadPoolSize) { + this.wxCpService = wxMpService; + this.executorService = Executors.newFixedThreadPool(threadPoolSize); + } /** * 开始一个新的Route规则 * @return */ public Rule rule() { - return new Rule(this); + return new Rule(this, wxCpService); } /** @@ -73,7 +87,7 @@ public class WxCpMessageRouter { if (matchRules.get(0).async) { // 只要第一个是异步的,那就异步执行 // 在另一个线程里执行 - es.submit(new Runnable() { + executorService.submit(new Runnable() { public void run() { for (final Rule rule : matchRules) { rule.service(wxMessage); @@ -101,8 +115,12 @@ public class WxCpMessageRouter { private final WxCpMessageRouter routerBuilder; + private final WxCpService wxCpService; + private boolean async = true; + private String fromUser; + private String msgType; private String event; @@ -121,8 +139,9 @@ public class WxCpMessageRouter { private List interceptors = new ArrayList(); - protected Rule(WxCpMessageRouter routerBuilder) { + protected Rule(WxCpMessageRouter routerBuilder, WxCpService wxCpService) { this.routerBuilder = routerBuilder; + this.wxCpService = wxCpService; } /** @@ -195,6 +214,16 @@ public class WxCpMessageRouter { return this; } + /** + * 如果fromUser等于某值 + * @param fromUser + * @return + */ + public Rule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + /** * 设置微信消息拦截器 * @param interceptor @@ -265,6 +294,8 @@ public class WxCpMessageRouter { 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())) @@ -288,7 +319,7 @@ public class WxCpMessageRouter { Map context = new HashMap(); // 如果拦截器不通过 for (WxCpMessageInterceptor interceptor : this.interceptors) { - if (!interceptor.intercept(wxMessage, context)) { + if (!interceptor.intercept(wxMessage, context, wxCpService)) { return null; } } @@ -297,7 +328,7 @@ public class WxCpMessageRouter { WxCpXmlOutMessage res = null; for (WxCpMessageHandler handler : this.handlers) { // 返回最后handler的结果 - res = handler.handle(wxMessage, context); + res = handler.handle(wxMessage, context, wxCpService); } return res; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 1355f17a..cc520f90 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -274,6 +274,27 @@ public interface WxCpService { */ public void tagAddUsers(String tagId, List userIds) throws WxErrorException; + /** + *
+   * 构造oauth2授权的url连接
+   * 详情请见: http://qydev.weixin.qq.com/wiki/index.php?title=企业获取code
+   * 
+ * @param state + * @return code + */ + public String oauth2buildAuthorizationUrl(String state); + + /** + *
+   * 用oauth2获取用户信息
+   * http://qydev.weixin.qq.com/wiki/index.php?title=根据code获取成员信息
+   * 因为企业号oauth2.0必须在应用设置里设置通过ICP备案的可信域名,所以无法测试,因此这个方法很可能是坏的。
+   * 
+ * @param code + * @return [userid, deviceid] + */ + public String[] oauth2getUserInfo(String code) throws WxErrorException; + /** * 移除标签成员 * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java index 39b8e3db..c83d4b55 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java @@ -1,25 +1,27 @@ 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.JsonElement; import com.google.gson.JsonObject; 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.WxMenu; +import me.chanjar.weixin.common.bean.result.WxError; 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.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 org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; 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.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 { @@ -321,6 +316,41 @@ public class WxCpServiceImpl implements WxCpService { execute(new SimplePostRequestExecutor(), url, jsonObject.toString()); } + @Override + public String oauth2buildAuthorizationUrl(String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" ; + url += "appid=" + wxCpConfigStorage.getCorpId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(wxCpConfigStorage.getOauth2redirectUri()); + url += "&response_type=code"; + url += "&scope=snsapi_base"; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public String[] oauth2getUserInfo(String code) throws WxErrorException { + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?"; + url += "access_token=" + wxCpConfigStorage.getAccessToken(); + url += "&code=" + code; + url += "agendid=" + wxCpConfigStorage.getAgentId(); + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), httpProxy, url, null); + JsonElement je = Streams.parse(new JsonReader(new StringReader(responseText))); + JsonObject jo = je.getAsJsonObject(); + return new String[] {GsonHelper.getString(jo, "UserId"), GsonHelper.getString(jo, "DeviceId")}; + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String get(String url, String queryParam) throws WxErrorException { return execute(new SimpleGetRequestExecutor(), url, queryParam); } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java similarity index 95% rename from weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java rename to weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java index 63c01fbf..76f28e2e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMewsMessage.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessage.java @@ -10,7 +10,7 @@ import java.util.List; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxCpXmlOutMewsMessage extends WxCpXmlOutMessage { +public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage { @XmlElement(name = "ArticleCount") protected int articleCount; @@ -19,7 +19,7 @@ public class WxCpXmlOutMewsMessage extends WxCpXmlOutMessage { @XmlElement(name = "item") protected final List articles = new ArrayList(); - public WxCpXmlOutMewsMessage() { + public WxCpXmlOutNewsMessage() { this.msgType = WxConsts.XML_MSG_NEWS; } diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java index 1785f714..5f0fa614 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/outxmlbuilder/NewsBuilder.java @@ -3,14 +3,14 @@ package me.chanjar.weixin.cp.bean.outxmlbuilder; import java.util.ArrayList; import java.util.List; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMewsMessage; -import me.chanjar.weixin.cp.bean.WxCpXmlOutMewsMessage.Item; +import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutNewsMessage.Item; /** * 图文消息builder * @author Daniel Qian */ -public final class NewsBuilder extends BaseBuilder { +public final class NewsBuilder extends BaseBuilder { protected final List articles = new ArrayList(); @@ -19,8 +19,8 @@ public final class NewsBuilder extends BaseBuilder { messageJson.addProperty("msgtype", message.getMsgType()); if (StringUtils.isNotBlank(message.getToParty())) { - messageJson.addProperty("toparty", message.getToUser()); + messageJson.addProperty("toparty", message.getToParty()); } if (StringUtils.isNotBlank(message.getToTag())) { messageJson.addProperty("totag", message.getToUser()); @@ -75,6 +70,7 @@ public class WxCpMessageGsonAdapter implements JsonSerializer { } if (WxConsts.CUSTOM_MSG_NEWS.equals(message.getMsgType())) { + JsonObject newsJsonObject = new JsonObject(); JsonArray articleJsonArray = new JsonArray(); for (WxCpMessage.WxArticle article : message.getArticles()) { JsonObject articleJson = new JsonObject(); @@ -84,7 +80,8 @@ public class WxCpMessageGsonAdapter implements JsonSerializer { articleJson.addProperty("picurl", article.getPicUrl()); articleJsonArray.add(articleJson); } - messageJson.add("articles", articleJsonArray); + newsJsonObject.add("articles", articleJsonArray); + messageJson.add("news", newsJsonObject); } return messageJson; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java index 39914f44..21bb7a77 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XmlTransformer.java @@ -59,6 +59,7 @@ public class XmlTransformer { Marshaller m = JAXB_CONTEXT.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.setProperty(CharacterEscapeHandler.class.getName(), CHAR_ESCAPE_HANDLER); + m.setProperty(Marshaller.JAXB_FRAGMENT, true); m.marshal(object, writer); } @@ -79,7 +80,7 @@ public class XmlTransformer { return JAXBContext.newInstance( WxCpXmlOutMessage.class, WxCpXmlOutImageMessage.class, - WxCpXmlOutMewsMessage.class, + WxCpXmlOutNewsMessage.class, WxCpXmlOutTextMessage.class, WxCpXmlOutVideoMessage.class, WxCpXmlOutVoiceMessage.class, diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java index 07d7d0a6..032165eb 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpBaseAPITest.java @@ -1,6 +1,6 @@ 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.annotations.Guice; import org.testng.annotations.Test; diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java index 59962c6f..6b178f9b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMessageRouterTest.java @@ -47,7 +47,7 @@ public class WxCpMessageRouterTest { @Test(dataProvider="messages-1") public void testSync(WxCpXmlMessage message, String expected) { StringBuffer sb = new StringBuffer(); - WxCpMessageRouter router = new WxCpMessageRouter(); + WxCpMessageRouter router = new WxCpMessageRouter(null); prepare(false, sb, router); router.route(message); Assert.assertEquals(sb.toString(), expected); @@ -56,7 +56,7 @@ public class WxCpMessageRouterTest { @Test(dataProvider="messages-1") public void testAsync(WxCpXmlMessage message, String expected) throws InterruptedException { StringBuffer sb = new StringBuffer(); - WxCpMessageRouter router = new WxCpMessageRouter(); + WxCpMessageRouter router = new WxCpMessageRouter(null); prepare(true, sb, router); router.route(message); Thread.sleep(500l); @@ -64,10 +64,10 @@ public class WxCpMessageRouterTest { } public void testConcurrency() throws InterruptedException { - final WxCpMessageRouter router = new WxCpMessageRouter(); + final WxCpMessageRouter router = new WxCpMessageRouter(null); router.rule().handler(new WxCpMessageHandler() { @Override - public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, WxCpService wxCpService) { return null; } }).end(); @@ -149,7 +149,7 @@ public class WxCpMessageRouterTest { } @Override - public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, WxCpService wxCpService) { sb.append(this.echoStr).append(','); return null; } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java index c5b9e5b9..72169d2b 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpMessageTest.java @@ -83,8 +83,8 @@ public class WxCpMessageTest { article2.setTitle("Happy Day"); reply.getArticles().add(article2); - - Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); } public void testNewsBuild() { @@ -101,8 +101,8 @@ public class WxCpMessageTest { article2.setTitle("Happy Day"); WxCpMessage reply = WxCpMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); - - Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java index 9f97e4b8..aef4ec45 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutImageMessageTest.java @@ -13,8 +13,7 @@ public class WxCpXmlOutImageMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxCpXmlOutImageMessageTest { public void testBuild() { WxCpXmlOutImageMessage m = WxCpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java index f72c76b3..7848bfcd 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutNewsMessageTest.java @@ -7,20 +7,19 @@ import org.testng.annotations.Test; public class WxCpXmlOutNewsMessageTest { public void test() { - WxCpXmlOutMewsMessage m = new WxCpXmlOutMewsMessage(); + WxCpXmlOutNewsMessage m = new WxCpXmlOutNewsMessage(); m.setCreateTime(1122l); m.setFromUserName("fromUser"); m.setToUserName("toUser"); - WxCpXmlOutMewsMessage.Item item = new WxCpXmlOutMewsMessage.Item(); + WxCpXmlOutNewsMessage.Item item = new WxCpXmlOutNewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); item.setUrl("url"); m.addArticle(item); m.addArticle(item); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -46,20 +45,19 @@ public class WxCpXmlOutNewsMessageTest { } public void testBuild() { - WxCpXmlOutMewsMessage.Item item = new WxCpXmlOutMewsMessage.Item(); + WxCpXmlOutNewsMessage.Item item = new WxCpXmlOutNewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); item.setUrl("url"); - WxCpXmlOutMewsMessage m = WxCpXmlOutMessage.NEWS() + WxCpXmlOutNewsMessage m = WxCpXmlOutMessage.NEWS() .fromUser("fromUser") .toUser("toUser") .addArticle(item) .addArticle(item) .build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java index 4dce4f16..75343cb4 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutTextMessageTest.java @@ -13,8 +13,7 @@ public class WxCpXmlOutTextMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxCpXmlOutTextMessageTest { public void testBuild() { WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java index b5ba2456..61e1cbfb 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVideoMessageTest.java @@ -15,8 +15,7 @@ public class WxCpXmlOutVideoMessageTest { m.setFromUserName("fromUser"); m.setToUserName("toUser"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -39,8 +38,7 @@ public class WxCpXmlOutVideoMessageTest { .title("title") .description("ddfff") .build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java index fa73a329..897f5c37 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/WxCpXmlOutVoiceMessageTest.java @@ -13,8 +13,7 @@ public class WxCpXmlOutVoiceMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxCpXmlOutVoiceMessageTest { public void testBuild() { WxCpXmlOutVoiceMessage m = WxCpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java index b56d1780..2a248f98 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServer.java @@ -1,20 +1,94 @@ package me.chanjar.weixin.cp.demo; +import me.chanjar.weixin.cp.api.*; +import me.chanjar.weixin.cp.bean.WxCpXmlMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; +import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +import javax.xml.bind.JAXBException; +import java.io.InputStream; +import java.util.Map; -/** - * @author Daniel Qian - */ public class WxCpDemoServer { + + private static WxCpConfigStorage wxCpConfigStorage; + private static WxCpService wxCpService; + private static WxCpMessageRouter wxCpMessageRouter; + public static void main(String[] args) throws Exception { + initWeixin(); + Server server = new Server(8080); - ServletHandler handler = new ServletHandler(); - server.setHandler(handler); + ServletHandler servletHandler = new ServletHandler(); + server.setHandler(servletHandler); + + ServletHolder endpointServletHolder = new ServletHolder(new WxCpEndpointServlet(wxCpConfigStorage, wxCpService, wxCpMessageRouter)); + servletHandler.addServletWithMapping(endpointServletHolder, "/*"); + + ServletHolder oauthServletHolder = new ServletHolder(new WxCpOAuth2Servlet(wxCpService)); + servletHandler.addServletWithMapping(oauthServletHolder, "/oauth2/*"); - handler.addServletWithMapping(WxCpDemoServlet.class, "/*"); server.start(); server.join(); } + + private static void initWeixin() { + try { + InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); + WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(is1); + + wxCpConfigStorage = config; + wxCpService = new WxCpServiceImpl(); + wxCpService.setWxCpConfigStorage(config); + + WxCpMessageHandler handler = new WxCpMessageHandler() { + @Override + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, + WxCpService wxCpService) { + WxCpXmlOutTextMessage m = WxCpXmlOutMessage + .TEXT() + .content("测试加密消息") + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()) + .build(); + return m; + } + }; + + WxCpMessageHandler oauth2handler = new WxCpMessageHandler() { + @Override + public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context, + WxCpService wxCpService) { + String href = "测试oauth2"; + return WxCpXmlOutMessage + .TEXT() + .content(href) + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); + } + }; + + wxCpMessageRouter = new WxCpMessageRouter(wxCpService); + wxCpMessageRouter + .rule() + .async(false) + .content("哈哈") // 拦截内容为“哈哈”的消息 + .handler(handler) + .end() + .rule() + .async(false) + .content("oauth") + .handler(oauth2handler) + .end() + ; + + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java similarity index 55% rename from weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java rename to weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java index b84d786f..320cc540 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpDemoServlet.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpEndpointServlet.java @@ -1,11 +1,11 @@ package me.chanjar.weixin.cp.demo; +import me.chanjar.weixin.common.util.StringUtils; import me.chanjar.weixin.cp.api.*; import me.chanjar.weixin.cp.bean.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; -import org.apache.commons.lang3.StringUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -19,58 +19,31 @@ import java.util.Map; /** * @author Daniel Qian */ -public class WxCpDemoServlet extends HttpServlet { +public class WxCpEndpointServlet extends HttpServlet { - protected WxCpService wxCpService; protected WxCpConfigStorage wxCpConfigStorage; + protected WxCpService wxCpService; protected WxCpMessageRouter wxCpMessageRouter; - @Override public void init() throws ServletException { - // - super.init(); - try { - InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); - WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(is1); - - wxCpConfigStorage = config; - wxCpService = new WxCpServiceImpl(); - wxCpService.setWxCpConfigStorage(config); - - WxCpMessageHandler handler = new WxCpMessageHandler() { - @Override public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map context) { - WxCpXmlOutTextMessage m = WxCpXmlOutMessage - .TEXT() - .content("测试加密消息") - .fromUser(wxMessage.getToUserName()) - .toUser(wxMessage.getFromUserName()) - .build(); - return m; - } - }; - - wxCpMessageRouter = new WxCpMessageRouter(); - wxCpMessageRouter - .rule() - .async(false) - .content("哈哈") // 拦截内容为“哈哈”的消息 - .handler(handler) - .end(); - - } catch (JAXBException e) { - throw new RuntimeException(e); - } + public WxCpEndpointServlet(WxCpConfigStorage wxCpConfigStorage, WxCpService wxCpService, + WxCpMessageRouter wxCpMessageRouter) { + this.wxCpConfigStorage = wxCpConfigStorage; + this.wxCpService = wxCpService; + this.wxCpMessageRouter = wxCpMessageRouter; } - @Override protected void service(HttpServletRequest request, HttpServletResponse response) + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + String msgSignature = request.getParameter("msg_signature"); String nonce = request.getParameter("nonce"); String timestamp = request.getParameter("timestamp"); String echostr = request.getParameter("echostr"); - response.setContentType("text/html;charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); if (StringUtils.isNotBlank(echostr)) { if (!wxCpService.checkSignature(msgSignature, timestamp, nonce, echostr)) { // 消息签名不正确,说明不是公众平台发过来的消息 @@ -84,11 +57,9 @@ public class WxCpDemoServlet extends HttpServlet { 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); - if (outMessage != null) { response.getWriter().write(outMessage.toEncryptedXml(wxCpConfigStorage)); } diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java new file mode 100644 index 00000000..02b1bf5d --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpOAuth2Servlet.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.cp.demo; + +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.cp.api.WxCpService; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; + +/** + * Created by qianjia on 14/11/28. + */ +public class WxCpOAuth2Servlet extends HttpServlet { + + protected WxCpService wxCpService; + + public WxCpOAuth2Servlet(WxCpService wxCpService) { + this.wxCpService = wxCpService; + } + + @Override protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + String code = request.getParameter("code"); + try { + response.getWriter().println("

code

"); + response.getWriter().println(code); + + String[] res = wxCpService.oauth2getUserInfo(code); + response.getWriter().println("

result

"); + response.getWriter().println(Arrays.toString(res)); + } catch (WxErrorException e) { + e.printStackTrace(); + } + + response.getWriter().flush(); + response.getWriter().close(); + + } + + +} diff --git a/weixin-java-cp/src/test/resources/test-config.sample.xml b/weixin-java-cp/src/test/resources/test-config.sample.xml index c30d7e35..02c98f3f 100644 --- a/weixin-java-cp/src/test/resources/test-config.sample.xml +++ b/weixin-java-cp/src/test/resources/test-config.sample.xml @@ -9,4 +9,5 @@ 企业号通讯录里的某个userid 企业号通讯录的某个部门id 企业号通讯录里的某个tagid + 网页授权获取用户信息回调地址
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 940e79f3..f91e8291 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -6,7 +6,7 @@ me.chanjar weixin-java-parent - 1.0.4 + 1.0.5 weixin-java-mp WeiXin Java Tools - MP diff --git a/weixin-java-mp/pom.xml.versionsBackup b/weixin-java-mp/pom.xml.versionsBackup new file mode 100644 index 00000000..2e10c3ed --- /dev/null +++ b/weixin-java-mp/pom.xml.versionsBackup @@ -0,0 +1,72 @@ + + + 4.0.0 + + me.chanjar + weixin-java-parent + 1.0.5-SNAPSHOT + + weixin-java-mp + WeiXin Java Tools - MP + 微信公众号Java SDK + + + + me.chanjar + weixin-java-common + ${project.version} + + + junit + junit + test + + + org.testng + testng + 6.8.7 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + com.google.inject + guice + 3.0 + test + + + org.eclipse.jetty + jetty-server + 9.3.0.M0 + test + + + org.eclipse.jetty + jetty-servlet + 9.3.0.M0 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + src/test/resources/testng.xml + + + + + + + diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java index e7ee779c..3ecbf155 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java @@ -25,6 +25,8 @@ public interface WxMpConfigStorage { public int getExpiresIn(); + public String getOauth2redirectUri(); + public String getHttp_proxy_host(); public int getHttp_proxy_port(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java index d0f9c33d..82c3d621 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java @@ -16,6 +16,8 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { protected String aesKey; protected int expiresIn; + protected String oauth2redirectUri; + protected String http_proxy_host; protected int http_proxy_port; protected String http_proxy_username; @@ -78,6 +80,15 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { this.expiresIn = expiresIn; } + @Override + public String getOauth2redirectUri() { + return this.oauth2redirectUri; + } + + public void setOauth2redirectUri(String oauth2redirectUri) { + this.oauth2redirectUri = oauth2redirectUri; + } + public String getHttp_proxy_host() { return http_proxy_host; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java index e80ff5a1..8e6deeb6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageHandler.java @@ -16,8 +16,9 @@ public interface WxMpMessageHandler { * * @param wxMessage * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxMpService * @return xml格式的消息,如果在异步规则里处理的话,可以返回null */ - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context); + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java index 901defea..d940804f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageInterceptor.java @@ -15,8 +15,9 @@ public interface WxMpMessageInterceptor { * 拦截微信消息 * @param wxMessage * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个 + * @param wxMpService * @return true代表OK,false代表不OK */ - public boolean intercept(WxMpXmlMessage wxMessage, Map context); + public boolean intercept(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java index f49cafe6..07451d6f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java @@ -40,17 +40,31 @@ import java.util.regex.Pattern; * */ public class WxMpMessageRouter { - + + private static final int DEFAULT_THREAD_POOL_SIZE = 20; + private final List rules = new ArrayList(); - private final ExecutorService es = Executors.newCachedThreadPool(); - + private final ExecutorService executorService; + + private final WxMpService wxMpService; + + public WxMpMessageRouter(WxMpService wxMpService) { + this.wxMpService = wxMpService; + this.executorService = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE); + } + + public WxMpMessageRouter(WxMpService wxMpService, int threadPoolSize) { + this.wxMpService = wxMpService; + this.executorService = Executors.newFixedThreadPool(threadPoolSize); + } + /** * 开始一个新的Route规则 * @return */ public Rule rule() { - return new Rule(this); + return new Rule(this, wxMpService); } /** @@ -73,7 +87,7 @@ public class WxMpMessageRouter { if (matchRules.get(0).async) { // 只要第一个是异步的,那就异步执行 // 在另一个线程里执行 - es.submit(new Runnable() { + executorService.execute(new Runnable() { public void run() { for (final Rule rule : matchRules) { rule.service(wxMessage); @@ -101,7 +115,11 @@ public class WxMpMessageRouter { private final WxMpMessageRouter routerBuilder; + private final WxMpService wxMpService; + private boolean async = true; + + private String fromUser; private String msgType; @@ -119,8 +137,9 @@ public class WxMpMessageRouter { private List interceptors = new ArrayList(); - protected Rule(WxMpMessageRouter routerBuilder) { + protected Rule(WxMpMessageRouter routerBuilder, WxMpService wxMpService) { this.routerBuilder = routerBuilder; + this.wxMpService = wxMpService; } /** @@ -182,7 +201,17 @@ public class WxMpMessageRouter { this.rContent = regex; return this; } - + + /** + * 如果fromUser等于某值 + * @param fromUser + * @return + */ + public Rule fromUser(String fromUser) { + this.fromUser = fromUser; + return this; + } + /** * 设置微信消息拦截器 * @param interceptor @@ -252,7 +281,9 @@ public class WxMpMessageRouter { } protected boolean test(WxMpXmlMessage wxMessage) { - return + 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())) @@ -274,7 +305,7 @@ public class WxMpMessageRouter { Map context = new HashMap(); // 如果拦截器不通过 for (WxMpMessageInterceptor interceptor : this.interceptors) { - if (!interceptor.intercept(wxMessage, context)) { + if (!interceptor.intercept(wxMessage, context, wxMpService)) { return null; } } @@ -283,7 +314,7 @@ public class WxMpMessageRouter { WxMpXmlOutMessage res = null; for (WxMpMessageHandler handler : this.handlers) { // 返回最后handler的结果 - res = handler.handle(wxMessage, context); + res = handler.handle(wxMessage, context, wxMpService); } return res; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index daaa062f..8fc70e8e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -329,6 +329,54 @@ public interface WxMpService { */ WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException; + /** + *
+   * 构造oauth2授权的url连接
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
+   * 
+ * @param scope + * @param state + * @return code + */ + public String oauth2buildAuthorizationUrl(String scope, String state); + + /** + *
+   * 用code换取oauth2的access token
+   * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
+   * 
+ * @param code + * @return + */ + public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException; + + /** + *
+   * 刷新oauth2的access token
+   * 
+ * @param refreshToken + * @return + */ + public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException; + + /** + *
+   * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以
+   * 
+ * @param oAuth2AccessToken + * @param lang zh_CN, zh_TW, en + */ + public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException; + + /** + *
+   * 验证oauth2的access token是否有效
+   * 
+ * @param oAuth2AccessToken + * @return + */ + public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken); + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 * @param url diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java index a4b4cc37..93686ef6 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java @@ -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.WxMediaUploadResult; 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.fs.FileUtils; 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.util.http.QrCodeRequestExecutor; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; 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.methods.CloseableHttpResponse; 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.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; @@ -38,7 +37,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -299,6 +297,98 @@ public class WxMpServiceImpl implements WxMpService { return WxMpSemanticQueryResult.fromJson(responseContent); } + @Override + public String oauth2buildAuthorizationUrl(String scope, String state) { + String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" ; + url += "appid=" + wxMpConfigStorage.getAppId(); + url += "&redirect_uri=" + URIUtil.encodeURIComponent(wxMpConfigStorage.getOauth2redirectUri()); + url += "&response_type=code"; + url += "&scope=" + scope; + if (state != null) { + url += "&state=" + state; + } + url += "#wechat_redirect"; + return url; + } + + @Override + public WxMpOAuth2AccessToken oauth2getAccessToken(String code) throws WxErrorException { + String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"; + url += "appid=" + wxMpConfigStorage.getAppId(); + url += "&secret=" + wxMpConfigStorage.getSecret(); + url += "&code=" + code; + url += "&grant_type=authorization_code"; + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), httpProxy, url, null); + return WxMpOAuth2AccessToken.fromJson(responseText); + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException { + String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?"; + url += "appid=" + wxMpConfigStorage.getAppId(); + url += "&grant_type=refresh_token"; + url += "&refresh_token=" + refreshToken; + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), httpProxy, url, null); + return WxMpOAuth2AccessToken.fromJson(responseText); + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public WxMpUser oauth2getUserInfo(WxMpOAuth2AccessToken oAuth2AccessToken, String lang) throws WxErrorException { + String url = "https://api.weixin.qq.com/sns/userinfo?"; + url += "access_token=" + oAuth2AccessToken.getAccessToken(); + url += "&openid=" + oAuth2AccessToken.getOpenId(); + if (lang == null) { + url += "&lang=zh_CN"; + } else { + url += "&lang=" + lang; + } + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + String responseText = executor.execute(getHttpclient(), httpProxy, url, null); + return WxMpUser.fromJson(responseText); + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken) { + String url = "https://api.weixin.qq.com/sns/auth?"; + url += "access_token=" + oAuth2AccessToken; + url += "&openid=" + oAuth2AccessToken.getOpenId(); + + try { + RequestExecutor executor = new SimpleGetRequestExecutor(); + executor.execute(getHttpclient(), httpProxy, url, null); + } catch (ClientProtocolException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (WxErrorException e) { + return false; + } + return true; + } + public String get(String url, String queryParam) throws WxErrorException { return execute(new SimpleGetRequestExecutor(), url, queryParam); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutNewsMessage.java similarity index 95% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java rename to weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutNewsMessage.java index 527dc6a7..4730a99b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMewsMessage.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutNewsMessage.java @@ -10,7 +10,7 @@ import java.util.List; @XmlRootElement(name = "xml") @XmlAccessorType(XmlAccessType.FIELD) -public class WxMpXmlOutMewsMessage extends WxMpXmlOutMessage { +public class WxMpXmlOutNewsMessage extends WxMpXmlOutMessage { @XmlElement(name = "ArticleCount") protected int articleCount; @@ -19,7 +19,7 @@ public class WxMpXmlOutMewsMessage extends WxMpXmlOutMessage { @XmlElement(name = "item") protected final List articles = new ArrayList(); - public WxMpXmlOutMewsMessage() { + public WxMpXmlOutNewsMessage() { this.msgType = WxConsts.XML_MSG_NEWS; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/NewsBuilder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/NewsBuilder.java index 08a9da1e..6f225825 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/NewsBuilder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/NewsBuilder.java @@ -1,6 +1,6 @@ package me.chanjar.weixin.mp.bean.outxmlbuilder; -import me.chanjar.weixin.mp.bean.WxMpXmlOutMewsMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutNewsMessage; import java.util.ArrayList; import java.util.List; @@ -9,18 +9,18 @@ import java.util.List; * 图文消息builder * @author chanjarster */ -public final class NewsBuilder extends BaseBuilder { +public final class NewsBuilder extends BaseBuilder { - protected final List articles = new ArrayList(); + protected final List articles = new ArrayList(); - public NewsBuilder addArticle(WxMpXmlOutMewsMessage.Item item) { + public NewsBuilder addArticle(WxMpXmlOutNewsMessage.Item item) { this.articles.add(item); return this; } - public WxMpXmlOutMewsMessage build() { - WxMpXmlOutMewsMessage m = new WxMpXmlOutMewsMessage(); - for(WxMpXmlOutMewsMessage.Item item : articles) { + public WxMpXmlOutNewsMessage build() { + WxMpXmlOutNewsMessage m = new WxMpXmlOutNewsMessage(); + for(WxMpXmlOutNewsMessage.Item item : articles) { m.addArticle(item); } setCommon(m); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java new file mode 100644 index 00000000..88b732f9 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpOAuth2AccessToken.java @@ -0,0 +1,75 @@ +package me.chanjar.weixin.mp.bean.result; + +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; + +/** + * Created by qianjia on 14/11/26. + */ +public class WxMpOAuth2AccessToken { + + private String accessToken; + + private int expiresIn = -1; + + private String refreshToken; + + private String openId; + + private String scope; + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public int getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(int expiresIn) { + this.expiresIn = expiresIn; + } + + public static WxMpOAuth2AccessToken fromJson(String json) { + return WxMpGsonBuilder.create().fromJson(json, WxMpOAuth2AccessToken.class); + } + + @Override + public String toString() { + return "WxMpOAuth2AccessToken{" + + "accessToken='" + accessToken + '\'' + + ", expiresIn=" + expiresIn + + ", refreshToken='" + refreshToken + '\'' + + ", openId='" + openId + '\'' + + ", scope='" + scope + '\'' + + '}'; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java index fa4aee6d..554a07db 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUser.java @@ -9,7 +9,7 @@ import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; */ public class WxMpUser { - protected boolean subscribe; + protected Boolean subscribe; protected String openId; protected String nickname; protected String sex; @@ -18,13 +18,13 @@ public class WxMpUser { protected String province; protected String country; protected String headImgUrl; - protected long subscribeTime; + protected Long subscribeTime; protected String unionId; - public boolean isSubscribe() { + public Boolean isSubscribe() { return subscribe; } - public void setSubscribe(boolean subscribe) { + public void setSubscribe(Boolean subscribe) { this.subscribe = subscribe; } public String getOpenId() { @@ -75,10 +75,10 @@ public class WxMpUser { public void setHeadImgUrl(String headImgUrl) { this.headImgUrl = headImgUrl; } - public long getSubscribeTime() { + public Long getSubscribeTime() { return subscribeTime; } - public void setSubscribeTime(long subscribeTime) { + public void setSubscribeTime(Long subscribeTime) { this.subscribeTime = subscribeTime; } public String getUnionId() { @@ -91,5 +91,21 @@ public class WxMpUser { public static WxMpUser fromJson(String json) { return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUser.class); } - + + @Override + public String toString() { + return "WxMpUser{" + + "subscribe=" + subscribe + + ", openId='" + openId + '\'' + + ", nickname='" + nickname + '\'' + + ", sex='" + sex + '\'' + + ", language='" + language + '\'' + + ", city='" + city + '\'' + + ", province='" + province + '\'' + + ", country='" + country + '\'' + + ", headImgUrl='" + headImgUrl + '\'' + + ", subscribeTime=" + subscribeTime + + ", unionId='" + unionId + '\'' + + '}'; + } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java index 6ff4b773..488dd8df 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxMpCustomMessageGsonAdapter.java @@ -64,6 +64,7 @@ public class WxMpCustomMessageGsonAdapter implements JsonSerializer { + + public WxMpOAuth2AccessToken deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws + JsonParseException { + WxMpOAuth2AccessToken accessToken = new WxMpOAuth2AccessToken(); + JsonObject accessTokenJsonObject = json.getAsJsonObject(); + + if (accessTokenJsonObject.get("access_token") != null && !accessTokenJsonObject.get("access_token").isJsonNull()) { + accessToken.setAccessToken(GsonHelper.getAsString(accessTokenJsonObject.get("access_token"))); + } + if (accessTokenJsonObject.get("expires_in") != null && !accessTokenJsonObject.get("expires_in").isJsonNull()) { + accessToken.setExpiresIn(GsonHelper.getAsPrimitiveInt(accessTokenJsonObject.get("expires_in"))); + } + if (accessTokenJsonObject.get("refresh_token") != null && !accessTokenJsonObject.get("refresh_token").isJsonNull()) { + accessToken.setRefreshToken(GsonHelper.getAsString(accessTokenJsonObject.get("refresh_token"))); + } + if (accessTokenJsonObject.get("openid") != null && !accessTokenJsonObject.get("openid").isJsonNull()) { + accessToken.setOpenId(GsonHelper.getAsString(accessTokenJsonObject.get("openid"))); + } + if (accessTokenJsonObject.get("scope") != null && !accessTokenJsonObject.get("scope").isJsonNull()) { + accessToken.setScope(GsonHelper.getAsString(accessTokenJsonObject.get("scope"))); + } + return accessToken; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java index 5e619746..bff84eab 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/xml/XmlTransformer.java @@ -56,6 +56,7 @@ public class XmlTransformer { Marshaller m = JAXB_CONTEXT.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.setProperty(CharacterEscapeHandler.class.getName(), CHAR_ESCAPE_HANDLER); + m.setProperty(Marshaller.JAXB_FRAGMENT, true); m.marshal(object, writer); } @@ -76,7 +77,7 @@ public class XmlTransformer { return JAXBContext.newInstance( WxMpXmlOutMessage.class, WxMpMpXmlOutImageMessage.class, - WxMpXmlOutMewsMessage.class, + WxMpXmlOutNewsMessage.class, WxMpXmlOutMusicMessage.class, WxMpXmlOutTextMessage.class, WxMpXmlOutVideoMessage.class, diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java index 65d88928..f87d97a4 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxBaseAPITest.java @@ -1,6 +1,6 @@ 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.annotations.Guice; import org.testng.annotations.Test; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java index b43ca3c8..b3c2460b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpMessageRouterTest.java @@ -47,7 +47,7 @@ public class WxMpMessageRouterTest { @Test(dataProvider="messages-1") public void testSync(WxMpXmlMessage message, String expected) { StringBuffer sb = new StringBuffer(); - WxMpMessageRouter router = new WxMpMessageRouter(); + WxMpMessageRouter router = new WxMpMessageRouter(null); prepare(false, sb, router); router.route(message); Assert.assertEquals(sb.toString(), expected); @@ -56,7 +56,7 @@ public class WxMpMessageRouterTest { @Test(dataProvider="messages-1") public void testAsync(WxMpXmlMessage message, String expected) throws InterruptedException { StringBuffer sb = new StringBuffer(); - WxMpMessageRouter router = new WxMpMessageRouter(); + WxMpMessageRouter router = new WxMpMessageRouter(null); prepare(true, sb, router); router.route(message); Thread.sleep(500l); @@ -64,10 +64,10 @@ public class WxMpMessageRouterTest { } public void testConcurrency() throws InterruptedException { - final WxMpMessageRouter router = new WxMpMessageRouter(); + final WxMpMessageRouter router = new WxMpMessageRouter(null); router.rule().handler(new WxMpMessageHandler() { @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService) { return null; } }).end(); @@ -149,7 +149,7 @@ public class WxMpMessageRouterTest { } @Override - public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService) { sb.append(this.echoStr).append(','); return null; } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java index 68947b41..5e3d5620 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpCustomMessageTest.java @@ -108,7 +108,7 @@ public class WxMpCustomMessageTest { reply.getArticles().add(article2); - Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); } public void testNewsBuild() { @@ -125,8 +125,8 @@ public class WxMpCustomMessageTest { article2.setTitle("Happy Day"); WxMpCustomMessage reply = WxMpCustomMessage.NEWS().toUser("OPENID").addArticle(article1).addArticle(article2).build(); - - Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}"); + + Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"},{\"title\":\"Happy Day\",\"description\":\"Is Really A Happy Day\",\"url\":\"URL\",\"picurl\":\"PIC_URL\"}]}}"); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java index e0377cb6..f4b50e1d 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxMpXmlOutImageMessageTest.java @@ -13,8 +13,7 @@ public class WxMpXmlOutImageMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxMpXmlOutImageMessageTest { public void testBuild() { WxMpMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java index 0471e2c3..4397a677 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutMusicMessageTest.java @@ -17,8 +17,7 @@ public class WxXmlOutMusicMessageTest { m.setFromUserName("fromUser"); m.setToUserName("toUser"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -45,8 +44,7 @@ public class WxXmlOutMusicMessageTest { .musicUrl("musicUrl") .thumbMediaId("thumbMediaId") .build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java index 782a6abe..5e2da0b0 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutNewsMessageTest.java @@ -7,20 +7,19 @@ import org.testng.annotations.Test; public class WxXmlOutNewsMessageTest { public void test() { - WxMpXmlOutMewsMessage m = new WxMpXmlOutMewsMessage(); + WxMpXmlOutNewsMessage m = new WxMpXmlOutNewsMessage(); m.setCreateTime(1122l); m.setFromUserName("fromUser"); m.setToUserName("toUser"); - WxMpXmlOutMewsMessage.Item item = new WxMpXmlOutMewsMessage.Item(); + WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); item.setUrl("url"); m.addArticle(item); m.addArticle(item); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -46,20 +45,19 @@ public class WxXmlOutNewsMessageTest { } public void testBuild() { - WxMpXmlOutMewsMessage.Item item = new WxMpXmlOutMewsMessage.Item(); + WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item(); item.setDescription("description"); item.setPicUrl("picUrl"); item.setTitle("title"); item.setUrl("url"); - WxMpXmlOutMewsMessage m = WxMpXmlOutMessage.NEWS() + WxMpXmlOutNewsMessage m = WxMpXmlOutMessage.NEWS() .fromUser("fromUser") .toUser("toUser") .addArticle(item) .addArticle(item) .build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java index a845abcd..2a752051 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutTextMessageTest.java @@ -13,8 +13,7 @@ public class WxXmlOutTextMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxXmlOutTextMessageTest { public void testBuild() { WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java index b033b040..19fbe62a 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVideoMessageTest.java @@ -15,8 +15,7 @@ public class WxXmlOutVideoMessageTest { m.setFromUserName("fromUser"); m.setToUserName("toUser"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -39,8 +38,7 @@ public class WxXmlOutVideoMessageTest { .title("title") .description("ddfff") .build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java index 65644f3d..0eb848cd 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/WxXmlOutVoiceMessageTest.java @@ -13,8 +13,7 @@ public class WxXmlOutVoiceMessageTest { m.setFromUserName("from"); m.setToUserName("to"); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" @@ -27,8 +26,7 @@ public class WxXmlOutVoiceMessageTest { public void testBuild() { WxMpXmlOutVoiceMessage m = WxMpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); - String expected = "" - + "" + String expected = "" + "" + "" + "1122" diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java index e0bb6498..0d7b126d 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServer.java @@ -1,20 +1,124 @@ package me.chanjar.weixin.mp.demo; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.WxMpMpXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.*; + +import javax.xml.bind.JAXBException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; -/** - * @author Daniel Qian - */ public class WxMpDemoServer { + + private static WxMpConfigStorage wxMpConfigStorage; + private static WxMpService wxMpService; + private static WxMpMessageRouter wxMpMessageRouter; + public static void main(String[] args) throws Exception { + initWeixin(); + Server server = new Server(8080); - ServletHandler handler = new ServletHandler(); - server.setHandler(handler); + ServletHandler servletHandler = new ServletHandler(); + server.setHandler(servletHandler); + + ServletHolder endpointServletHolder = new ServletHolder(new WxMpEndpointServlt(wxMpConfigStorage, wxMpService, wxMpMessageRouter)); + servletHandler.addServletWithMapping(endpointServletHolder, "/*"); + + ServletHolder oauthServletHolder = new ServletHolder(new WxMpOAuth2Servlet(wxMpService)); + servletHandler.addServletWithMapping(oauthServletHolder, "/oauth2/*"); - handler.addServletWithMapping(WxMpDemoServlet.class, "/*"); server.start(); server.join(); } + + private static void initWeixin() { + try { + InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); + WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage.fromXml(is1); + + wxMpConfigStorage = config; + wxMpService = new WxMpServiceImpl(); + wxMpService.setWxMpConfigStorage(config); + + WxMpMessageHandler textHandler = new WxMpMessageHandler() { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService) { + WxMpXmlOutTextMessage m + = WxMpXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); + return m; + } + }; + + WxMpMessageHandler imageHandler = new WxMpMessageHandler() { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService) { + try { + WxMediaUploadResult wxMediaUploadResult = wxMpService + .mediaUpload(WxConsts.MEDIA_IMAGE, WxConsts.FILE_JPG, ClassLoader.getSystemResourceAsStream("mm.jpeg")); + WxMpMpXmlOutImageMessage m + = WxMpXmlOutMessage + .IMAGE() + .mediaId(wxMediaUploadResult.getMediaId()) + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()) + .build(); + return m; + } catch (WxErrorException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + }; + + WxMpMessageHandler oauth2handler = new WxMpMessageHandler() { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, + WxMpService wxMpService) { + String href = "测试oauth2"; + return WxMpXmlOutMessage + .TEXT() + .content(href) + .fromUser(wxMessage.getToUserName()) + .toUser(wxMessage.getFromUserName()).build(); + } + }; + + wxMpMessageRouter = new WxMpMessageRouter(wxMpService); + wxMpMessageRouter + .rule() + .async(false) + .content("哈哈") // 拦截内容为“哈哈”的消息 + .handler(textHandler) + .end() + .rule() + .async(false) + .content("图片") + .handler(imageHandler) + .end() + .rule() + .async(false) + .content("oauth") + .handler(oauth2handler) + .end() + ; + + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlt.java similarity index 50% rename from weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java rename to weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlt.java index 7ceb2e26..c99cd8b3 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoServlet.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpEndpointServlt.java @@ -1,10 +1,14 @@ package me.chanjar.weixin.mp.demo; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.StringUtils; import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.WxMpMpXmlOutImageMessage; import me.chanjar.weixin.mp.bean.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; -import org.apache.commons.lang3.StringUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -18,55 +22,29 @@ import java.util.Map; /** * @author Daniel Qian */ -public class WxMpDemoServlet extends HttpServlet { +public class WxMpEndpointServlt extends HttpServlet { - protected WxMpService wxMpService; protected WxMpConfigStorage wxMpConfigStorage; + protected WxMpService wxMpService; protected WxMpMessageRouter wxMpMessageRouter; - @Override public void init() throws ServletException { - // - super.init(); - try { - InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); - WxMpDemoInMemoryConfigStorage config = WxMpDemoInMemoryConfigStorage.fromXml(is1); - - wxMpConfigStorage = config; - wxMpService = new WxMpServiceImpl(); - wxMpService.setWxMpConfigStorage(config); - - WxMpMessageHandler handler = new WxMpMessageHandler() { - @Override public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context) { - WxMpXmlOutTextMessage m - = WxMpXmlOutMessage.TEXT().content("测试加密消息").fromUser(wxMessage.getToUserName()) - .toUser(wxMessage.getFromUserName()).build(); - return m; - } - }; - - wxMpMessageRouter = new WxMpMessageRouter(); - wxMpMessageRouter - .rule() - .async(false) - .content("哈哈") // 拦截内容为“哈哈”的消息 - .handler(handler) - .end(); - - } catch (JAXBException e) { - throw new RuntimeException(e); - } + public WxMpEndpointServlt(WxMpConfigStorage wxMpConfigStorage, WxMpService wxMpService, + WxMpMessageRouter wxMpMessageRouter) { + this.wxMpConfigStorage = wxMpConfigStorage; + this.wxMpService = wxMpService; + this.wxMpMessageRouter = wxMpMessageRouter; } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + String signature = request.getParameter("signature"); String nonce = request.getParameter("nonce"); String timestamp = request.getParameter("timestamp"); - response.setContentType("text/html;charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - if (!wxMpService.checkSignature(timestamp, nonce, signature)) { // 消息签名不正确,说明不是公众平台发过来的消息 response.getWriter().println("非法请求"); @@ -84,31 +62,25 @@ public class WxMpDemoServlet extends HttpServlet { "raw" : request.getParameter("encrypt_type"); - WxMpXmlMessage inMessage = null; - 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; } - 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; } + response.getWriter().println("不可识别的加密类型"); + return; } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpOAuth2Servlet.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpOAuth2Servlet.java new file mode 100644 index 00000000..6ddf4ad3 --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpOAuth2Servlet.java @@ -0,0 +1,65 @@ +package me.chanjar.weixin.mp.demo; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.StringUtils; +import me.chanjar.weixin.mp.api.*; +import me.chanjar.weixin.mp.bean.WxMpMpXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage; +import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; +import me.chanjar.weixin.mp.bean.result.WxMpUser; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +public class WxMpOAuth2Servlet extends HttpServlet { + + protected WxMpService wxMpService; + + public WxMpOAuth2Servlet(WxMpService wxMpService) { + this.wxMpService = wxMpService; + } + + @Override protected void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + String code = request.getParameter("code"); + try { + response.getWriter().println("

code

"); + response.getWriter().println(code); + + WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code); + response.getWriter().println("

access token

"); + response.getWriter().println(wxMpOAuth2AccessToken.toString()); + + WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null); + response.getWriter().println("

user info

"); + response.getWriter().println(wxMpUser.toString()); + + wxMpOAuth2AccessToken = wxMpService.oauth2refreshAccessToken(wxMpOAuth2AccessToken.getRefreshToken()); + response.getWriter().println("

after refresh

"); + response.getWriter().println(wxMpOAuth2AccessToken.toString()); + + } catch (WxErrorException e) { + e.printStackTrace(); + } + + response.getWriter().flush(); + response.getWriter().close(); + + } + +} diff --git a/weixin-java-mp/src/test/resources/test-config.sample.xml b/weixin-java-mp/src/test/resources/test-config.sample.xml index 501620cd..19535f3c 100644 --- a/weixin-java-mp/src/test/resources/test-config.sample.xml +++ b/weixin-java-mp/src/test/resources/test-config.sample.xml @@ -6,4 +6,5 @@ 可以不填写 可以不填写 某个加你公众号的用户的openId + 网页授权获取用户信息回调地址