Переглянути джерело

Merge pull request #14 from binarywang/develop

merge Develop
master
Binary Wang 8 роки тому
committed by GitHub
джерело
коміт
331f06ef30
100 змінених файлів з 4201 додано та 1432 видалено
  1. +39
    -20
      pom.xml
  2. +0
    -25
      spring-demo/pom.xml
  3. +1
    -1
      weixin-java-common/pom.xml
  4. +14
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
  5. +5
    -9
      weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java
  6. +0
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java
  7. +0
    -6
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java
  8. +52
    -53
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
  9. +0
    -4
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java
  10. +0
    -5
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java
  11. +0
    -1
      weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
  12. +1
    -1
      weixin-java-cp/pom.xml
  13. +0
    -2
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java
  14. +0
    -1
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java
  15. +0
    -15
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java
  16. +4
    -25
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java
  17. +0
    -6
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java
  18. +11
    -17
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java
  19. +0
    -4
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java
  20. +6
    -12
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java
  21. +0
    -7
      weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
  22. +1
    -0
      weixin-java-demo-with-spring/.gitignore
  23. +7
    -0
      weixin-java-demo-with-spring/README.md
  24. +91
    -0
      weixin-java-demo-with-spring/pom.xml
  25. +80
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/aop/ControllerLogAspect.java
  26. +21
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/AbstractBuilder.java
  27. +27
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/ImageBuilder.java
  28. +25
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/TextBuilder.java
  29. +41
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxAccountEnum.java
  30. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxConfig.java
  31. +50
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh1Config.java
  32. +50
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh2Config.java
  33. +80
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/AbstractWxPortalController.java
  34. +26
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh1WxPortalController.java
  35. +26
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh2WxPortalController.java
  36. +44
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/dto/WxMenuKey.java
  37. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/AbstractHandler.java
  38. +36
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/KfSessionHandler.java
  39. +47
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LocationHandler.java
  40. +34
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LogHandler.java
  41. +71
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MenuHandler.java
  42. +48
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MsgHandler.java
  43. +34
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/NullHandler.java
  44. +10
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/ScanHandler.java
  45. +61
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/SubscribeHandler.java
  46. +27
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/UnsubscribeHandler.java
  47. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1LocationHandler.java
  48. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MenuHandler.java
  49. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MsgHandler.java
  50. +32
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1SubscribeHandler.java
  51. +23
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1UnSubscribeHandler.java
  52. +138
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/BaseWxService.java
  53. +79
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh1WxService.java
  54. +66
    -0
      weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh2WxService.java
  55. +2
    -0
      weixin-java-demo-with-spring/src/main/resources/.gitignore
  56. +17
    -0
      weixin-java-demo-with-spring/src/main/resources/applicationContext.xml
  57. +8
    -0
      weixin-java-demo-with-spring/src/main/resources/log4j.properties
  58. +29
    -0
      weixin-java-demo-with-spring/src/main/resources/spring-service-bean.xml
  59. +43
    -0
      weixin-java-demo-with-spring/src/main/resources/spring-servlet-common.xml
  60. +4
    -0
      weixin-java-demo-with-spring/src/main/resources/wx-gzh1.properties.template
  61. +4
    -0
      weixin-java-demo-with-spring/src/main/resources/wx-gzh2.properties.template
  62. +0
    -8
      weixin-java-demo-with-spring/src/main/webapp/WEB-INF/web.xml
  63. +7
    -1
      weixin-java-mp/pom.xml
  64. +69
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java
  65. +172
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java
  66. +195
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java
  67. +59
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
  68. +0
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java
  69. +0
    -1
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
  70. +18
    -59
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java
  71. +77
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
  72. +166
    -578
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
  73. +72
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
  74. +85
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java
  75. +182
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
  76. +158
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
  77. +74
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java
  78. +102
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
  79. +50
    -371
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java
  80. +83
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java
  81. +26
    -22
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java
  82. +6
    -6
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java
  83. +168
    -139
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java
  84. +9
    -15
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java
  85. +4
    -2
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java
  86. +105
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java
  87. +49
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java
  88. +164
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java
  89. +36
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java
  90. +55
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java
  91. +87
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java
  92. +36
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java
  93. +76
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java
  94. +53
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java
  95. +41
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java
  96. +48
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java
  97. +5
    -5
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java
  98. +5
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java
  99. +5
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java
  100. +24
    -0
      weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java

+ 39
- 20
pom.xml Переглянути файл

@@ -1,11 +1,11 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>1.3.5</version>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>WeiXin Java Tools - Parent</name>
<description>微信公众号、企业号上级POM</description>
@@ -39,7 +39,6 @@
<module>weixin-java-common</module>
<module>weixin-java-cp</module>
<module>weixin-java-mp</module>
<module>spring-demo</module>
</modules>

<properties>
@@ -50,6 +49,13 @@
<slf4j.version>1.7.10</slf4j.version>
<logback.version>1.1.2</logback.version>
<jodd-http.version>3.6.7</jodd-http.version>
<jackson.version>2.8.0</jackson.version>
<gson.version>2.7</gson.version>
<commons-lang3.version>3.4</commons-lang3.version>
<commons-io.version>2.5</commons-io.version>
<commons-codec.version>1.10</commons-codec.version>
<jetty.version>9.3.0.M0</jetty.version>
<jetty-new.version>9.3.10.v20160621</jetty-new.version>
</properties>

<dependencies>
@@ -82,20 +88,30 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2</version>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
@@ -125,13 +141,13 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.3.0.M0</version>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.3.0.M0</version>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -149,16 +165,16 @@
</distributionManagement>

<profiles>
<profile>
<id>doclint-java8-disable</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
</profile>
<profile>
<id>doclint-java8-disable</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
</profile>
<profile>
<id>release</id>
<build>
@@ -220,6 +236,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</pluginManagement>


+ 0
- 25
spring-demo/pom.xml Переглянути файл

@@ -1,25 +0,0 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>1.3.5</version>
</parent>
<artifactId>spring-demo</artifactId>
<packaging>war</packaging>
<name>WeiXin Java Tools - demo with spring</name>
<description>spring demo</description>
<url>https://github.com/binarywang/weixin-java-tools</url>
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

</project>

+ 1
- 1
weixin-java-common/pom.xml Переглянути файл

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>1.3.5</version>
<version>2.0.0-SNAPSHOT</version>
</parent>

<artifactId>weixin-java-common</artifactId>


+ 14
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java Переглянути файл

@@ -11,6 +11,7 @@ public class WxConsts {
public static final String XML_MSG_TEXT = "text";
public static final String XML_MSG_IMAGE = "image";
public static final String XML_MSG_VOICE = "voice";
public static final String XML_MSG_SHORTVIDEO = "shortvideo";
public static final String XML_MSG_VIDEO = "video";
public static final String XML_MSG_NEWS = "news";
public static final String XML_MSG_MUSIC = "music";
@@ -20,7 +21,7 @@ public class WxConsts {
public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
///////////////////////
// 主动发送消息的消息类型
// 主动发送消息(即客服消息)的消息类型
///////////////////////
public static final String CUSTOM_MSG_TEXT = "text";
public static final String CUSTOM_MSG_IMAGE = "image";
@@ -103,6 +104,10 @@ public class WxConsts {
public static final String EVT_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card";
public static final String EVT_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警

public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话
public static final String EVT_KF_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话
public static final String EVT_KF_SWITCH_SESSION = "kf_switch_session"; // 客服转接会话

///////////////////////
// 上传多媒体文件的类型
///////////////////////
@@ -133,13 +138,17 @@ public class WxConsts {
/** 扫码推事件且弹出“消息接收中”提示框 */
public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg";
/** 弹出系统拍照发图 */
public static final String PIC_SYSPHOTO = "pic_sysphoto";
public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto";
/** 弹出拍照或者相册发图 */
public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
public static final String BUTTON_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album";
/** 弹出微信相册发图器 */
public static final String PIC_WEIXIN = "pic_weixin";
public static final String BUTTON_PIC_WEIXIN = "pic_weixin";
/** 弹出地理位置选择器 */
public static final String LOCATION_SELECT = "location_select";
public static final String BUTTON_LOCATION_SELECT = "location_select";
/** 下发消息(除文本消息) */
public static final String BUTTON_MEDIA_ID = "media_id";
/** 跳转图文消息URL */
public static final String BUTTON_VIEW_LIMITED = "view_limited";

///////////////////////
// oauth2网页授权的scope


+ 5
- 9
weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/WxMenu.java Переглянути файл

@@ -1,14 +1,14 @@
package me.chanjar.weixin.common.bean;

import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.apache.commons.codec.Charsets;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import me.chanjar.weixin.common.util.json.WxGsonBuilder;

/**
* 企业号菜单
* @author Daniel Qian
@@ -45,8 +45,6 @@ public class WxMenu implements Serializable {
/**
* 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu
* @param json
* @return
*/
public static WxMenu fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxMenu.class);
@@ -55,11 +53,9 @@ public class WxMenu implements Serializable {
/**
* 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu
* @param is
* @return
*/
public static WxMenu fromJson(InputStream is) {
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, Charsets.UTF_8), WxMenu.class);
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class);
}

@Override
@@ -195,7 +191,7 @@ public class WxMenu implements Serializable {
this.language = language;
}

@Override
@Override
public String toString() {
return "matchrule:{" +
"tag_id='" + tagId + '\'' +


+ 0
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/session/WxSessionManager.java Переглянути файл

@@ -4,16 +4,11 @@ public interface WxSessionManager {

/**
* 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。
* @param sessionId
* @return
*/
public WxSession getSession(String sessionId);

/**
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。
* @param sessionId
* @param create
* @return
*/
public WxSession getSession(String sessionId, boolean create);



+ 0
- 6
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java Переглянути файл

@@ -12,9 +12,6 @@ public class SHA1 {

/**
* 串接arr参数,生成sha1 digest
*
* @param arr
* @return
*/
public static String gen(String... arr) throws NoSuchAlgorithmException {
Arrays.sort(arr);
@@ -27,9 +24,6 @@ public class SHA1 {

/**
* 用&串接arr参数,生成sha1 digest
*
* @param arr
* @return
*/
public static String genWithAmple(String... arr) throws NoSuchAlgorithmException {
Arrays.sort(arr);


+ 52
- 53
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java Переглянути файл

@@ -35,16 +35,16 @@ public class WxCryptUtil {
private static final Base64 base64 = new Base64();
private static final Charset CHARSET = Charset.forName("utf-8");
private static final ThreadLocal<DocumentBuilder> builderLocal =
new ThreadLocal<DocumentBuilder>() {
@Override protected DocumentBuilder initialValue() {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException exc) {
throw new IllegalArgumentException(exc);
}
}
};
private static final ThreadLocal<DocumentBuilder> builderLocal = new ThreadLocal<DocumentBuilder>() {
@Override
protected DocumentBuilder initialValue() {
try {
return DocumentBuilderFactory.newInstance().newDocumentBuilder();
} catch (ParserConfigurationException exc) {
throw new IllegalArgumentException(exc);
}
}
};
protected byte[] aesKey;
protected String token;
@@ -61,7 +61,8 @@ public class WxCryptUtil {
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
* @param appidOrCorpid 公众平台appid/corpid
*/
public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) {
public WxCryptUtil(String token, String encodingAesKey,
String appidOrCorpid) {
this.token = token;
this.appidOrCorpid = appidOrCorpid;
this.aesKey = Base64.decodeBase64(encodingAesKey + "=");
@@ -105,7 +106,8 @@ public class WxCryptUtil {
ByteGroup byteCollector = new ByteGroup();
byte[] randomStringBytes = randomStr.getBytes(CHARSET);
byte[] plainTextBytes = plainText.getBytes(CHARSET);
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length);
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(
plainTextBytes.length);
byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET);
// randomStr + networkBytesOrder + text + appid
@@ -154,7 +156,8 @@ public class WxCryptUtil {
* @param encryptedXml 密文,对应POST请求的数据
* @return 解密后的原文
*/
public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) {
public String decrypt(String msgSignature, String timeStamp, String nonce,
String encryptedXml) {
// 密钥,公众账号的app corpSecret
// 提取密文
String cipherText = extractEncryptPart(encryptedXml);
@@ -186,7 +189,8 @@ public class WxCryptUtil {
// 设置解密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
IvParameterSpec iv = new IvParameterSpec(
Arrays.copyOfRange(aesKey, 0, 16));
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// 使用BASE64对密文进行解码
@@ -208,9 +212,10 @@ public class WxCryptUtil {
int xmlLength = bytesNetworkOrder2Number(networkOrder);
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength),
CHARSET);
from_appid = new String(
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -224,34 +229,32 @@ public class WxCryptUtil {
}
/**
* 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3)
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @param charset 编码
* @return 签名字符串
*/
public static String createSign(Map<String, String> packageParams, String signKey) {
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
sortedMap.putAll(packageParams);
List<String> keys = new ArrayList<String>(packageParams.keySet());
Collections.sort(keys);
StringBuffer toSign = new StringBuffer();
for (String key : keys) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}
toSign.append("key=" + signKey);
String sign = DigestUtils.md5Hex(toSign.toString())
.toUpperCase();
return sign;
/**
* 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3)
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @return 签名字符串
*/
public static String createSign(Map<String, String> packageParams,
String signKey) {
SortedMap<String, String> sortedMap = new TreeMap<String, String>();
sortedMap.putAll(packageParams);
List<String> keys = new ArrayList<String>(packageParams.keySet());
Collections.sort(keys);
StringBuffer toSign = new StringBuffer();
for (String key : keys) {
String value = packageParams.get(key);
if (null != value && !"".equals(value) && !"sign".equals(key)
&& !"key".equals(key)) {
toSign.append(key + "=" + value + "&");
}
}
toSign.append("key=" + signKey);
String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase();
return sign;
}
/**
* 将一个数字转换成生成4个字节的网络字节序bytes数组
@@ -283,8 +286,6 @@ public class WxCryptUtil {
/**
* 随机生成16位字符串
*
* @return
*/
private String genRandomStr() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@@ -306,14 +307,12 @@ public class WxCryptUtil {
* @param nonce 随机字符串
* @return 生成的xml字符串
*/
private String generateXml(String encrypt, String signature, String timestamp, String nonce) {
String format =
"<xml>\n"
+ "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+ "<TimeStamp>%3$s</TimeStamp>\n"
+ "<Nonce><![CDATA[%4$s]]></Nonce>\n"
+ "</xml>";
private String generateXml(String encrypt, String signature, String timestamp,
String nonce) {
String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n"
+ "</xml>";
return String.format(format, encrypt, signature, timestamp, nonce);
}


+ 0
- 4
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java Переглянути файл

@@ -14,8 +14,6 @@ public class FileUtils {
* @param name 文件名
* @param ext 扩展名
* @param tmpDirFile 临时文件夹目录
* @return
* @throws IOException
*/
public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException {
FileOutputStream fos = null;
@@ -56,8 +54,6 @@ public class FileUtils {
* @param inputStream
* @param name 文件名
* @param ext 扩展名
* @return
* @throws IOException
*/
public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException {
return createTmpFile(inputStream, name, ext, null);


+ 0
- 5
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/ApacheHttpClientBuilder.java Переглянути файл

@@ -17,35 +17,30 @@ public interface ApacheHttpClientBuilder {
/**
* 代理服务器地址
* @param httpProxyHost
* @return
*/
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost);

/**
* 代理服务器端口
* @param httpProxyPort
* @return
*/
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort);

/**
* 代理服务器用户名
* @param httpProxyUsername
* @return
*/
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername);

/**
* 代理服务器密码
* @param httpProxyPassword
* @return
*/
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword);

/**
* ssl连接socket工厂
* @param sslConnectionSocketFactory
* @return
*/
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
}

+ 0
- 1
weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java Переглянути файл

@@ -22,7 +22,6 @@ public interface RequestExecutor<T, E> {
* @param httpProxy http代理对象,如果没有配置代理则为空
* @param uri uri
* @param data 数据
* @return
* @throws WxErrorException
* @throws ClientProtocolException
* @throws IOException


+ 1
- 1
weixin-java-cp/pom.xml Переглянути файл

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>1.3.5</version>
<version>2.0.0-SNAPSHOT</version>
</parent>

<artifactId>weixin-java-cp</artifactId>


+ 0
- 2
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageMatcher.java Переглянути файл

@@ -9,8 +9,6 @@ public interface WxCpMessageMatcher {

/**
* 消息是否匹配某种模式
* @param message
* @return
*/
public boolean match(WxCpXmlMessage message);



+ 0
- 1
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouter.java Переглянути файл

@@ -124,7 +124,6 @@ public class WxCpMessageRouter {

/**
* 开始一个新的Route规则
* @return
*/
public WxCpMessageRouterRule rule() {
return new WxCpMessageRouterRule(this);


+ 0
- 15
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMessageRouterRule.java Переглянути файл

@@ -48,7 +48,6 @@ public class WxCpMessageRouterRule {
* 设置是否异步执行,默认是true
*
* @param async
* @return
*/
public WxCpMessageRouterRule async(boolean async) {
this.async = async;
@@ -59,7 +58,6 @@ public class WxCpMessageRouterRule {
* 如果agentId匹配
*
* @param agentId
* @return
*/
public WxCpMessageRouterRule agentId(Integer agentId) {
this.agentId = agentId;
@@ -70,7 +68,6 @@ public class WxCpMessageRouterRule {
* 如果msgType等于某值
*
* @param msgType
* @return
*/
public WxCpMessageRouterRule msgType(String msgType) {
this.msgType = msgType;
@@ -81,7 +78,6 @@ public class WxCpMessageRouterRule {
* 如果event等于某值
*
* @param event
* @return
*/
public WxCpMessageRouterRule event(String event) {
this.event = event;
@@ -92,7 +88,6 @@ public class WxCpMessageRouterRule {
* 如果eventKey等于某值
*
* @param eventKey
* @return
*/
public WxCpMessageRouterRule eventKey(String eventKey) {
this.eventKey = eventKey;
@@ -103,7 +98,6 @@ public class WxCpMessageRouterRule {
* 如果content等于某值
*
* @param content
* @return
*/
public WxCpMessageRouterRule content(String content) {
this.content = content;
@@ -114,7 +108,6 @@ public class WxCpMessageRouterRule {
* 如果content匹配该正则表达式
*
* @param regex
* @return
*/
public WxCpMessageRouterRule rContent(String regex) {
this.rContent = regex;
@@ -125,7 +118,6 @@ public class WxCpMessageRouterRule {
* 如果fromUser等于某值
*
* @param fromUser
* @return
*/
public WxCpMessageRouterRule fromUser(String fromUser) {
this.fromUser = fromUser;
@@ -136,7 +128,6 @@ public class WxCpMessageRouterRule {
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
*
* @param matcher
* @return
*/
public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) {
this.matcher = matcher;
@@ -147,7 +138,6 @@ public class WxCpMessageRouterRule {
* 设置微信消息拦截器
*
* @param interceptor
* @return
*/
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) {
return interceptor(interceptor, (WxCpMessageInterceptor[]) null);
@@ -158,7 +148,6 @@ public class WxCpMessageRouterRule {
*
* @param interceptor
* @param otherInterceptors
* @return
*/
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) {
this.interceptors.add(interceptor);
@@ -174,7 +163,6 @@ public class WxCpMessageRouterRule {
* 设置微信消息处理器
*
* @param handler
* @return
*/
public WxCpMessageRouterRule handler(WxCpMessageHandler handler) {
return handler(handler, (WxCpMessageHandler[]) null);
@@ -185,7 +173,6 @@ public class WxCpMessageRouterRule {
*
* @param handler
* @param otherHandlers
* @return
*/
public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) {
this.handlers.add(handler);
@@ -200,7 +187,6 @@ public class WxCpMessageRouterRule {
/**
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
*
* @return
*/
public WxCpMessageRouter end() {
this.routerBuilder.getRules().add(this);
@@ -210,7 +196,6 @@ public class WxCpMessageRouterRule {
/**
* 规则结束,但是消息还会进入其他规则
*
* @return
*/
public WxCpMessageRouter next() {
this.reEnter = true;


+ 4
- 25
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java Переглянути файл

@@ -32,7 +32,6 @@ public interface WxCpService {
* @param timestamp
* @param nonce
* @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息
* @return
*/
boolean checkSignature(String msgSignature, String timestamp, String nonce, String data);

@@ -49,7 +48,6 @@ public interface WxCpService {
/**
* 获取access_token, 不强制刷新access_token
* @see #getAccessToken(boolean)
* @return
* @throws WxErrorException
*/
String getAccessToken() throws WxErrorException;
@@ -63,7 +61,6 @@ public interface WxCpService {
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token
* </pre>
* @param forceRefresh 强制刷新
* @return
* @throws me.chanjar.weixin.common.exception.WxErrorException
*/
String getAccessToken(boolean forceRefresh) throws WxErrorException;
@@ -71,7 +68,6 @@ public interface WxCpService {
/**
* 获得jsapi_ticket,不强制刷新jsapi_ticket
* @see #getJsapiTicket(boolean)
* @return
* @throws WxErrorException
*/
public String getJsapiTicket() throws WxErrorException;
@@ -84,7 +80,6 @@ public interface WxCpService {
* 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
* </pre>
* @param forceRefresh 强制刷新
* @return
* @throws WxErrorException
*/
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
@@ -96,7 +91,6 @@ public interface WxCpService {
* 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95
* </pre>
* @param url url
* @return
*/
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException;

@@ -136,7 +130,7 @@ public interface WxCpService {
*
* @return 保存到本地的临时文件
* @throws WxErrorException
* @params media_id
* @param media_id
*/
File mediaDownload(String media_id) throws WxErrorException;

@@ -216,7 +210,6 @@ public interface WxCpService {
* </pre>
* @see #menuGet(String)
*
* @return
* @throws WxErrorException
*/
WxMenu menuGet() throws WxErrorException;
@@ -231,7 +224,6 @@ public interface WxCpService {
* @see #menuGet()
*
* @param agentId 企业号应用的id
* @return
* @throws WxErrorException
*/
WxMenu menuGet(String agentId) throws WxErrorException;
@@ -255,7 +247,6 @@ public interface WxCpService {
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口
* </pre>
*
* @return
* @throws WxErrorException
*/
List<WxCpDepart> departGet() throws WxErrorException;
@@ -291,7 +282,6 @@ public interface WxCpService {
* @param departId 必填。部门id
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
* @return
* @throws WxErrorException
*/
List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException;
@@ -306,7 +296,6 @@ public interface WxCpService {
* @param departId 必填。部门id
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
* @return
* @throws WxErrorException
*/
List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException;
@@ -350,7 +339,6 @@ public interface WxCpService {
* 获取用户
*
* @param userid
* @return
* @throws WxErrorException
*/
WxCpUser userGet(String userid) throws WxErrorException;
@@ -359,7 +347,6 @@ public interface WxCpService {
* 创建标签
*
* @param tagName
* @return
*/
String tagCreate(String tagName) throws WxErrorException;

@@ -381,7 +368,6 @@ public interface WxCpService {
/**
* 获得标签列表
*
* @return
*/
List<WxCpTag> tagGet() throws WxErrorException;

@@ -389,7 +375,6 @@ public interface WxCpService {
* 获取标签成员
*
* @param tagId
* @return
*/
List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException;

@@ -478,7 +463,6 @@ public interface WxCpService {
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求
* @param url
* @param queryParam
* @return
* @throws WxErrorException
*/
String get(String url, String queryParam) throws WxErrorException;
@@ -487,7 +471,6 @@ public interface WxCpService {
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求
* @param url
* @param postData
* @return
* @throws WxErrorException
*/
String post(String url, String postData) throws WxErrorException;
@@ -503,7 +486,6 @@ public interface WxCpService {
* @param data
* @param <T>
* @param <E>
* @return
* @throws WxErrorException
*/
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException;
@@ -536,7 +518,6 @@ public interface WxCpService {
/**
* 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。
* @param id id可以为任意字符串,建议使用FromUserName作为id
* @return
*/
WxSession getSession(String id);

@@ -544,7 +525,6 @@ public interface WxCpService {
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。
* @param id id可以为任意字符串,建议使用FromUserName作为id
* @param create
* @return
*/
WxSession getSession(String id, boolean create);

@@ -556,25 +536,24 @@ public interface WxCpService {
* @param sessionManager
*/
void setSessionManager(WxSessionManager sessionManager);
/**
* 上传部门列表覆盖企业号上的部门信息
* @param mediaId
* @throws WxErrorException
*/
String replaceParty(String mediaId) throws WxErrorException;
/**
* 上传用户列表覆盖企业号上的用户信息
* @param mediaId
* @throws WxErrorException
*/
String replaceUser(String mediaId) throws WxErrorException;
/**
* 获取异步任务结果
* @param joinId
* @return
* @throws WxErrorException
*/
String getTaskResult(String joinId) throws WxErrorException;


+ 0
- 6
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpServiceImpl.java Переглянути файл

@@ -510,12 +510,6 @@ public class WxCpServiceImpl implements WxCpService {

/**
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
*
* @param executor
* @param uri
* @param data
* @return
* @throws WxErrorException
*/
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
int retryTimes = 0;


+ 11
- 17
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpMessage.java Переглянути файл

@@ -28,7 +28,7 @@ public class WxCpMessage implements Serializable {
private String hqMusicUrl;
private String safe;
private List<WxArticle> articles = new ArrayList<WxArticle>();
public String getToUser() {
return toUser;
}
@@ -63,7 +63,7 @@ public class WxCpMessage implements Serializable {
public String getMsgType() {
return msgType;
}
public String getSafe() {
return safe;
}
@@ -135,18 +135,18 @@ public class WxCpMessage implements Serializable {
public void setArticles(List<WxArticle> articles) {
this.articles = articles;
}
public String toJson() {
return WxCpGsonBuilder.INSTANCE.create().toJson(this);
}
public static class WxArticle {
private String title;
private String description;
private String url;
private String picUrl;
public String getTitle() {
return title;
}
@@ -171,12 +171,11 @@ public class WxCpMessage implements Serializable {
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
}
/**
* 获得文本消息builder
* @return
*/
public static TextBuilder TEXT() {
return new TextBuilder();
@@ -184,7 +183,6 @@ public class WxCpMessage implements Serializable {

/**
* 获得图片消息builder
* @return
*/
public static ImageBuilder IMAGE() {
return new ImageBuilder();
@@ -192,23 +190,20 @@ public class WxCpMessage implements Serializable {

/**
* 获得语音消息builder
* @return
*/
public static VoiceBuilder VOICE() {
return new VoiceBuilder();
}
/**
* 获得视频消息builder
* @return
*/
public static VideoBuilder VIDEO() {
return new VideoBuilder();
}
/**
* 获得图文消息builder
* @return
*/
public static NewsBuilder NEWS() {
return new NewsBuilder();
@@ -216,10 +211,9 @@ public class WxCpMessage implements Serializable {

/**
* 获得文件消息builder
* @return
*/
public static FileBuilder FILE() {
return new FileBuilder();
}
}

+ 0
- 4
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlMessage.java Переглянути файл

@@ -198,7 +198,6 @@ public class WxCpXmlMessage implements Serializable {
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT}
* </pre>
*
* @return
*/
public String getMsgType() {
return msgType;
@@ -404,7 +403,6 @@ public class WxCpXmlMessage implements Serializable {
* @param timestamp
* @param nonce
* @param msgSignature
* @return
*/
public static WxCpXmlMessage fromEncryptedXml(
String encryptedXml,
@@ -542,7 +540,6 @@ public class WxCpXmlMessage implements Serializable {

/**
* 扫描类型,一般是qrcode
* @return
*/
public String getScanType() {

@@ -555,7 +552,6 @@ public class WxCpXmlMessage implements Serializable {

/**
* 扫描结果,即二维码对应的字符串信息
* @return
*/
public String getScanResult() {
return scanResult;


+ 6
- 12
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpXmlOutMessage.java Переглянути файл

@@ -14,14 +14,14 @@ public abstract class WxCpXmlOutMessage {
@XStreamAlias("ToUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
protected String toUserName;
@XStreamAlias("FromUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
protected String fromUserName;
@XStreamAlias("CreateTime")
protected Long createTime;
@XStreamAlias("MsgType")
@XStreamConverter(value=XStreamCDataConverter.class)
protected String msgType;
@@ -57,14 +57,13 @@ public abstract class WxCpXmlOutMessage {
public void setMsgType(String msgType) {
this.msgType = msgType;
}
protected String toXml() {
return XStreamTransformer.toXml((Class)this.getClass(), this);
}

/**
* 转换成加密的xml格式
* @return
*/
public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) {
String plainXml = toXml();
@@ -74,7 +73,6 @@ public abstract class WxCpXmlOutMessage {

/**
* 获得文本消息builder
* @return
*/
public static TextBuilder TEXT() {
return new TextBuilder();
@@ -82,7 +80,6 @@ public abstract class WxCpXmlOutMessage {

/**
* 获得图片消息builder
* @return
*/
public static ImageBuilder IMAGE() {
return new ImageBuilder();
@@ -90,23 +87,20 @@ public abstract class WxCpXmlOutMessage {

/**
* 获得语音消息builder
* @return
*/
public static VoiceBuilder VOICE() {
return new VoiceBuilder();
}
/**
* 获得视频消息builder
* @return
*/
public static VideoBuilder VIDEO() {
return new VideoBuilder();
}
/**
* 获得图文消息builder
* @return
*/
public static NewsBuilder NEWS() {
return new NewsBuilder();


+ 0
- 7
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java Переглянути файл

@@ -14,10 +14,6 @@ public class XStreamTransformer {

/**
* xml -> pojo
*
* @param clazz
* @param xml
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T fromXml(Class<T> clazz, String xml) {
@@ -43,9 +39,6 @@ public class XStreamTransformer {
/**
* pojo -> xml
*
* @param clazz
* @param object
* @return
*/
public static <T> String toXml(Class<T> clazz, T object) {
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);


+ 1
- 0
weixin-java-demo-with-spring/.gitignore Переглянути файл

@@ -0,0 +1 @@
*.pmd

+ 7
- 0
weixin-java-demo-with-spring/README.md Переглянути файл

@@ -0,0 +1,7 @@
#### 本Demo使用Spring MVC 框架实现微信公众号后台管理功能,支持多公众号,欢迎帮忙维护添加新功能,或提供更好的实现。
### 1. 配置
复制/src/main/resources/wx-gzh1.properties.template 生成wx-gzh1.properties 文件,填写相关配置;
复制/src/main/resources/wx-gzh2.properties.template 生成wx-gzh2.properties 文件,填写相关配置.
### 2. 使用maven运行demo程序
mvn jetty:run

+ 91
- 0
weixin-java-demo-with-spring/pom.xml Переглянути файл

@@ -0,0 +1,91 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>weixin-java-demo-with-spring</artifactId>
<packaging>war</packaging>
<name>WeiXin Java Tools - DemoWithSpring</name>
<description>spring demo</description>
<url>https://github.com/binarywang/weixin-java-tools</url>
<properties>
<spring.version>4.3.0.RELEASE</spring.version>
<spring-security.version>4.1.0.RELEASE</spring-security.version>
<guava.version>19.0</guava.version>
<slf4j.version>1.7.2</slf4j.version>
<aspectj.version>1.8.9</aspectj.version>
<fastjson.version>1.2.6</fastjson.version>
<commons-lang3.version>3.4</commons-lang3.version>
<jetty-maven-plugin.version>9.3.10.v20160621</jetty-maven-plugin.version>
</properties>

<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring-security.version}</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty-maven-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>

+ 80
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/aop/ControllerLogAspect.java Переглянути файл

@@ -0,0 +1,80 @@
package com.github.binarywang.demo.spring.aop;

import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

/**
*
* @author Binary Wang
*
*/
@Aspect
@Component
public class ControllerLogAspect {
private Logger logger = LoggerFactory.getLogger(getClass());

@Pointcut("within(com.github.binarywang.demo.spring..*.controller..*)")
public void inController() {
}

@Pointcut("execution(public * com.github.binarywang.demo.spring..*.controller..*.*(..))")
public void controller() {
}

@Before("inController()")
public void writeBeforeLog(JoinPoint jp) {
this.debugInController(jp, "Start");
}

@After("inController()")
public void writeAfterLog(JoinPoint jp) {
this.debugInController(jp, "End");
}

private void debugInController(JoinPoint jp, String msg) {
String userName = getLoginUserName();

this.logger.debug("\n【{}】{}.{}() {} ", userName,
jp.getTarget()
.getClass().getSimpleName(), jp.getSignature().getName(), msg);
}

private static String getLoginUserName() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null) {
return authentication.getName();
}

return "Anonymous";
}

@Before("controller()")
public void writeParams(JoinPoint jp) {
String[] names = ((CodeSignature) jp.getSignature())
.getParameterNames();
Object[] args = jp.getArgs();

if (ArrayUtils.isEmpty(names)) {
return;
}

StringBuilder sb = new StringBuilder("Arguments: ");
for (int i = 0; i < names.length; i++) {
sb.append(names[i] + " = " + args[i] + ",");
}

debugInController(jp, sb.toString());
}

}

+ 21
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/AbstractBuilder.java Переглянути файл

@@ -0,0 +1,21 @@
package com.github.binarywang.demo.spring.builder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class AbstractBuilder {
protected final Logger logger = LoggerFactory.getLogger(getClass());

public abstract WxMpXmlOutMessage build(String content,
WxMpXmlMessage wxMessage, BaseWxService service) ;
}

+ 27
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/ImageBuilder.java Переглянути файл

@@ -0,0 +1,27 @@
package com.github.binarywang.demo.spring.builder;

import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutImageMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public class ImageBuilder extends AbstractBuilder {

@Override
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
BaseWxService service) {

WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content)
.fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName())
.build();

return m;
}

}

+ 25
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/builder/TextBuilder.java Переглянути файл

@@ -0,0 +1,25 @@
package com.github.binarywang.demo.spring.builder;

import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutTextMessage;

/**
*
* @author Binary Wang
*
*/
public class TextBuilder extends AbstractBuilder {

@Override
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
BaseWxService service) {
WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content)
.fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName())
.build();
return m;
}

}

+ 41
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxAccountEnum.java Переглянути файл

@@ -0,0 +1,41 @@
package com.github.binarywang.demo.spring.config;

/**
* 公众号标识的枚举类
* @author Binary Wang
*
*/
public enum WxAccountEnum {
GZH1(1, "公众号1"),
GZH2(2, "公众号2");

private int pubid;
private String name;

private WxAccountEnum(int pubid, String name) {
this.name = name;
this.pubid = pubid;
}

public int getPubid() {
return this.pubid;
}

public String getName() {
return this.name;
}

public static int queryPubid(String wxCode) {
return WxAccountEnum.valueOf(wxCode.toUpperCase()).getPubid();
}

public static String queryWxCode(int pubid) {
for (WxAccountEnum e : values()) {
if (e.getPubid() == pubid) {
return e.name().toLowerCase();
}
}

return null;
}
}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxConfig.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.config;

/**
* 微信配置的抽象实现类
* @author Binary Wang
*
*/
public abstract class WxConfig {
public abstract String getToken();

public abstract String getAppid();

public abstract String getAppsecret();

public abstract String getAesKey();

public abstract WxAccountEnum getWxAccountEnum();

public int getPubId() {
return getWxAccountEnum().getPubid();
}

}

+ 50
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh1Config.java Переглянути файл

@@ -0,0 +1,50 @@
package com.github.binarywang.demo.spring.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
*
* @author Binary Wang
*
*/
@Configuration
public class WxGzh1Config extends WxConfig {
@Value("#{gzh1WxProperties.wx_token}")
private String token;

@Value("#{gzh1WxProperties.wx_appid}")
private String appid;

@Value("#{gzh1WxProperties.wx_appsecret}")
private String appsecret;

@Value("#{gzh1WxProperties.wx_aeskey}")
private String aesKey;

@Override
public String getToken() {
return this.token;
}

@Override
public String getAppid() {
return this.appid;
}

@Override
public String getAppsecret() {
return this.appsecret;
}

@Override
public String getAesKey() {
return this.aesKey;
}

@Override
public WxAccountEnum getWxAccountEnum() {
return WxAccountEnum.GZH1;
}

}

+ 50
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/config/WxGzh2Config.java Переглянути файл

@@ -0,0 +1,50 @@
package com.github.binarywang.demo.spring.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
*
* @author Binary Wang
*
*/
@Configuration
public class WxGzh2Config extends WxConfig {
@Value("#{gzh2WxProperties.wx_token}")
private String token;

@Value("#{gzh2WxProperties.wx_appid}")
private String appid;

@Value("#{gzh2WxProperties.wx_appsecret}")
private String appsecret;

@Value("#{gzh2WxProperties.wx_aeskey}")
private String aesKey;

@Override
public String getToken() {
return this.token;
}

@Override
public String getAppid() {
return this.appid;
}

@Override
public String getAppsecret() {
return this.appsecret;
}

@Override
public String getAesKey() {
return this.aesKey;
}

@Override
public WxAccountEnum getWxAccountEnum() {
return WxAccountEnum.GZH2;
}

}

+ 80
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/AbstractWxPortalController.java Переглянути файл

@@ -0,0 +1,80 @@
package com.github.binarywang.demo.spring.controller;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class AbstractWxPortalController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@RequestMapping(method = RequestMethod.GET, produces = "text/plain;charset=utf-8")
public @ResponseBody String authGet(
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("echostr") String echostr) {
this.logger.info("\n接收到来自微信服务器的认证消息:[{},{},{},{}]",
signature, timestamp, nonce, echostr);

if (this.getWxService().checkSignature(timestamp, nonce, signature)) {
return echostr;
}

return "非法请求";
}

@RequestMapping(method = RequestMethod.POST, produces = "application/xml; charset=UTF-8")
public @ResponseBody String post(@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("encrypt_type") String encType,
@RequestParam("msg_signature") String msgSignature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce) {
this.logger.info("\n接收微信请求:[{},{},{},{},{}]\n{} ",
signature, encType, msgSignature, timestamp, nonce, requestBody);

String out = null;
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toXml();
}else if ("aes".equals(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody,
this.getWxService().getWxMpConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);
if (outMessage == null) {
return "";
}

out = outMessage.toEncryptedXml(this.getWxService().getWxMpConfigStorage());
}

this.logger.debug("\n组装回复信息:{}", out);

return out;
}

protected abstract BaseWxService getWxService();

}

+ 26
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh1WxPortalController.java Переглянути файл

@@ -0,0 +1,26 @@
package com.github.binarywang.demo.spring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.github.binarywang.demo.spring.service.BaseWxService;
import com.github.binarywang.demo.spring.service.Gzh1WxService;

/**
* 第一个公众号的微信交互接口
* @author Binary Wang
*
*/
@RestController
@RequestMapping("/api/gzh1/portal")
public class Gzh1WxPortalController extends AbstractWxPortalController{
@Autowired
private Gzh1WxService wxService;
@Override
protected BaseWxService getWxService() {
return this.wxService;
}

}

+ 26
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/controller/Gzh2WxPortalController.java Переглянути файл

@@ -0,0 +1,26 @@
package com.github.binarywang.demo.spring.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.github.binarywang.demo.spring.service.BaseWxService;
import com.github.binarywang.demo.spring.service.Gzh2WxService;

/**
* 第二个公众号的微信交互接口
* @author Binary Wang
*
*/
@RestController
@RequestMapping("/api/gzh2/portal")
public class Gzh2WxPortalController extends AbstractWxPortalController{
@Autowired
private Gzh2WxService wxService;
@Override
protected BaseWxService getWxService() {
return this.wxService;
}

}

+ 44
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/dto/WxMenuKey.java Переглянути файл

@@ -0,0 +1,44 @@
package com.github.binarywang.demo.spring.dto;

import org.apache.commons.lang3.builder.ToStringBuilder;

/**
* 菜单的dto对象
* @author Binary Wang
*
*/
public class WxMenuKey {
private String type;
private String content;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}

public WxMenuKey() {

}

public WxMenuKey(String type, String content) {
this.type = type;
this.content = content;
}

public String getType() {
return this.type;
}

public void setType(String type) {
this.type = type;
}

public String getContent() {
return this.content;
}

public void setContent(String content) {
this.content = content;
}

}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/AbstractHandler.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.google.gson.Gson;

import me.chanjar.weixin.mp.api.WxMpMessageHandler;

/**
*
* @author Binary Wang
*
*/
public abstract class AbstractHandler implements WxMpMessageHandler {

protected Logger logger = LoggerFactory.getLogger(getClass());
protected final Gson gson = new Gson();

protected abstract WxConfig getWxConfig();
}

+ 36
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/KfSessionHandler.java Переглянути файл

@@ -0,0 +1,36 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
@Component
public class KfSessionHandler extends AbstractHandler{

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) throws WxErrorException {
//TODO 对会话做处理
return null;
}

@Override
protected WxConfig getWxConfig() {
return null;
}

}

+ 47
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LocationHandler.java Переглянути файл

@@ -0,0 +1,47 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import com.github.binarywang.demo.spring.builder.TextBuilder;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class LocationHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) throws WxErrorException {
if (wxMessage.getMsgType().equals(WxConsts.XML_MSG_LOCATION)) {
//TODO 接收处理用户发送的地理位置消息
try {
String content = "感谢反馈,您的的地理位置已收到!";
return new TextBuilder().build(content, wxMessage, null);
} catch (Exception e) {
this.logger.error("位置消息接收处理失败", e);
return null;
}
}

//上报地理位置事件
this.logger.info("\n上报地理位置 。。。 ");
this.logger.info("\n纬度 : " + wxMessage.getLatitude());
this.logger.info("\n经度 : " + wxMessage.getLongitude());
this.logger.info("\n精度 : " + String.valueOf(wxMessage.getPrecision()));
//TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
return null;
}

}

+ 34
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/LogHandler.java Переглянути файл

@@ -0,0 +1,34 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
@Component
public class LogHandler extends AbstractHandler {
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
this.logger.info("\n接收到请求消息,内容:【{}】", wxMessage.toString());
return null;
}

@Override
protected WxConfig getWxConfig() {
return null;
}

}

+ 71
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MenuHandler.java Переглянути файл

@@ -0,0 +1,71 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.demo.spring.builder.AbstractBuilder;
import com.github.binarywang.demo.spring.builder.ImageBuilder;
import com.github.binarywang.demo.spring.builder.TextBuilder;
import com.github.binarywang.demo.spring.dto.WxMenuKey;
import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class MenuHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
BaseWxService weixinService = (BaseWxService) wxMpService;

String key = wxMessage.getEventKey();
WxMenuKey menuKey = null;
try {
menuKey = JSON.parseObject(key, WxMenuKey.class);
} catch (Exception e) {
return WxMpXmlOutMessage.TEXT().content(key)
.fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName()).build();
}

AbstractBuilder builder = null;
switch (menuKey.getType()) {
case WxConsts.XML_MSG_TEXT:
builder = new TextBuilder();
break;
case WxConsts.XML_MSG_IMAGE:
builder = new ImageBuilder();
break;
case WxConsts.XML_MSG_VOICE:
break;
case WxConsts.XML_MSG_VIDEO:
break;
case WxConsts.XML_MSG_NEWS:
break;
default:
break;
}

if (builder != null) {
try {
return builder.build(menuKey.getContent(), wxMessage, weixinService);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}
}

return null;

}

}

+ 48
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/MsgHandler.java Переглянути файл

@@ -0,0 +1,48 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.github.binarywang.demo.spring.builder.TextBuilder;
import com.github.binarywang.demo.spring.service.BaseWxService;

import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class MsgHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {

BaseWxService weixinService = (BaseWxService) wxMpService;

if (!wxMessage.getMsgType().equals(WxConsts.XML_MSG_EVENT)) {
//TODO 可以选择将消息保存到本地
}

//当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服
if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服")
&& weixinService.hasKefuOnline()) {
return WxMpXmlOutMessage
.TRANSFER_CUSTOMER_SERVICE().fromUser(wxMessage.getToUserName())
.toUser(wxMessage.getFromUserName()).build();
}

//TODO 组装回复消息
String content = "回复信息内容";
return new TextBuilder().build(content, wxMessage, weixinService);

}

}

+ 34
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/NullHandler.java Переглянути файл

@@ -0,0 +1,34 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
@Component
public class NullHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
return null;
}

@Override
protected WxConfig getWxConfig() {
return null;
}

}

+ 10
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/ScanHandler.java Переглянути файл

@@ -0,0 +1,10 @@
package com.github.binarywang.demo.spring.handler;

/**
*
* @author Binary Wang
*
*/
public abstract class ScanHandler extends AbstractHandler {

}

+ 61
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/SubscribeHandler.java Переглянути файл

@@ -0,0 +1,61 @@
package com.github.binarywang.demo.spring.handler;

import com.github.binarywang.demo.spring.builder.TextBuilder;
import com.github.binarywang.demo.spring.service.BaseWxService;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;

import java.util.Map;

/**
*
* @author Binary Wang
*
*/
public abstract class SubscribeHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) throws WxErrorException {

this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUserName());

BaseWxService weixinService = (BaseWxService) wxMpService;

// 获取微信用户基本信息
WxMpUser userWxInfo = weixinService.getUserService().userInfo(wxMessage.getFromUserName(), null);

if (userWxInfo != null) {
// TODO 可以添加关注用户到本地
}

WxMpXmlOutMessage responseResult = null;
try {
responseResult = handleSpecial(wxMessage);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

if (responseResult != null) {
return responseResult;
}

try {
return new TextBuilder().build("感谢关注", wxMessage, weixinService);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

return null;
}

/**
* 处理特殊请求,比如如果是扫码进来的,可以做相应处理
*/
protected abstract WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) throws Exception;

}

+ 27
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/UnsubscribeHandler.java Переглянути файл

@@ -0,0 +1,27 @@
package com.github.binarywang.demo.spring.handler;

import java.util.Map;

import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

/**
*
* @author Binary Wang
*
*/
public abstract class UnsubscribeHandler extends AbstractHandler {

@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
String openId = wxMessage.getFromUserName();
this.logger.info("取消关注用户 OPENID: " + openId);
// TODO 可以更新本地数据库为取消关注状态
return null;
}

}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1LocationHandler.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.handler.gzh1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.handler.LocationHandler;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Gzh1LocationHandler extends LocationHandler {
@Autowired
private WxGzh1Config wxConfig;

@Override
protected WxConfig getWxConfig() {
return this.wxConfig;
}

}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MenuHandler.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.handler.gzh1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.handler.MenuHandler;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Gzh1MenuHandler extends MenuHandler {
@Autowired
private WxGzh1Config wxConfig;

@Override
protected WxConfig getWxConfig() {
return this.wxConfig;
}

}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1MsgHandler.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.handler.gzh1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.handler.MsgHandler;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Gzh1MsgHandler extends MsgHandler {
@Autowired
private WxGzh1Config wxConfig;

@Override
protected WxConfig getWxConfig() {
return this.wxConfig;
}

}

+ 32
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1SubscribeHandler.java Переглянути файл

@@ -0,0 +1,32 @@
package com.github.binarywang.demo.spring.handler.gzh1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.handler.SubscribeHandler;

import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Gzh1SubscribeHandler extends SubscribeHandler {
@Autowired
private WxGzh1Config wxConfig;

@Override
protected WxConfig getWxConfig() {
return this.wxConfig;
}

@Override
protected WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
throws Exception {
return null;
}

}

+ 23
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/handler/gzh1/Gzh1UnSubscribeHandler.java Переглянути файл

@@ -0,0 +1,23 @@
package com.github.binarywang.demo.spring.handler.gzh1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.handler.UnsubscribeHandler;

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Gzh1UnSubscribeHandler extends UnsubscribeHandler {
@Autowired
private WxGzh1Config wxConfig;

@Override
protected WxConfig getWxConfig() {
return this.wxConfig;
}

}

+ 138
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/BaseWxService.java Переглянути файл

@@ -0,0 +1,138 @@
package com.github.binarywang.demo.spring.service;

import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.handler.*;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;

/**
*
* @author Binary Wang
*
*/
public abstract class BaseWxService extends WxMpServiceImpl {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
protected LogHandler logHandler;

@Autowired
protected NullHandler nullHandler;

@Autowired
protected KfSessionHandler kfSessionHandler;

private WxMpMessageRouter router;

protected abstract WxConfig getServerConfig();

protected abstract MenuHandler getMenuHandler();

protected abstract SubscribeHandler getSubscribeHandler();

protected abstract UnsubscribeHandler getUnsubscribeHandler();

protected abstract AbstractHandler getLocationHandler();

protected abstract MsgHandler getMsgHandler();
protected abstract AbstractHandler getScanHandler();

@PostConstruct
public void init() {
final WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();
config.setAppId(this.getServerConfig().getAppid());// 设置微信公众号的appid
config.setSecret(this.getServerConfig().getAppsecret());// 设置微信公众号的app corpSecret
config.setToken(this.getServerConfig().getToken());// 设置微信公众号的token
config.setAesKey(this.getServerConfig().getAesKey());// 设置消息加解密密钥
super.setWxMpConfigStorage(config);

this.refreshRouter();
}

private void refreshRouter() {

final WxMpMessageRouter newRouter = new WxMpMessageRouter(this);

// 记录所有事件的日志
newRouter.rule().handler(this.logHandler).next();

// 接收客服会话管理事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_KF_CREATE_SESSION).handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_KF_CLOSE_SESSION).handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_KF_SWITCH_SESSION).handler(this.kfSessionHandler).end();
// 自定义菜单事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.BUTTON_CLICK).handler(this.getMenuHandler()).end();

// 点击菜单连接事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.BUTTON_VIEW).handler(this.nullHandler).end();

// 关注事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_SUBSCRIBE).handler(this.getSubscribeHandler())
.end();

// 取消关注事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_UNSUBSCRIBE).handler(this.getUnsubscribeHandler())
.end();

// 上报地理位置事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_LOCATION).handler(this.getLocationHandler()).end();

// 接收地理位置消息
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_LOCATION)
.handler(this.getLocationHandler()).end();

// 扫码事件
newRouter.rule().async(false).msgType(WxConsts.XML_MSG_EVENT)
.event(WxConsts.EVT_SCAN).handler(this.getScanHandler()).end();

// 默认
newRouter.rule().async(false).handler(this.getMsgHandler()).end();

this.router = newRouter;
}


public WxMpXmlOutMessage route(WxMpXmlMessage message) {
try {
return this.router.route(message);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}

return null;
}

public boolean hasKefuOnline() {
try {
WxMpKfOnlineList kfOnlineList = this.getKefuService().kfOnlineList();
return kfOnlineList != null && kfOnlineList.getKfOnlineList().size() > 0;
} catch (Exception e) {
this.logger.error("获取客服在线状态异常: " + e.getMessage(), e);
}

return false;
}

}

+ 79
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh1WxService.java Переглянути файл

@@ -0,0 +1,79 @@
package com.github.binarywang.demo.spring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.binarywang.demo.spring.config.WxGzh1Config;
import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.handler.AbstractHandler;
import com.github.binarywang.demo.spring.handler.MenuHandler;
import com.github.binarywang.demo.spring.handler.MsgHandler;
import com.github.binarywang.demo.spring.handler.SubscribeHandler;
import com.github.binarywang.demo.spring.handler.UnsubscribeHandler;
import com.github.binarywang.demo.spring.handler.gzh1.Gzh1LocationHandler;
import com.github.binarywang.demo.spring.handler.gzh1.Gzh1MenuHandler;
import com.github.binarywang.demo.spring.handler.gzh1.Gzh1MsgHandler;
import com.github.binarywang.demo.spring.handler.gzh1.Gzh1SubscribeHandler;
import com.github.binarywang.demo.spring.handler.gzh1.Gzh1UnSubscribeHandler;

/**
*
* @author Binary Wang
*
*/
@Service
public class Gzh1WxService extends BaseWxService {
@Autowired
private WxGzh1Config wxConfig;

@Autowired
private Gzh1LocationHandler locationHandler;
@Autowired
private Gzh1MenuHandler menuHandler;
@Autowired
private Gzh1MsgHandler msgHandler;
@Autowired
private Gzh1UnSubscribeHandler unSubscribeHandler;
@Autowired
private Gzh1SubscribeHandler subscribeHandler;

@Override
protected WxConfig getServerConfig() {
return this.wxConfig;
}

@Override
protected MenuHandler getMenuHandler() {
return this.menuHandler;
}

@Override
protected SubscribeHandler getSubscribeHandler() {
return this.subscribeHandler;
}

@Override
protected UnsubscribeHandler getUnsubscribeHandler() {
return this.unSubscribeHandler;
}

@Override
protected AbstractHandler getLocationHandler() {
return this.locationHandler;
}

@Override
protected MsgHandler getMsgHandler() {
return this.msgHandler;
}

@Override
protected AbstractHandler getScanHandler() {
return null;
}

}

+ 66
- 0
weixin-java-demo-with-spring/src/main/java/com/github/binarywang/demo/spring/service/Gzh2WxService.java Переглянути файл

@@ -0,0 +1,66 @@
package com.github.binarywang.demo.spring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.binarywang.demo.spring.config.WxGzh2Config;
import com.github.binarywang.demo.spring.config.WxConfig;
import com.github.binarywang.demo.spring.handler.AbstractHandler;
import com.github.binarywang.demo.spring.handler.MenuHandler;
import com.github.binarywang.demo.spring.handler.MsgHandler;
import com.github.binarywang.demo.spring.handler.SubscribeHandler;
import com.github.binarywang.demo.spring.handler.UnsubscribeHandler;

/**
*
* @author Binary Wang
*
*/
@Service
public class Gzh2WxService extends BaseWxService {

@Autowired
private WxGzh2Config wxConfig;

@Override
protected WxConfig getServerConfig() {
return this.wxConfig;
}

@Override
protected MenuHandler getMenuHandler() {
// TODO Auto-generated method stub
return null;
}

@Override
protected SubscribeHandler getSubscribeHandler() {
// TODO Auto-generated method stub
return null;
}

@Override
protected UnsubscribeHandler getUnsubscribeHandler() {
// TODO Auto-generated method stub
return null;
}

@Override
protected AbstractHandler getLocationHandler() {
// TODO Auto-generated method stub
return null;
}

@Override
protected MsgHandler getMsgHandler() {
// TODO Auto-generated method stub
return null;
}

@Override
protected AbstractHandler getScanHandler() {
// TODO Auto-generated method stub
return null;
}

}

+ 2
- 0
weixin-java-demo-with-spring/src/main/resources/.gitignore Переглянути файл

@@ -0,0 +1,2 @@
/wx-gzh1.properties
/wx-gzh2.properties

+ 17
- 0
weixin-java-demo-with-spring/src/main/resources/applicationContext.xml Переглянути файл

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<import resource="classpath*:spring-service-bean.xml" />

<util:properties id="gzh1WxProperties" location="classpath:/wx-gzh1.properties" />
<util:properties id="gzh2WxProperties" location="classpath:/wx-gzh2.properties" />

</beans>

+ 8
- 0
weixin-java-demo-with-spring/src/main/resources/log4j.properties Переглянути файл

@@ -0,0 +1,8 @@
log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%t]:%c:%L#%M() %m%n

log4j.logger.org.apache.http.impl.conn.PoolingHttpClientConnectionManager=INFO

+ 29
- 0
weixin-java-demo-with-spring/src/main/resources/spring-service-bean.xml Переглянути файл

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:amq="http://activemq.apache.org/schema/core" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:component-scan base-package="com.github.binarywang.demo.spring">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg>
<value>UTF-8</value>
</constructor-arg>
</bean>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>

</beans>

+ 43
- 0
weixin-java-demo-with-spring/src/main/resources/spring-servlet-common.xml Переглянути файл

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!-- only scan the Controller class for web context -->
<context:component-scan base-package="com.github.binarywang.demo.spring">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="jsonConverter" />
<ref bean="stringHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>

<mvc:default-servlet-handler />

<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>

<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>

<aop:aspectj-autoproxy proxy-target-class="true" />

</beans>

+ 4
- 0
weixin-java-demo-with-spring/src/main/resources/wx-gzh1.properties.template Переглянути файл

@@ -0,0 +1,4 @@
wx_appid=
wx_appsecret=
wx_token=
wx_aeskey=

+ 4
- 0
weixin-java-demo-with-spring/src/main/resources/wx-gzh2.properties.template Переглянути файл

@@ -0,0 +1,4 @@
wx_appid=
wx_appsecret=
wx_token=
wx_aeskey=

spring-demo/src/main/webapp/WEB-INF/web.xml → weixin-java-demo-with-spring/src/main/webapp/WEB-INF/web.xml Переглянути файл

@@ -20,14 +20,6 @@
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/v1/admin/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

+ 7
- 1
weixin-java-mp/pom.xml Переглянути файл

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-parent</artifactId>
<version>1.3.5</version>
<version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>weixin-java-mp</artifactId>
<name>WeiXin Java Tools - MP</name>
@@ -47,6 +47,12 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency><!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
<scope>test</scope>
</dependency>
</dependencies>



+ 69
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpGroupService.java Переглянути файл

@@ -0,0 +1,69 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.WxMpGroup;

import java.util.List;

/**
* 用户分组相关操作接口
* @author Binary Wang
*
*/
public interface WxMpGroupService {


/**
* <pre>
* 分组管理接口 - 创建分组
* 最多支持创建500个分组
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
* </pre>
*
* @param name 分组名字(30个字符以内)
*/
public WxMpGroup groupCreate(String name) throws WxErrorException;

/**
* <pre>
* 分组管理接口 - 查询所有分组
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
* </pre>
*/
public List<WxMpGroup> groupGet() throws WxErrorException;

/**
* <pre>
* 分组管理接口 - 查询用户所在分组
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
* </pre>
*
* @param openid 微信用户的openid
*/
public long userGetGroup(String openid) throws WxErrorException;

/**
* <pre>
* 分组管理接口 - 修改分组名
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
*
* 如果id为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
* </pre>
*
* @param group 要更新的group,group的id,name必须设置
*/
public void groupUpdate(WxMpGroup group) throws WxErrorException;

/**
* <pre>
* 分组管理接口 - 移动用户分组
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口
*
* 如果to_groupid为0(未分组),1(黑名单),2(星标组),或者不存在的id,微信会返回系统繁忙的错误
* </pre>
*
* @param openid 用户openid
* @param to_groupid 移动到的分组id
*/
public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException;
}

+ 172
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpKefuService.java Переглянути файл

@@ -0,0 +1,172 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.result.*;

import java.io.File;
import java.util.Date;

/**
* 客服接口 ,
* 命名采用kefu拼音的原因是:
* 其英文CustomerService如果再加上Service后缀显得有点啰嗦,
* 如果不加又显得表意不完整
*
* @author Binary Wang
*/
public interface WxMpKefuService {

//*******************客服管理接口***********************//

/**
* <pre>
* 获取客服基本信息
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
* </pre>
*/
WxMpKfList kfList() throws WxErrorException;

/**
* <pre>
* 获取在线客服接待信息
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN
* </pre>
*/
WxMpKfOnlineList kfOnlineList() throws WxErrorException;

/**
* <pre>
* 添加客服账号
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
* </pre>
*/
boolean kfAccountAdd(WxMpKfAccountRequest request) throws WxErrorException;

/**
* <pre>
* 设置客服信息(即更新客服信息)
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
* </pre>
*/
boolean kfAccountUpdate(WxMpKfAccountRequest request) throws WxErrorException;

/**
* <pre>
* 设置客服信息(即更新客服信息)
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN
* </pre>
*/
boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException;

/**
* <pre>
* 上传客服头像
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:http://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
* </pre>
*/
boolean kfAccountUploadHeadImg(String kfAccount, File imgFile)
throws WxErrorException;

/**
* <pre>
* 删除客服账号
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044813&token=&lang=zh_CN">客服管理</a>
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
* </pre>
*/
boolean kfAccountDel(String kfAccount) throws WxErrorException;

//*******************客服会话控制接口***********************//

/**
* <pre>
* 创建会话
* 此接口在客服和用户之间创建一个会话,如果该客服和用户会话已存在,则直接返回0。指定的客服帐号必须已经绑定微信号且在线。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044820&token=&lang=zh_CN">客服会话控制接口</a>
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN
* </pre>
*/
boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException;

/**
* <pre>
* 关闭会话
* 开发者可以使用本接口,关闭一个会话。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044820&token=&lang=zh_CN">客服会话控制接口</a>
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN
* </pre>
*/
boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException;

/**
* <pre>
* 获取客户的会话状态
* 此接口获取一个客户的会话,如果不存在,则kf_account为空。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044820&token=&lang=zh_CN">客服会话控制接口</a>
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID
* </pre>
*/
WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException;

/**
* <pre>
* 获取客服的会话列表
* 开发者可以通过本接口获取某个客服正在接待的会话列表。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044820&token=&lang=zh_CN">客服会话控制</a>
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
* </pre>
*/
WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException;

/**
* <pre>
* 获取未接入会话列表
* 开发者可以通过本接口获取当前正在等待队列中的会话列表,此接口最多返回最早进入队列的100个未接入会话。
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1458044820&token=&lang=zh_CN">客服会话控制</a>
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getwaitcase?access_token=ACCESS_TOKEN
* </pre>
*/
WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException;

//*******************获取聊天记录的接口***********************//

/**
* <pre>
* 获取聊天记录(原始接口)
* 此接口返回的聊天记录中,对于图片、语音、视频,分别展示成文本格式的[image]、[voice]、[video]
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1464937269_mUtmK&token=&lang=zh_CN">获取聊天记录</a>
* 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
* </pre>
*
* @param startTime 起始时间
* @param endTime 结束时间
* @param msgId 消息id顺序从小到大,从1开始
* @param number 每次获取条数,最多10000条
* @return 聊天记录对象
* @throws WxErrorException
*/
WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException;

/**
* <pre>
* 获取聊天记录(优化接口,返回指定时间段内所有的聊天记录)
* 此接口返回的聊天记录中,对于图片、语音、视频,分别展示成文本格式的[image]、[voice]、[video]
* 详情请见:<a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1464937269_mUtmK&token=&lang=zh_CN">获取聊天记录</a>
* 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
* </pre>
*
* @param startTime 起始时间
* @param endTime 结束时间
* @return 聊天记录对象
* @throws WxErrorException
*/
WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException;

}

+ 195
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java Переглянути файл

@@ -0,0 +1,195 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.*;
import me.chanjar.weixin.mp.bean.result.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
* Created by Binary Wang on 2016/7/21.
* 素材管理的相关接口,包括媒体管理的接口,
* 即以https://api.weixin.qq.com/cgi-bin/material
* 和 https://api.weixin.qq.com/cgi-bin/media开头的接口
*/
public interface WxMpMaterialService {

/**
* 新增临时素材
*
* @param mediaType
* @param file
* @throws WxErrorException
* @see #mediaUpload(String, String, InputStream)
*/
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException;

/**
* <pre>
* 获取临时素材
* 本接口即为原“下载多媒体文件”接口。
* 根据微信文档,视频文件下载不了,会返回null
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/9/677a85e3f3849af35de54bb5516c2521.html">获取临时素材</a>
* </pre>
*
* @param media_id
* @return 保存到本地的临时文件
* @throws WxErrorException
*/
public File mediaDownload(String media_id) throws WxErrorException;

/**
* <pre>
* 上传图文消息内的图片获取URL
* 详情请见:http://mp.weixin.qq.com/wiki/15/40b6865b893947b764e2de8e4a1fb55f.html#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E5.86.85.E7.9A.84.E5.9B.BE.E7.89.87.E8.8E.B7.E5.8F.96URL.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91
* </pre>
*
* @param file
* @return WxMediaImgUploadResult 返回图片url
* @throws WxErrorException
*/
public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException;

/**
* <pre>
* 新增临时素材
* 本接口即为原“上传多媒体文件”接口。
*
* 上传的多媒体文件有格式和大小限制,如下:
* 图片(image): 1M,支持JPG格式
* 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
* 视频(video):10MB,支持MP4格式
* 缩略图(thumb):64KB,支持JPG格式
*
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/15/2d353966323806a202cd2deaafe8e557.html">新增临时素材</a>
* </pre>
*
* @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param inputStream 输入流
* @throws WxErrorException
*/
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException;

/**
* <pre>
* 上传非图文永久素材
*
* 上传的多媒体文件有格式和大小限制,如下:
* 图片(image): 图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式
* 语音(voice):语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式
* 视频(video):在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息,内容格式为JSON
* 缩略图(thumb):文档未说明
*
* 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
* </pre>
*
* @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param material 上传的素材, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterial}
*/
public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException;

/**
* <pre>
* 上传永久图文素材
*
* 详情请见: http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html
* </pre>
*
* @param news 上传的图文消息, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialNews}
*/
public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException;

/**
* <pre>
* 下载声音或者图片永久素材
*
* 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
* </pre>
*
* @param media_id 永久素材的id
*/
public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException;

/**
* <pre>
* 获取视频永久素材的信息和下载地址
*
* 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
* </pre>
*
* @param media_id 永久素材的id
*/
public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException;

/**
* <pre>
* 获取图文永久素材的信息
*
* 详情请见: http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html
* </pre>
*
* @param media_id 永久素材的id
*/
public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException;

/**
* <pre>
* 更新图文永久素材
*
* 详情请见: http://mp.weixin.qq.com/wiki/4/19a59cba020d506e767360ca1be29450.html
* </pre>
*
* @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate}
*/
public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException;

/**
* <pre>
* 删除永久素材
*
* 详情请见: http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html
* </pre>
*
* @param media_id 永久素材的id
*/
public boolean materialDelete(String media_id) throws WxErrorException;

/**
* <pre>
* 获取各类素材总数
*
* 详情请见: http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html
* </pre>
*/
public WxMpMaterialCountResult materialCount() throws WxErrorException;

/**
* <pre>
* 分页获取图文素材列表
*
* 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
* </pre>
*
* @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
* @param count 返回素材的数量,取值在1到20之间
*/
public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException;

/**
* <pre>
* 分页获取其他媒体素材列表
*
* 详情请见: http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html
* </pre>
*
* @param type 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
* @param count 返回素材的数量,取值在1到20之间
*/
public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException;

}

+ 59
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java Переглянути файл

@@ -0,0 +1,59 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.bean.WxMenu;
import me.chanjar.weixin.common.exception.WxErrorException;

/**
* 菜单相关操作接口
*
* @author Binary Wang
*/
public interface WxMpMenuService {

/**
* <pre>
* 自定义菜单创建接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单创建接口
* 如果要创建个性化菜单,请设置matchrule属性
* 详情请见:http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* </pre>
*/
public void menuCreate(WxMenu menu) throws WxErrorException;

/**
* <pre>
* 自定义菜单删除接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单删除接口
* </pre>
*/
public void menuDelete() throws WxErrorException;

/**
* <pre>
* 删除个性化菜单接口
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* </pre>
*
* @param menuid
*/
public void menuDelete(String menuid) throws WxErrorException;

/**
* <pre>
* 自定义菜单查询接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=自定义菜单查询接口
* </pre>
*/
public WxMenu menuGet() throws WxErrorException;

/**
* <pre>
* 测试个性化菜单匹配结果
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
* </pre>
*
* @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。
*/
public WxMenu menuTryMatch(String userid) throws WxErrorException;

}

+ 0
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageMatcher.java Переглянути файл

@@ -10,7 +10,6 @@ public interface WxMpMessageMatcher {
/**
* 消息是否匹配某种模式
* @param message
* @return
*/
public boolean match(WxMpXmlMessage message);



+ 0
- 1
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java Переглянути файл

@@ -124,7 +124,6 @@ public class WxMpMessageRouter {
/**
* 开始一个新的Route规则
* @return
*/
public WxMpMessageRouterRule rule() {
return new WxMpMessageRouterRule(this);


+ 18
- 59
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouterRule.java Переглянути файл

@@ -34,9 +34,9 @@ public class WxMpMessageRouterRule {

private boolean reEnter = false;

private List<WxMpMessageHandler> handlers = new ArrayList<WxMpMessageHandler>();
private List<WxMpMessageHandler> handlers = new ArrayList<>();

private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>();
private List<WxMpMessageInterceptor> interceptors = new ArrayList<>();

public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) {
this.routerBuilder = routerBuilder;
@@ -44,9 +44,6 @@ public class WxMpMessageRouterRule {

/**
* 设置是否异步执行,默认是true
*
* @param async
* @return
*/
public WxMpMessageRouterRule async(boolean async) {
this.async = async;
@@ -55,9 +52,6 @@ public class WxMpMessageRouterRule {

/**
* 如果msgType等于某值
*
* @param msgType
* @return
*/
public WxMpMessageRouterRule msgType(String msgType) {
this.msgType = msgType;
@@ -66,9 +60,6 @@ public class WxMpMessageRouterRule {

/**
* 如果event等于某值
*
* @param event
* @return
*/
public WxMpMessageRouterRule event(String event) {
this.event = event;
@@ -77,9 +68,6 @@ public class WxMpMessageRouterRule {

/**
* 如果eventKey等于某值
*
* @param eventKey
* @return
*/
public WxMpMessageRouterRule eventKey(String eventKey) {
this.eventKey = eventKey;
@@ -88,9 +76,6 @@ public class WxMpMessageRouterRule {

/**
* 如果content等于某值
*
* @param content
* @return
*/
public WxMpMessageRouterRule content(String content) {
this.content = content;
@@ -99,9 +84,6 @@ public class WxMpMessageRouterRule {

/**
* 如果content匹配该正则表达式
*
* @param regex
* @return
*/
public WxMpMessageRouterRule rContent(String regex) {
this.rContent = regex;
@@ -110,9 +92,6 @@ public class WxMpMessageRouterRule {

/**
* 如果fromUser等于某值
*
* @param fromUser
* @return
*/
public WxMpMessageRouterRule fromUser(String fromUser) {
this.fromUser = fromUser;
@@ -121,9 +100,6 @@ public class WxMpMessageRouterRule {

/**
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
*
* @param matcher
* @return
*/
public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) {
this.matcher = matcher;
@@ -132,9 +108,6 @@ public class WxMpMessageRouterRule {

/**
* 设置微信消息拦截器
*
* @param interceptor
* @return
*/
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) {
return interceptor(interceptor, (WxMpMessageInterceptor[]) null);
@@ -142,10 +115,6 @@ public class WxMpMessageRouterRule {

/**
* 设置微信消息拦截器
*
* @param interceptor
* @param otherInterceptors
* @return
*/
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) {
this.interceptors.add(interceptor);
@@ -159,9 +128,6 @@ public class WxMpMessageRouterRule {

/**
* 设置微信消息处理器
*
* @param handler
* @return
*/
public WxMpMessageRouterRule handler(WxMpMessageHandler handler) {
return handler(handler, (WxMpMessageHandler[]) null);
@@ -169,10 +135,6 @@ public class WxMpMessageRouterRule {

/**
* 设置微信消息处理器
*
* @param handler
* @param otherHandlers
* @return
*/
public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) {
this.handlers.add(handler);
@@ -186,8 +148,6 @@ public class WxMpMessageRouterRule {

/**
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
*
* @return
*/
public WxMpMessageRouter end() {
this.routerBuilder.getRules().add(this);
@@ -196,8 +156,6 @@ public class WxMpMessageRouterRule {

/**
* 规则结束,但是消息还会进入其他规则
*
* @return
*/
public WxMpMessageRouter next() {
this.reEnter = true;
@@ -207,8 +165,6 @@ public class WxMpMessageRouterRule {
/**
* 将微信自定义的事件修正为不区分大小写,
* 比如框架定义的事件常量为click,但微信传递过来的却是CLICK
* @param wxMessage
* @return
*/
protected boolean test(WxMpXmlMessage wxMessage) {
return
@@ -243,7 +199,7 @@ public class WxMpMessageRouterRule {

try {

Map<String, Object> context = new HashMap<String, Object>();
Map<String, Object> context = new HashMap<>();
// 如果拦截器不通过
for (WxMpMessageInterceptor interceptor : this.interceptors) {
if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) {
@@ -255,6 +211,9 @@ public class WxMpMessageRouterRule {
WxMpXmlOutMessage res = null;
for (WxMpMessageHandler handler : this.handlers) {
// 返回最后handler的结果
if(handler == null){
continue;
}
res = handler.handle(wxMessage, context, wxMpService, sessionManager);
}
return res;
@@ -266,11 +225,11 @@ public class WxMpMessageRouterRule {
}

public WxMpMessageRouter getRouterBuilder() {
return routerBuilder;
return this.routerBuilder;
}

public boolean isAsync() {
return async;
return this.async;
}

public void setAsync(boolean async) {
@@ -278,7 +237,7 @@ public class WxMpMessageRouterRule {
}

public String getFromUser() {
return fromUser;
return this.fromUser;
}

public void setFromUser(String fromUser) {
@@ -286,7 +245,7 @@ public class WxMpMessageRouterRule {
}

public String getMsgType() {
return msgType;
return this.msgType;
}

public void setMsgType(String msgType) {
@@ -294,7 +253,7 @@ public class WxMpMessageRouterRule {
}

public String getEvent() {
return event;
return this.event;
}

public void setEvent(String event) {
@@ -302,7 +261,7 @@ public class WxMpMessageRouterRule {
}

public String getEventKey() {
return eventKey;
return this.eventKey;
}

public void setEventKey(String eventKey) {
@@ -310,7 +269,7 @@ public class WxMpMessageRouterRule {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {
@@ -318,7 +277,7 @@ public class WxMpMessageRouterRule {
}

public String getrContent() {
return rContent;
return this.rContent;
}

public void setrContent(String rContent) {
@@ -326,7 +285,7 @@ public class WxMpMessageRouterRule {
}

public WxMpMessageMatcher getMatcher() {
return matcher;
return this.matcher;
}

public void setMatcher(WxMpMessageMatcher matcher) {
@@ -334,7 +293,7 @@ public class WxMpMessageRouterRule {
}

public boolean isReEnter() {
return reEnter;
return this.reEnter;
}

public void setReEnter(boolean reEnter) {
@@ -342,7 +301,7 @@ public class WxMpMessageRouterRule {
}

public List<WxMpMessageHandler> getHandlers() {
return handlers;
return this.handlers;
}

public void setHandlers(List<WxMpMessageHandler> handlers) {
@@ -350,7 +309,7 @@ public class WxMpMessageRouterRule {
}

public List<WxMpMessageInterceptor> getInterceptors() {
return interceptors;
return this.interceptors;
}

public void setInterceptors(List<WxMpMessageInterceptor> interceptors) {


+ 77
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java Переглянути файл

@@ -0,0 +1,77 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;

import java.io.File;

/**
* 二维码相关操作接口
*
* @author Binary Wang
*/
public interface WxMpQrcodeService {

/**
* <pre>
* 换取临时二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param scene_id 参数。
* @param expire_seconds 过期秒数,默认60秒,最小60秒,最大1800秒
*/
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException;

/**
* <pre>
* 换取永久二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param scene_id 参数。永久二维码时最大值为100000(目前参数只支持1--100000)
*/
public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException;

/**
* <pre>
* 换取永久字符串二维码ticket
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param scene_str 参数。字符串类型长度现在为1到64
*/
public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException;

/**
* <pre>
* 换取二维码图片文件,jpg格式
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param ticket 二维码ticket
*/
public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException;

/**
* <pre>
* 换取二维码图片url地址(可以选择是否生成压缩的网址)
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param ticket 二维码ticket
* @param needShortUrl 是否需要压缩的二维码地址
*/
public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;

/**
* <pre>
* 换取二维码图片url地址
* 详情请见: <a href="http://mp.weixin.qq.com/wiki/18/167e7d94df85d8389df6c94a7a8f78ba.html">生成带参数的二维码</a>
* </pre>
*
* @param ticket 二维码ticket
*/
public String qrCodePictureUrl(String ticket) throws WxErrorException;

}

+ 166
- 578
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 72
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java Переглянути файл

@@ -0,0 +1,72 @@
package me.chanjar.weixin.mp.api;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import me.chanjar.weixin.mp.bean.result.WxMpUserSummary;

import java.util.Date;
import java.util.List;

/**
* 用户管理和统计相关操作接口
*
* @author Binary Wang
*/
public interface WxMpUserService {

/**
* <pre>
* 设置用户备注名接口
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=设置用户备注名接口
* </pre>
*
* @param openid 用户openid
* @param remark 备注名
*/
public void userUpdateRemark(String openid, String remark) throws WxErrorException;

/**
* <pre>
* 获取用户基本信息
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取用户基本信息
* </pre>
*
* @param openid 用户openid
* @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语
*/
public WxMpUser userInfo(String openid, String lang) throws WxErrorException;

/**
* <pre>
* 获取关注者列表
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取关注者列表
* </pre>
*
* @param next_openid 可选,第一个拉取的OPENID,null为从头开始拉取
*/
public WxMpUserList userList(String next_openid) throws WxErrorException;

/**
* <pre>
* 获取用户增减数据
* http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
* </pre>
*
* @param beginDate 最大时间跨度7天
* @param endDate endDate不能早于begingDate
*/
List<WxMpUserSummary> dataCubeUserSummary(Date beginDate, Date endDate) throws WxErrorException;

/**
* <pre>
* 获取累计用户数据
* http://mp.weixin.qq.com/wiki/3/ecfed6e1a0a03b5f35e5efac98e864b7.html
* </pre>
*
* @param beginDate 最大时间跨度7天
* @param endDate endDate不能早于begingDate
*/
List<WxMpUserCumulate> dataCubeUserCumulate(Date beginDate, Date endDate) throws WxErrorException;
}

+ 85
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGroupServiceImpl.java Переглянути файл

@@ -0,0 +1,85 @@
package me.chanjar.weixin.mp.api.impl;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.common.util.json.GsonHelper;
import me.chanjar.weixin.mp.api.WxMpGroupService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpGroup;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import java.io.StringReader;
import java.util.List;

/**
* Created by Binary Wang on 2016/7/21.
*/
public class WxMpGroupServiceImpl implements WxMpGroupService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/groups";
private WxMpService wxMpService;

public WxMpGroupServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxMpGroup groupCreate(String name) throws WxErrorException {
String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject();
JsonObject groupJson = new JsonObject();
json.add("group", groupJson);
groupJson.addProperty("name", name);

String responseContent = this.wxMpService.execute(
new SimplePostRequestExecutor(),
url,
json.toString());
return WxMpGroup.fromJson(responseContent);
}

@Override
public List<WxMpGroup> groupGet() throws WxErrorException {
String url = API_URL_PREFIX + "/get";
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
/*
* 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} }
* 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
*/
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"),
new TypeToken<List<WxMpGroup>>() {
}.getType());
}

@Override
public long userGetGroup(String openid) throws WxErrorException {
String url = API_URL_PREFIX + "/getid";
JsonObject o = new JsonObject();
o.addProperty("openid", openid);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, o.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid"));
}

@Override
public void groupUpdate(WxMpGroup group) throws WxErrorException {
String url = API_URL_PREFIX + "/update";
this.wxMpService.execute(new SimplePostRequestExecutor(), url, group.toJson());
}

@Override
public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException {
String url = API_URL_PREFIX + "/members/update";
JsonObject json = new JsonObject();
json.addProperty("openid", openid);
json.addProperty("to_groupid", to_groupid);
this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
}

}

+ 182
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java Переглянути файл

@@ -0,0 +1,182 @@
package me.chanjar.weixin.mp.api.impl;

import java.io.File;
import java.util.Date;

import com.google.gson.JsonObject;

import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpKefuService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfAccountRequest;
import me.chanjar.weixin.mp.bean.kefu.request.WxMpKfSessionRequest;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfMsgList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionGetResult;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionList;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfSessionWaitCaseList;

/**
*
* @author Binary Wang
*
*/
public class WxMpKefuServiceImpl implements WxMpKefuService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/customservice";
private WxMpService wxMpService;

public WxMpKefuServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxMpKfList kfList() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
return WxMpKfList.fromJson(responseContent);
}

@Override
public WxMpKfOnlineList kfOnlineList() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
return WxMpKfOnlineList.fromJson(responseContent);
}

@Override
public boolean kfAccountAdd(WxMpKfAccountRequest request)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/add";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
return true;
}

@Override
public boolean kfAccountUpdate(WxMpKfAccountRequest request)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/update";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
return true;
}

@Override
public boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/inviteworker";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
return true;
}

@Override
public boolean kfAccountUploadHeadImg(String kfAccount, File imgFile)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/uploadheadimg?kf_account=" + kfAccount;
this.wxMpService.execute(new MediaUploadRequestExecutor(), url, imgFile);
return true;
}

@Override
public boolean kfAccountDel(String kfAccount) throws WxErrorException {
String url = API_URL_PREFIX + "/kfaccount/del?kf_account=" + kfAccount;
this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
return true;
}

@Override
public boolean kfSessionCreate(String openid, String kfAccount)
throws WxErrorException {
WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid);
String url = API_URL_PREFIX + "/kfsession/create";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
return true;
}

@Override
public boolean kfSessionClose(String openid, String kfAccount)
throws WxErrorException {
WxMpKfSessionRequest request = new WxMpKfSessionRequest(kfAccount, openid);
String url = API_URL_PREFIX + "/kfsession/close";
this.wxMpService.execute(new SimplePostRequestExecutor(), url,
request.toJson());
return true;
}

@Override
public WxMpKfSessionGetResult kfSessionGet(String openid)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getsession?openid=" + openid;
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
return WxMpKfSessionGetResult.fromJson(responseContent);
}

@Override
public WxMpKfSessionList kfSessionList(String kfAccount)
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getsessionlist?kf_account=" + kfAccount;
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
return WxMpKfSessionList.fromJson(responseContent);
}

@Override
public WxMpKfSessionWaitCaseList kfSessionGetWaitCase()
throws WxErrorException {
String url = API_URL_PREFIX + "/kfsession/getwaitcase";
String responseContent = this.wxMpService
.execute(new SimpleGetRequestExecutor(), url, null);
return WxMpKfSessionWaitCaseList.fromJson(responseContent);
}

@Override
public WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException {
if(number > 10000){
throw new WxErrorException(WxError.newBuilder().setErrorMsg("非法参数请求,每次最多查询10000条记录!").build());
}

if(startTime.after(endTime)){
throw new WxErrorException(WxError.newBuilder().setErrorMsg("起始时间不能晚于结束时间!").build());
}

String url = API_URL_PREFIX + "/msgrecord/getmsglist";

JsonObject param = new JsonObject();
param.addProperty("starttime", startTime.getTime() / 1000); //starttime 起始时间,unix时间戳
param.addProperty("endtime", endTime.getTime() / 1000); //endtime 结束时间,unix时间戳,每次查询时段不能超过24小时
param.addProperty("msgid", msgId); //msgid 消息id顺序从小到大,从1开始
param.addProperty("number", number); //number 每次获取条数,最多10000条

String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, param.toString());
return WxMpKfMsgList.fromJson(responseContent);
}

@Override
public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException {
int number = 10000;
WxMpKfMsgList result = this.kfMsgList(startTime,endTime, 1L, number);

if(result != null && result.getNumber() == number){
Long msgId = result.getMsgId();
WxMpKfMsgList followingResult = this.kfMsgList(startTime,endTime, msgId, number);
while(followingResult != null && followingResult.getRecords().size() > 0){
result.getRecords().addAll(followingResult.getRecords());
result.setNumber(result.getNumber() + followingResult.getNumber());
result.setMsgId(followingResult.getMsgId());
followingResult = this.kfMsgList(startTime,endTime, followingResult.getMsgId(), number);
}
}

return result;
}

}

+ 158
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java Переглянути файл

@@ -0,0 +1,158 @@
package me.chanjar.weixin.mp.api.impl;

import me.chanjar.weixin.common.api.WxConsts;
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.fs.FileUtils;
import me.chanjar.weixin.common.util.http.MediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.mp.api.WxMpMaterialService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpMaterial;
import me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate;
import me.chanjar.weixin.mp.bean.WxMpMaterialNews;
import me.chanjar.weixin.mp.bean.result.*;
import me.chanjar.weixin.mp.util.http.*;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
* Created by Binary Wang on 2016/7/21.
*/
public class WxMpMaterialServiceImpl implements WxMpMaterialService {
private static final String MEDIA_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/media";
private static final String MATERIAL_API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/material";
private WxMpService wxMpService;

public WxMpMaterialServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException {
return this.mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
String url = MEDIA_API_URL_PREFIX + "/upload?type=" + mediaType;
return this.wxMpService.execute(new MediaUploadRequestExecutor(), url, file);
}

@Override
public File mediaDownload(String media_id) throws WxErrorException {
String url = MEDIA_API_URL_PREFIX + "/get";
return this.wxMpService.execute(new MediaDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, "media_id=" + media_id);
}

@Override
public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException {
String url = MEDIA_API_URL_PREFIX + "/uploadimg";
return this.wxMpService.execute(new MediaImgUploadRequestExecutor(), url, file);
}

@Override
public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/add_material?type=" + mediaType;
return this.wxMpService.execute(new MaterialUploadRequestExecutor(), url, material);
}

@Override
public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException {
if (news == null || news.isEmpty()) {
throw new IllegalArgumentException("news is empty!");
}
String url = MATERIAL_API_URL_PREFIX + "/add_news";
String responseContent = this.wxMpService.post(url, news.toJson());
return WxMpMaterialUploadResult.fromJson(responseContent);
}

@Override
public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/get_material";
return this.wxMpService.execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpService.getWxMpConfigStorage().getTmpDirFile()), url, media_id);
}

@Override
public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/get_material";
return this.wxMpService.execute(new MaterialVideoInfoRequestExecutor(), url, media_id);
}

@Override
public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/get_material";
return this.wxMpService.execute(new MaterialNewsInfoRequestExecutor(), url, media_id);
}

@Override
public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/update_news";
String responseText = this.wxMpService.post(url, wxMpMaterialArticleUpdate.toJson());
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return true;
} else {
throw new WxErrorException(wxError);
}
}

@Override
public boolean materialDelete(String media_id) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/del_material";
return this.wxMpService.execute(new MaterialDeleteRequestExecutor(), url, media_id);
}

@Override
public WxMpMaterialCountResult materialCount() throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/get_materialcount";
String responseText = this.wxMpService.get(url, null);
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class);
} else {
throw new WxErrorException(wxError);
}
}

@Override
public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/batchget_material";
Map<String, Object> params = new HashMap<>();
params.put("type", WxConsts.MATERIAL_NEWS);
params.put("offset", offset);
params.put("count", count);
String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class);
} else {
throw new WxErrorException(wxError);
}
}

@Override
public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException {
String url = MATERIAL_API_URL_PREFIX + "/batchget_material";
Map<String, Object> params = new HashMap<>();
params.put("type", type);
params.put("offset", offset);
params.put("count", count);
String responseText = this.wxMpService.post(url, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class);
} else {
throw new WxErrorException(wxError);
}
}

}

+ 74
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMenuServiceImpl.java Переглянути файл

@@ -0,0 +1,74 @@
package me.chanjar.weixin.mp.api.impl;

import me.chanjar.weixin.common.bean.WxMenu;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpMenuService;
import me.chanjar.weixin.mp.api.WxMpService;

/**
* Created by Binary Wang on 2016/7/21.
*/
public class WxMpMenuServiceImpl implements WxMpMenuService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/menu";

private WxMpService wxMpService;

public WxMpMenuServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public void menuCreate(WxMenu menu) throws WxErrorException {
if (menu.getMatchRule() != null) {
String url = API_URL_PREFIX + "/addconditional";
this.wxMpService.execute(new SimplePostRequestExecutor(), url, menu.toJson());
} else {
String url = API_URL_PREFIX + "/create";
this.wxMpService.execute(new SimplePostRequestExecutor(), url, menu.toJson());
}
}

@Override
public void menuDelete() throws WxErrorException {
String url = API_URL_PREFIX + "/delete";
this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
}

@Override
public void menuDelete(String menuid) throws WxErrorException {
String url = API_URL_PREFIX + "/delconditional";
this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "menuid=" + menuid);
}

@Override
public WxMenu menuGet() throws WxErrorException {
String url = API_URL_PREFIX + "/get";
try {
String resultContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
return WxMenu.fromJson(resultContent);
} catch (WxErrorException e) {
// 46003 不存在的菜单数据
if (e.getError().getErrorCode() == 46003) {
return null;
}
throw e;
}
}

@Override
public WxMenu menuTryMatch(String userid) throws WxErrorException {
String url = API_URL_PREFIX + "/trymatch";
try {
String resultContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "user_id=" + userid);
return WxMenu.fromJson(resultContent);
} catch (WxErrorException e) {
// 46003 不存在的菜单数据 46002 不存在的菜单版本
if (e.getError().getErrorCode() == 46003 || e.getError().getErrorCode() == 46002) {
return null;
}
throw e;
}
}
}

+ 102
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java Переглянути файл

@@ -0,0 +1,102 @@
package me.chanjar.weixin.mp.api.impl;

import com.google.gson.JsonObject;
import me.chanjar.weixin.common.bean.result.WxError;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpQrcodeService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import me.chanjar.weixin.mp.util.http.QrCodeRequestExecutor;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
* Created by Binary Wang on 2016/7/21.
*/
public class WxMpQrcodeServiceImpl implements WxMpQrcodeService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/qrcode";
private WxMpService wxMpService;

public WxMpQrcodeServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_SCENE");
if (expire_seconds != null) {
json.addProperty("expire_seconds", expire_seconds);
}
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_SCENE");
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException {
String url = API_URL_PREFIX + "/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_STR_SCENE");
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_str", scene_str);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
return this.wxMpService.execute(new QrCodeRequestExecutor(), url, ticket);
}

@Override
public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException {
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
try {
String resultUrl = String.format(url,
URLEncoder.encode(ticket, StandardCharsets.UTF_8.name()));
if (needShortUrl) {
return this.wxMpService.shortUrl(resultUrl);
}

return resultUrl;
} catch (UnsupportedEncodingException e) {
WxError error = WxError.newBuilder().setErrorCode(-1)
.setErrorMsg(e.getMessage()).build();
throw new WxErrorException(error);
}
}

@Override
public String qrCodePictureUrl(String ticket) throws WxErrorException {
return qrCodePictureUrl(ticket, false);
}

}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java → weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImpl.java Переглянути файл

@@ -1,34 +1,26 @@
package me.chanjar.weixin.mp.api;
package me.chanjar.weixin.mp.api.impl;

import com.google.gson.*;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.thoughtworks.xstream.XStream;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.bean.WxCardApiSignature;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
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.session.StandardSessionManager;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.crypto.WxCryptUtil;
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.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.api.*;
import me.chanjar.weixin.mp.bean.*;
import me.chanjar.weixin.mp.bean.result.*;
import me.chanjar.weixin.mp.util.http.*;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import org.apache.commons.io.Charsets;
import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
@@ -44,12 +36,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;
@@ -74,6 +62,18 @@ public class WxMpServiceImpl implements WxMpService {
protected final Object globalCardApiTicketRefreshLock = new Object();

protected WxMpConfigStorage wxMpConfigStorage;
protected WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);

protected WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this);

protected WxMpMenuService menuService = new WxMpMenuServiceImpl(this);

protected WxMpUserService userService = new WxMpUserServiceImpl(this);

protected WxMpGroupService groupService = new WxMpGroupServiceImpl(this);

protected WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this);

protected CloseableHttpClient httpClient;

@@ -195,172 +195,6 @@ public class WxMpServiceImpl implements WxMpService {
execute(new SimplePostRequestExecutor(), url, message.toJson());
}

@Override
public void menuCreate(WxMenu menu) throws WxErrorException {
if (menu.getMatchRule() != null) {
String url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional";
execute(new SimplePostRequestExecutor(), url, menu.toJson());
} else {
String url = "https://api.weixin.qq.com/cgi-bin/menu/create";
execute(new SimplePostRequestExecutor(), url, menu.toJson());
}
}

@Override
public void menuDelete() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/menu/delete";
execute(new SimpleGetRequestExecutor(), url, null);
}
@Override
public void menuDelete(String menuid) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional";
execute(new SimpleGetRequestExecutor(), url, "menuid=" + menuid);
}

@Override
public WxMenu menuGet() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/menu/get";
try {
String resultContent = execute(new SimpleGetRequestExecutor(), url, null);
return WxMenu.fromJson(resultContent);
} catch (WxErrorException e) {
// 46003 不存在的菜单数据
if (e.getError().getErrorCode() == 46003) {
return null;
}
throw e;
}
}
@Override
public WxMenu menuTryMatch(String userid) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/menu/trymatch";
try {
String resultContent = execute(new SimpleGetRequestExecutor(), url, "user_id=" + userid);
return WxMenu.fromJson(resultContent);
} catch (WxErrorException e) {
// 46003 不存在的菜单数据 46002 不存在的菜单版本
if (e.getError().getErrorCode() == 46003 || e.getError().getErrorCode() == 46002) {
return null;
}
throw e;
}
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException {
return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
}

@Override
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType;
return execute(new MediaUploadRequestExecutor(), url, file);
}

@Override
public File mediaDownload(String media_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/media/get";
return execute(new MediaDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, "media_id=" + media_id);
}

@Override
public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=" + mediaType;
return execute(new MaterialUploadRequestExecutor(), url, material);
}

@Override
public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException {
if (news == null || news.isEmpty()) {
throw new IllegalArgumentException("news is empty!");
}
String url = "https://api.weixin.qq.com/cgi-bin/material/add_news";
String responseContent = post(url, news.toJson());
return WxMpMaterialUploadResult.fromJson(responseContent);
}

@Override
public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material";
return execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, media_id);
}

@Override
public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material";
return execute(new MaterialVideoInfoRequestExecutor(), url, media_id);
}

@Override
public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material";
return execute(new MaterialNewsInfoRequestExecutor(), url, media_id);
}

@Override
public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/update_news";
String responseText = post(url, wxMpMaterialArticleUpdate.toJson());
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return true;
} else {
throw new WxErrorException(wxError);
}
}

@Override
public boolean materialDelete(String media_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/del_material";
return execute(new MaterialDeleteRequestExecutor(), url, media_id);
}

@Override
public WxMpMaterialCountResult materialCount() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount";
String responseText = get(url, null);
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class);
} else {
throw new WxErrorException(wxError);
}
}

@Override
public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material";
Map<String, Object> params = new HashMap<>();
params.put("type", WxConsts.MATERIAL_NEWS);
params.put("offset", offset);
params.put("count", count);
String responseText = post(url, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class);
} else {
throw new WxErrorException(wxError);
}
}

@Override
public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material";
Map<String, Object> params = new HashMap<>();
params.put("type", type);
params.put("offset", offset);
params.put("count", count);
String responseText = post(url, WxGsonBuilder.create().toJson(params));
WxError wxError = WxError.fromJson(responseText);
if (wxError.getErrorCode() == 0) {
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class);
} else {
throw new WxErrorException(wxError);
}
}

@Override
public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews";
@@ -389,158 +223,6 @@ public class WxMpServiceImpl implements WxMpService {
return WxMpMassSendResult.fromJson(responseContent);
}

@Override
public WxMpGroup groupCreate(String name) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/groups/create";
JsonObject json = new JsonObject();
JsonObject groupJson = new JsonObject();
json.add("group", groupJson);
groupJson.addProperty("name", name);

String responseContent = execute(
new SimplePostRequestExecutor(),
url,
json.toString());
return WxMpGroup.fromJson(responseContent);
}

@Override
public List<WxMpGroup> groupGet() throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/groups/get";
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
/*
* 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} }
* 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] }
*/
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"),
new TypeToken<List<WxMpGroup>>() {
}.getType());
}

@Override
public long userGetGroup(String openid) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/groups/getid";
JsonObject o = new JsonObject();
o.addProperty("openid", openid);
String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid"));
}

@Override
public void groupUpdate(WxMpGroup group) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/groups/update";
execute(new SimplePostRequestExecutor(), url, group.toJson());
}

@Override
public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/groups/members/update";
JsonObject json = new JsonObject();
json.addProperty("openid", openid);
json.addProperty("to_groupid", to_groupid);
execute(new SimplePostRequestExecutor(), url, json.toString());
}

@Override
public void userUpdateRemark(String openid, String remark) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark";
JsonObject json = new JsonObject();
json.addProperty("openid", openid);
json.addProperty("remark", remark);
execute(new SimplePostRequestExecutor(), url, json.toString());
}

@Override
public WxMpUser userInfo(String openid, String lang) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/user/info";
lang = lang == null ? "zh_CN" : lang;
String responseContent = execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang);
return WxMpUser.fromJson(responseContent);
}

@Override
public WxMpUserList userList(String next_openid) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/user/get";
String responseContent = execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid);
return WxMpUserList.fromJson(responseContent);
}

@Override
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_SCENE");
if (expire_seconds != null) {
json.addProperty("expire_seconds", expire_seconds);
}
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_SCENE");
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_id", scene_id);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
JsonObject json = new JsonObject();
json.addProperty("action_name", "QR_LIMIT_STR_SCENE");
JsonObject actionInfo = new JsonObject();
JsonObject scene = new JsonObject();
scene.addProperty("scene_str", scene_str);
actionInfo.add("scene", scene);
json.add("action_info", actionInfo);
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString());
return WxMpQrCodeTicket.fromJson(responseContent);
}

@Override
public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException {
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
return execute(new QrCodeRequestExecutor(), url, ticket);
}

@Override
public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException {
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s";
try {
String resultUrl = String.format(url,
URLEncoder.encode(ticket, Charsets.UTF_8.name()));
if(needShortUrl){
return this.shortUrl(resultUrl);
}
return resultUrl;
} catch (UnsupportedEncodingException e) {
WxError error = WxError.newBuilder().setErrorCode(-1)
.setErrorMsg(e.getMessage()).build();
throw new WxErrorException(error);
}
}
@Override
public String qrCodePictureUrl(String ticket) throws WxErrorException {
return qrCodePictureUrl(ticket, false);
}

@Override
public String shortUrl(String long_url) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/shorturl";
@@ -685,33 +367,6 @@ public class WxMpServiceImpl implements WxMpService {
return ipArray;
}


@Override
public List<WxMpUserSummary> getUserSummary(Date beginDate, Date endDate) throws WxErrorException {
String url = "https://api.weixin.qq.com/datacube/getusersummary";
JsonObject param = new JsonObject();
param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate));
String responseContent = post(url, param.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"),
new TypeToken<List<WxMpUserSummary>>() {
}.getType());
}

@Override
public List<WxMpUserCumulate> getUserCumulate(Date beginDate, Date endDate) throws WxErrorException {
String url = "https://api.weixin.qq.com/datacube/getusercumulate";
JsonObject param = new JsonObject();
param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate));
String responseContent = post(url, param.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"),
new TypeToken<List<WxMpUserCumulate>>() {
}.getType());
}

@Override
public String get(String url, String queryParam) throws WxErrorException {
return execute(new SimpleGetRequestExecutor(), url, queryParam);
@@ -724,12 +379,6 @@ public class WxMpServiceImpl implements WxMpService {

/**
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
*
* @param executor
* @param uri
* @param data
* @return
* @throws WxErrorException
*/
@Override
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
@@ -822,6 +471,11 @@ public class WxMpServiceImpl implements WxMpService {
this.httpClient = apacheHttpClientBuilder.build();
}

@Override
public WxMpConfigStorage getWxMpConfigStorage() {
return this.wxMpConfigStorage;
}

@Override
public void setRetrySleepMillis(int retrySleepMillis) {
this.retrySleepMillis = retrySleepMillis;
@@ -1347,12 +1001,6 @@ public class WxMpServiceImpl implements WxMpService {
return WxMpMassSendResult.fromJson(responseContent);
}

@Override
public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException {
String url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg";
return execute(new MediaImgUploadRequestExecutor(), url, file);
}

@Override
public String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException {
if (null == wxMpIndustry.getPrimaryIndustry() || null == wxMpIndustry.getPrimaryIndustry().getId()
@@ -1369,4 +1017,35 @@ public class WxMpServiceImpl implements WxMpService {
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
return WxMpIndustry.fromJson(responseContent);
}

@Override
public WxMpKefuService getKefuService() {
return this.kefuService;
}

@Override
public WxMpMaterialService getMaterialService() {
return this.materialService;
}

@Override
public WxMpMenuService getMenuService() {
return this.menuService;
}

@Override
public WxMpUserService getUserService() {
return this.userService;
}

@Override
public WxMpGroupService getGroupService() {
return this.groupService;
}

@Override
public WxMpQrcodeService getQrcodeService() {
return this.qrCodeService;
}

}

+ 83
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpUserServiceImpl.java Переглянути файл

@@ -0,0 +1,83 @@
package me.chanjar.weixin.mp.api.impl;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.WxMpUserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.result.WxMpUserCumulate;
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
import me.chanjar.weixin.mp.bean.result.WxMpUserSummary;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

import java.io.StringReader;
import java.util.Date;
import java.util.List;

/**
* Created by Binary Wang on 2016/7/21.
*/
public class WxMpUserServiceImpl implements WxMpUserService {
private static final String API_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user";
private WxMpService wxMpService;

public WxMpUserServiceImpl(WxMpService wxMpService) {
this.wxMpService = wxMpService;
}

@Override
public void userUpdateRemark(String openid, String remark) throws WxErrorException {
String url = API_URL_PREFIX + "/info/updateremark";
JsonObject json = new JsonObject();
json.addProperty("openid", openid);
json.addProperty("remark", remark);
this.wxMpService.execute(new SimplePostRequestExecutor(), url, json.toString());
}

@Override
public WxMpUser userInfo(String openid, String lang) throws WxErrorException {
String url = API_URL_PREFIX + "/info";
lang = lang == null ? "zh_CN" : lang;
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang);
return WxMpUser.fromJson(responseContent);
}

@Override
public WxMpUserList userList(String next_openid) throws WxErrorException {
String url = API_URL_PREFIX + "/get";
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid);
return WxMpUserList.fromJson(responseContent);
}

@Override
public List<WxMpUserSummary> dataCubeUserSummary(Date beginDate, Date endDate) throws WxErrorException {
String url = "https://api.weixin.qq.com/datacube/getusersummary";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"),
new TypeToken<List<WxMpUserSummary>>() {
}.getType());
}

@Override
public List<WxMpUserCumulate> dataCubeUserCumulate(Date beginDate, Date endDate) throws WxErrorException {
String url = "https://api.weixin.qq.com/datacube/getusercumulate";
JsonObject param = new JsonObject();
param.addProperty("begin_date", WxMpService.SIMPLE_DATE_FORMAT.format(beginDate));
param.addProperty("end_date", WxMpService.SIMPLE_DATE_FORMAT.format(endDate));
String responseContent = this.wxMpService.post(url, param.toString());
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"),
new TypeToken<List<WxMpUserCumulate>>() {
}.getType());
}
}

+ 26
- 22
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpCustomMessage.java Переглянути файл

@@ -13,7 +13,8 @@ import java.util.List;
*
*/
public class WxMpCustomMessage implements Serializable {

private static final long serialVersionUID = -9196732086954365246L;
private String toUser;
private String msgType;
private String content;
@@ -23,16 +24,17 @@ public class WxMpCustomMessage implements Serializable {
private String description;
private String musicUrl;
private String hqMusicUrl;
private List<WxArticle> articles = new ArrayList<WxArticle>();
private String kfAccount;
private List<WxArticle> articles = new ArrayList<>();
public String getToUser() {
return toUser;
return this.toUser;
}
public void setToUser(String toUser) {
this.toUser = toUser;
}
public String getMsgType() {
return msgType;
return this.msgType;
}
/**
@@ -51,49 +53,49 @@ public class WxMpCustomMessage implements Serializable {
this.msgType = msgType;
}
public String getContent() {
return content;
return this.content;
}
public void setContent(String content) {
this.content = content;
}
public String getMediaId() {
return mediaId;
return this.mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
return this.thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
public String getTitle() {
return title;
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getMusicUrl() {
return musicUrl;
return this.musicUrl;
}
public void setMusicUrl(String musicUrl) {
this.musicUrl = musicUrl;
}
public String getHqMusicUrl() {
return hqMusicUrl;
return this.hqMusicUrl;
}
public void setHqMusicUrl(String hqMusicUrl) {
this.hqMusicUrl = hqMusicUrl;
}
public List<WxArticle> getArticles() {
return articles;
return this.articles;
}
public void setArticles(List<WxArticle> articles) {
this.articles = articles;
@@ -111,25 +113,25 @@ public class WxMpCustomMessage implements Serializable {
private String picUrl;
public String getTitle() {
return title;
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPicUrl() {
return picUrl;
return this.picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
@@ -139,7 +141,6 @@ public class WxMpCustomMessage implements Serializable {
/**
* 获得文本消息builder
* @return
*/
public static TextBuilder TEXT() {
return new TextBuilder();
@@ -147,7 +148,6 @@ public class WxMpCustomMessage implements Serializable {

/**
* 获得图片消息builder
* @return
*/
public static ImageBuilder IMAGE() {
return new ImageBuilder();
@@ -155,7 +155,6 @@ public class WxMpCustomMessage implements Serializable {

/**
* 获得语音消息builder
* @return
*/
public static VoiceBuilder VOICE() {
return new VoiceBuilder();
@@ -163,7 +162,6 @@ public class WxMpCustomMessage implements Serializable {
/**
* 获得视频消息builder
* @return
*/
public static VideoBuilder VIDEO() {
return new VideoBuilder();
@@ -171,7 +169,6 @@ public class WxMpCustomMessage implements Serializable {
/**
* 获得音乐消息builder
* @return
*/
public static MusicBuilder MUSIC() {
return new MusicBuilder();
@@ -179,10 +176,17 @@ public class WxMpCustomMessage implements Serializable {
/**
* 获得图文消息builder
* @return
*/
public static NewsBuilder NEWS() {
return new NewsBuilder();
}
public String getKfAccount() {
return kfAccount;
}
public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}
}

+ 6
- 6
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpMassOpenIdsMessage.java Переглянути файл

@@ -12,8 +12,9 @@ import java.util.List;
* @author chanjarster
*/
public class WxMpMassOpenIdsMessage implements Serializable {
private static final long serialVersionUID = -8022910911104788999L;
private List<String> toUsers = new ArrayList<String>();
private List<String> toUsers = new ArrayList<>();
private String msgType;
private String content;
private String mediaId;
@@ -23,7 +24,7 @@ public class WxMpMassOpenIdsMessage implements Serializable {
}
public String getMsgType() {
return msgType;
return this.msgType;
}

/**
@@ -43,7 +44,7 @@ public class WxMpMassOpenIdsMessage implements Serializable {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {
@@ -51,7 +52,7 @@ public class WxMpMassOpenIdsMessage implements Serializable {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {
@@ -64,10 +65,9 @@ public class WxMpMassOpenIdsMessage implements Serializable {

/**
* OpenId列表,最多支持10,000个
* @return
*/
public List<String> getToUsers() {
return toUsers;
return this.toUsers;
}

/**


+ 168
- 139
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlMessage.java Переглянути файл

@@ -1,18 +1,24 @@
package me.chanjar.weixin.mp.bean;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamConverter;

import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil;
import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
* <pre>
@@ -28,46 +34,49 @@ import java.util.List;
@XStreamAlias("xml")
public class WxMpXmlMessage implements Serializable {

private static final long serialVersionUID = -3586245291677274914L;

///////////////////////
// 以下都是微信推送过来的消息的xml的element所对应的属性
///////////////////////

@XStreamAlias("ToUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String toUserName;

@XStreamAlias("FromUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String fromUserName;

@XStreamAlias("CreateTime")
@JsonSerialize(using = WxLongTimeJsonSerializer.class)
private Long createTime;

@XStreamAlias("MsgType")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String msgType;

@XStreamAlias("Content")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String content;

@XStreamAlias("MsgId")
private Long msgId;

@XStreamAlias("PicUrl")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String picUrl;

@XStreamAlias("MediaId")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String mediaId;

@XStreamAlias("Format")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String format;

@XStreamAlias("ThumbMediaId")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String thumbMediaId;

@XStreamAlias("Location_X")
@@ -80,31 +89,31 @@ public class WxMpXmlMessage implements Serializable {
private Double scale;

@XStreamAlias("Label")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String label;

@XStreamAlias("Title")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String title;

@XStreamAlias("Description")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String description;

@XStreamAlias("Url")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String url;

@XStreamAlias("Event")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String event;

@XStreamAlias("EventKey")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String eventKey;

@XStreamAlias("Ticket")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String ticket;

@XStreamAlias("Latitude")
@@ -117,7 +126,7 @@ public class WxMpXmlMessage implements Serializable {
private Double precision;

@XStreamAlias("Recognition")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String recognition;

///////////////////////////////////////
@@ -127,7 +136,7 @@ public class WxMpXmlMessage implements Serializable {
* 群发的结果
*/
@XStreamAlias("Status")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String status;
/**
* group_id下粉丝数;或者openid_list中的粉丝数
@@ -150,26 +159,45 @@ public class WxMpXmlMessage implements Serializable {
@XStreamAlias("ErrorCount")
private Integer errorCount;

///////////////////////////////////////
// 客服会话管理相关事件推送
///////////////////////////////////////
/**
* 创建或关闭客服会话时的客服帐号
*/
@XStreamAlias("KfAccount")
private String kfAccount;
/**
* 转接客服会话时的转入客服帐号
*/
@XStreamAlias("ToKfAccount")
private String toKfAccount;
/**
* 转接客服会话时的转出客服帐号
*/
@XStreamAlias("FromKfAccount")
private String fromKfAccount;

///////////////////////////////////////
// 卡券相关事件推送
///////////////////////////////////////
@XStreamAlias("CardId")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String cardId;

@XStreamAlias("FriendUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String friendUserName;

@XStreamAlias("IsGiveByFriend")
private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否

@XStreamAlias("UserCardCode")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String userCardCode;

@XStreamAlias("OldUserCardCode")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String oldUserCardCode;

@XStreamAlias("OuterId")
@@ -185,7 +213,7 @@ public class WxMpXmlMessage implements Serializable {
private SendLocationInfo sendLocationInfo = new SendLocationInfo();

public String getToUserName() {
return toUserName;
return this.toUserName;
}

public void setToUserName(String toUserName) {
@@ -193,7 +221,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Long getCreateTime() {
return createTime;
return this.createTime;
}

public void setCreateTime(Long createTime) {
@@ -212,10 +240,9 @@ public class WxMpXmlMessage implements Serializable {
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT}
* </pre>
*
* @return
*/
public String getMsgType() {
return msgType;
return this.msgType;
}

/**
@@ -236,7 +263,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getContent() {
return content;
return this.content;
}

public void setContent(String content) {
@@ -244,7 +271,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Long getMsgId() {
return msgId;
return this.msgId;
}

public void setMsgId(Long msgId) {
@@ -252,7 +279,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getPicUrl() {
return picUrl;
return this.picUrl;
}

public void setPicUrl(String picUrl) {
@@ -260,7 +287,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getMediaId() {
return mediaId;
return this.mediaId;
}

public void setMediaId(String mediaId) {
@@ -268,7 +295,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getFormat() {
return format;
return this.format;
}

public void setFormat(String format) {
@@ -276,7 +303,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getThumbMediaId() {
return thumbMediaId;
return this.thumbMediaId;
}

public void setThumbMediaId(String thumbMediaId) {
@@ -284,7 +311,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getLocationX() {
return locationX;
return this.locationX;
}

public void setLocationX(Double locationX) {
@@ -292,7 +319,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getLocationY() {
return locationY;
return this.locationY;
}

public void setLocationY(Double locationY) {
@@ -300,7 +327,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getScale() {
return scale;
return this.scale;
}

public void setScale(Double scale) {
@@ -308,7 +335,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getLabel() {
return label;
return this.label;
}

public void setLabel(String label) {
@@ -316,7 +343,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getTitle() {
return title;
return this.title;
}

public void setTitle(String title) {
@@ -324,7 +351,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getDescription() {
return description;
return this.description;
}

public void setDescription(String description) {
@@ -332,7 +359,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getUrl() {
return url;
return this.url;
}

public void setUrl(String url) {
@@ -340,7 +367,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getEvent() {
return event;
return this.event;
}

public void setEvent(String event) {
@@ -348,7 +375,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getEventKey() {
return eventKey;
return this.eventKey;
}

public void setEventKey(String eventKey) {
@@ -356,7 +383,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getTicket() {
return ticket;
return this.ticket;
}

public void setTicket(String ticket) {
@@ -364,7 +391,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getLatitude() {
return latitude;
return this.latitude;
}

public void setLatitude(Double latitude) {
@@ -372,7 +399,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getLongitude() {
return longitude;
return this.longitude;
}

public void setLongitude(Double longitude) {
@@ -380,7 +407,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Double getPrecision() {
return precision;
return this.precision;
}

public void setPrecision(Double precision) {
@@ -388,7 +415,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getRecognition() {
return recognition;
return this.recognition;
}

public void setRecognition(String recognition) {
@@ -396,7 +423,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getFromUserName() {
return fromUserName;
return this.fromUserName;
}

public void setFromUserName(String fromUserName) {
@@ -419,30 +446,29 @@ public class WxMpXmlMessage implements Serializable {
* @param timestamp
* @param nonce
* @param msgSignature
* @return
*/
public static WxMpXmlMessage fromEncryptedXml(
String encryptedXml,
WxMpConfigStorage wxMpConfigStorage,
String timestamp, String nonce, String msgSignature) {
public static WxMpXmlMessage fromEncryptedXml(String encryptedXml,
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
String msgSignature) {
WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage);
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml);
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce,
encryptedXml);
return fromXml(plainText);
}

public static WxMpXmlMessage fromEncryptedXml(
InputStream is,
WxMpConfigStorage wxMpConfigStorage,
String timestamp, String nonce, String msgSignature) {
public static WxMpXmlMessage fromEncryptedXml(InputStream is,
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce,
String msgSignature) {
try {
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature);
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage,
timestamp, nonce, msgSignature);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public String getStatus() {
return status;
return this.status;
}

public void setStatus(String status) {
@@ -450,7 +476,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getTotalCount() {
return totalCount;
return this.totalCount;
}

public void setTotalCount(Integer totalCount) {
@@ -458,7 +484,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getFilterCount() {
return filterCount;
return this.filterCount;
}

public void setFilterCount(Integer filterCount) {
@@ -466,7 +492,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getSentCount() {
return sentCount;
return this.sentCount;
}

public void setSentCount(Integer sentCount) {
@@ -474,7 +500,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getErrorCount() {
return errorCount;
return this.errorCount;
}

public void setErrorCount(Integer errorCount) {
@@ -482,7 +508,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getCardId() {
return cardId;
return this.cardId;
}

public void setCardId(String cardId) {
@@ -490,7 +516,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getFriendUserName() {
return friendUserName;
return this.friendUserName;
}

public void setFriendUserName(String friendUserName) {
@@ -498,7 +524,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getIsGiveByFriend() {
return isGiveByFriend;
return this.isGiveByFriend;
}

public void setIsGiveByFriend(Integer isGiveByFriend) {
@@ -506,7 +532,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getUserCardCode() {
return userCardCode;
return this.userCardCode;
}

public void setUserCardCode(String userCardCode) {
@@ -514,7 +540,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getOldUserCardCode() {
return oldUserCardCode;
return this.oldUserCardCode;
}

public void setOldUserCardCode(String oldUserCardCode) {
@@ -522,7 +548,7 @@ public class WxMpXmlMessage implements Serializable {
}

public Integer getOuterId() {
return outerId;
return this.outerId;
}

public void setOuterId(Integer outerId) {
@@ -530,7 +556,7 @@ public class WxMpXmlMessage implements Serializable {
}

public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() {
return scanCodeInfo;
return this.scanCodeInfo;
}

public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) {
@@ -538,7 +564,7 @@ public class WxMpXmlMessage implements Serializable {
}

public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() {
return sendPicsInfo;
return this.sendPicsInfo;
}

public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) {
@@ -546,31 +572,59 @@ public class WxMpXmlMessage implements Serializable {
}

public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() {
return sendLocationInfo;
return this.sendLocationInfo;
}

public void setSendLocationInfo(WxMpXmlMessage.SendLocationInfo sendLocationInfo) {
public void setSendLocationInfo(
WxMpXmlMessage.SendLocationInfo sendLocationInfo) {
this.sendLocationInfo = sendLocationInfo;
}

public String getKfAccount() {
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}

public String getToKfAccount() {
return this.toKfAccount;
}

public void setToKfAccount(String toKfAccount) {
this.toKfAccount = toKfAccount;
}

public String getFromKfAccount() {
return this.fromKfAccount;
}

public void setFromKfAccount(String fromKfAccount) {
this.fromKfAccount = fromKfAccount;
}

@XStreamAlias("ScanCodeInfo")
public static class ScanCodeInfo {
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

@XStreamAlias("ScanType")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String scanType;

@XStreamAlias("ScanResult")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String scanResult;

/**
* 扫描类型,一般是qrcode
* @return
*/
public String getScanType() {

return scanType;
return this.scanType;
}

public void setScanType(String scanType) {
@@ -579,10 +633,9 @@ public class WxMpXmlMessage implements Serializable {

/**
* 扫描结果,即二维码对应的字符串信息
* @return
*/
public String getScanResult() {
return scanResult;
return this.scanResult;
}

public void setScanResult(String scanResult) {
@@ -593,15 +646,19 @@ public class WxMpXmlMessage implements Serializable {

@XStreamAlias("SendPicsInfo")
public static class SendPicsInfo {
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

@XStreamAlias("Count")
private Long count;

@XStreamAlias("PicList")
protected final List<Item> picList = new ArrayList<Item>();
protected final List<Item> picList = new ArrayList<>();

public Long getCount() {
return count;
return this.count;
}

public void setCount(Long count) {
@@ -609,18 +666,23 @@ public class WxMpXmlMessage implements Serializable {
}

public List<Item> getPicList() {
return picList;
return this.picList;
}

@XStreamAlias("item")
public static class Item {
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.JSON_STYLE);
}

@XStreamAlias("PicMd5Sum")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String picMd5Sum;

public String getPicMd5Sum() {
return picMd5Sum;
return this.picMd5Sum;
}

public void setPicMd5Sum(String picMd5Sum) {
@@ -633,27 +695,32 @@ public class WxMpXmlMessage implements Serializable {
public static class SendLocationInfo {

@XStreamAlias("Location_X")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String locationX;

@XStreamAlias("Location_Y")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String locationY;

@XStreamAlias("Scale")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String scale;

@XStreamAlias("Label")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String label;

@XStreamAlias("Poiname")
@XStreamConverter(value=XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataConverter.class)
private String poiname;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public String getLocationX() {
return locationX;
return this.locationX;
}

public void setLocationX(String locationX) {
@@ -661,7 +728,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getLocationY() {
return locationY;
return this.locationY;
}

public void setLocationY(String locationY) {
@@ -669,7 +736,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getScale() {
return scale;
return this.scale;
}

public void setScale(String scale) {
@@ -677,7 +744,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getLabel() {
return label;
return this.label;
}

public void setLabel(String label) {
@@ -685,7 +752,7 @@ public class WxMpXmlMessage implements Serializable {
}

public String getPoiname() {
return poiname;
return this.poiname;
}

public void setPoiname(String poiname) {
@@ -695,44 +762,6 @@ public class WxMpXmlMessage implements Serializable {

@Override
public String toString() {
return "WxMpXmlMessage{" +
"toUserName='" + toUserName + '\'' +
", fromUserName='" + fromUserName + '\'' +
", createTime=" + createTime +
", msgType='" + msgType + '\'' +
", content='" + content + '\'' +
", msgId=" + msgId +
", picUrl='" + picUrl + '\'' +
", mediaId='" + mediaId + '\'' +
", format='" + format + '\'' +
", thumbMediaId='" + thumbMediaId + '\'' +
", locationX=" + locationX +
", locationY=" + locationY +
", scale=" + scale +
", label='" + label + '\'' +
", title='" + title + '\'' +
", description='" + description + '\'' +
", url='" + url + '\'' +
", event='" + event + '\'' +
", eventKey='" + eventKey + '\'' +
", ticket='" + ticket + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
", precision=" + precision +
", recognition='" + recognition + '\'' +
", status='" + status + '\'' +
", totalCount=" + totalCount +
", filterCount=" + filterCount +
", sentCount=" + sentCount +
", errorCount=" + errorCount +
", cardId='" + cardId + '\'' +
", isGiveByFriend=" + isGiveByFriend +
", userCardCode='" + userCardCode + '\'' +
", oldUserCardCode='" + oldUserCardCode + '\'' +
", outerId=" + outerId +
", scanCodeInfo=" + scanCodeInfo +
", sendPicsInfo=" + sendPicsInfo +
", sendLocationInfo=" + sendLocationInfo +
'}';
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}

+ 9
- 15
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutMessage.java Переглянути файл

@@ -13,6 +13,8 @@ import java.io.Serializable;
@XStreamAlias("xml")
public abstract class WxMpXmlOutMessage implements Serializable {

private static final long serialVersionUID = -381382011286216263L;

@XStreamAlias("ToUserName")
@XStreamConverter(value=XStreamCDataConverter.class)
protected String toUserName;
@@ -29,7 +31,7 @@ public abstract class WxMpXmlOutMessage implements Serializable {
protected String msgType;

public String getToUserName() {
return toUserName;
return this.toUserName;
}

public void setToUserName(String toUserName) {
@@ -37,7 +39,7 @@ public abstract class WxMpXmlOutMessage implements Serializable {
}

public String getFromUserName() {
return fromUserName;
return this.fromUserName;
}

public void setFromUserName(String fromUserName) {
@@ -45,7 +47,7 @@ public abstract class WxMpXmlOutMessage implements Serializable {
}

public Long getCreateTime() {
return createTime;
return this.createTime;
}

public void setCreateTime(Long createTime) {
@@ -53,7 +55,7 @@ public abstract class WxMpXmlOutMessage implements Serializable {
}

public String getMsgType() {
return msgType;
return this.msgType;
}

public void setMsgType(String msgType) {
@@ -61,12 +63,11 @@ public abstract class WxMpXmlOutMessage implements Serializable {
}
public String toXml() {
return XStreamTransformer.toXml((Class) this.getClass(), this);
return XStreamTransformer.toXml((Class<WxMpXmlOutMessage>) this.getClass(), this);
}

/**
* 转换成加密的xml格式
* @return
*/
public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) {
String plainXml = toXml();
@@ -76,7 +77,6 @@ public abstract class WxMpXmlOutMessage implements Serializable {

/**
* 获得文本消息builder
* @return
*/
public static TextBuilder TEXT() {
return new TextBuilder();
@@ -84,7 +84,6 @@ public abstract class WxMpXmlOutMessage implements Serializable {

/**
* 获得图片消息builder
* @return
*/
public static ImageBuilder IMAGE() {
return new ImageBuilder();
@@ -92,7 +91,6 @@ public abstract class WxMpXmlOutMessage implements Serializable {

/**
* 获得语音消息builder
* @return
*/
public static VoiceBuilder VOICE() {
return new VoiceBuilder();
@@ -100,7 +98,6 @@ public abstract class WxMpXmlOutMessage implements Serializable {
/**
* 获得视频消息builder
* @return
*/
public static VideoBuilder VIDEO() {
return new VideoBuilder();
@@ -108,7 +105,6 @@ public abstract class WxMpXmlOutMessage implements Serializable {
/**
* 获得音乐消息builder
* @return
*/
public static MusicBuilder MUSIC() {
return new MusicBuilder();
@@ -116,15 +112,13 @@ public abstract class WxMpXmlOutMessage implements Serializable {
/**
* 获得图文消息builder
* @return
*/
public static NewsBuilder NEWS() {
return new NewsBuilder();
}
/**
/**
* 获得客服消息builder
*
* @return
*/
public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() {
return new TransferCustomerServiceBuilder();


+ 4
- 2
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpXmlOutTransferCustomerServiceMessage.java Переглянути файл

@@ -7,6 +7,8 @@ import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;

@XStreamAlias("xml")
public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage {
private static final long serialVersionUID = 1850903037285841322L;
@XStreamAlias("TransInfo")
protected TransInfo transInfo;

@@ -15,7 +17,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage
}

public TransInfo getTransInfo() {
return transInfo;
return this.transInfo;
}

public void setTransInfo(TransInfo transInfo) {
@@ -30,7 +32,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage
private String kfAccount;

public String getKfAccount() {
return kfAccount;
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {


+ 105
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfAccountRequest.java Переглянути файл

@@ -0,0 +1,105 @@
package me.chanjar.weixin.mp.bean.kefu.request;

import java.io.Serializable;

import org.apache.commons.lang3.builder.ToStringBuilder;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

public class WxMpKfAccountRequest implements Serializable {
private static final long serialVersionUID = -5451863610674856927L;

/**
* kf_account 完整客服账号,格式为:账号前缀@公众号微信号
*/
@SerializedName("kf_account")
private String kfAccount;
/**
* nickname 客服昵称,最长6个汉字或12个英文字符
*/
@SerializedName("nickname")
private String nickName;

/**
* invite_wx 接收绑定邀请的客服微信号
*/
@SerializedName("invite_wx")
private String inviteWx;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public String toJson() {
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
}

public String getKfAccount() {
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}

public String getNickName() {
return this.nickName;
}

public void setNickName(String nickName) {
this.nickName = nickName;
}

public static Builder builder() {
return new Builder();
}

public String getInviteWx() {
return this.inviteWx;
}

public void setInviteWx(String inviteWx) {
this.inviteWx = inviteWx;
}

public static class Builder {
private String kfAccount;
private String nickName;
private String inviteWx;

public Builder kfAccount(String kfAccount) {
this.kfAccount = kfAccount;
return this;
}

public Builder nickName(String nickName) {
this.nickName = nickName;
return this;
}

public Builder inviteWx(String inviteWx) {
this.inviteWx = inviteWx;
return this;
}

public Builder from(WxMpKfAccountRequest origin) {
this.kfAccount(origin.kfAccount);
this.nickName(origin.nickName);
this.inviteWx(origin.inviteWx);
return this;
}

public WxMpKfAccountRequest build() {
WxMpKfAccountRequest m = new WxMpKfAccountRequest();
m.kfAccount = this.kfAccount;
m.nickName = this.nickName;
m.inviteWx = this.inviteWx;
return m;
}
}

}

+ 49
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/request/WxMpKfSessionRequest.java Переглянути файл

@@ -0,0 +1,49 @@
package me.chanjar.weixin.mp.bean.kefu.request;

import java.io.Serializable;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

public class WxMpKfSessionRequest implements Serializable {
private static final long serialVersionUID = -5451863610674856927L;

/**
* kf_account 完整客服账号,格式为:账号前缀@公众号微信号
*/
@SerializedName("kf_account")
private String kfAccount;
/**
* openid 客户openid
*/
@SerializedName("openid")
private String openid;

public WxMpKfSessionRequest(String kfAccount, String openid) {
this.kfAccount = kfAccount;
this.openid = openid;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public String toJson() {
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
}

public String getKfAccount() {
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}

}

+ 164
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfInfo.java Переглянути файл

@@ -0,0 +1,164 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import java.io.Serializable;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

/**
* 客服基本信息以及客服在线状态信息
* @author Binary Wang
*
*/
public class WxMpKfInfo implements Serializable {
private static final long serialVersionUID = -5877300750666022290L;

/**
* kf_account 完整客服账号,格式为:账号前缀@公众号微信号
*/
@SerializedName("kf_account")
private String account;

/**
* kf_headimgurl 客服头像地址
*/
@SerializedName("kf_headimgurl")
private String headImgUrl;

/**
* kf_id 客服工号
*/
@SerializedName("kf_id")
private String id;

/**
* kf_nick 客服昵称
*/
@SerializedName("kf_nick")
private String nick;

/**
* kf_wx 如果客服帐号已绑定了客服人员微信号,则此处显示微信号
*/
@SerializedName("kf_wx")
private String wxAccount;

/**
* invite_wx 如果客服帐号尚未绑定微信号,但是已经发起了一个绑定邀请,则此处显示绑定邀请的微信号
*/
@SerializedName("invite_wx")
private String inviteWx;

/**
* invite_expire_time 如果客服帐号尚未绑定微信号,但是已经发起过一个绑定邀请,则此处显示为邀请的过期时间,为unix 时间戳
*/
@SerializedName("invite_expire_time")
private Long inviteExpireTime;

/**
* invite_status 邀请的状态,有等待确认“waiting”,被拒绝“rejected”,过期“expired”
*/
@SerializedName("invite_status")
private String inviteStatus;

/**
* status 客服在线状态,目前为:1、web 在线
*/
@SerializedName("status")
private Integer status;

/**
* accepted_case 客服当前正在接待的会话数
*/
@Expose
@SerializedName("accepted_case")
private Integer acceptedCase;

public Integer getStatus() {
return this.status;
}

public void setStatus(Integer status) {
this.status = status;
}

public Integer getAcceptedCase() {
return this.acceptedCase;
}

public void setAcceptedCase(Integer acceptedCase) {
this.acceptedCase = acceptedCase;
}

public String getAccount() {
return this.account;
}

public void setAccount(String account) {
this.account = account;
}

public String getHeadImgUrl() {
return this.headImgUrl;
}

public void setHeadImgUrl(String headImgUrl) {
this.headImgUrl = headImgUrl;
}

public String getId() {
return this.id;
}

public void setId(String id) {
this.id = id;
}

public String getNick() {
return this.nick;
}

public void setNick(String nick) {
this.nick = nick;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public String getWxAccount() {
return this.wxAccount;
}

public void setWxAccount(String wxAccount) {
this.wxAccount = wxAccount;
}

public String getInviteWx() {
return this.inviteWx;
}

public void setInviteWx(String inviteWx) {
this.inviteWx = inviteWx;
}

public Long getInviteExpireTime() {
return this.inviteExpireTime;
}

public void setInviteExpireTime(Long inviteExpireTime) {
this.inviteExpireTime = inviteExpireTime;
}

public String getInviteStatus() {
return this.inviteStatus;
}

public void setInviteStatus(String inviteStatus) {
this.inviteStatus = inviteStatus;
}
}

+ 36
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfList.java Переглянути файл

@@ -0,0 +1,36 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
/**
*
* @author Binary Wang
*
*/
public class WxMpKfList {
@SerializedName("kf_list")
private List<WxMpKfInfo> kfList;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public List<WxMpKfInfo> getKfList() {
return this.kfList;
}

public void setKfList(List<WxMpKfInfo> kfList) {
this.kfList = kfList;
}
public static WxMpKfList fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfList.class);
}
}

+ 55
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgList.java Переглянути файл

@@ -0,0 +1,55 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.util.List;

/**
* Created by Binary Wang on 2016/7/15.
*/
public class WxMpKfMsgList {
@SerializedName("recordlist")
private List<WxMpKfMsgRecord> records;

@SerializedName("number")
private Integer number;

@SerializedName("msgid")
private Long msgId;

public List<WxMpKfMsgRecord> getRecords() {
return records;
}

public void setRecords(List<WxMpKfMsgRecord> records) {
this.records = records;
}

public Integer getNumber() {
return number;
}

public void setNumber(Integer number) {
this.number = number;
}

public Long getMsgId() {
return msgId;
}

public void setMsgId(Long msgId) {
this.msgId = msgId;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public static WxMpKfMsgList fromJson(String responseContent) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(responseContent, WxMpKfMsgList.class);
}
}

+ 87
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfMsgRecord.java Переглянути файл

@@ -0,0 +1,87 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.gson.annotations.SerializedName;
import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
* Created by Binary Wang on 2016/7/18.
*/
public class WxMpKfMsgRecord {
/**
* worker 完整客服帐号,格式为:帐号前缀@公众号微信号
*/
@SerializedName("worker")
private String worker;

/**
* openid 用户标识
*/
@SerializedName("openid")
private String openid;

/**
* opercode 操作码,2002(客服发送信息),2003(客服接收消息)
*/
@SerializedName("opercode")
private Integer operateCode;

/**
* text 聊天记录
*/
@SerializedName("text")
private String text;

/**
* time 操作时间,unix时间戳
*/
@SerializedName("time")
@JsonSerialize(using = WxLongTimeJsonSerializer.class)
private Long time;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public String getWorker() {
return worker;
}

public void setWorker(String worker) {
this.worker = worker;
}

public String getOpenid() {
return openid;
}

public void setOpenid(String openid) {
this.openid = openid;
}

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}

public Long getTime() {
return time;
}

public void setTime(Long time) {
this.time = time;
}

public Integer getOperateCode() {
return operateCode;
}

public void setOperateCode(Integer operateCode) {
this.operateCode = operateCode;
}
}

+ 36
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfOnlineList.java Переглянути файл

@@ -0,0 +1,36 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
/**
*
* @author Binary Wang
*
*/
public class WxMpKfOnlineList {
@SerializedName("kf_online_list")
private List<WxMpKfInfo> kfOnlineList;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public List<WxMpKfInfo> getKfOnlineList() {
return this.kfOnlineList;
}

public void setKfOnlineList(List<WxMpKfInfo> kfOnlineList) {
this.kfOnlineList = kfOnlineList;
}

public static WxMpKfOnlineList fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfOnlineList.class);
}
}

+ 76
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSession.java Переглянути файл

@@ -0,0 +1,76 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

/**
*
* @author Binary Wang
*
*/
public class WxMpKfSession {
/**
* kf_account 正在接待的客服,为空表示没有人在接待
*/
@SerializedName("kf_account")
private String kfAccount;

/**
* createtime 会话接入的时间,UNIX时间戳
* 该返回值 存在于 获取客服会话列表接口
*/
@SerializedName("createtime")
private long createTime;

/**
* latest_time 粉丝的最后一条消息的时间,UNIX时间戳
* 该返回值 存在于 获取未接入会话列表接口
*/
@SerializedName("latest_time")
private long latestTime;

/**
* openid 客户openid
*/
@SerializedName("openid")
private String openid;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public String getKfAccount() {
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}

public long getCreateTime() {
return this.createTime;
}

public void setCreateTime(long createTime) {
this.createTime = createTime;
}

public String getOpenid() {
return this.openid;
}

public void setOpenid(String openid) {
this.openid = openid;
}

public long getLatestTime() {
return this.latestTime;
}

public void setLatestTime(long latestTime) {
this.latestTime = latestTime;
}
}

+ 53
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionGetResult.java Переглянути файл

@@ -0,0 +1,53 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
*
* @author Binary Wang
*
*/
public class WxMpKfSessionGetResult {
/**
* kf_account 正在接待的客服,为空表示没有人在接待
*/
@SerializedName("kf_account")
private String kfAccount;

/**
* createtime 会话接入的时间 ,UNIX时间戳
*/
@SerializedName("createtime")
private long createTime;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
public static WxMpKfSessionGetResult fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpKfSessionGetResult.class);
}
public String getKfAccount() {
return this.kfAccount;
}

public void setKfAccount(String kfAccount) {
this.kfAccount = kfAccount;
}

public long getCreateTime() {
return this.createTime;
}

public void setCreateTime(long createTime) {
this.createTime = createTime;
}

}

+ 41
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionList.java Переглянути файл

@@ -0,0 +1,41 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
*
* @author Binary Wang
*
*/
public class WxMpKfSessionList {
/**
* 会话列表
*/
@SerializedName("sessionlist")
private List<WxMpKfSession> kfSessionList;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public static WxMpKfSessionList fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
WxMpKfSessionList.class);
}

public List<WxMpKfSession> getKfSessionList() {
return this.kfSessionList;
}

public void setKfSessionList(List<WxMpKfSession> kfSessionList) {
this.kfSessionList = kfSessionList;
}
}

+ 48
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/kefu/result/WxMpKfSessionWaitCaseList.java Переглянути файл

@@ -0,0 +1,48 @@
package me.chanjar.weixin.mp.bean.kefu.result;

import java.util.List;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import com.google.gson.annotations.SerializedName;

import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;

/**
*
* @author Binary Wang
*
*/
public class WxMpKfSessionWaitCaseList {
/**
* count 未接入会话数量
*/
@SerializedName("count")
private Long count;

/**
* waitcaselist 未接入会话列表,最多返回100条数据
*/
@SerializedName("waitcaselist")
private List<WxMpKfSession> kfSessionWaitCaseList;

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

public static WxMpKfSessionWaitCaseList fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json,
WxMpKfSessionWaitCaseList.class);
}

public List<WxMpKfSession> getKfSessionWaitCaseList() {
return this.kfSessionWaitCaseList;
}

public void setKfSessionWaitCaseList(List<WxMpKfSession> kfSessionWaitCaseList) {
this.kfSessionWaitCaseList = kfSessionWaitCaseList;
}

}

+ 5
- 5
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/outxmlbuilder/TransferCustomerServiceBuilder.java Переглянути файл

@@ -14,18 +14,18 @@ import me.chanjar.weixin.mp.bean.WxMpXmlOutTransferCustomerServiceMessage;
public final class TransferCustomerServiceBuilder extends BaseBuilder<TransferCustomerServiceBuilder, WxMpXmlOutTransferCustomerServiceMessage> {
private String kfAccount;

public TransferCustomerServiceBuilder kfAccount(String kfAccount) {
this.kfAccount = kfAccount;
public TransferCustomerServiceBuilder kfAccount(String kf) {
this.kfAccount = kf;
return this;
}

@Override
public WxMpXmlOutTransferCustomerServiceMessage build() {
WxMpXmlOutTransferCustomerServiceMessage m = new WxMpXmlOutTransferCustomerServiceMessage();
setCommon(m);
if(StringUtils.isNotBlank(kfAccount)){
if(StringUtils.isNotBlank(this.kfAccount)){
WxMpXmlOutTransferCustomerServiceMessage.TransInfo transInfo = new WxMpXmlOutTransferCustomerServiceMessage.TransInfo();
transInfo.setKfAccount(kfAccount);
transInfo.setKfAccount(this.kfAccount);
m.setTransInfo(transInfo);
}
return m;


+ 5
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpQrCodeTicket.java Переглянути файл

@@ -45,4 +45,9 @@ public class WxMpQrCodeTicket implements Serializable {
public static WxMpQrCodeTicket fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class);
}

@Override
public String toString() {
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
}
}

+ 5
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpUserList.java Переглянути файл

@@ -44,4 +44,9 @@ public class WxMpUserList {
public static WxMpUserList fromJson(String json) {
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class);
}

@Override
public String toString() {
return WxMpGsonBuilder.INSTANCE.create().toJson(this);
}
}

+ 24
- 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/json/WxLongTimeJsonSerializer.java Переглянути файл

@@ -0,0 +1,24 @@
package me.chanjar.weixin.mp.util.json;

import java.io.IOException;
import java.text.SimpleDateFormat;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

/**
* Created by Binary Wang on 2016/7/13.
*/
public class WxLongTimeJsonSerializer extends JsonSerializer<Long> {
private static SimpleDateFormat DF = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");

@Override
public void serialize(Long value, JsonGenerator gen,
SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeString(DF.format(value * 1000));
}
}

Деякі файли не було показано, через те що забагато файлів було змінено

Завантаження…
Відмінити
Зберегти