@@ -1,11 +1,11 @@ | |||||
<?xml version="1.0"?> | <?xml version="1.0"?> | ||||
<project | <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> | <modelVersion>4.0.0</modelVersion> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>1.3.5</version> | |||||
<version>2.0.0-SNAPSHOT</version> | |||||
<packaging>pom</packaging> | <packaging>pom</packaging> | ||||
<name>WeiXin Java Tools - Parent</name> | <name>WeiXin Java Tools - Parent</name> | ||||
<description>微信公众号、企业号上级POM</description> | <description>微信公众号、企业号上级POM</description> | ||||
@@ -39,7 +39,6 @@ | |||||
<module>weixin-java-common</module> | <module>weixin-java-common</module> | ||||
<module>weixin-java-cp</module> | <module>weixin-java-cp</module> | ||||
<module>weixin-java-mp</module> | <module>weixin-java-mp</module> | ||||
<module>spring-demo</module> | |||||
</modules> | </modules> | ||||
<properties> | <properties> | ||||
@@ -50,6 +49,13 @@ | |||||
<slf4j.version>1.7.10</slf4j.version> | <slf4j.version>1.7.10</slf4j.version> | ||||
<logback.version>1.1.2</logback.version> | <logback.version>1.1.2</logback.version> | ||||
<jodd-http.version>3.6.7</jodd-http.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> | </properties> | ||||
<dependencies> | <dependencies> | ||||
@@ -82,20 +88,30 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>com.google.code.gson</groupId> | <groupId>com.google.code.gson</groupId> | ||||
<artifactId>gson</artifactId> | <artifactId>gson</artifactId> | ||||
<version>2.2.2</version> | |||||
<version>${gson.version}</version> | |||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>commons-codec</groupId> | <groupId>commons-codec</groupId> | ||||
<artifactId>commons-codec</artifactId> | <artifactId>commons-codec</artifactId> | ||||
<version>1.9</version> | |||||
<version>${commons-codec.version}</version> | |||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>commons-io</groupId> | <groupId>commons-io</groupId> | ||||
<artifactId>commons-io</artifactId> | <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> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
<dependencyManagement> | <dependencyManagement> | ||||
<dependencies> | <dependencies> | ||||
<dependency> | <dependency> | ||||
@@ -125,13 +141,13 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>org.eclipse.jetty</groupId> | <groupId>org.eclipse.jetty</groupId> | ||||
<artifactId>jetty-server</artifactId> | <artifactId>jetty-server</artifactId> | ||||
<version>9.3.0.M0</version> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>org.eclipse.jetty</groupId> | <groupId>org.eclipse.jetty</groupId> | ||||
<artifactId>jetty-servlet</artifactId> | <artifactId>jetty-servlet</artifactId> | ||||
<version>9.3.0.M0</version> | |||||
<version>${jetty.version}</version> | |||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
@@ -149,16 +165,16 @@ | |||||
</distributionManagement> | </distributionManagement> | ||||
<profiles> | <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> | <profile> | ||||
<id>release</id> | <id>release</id> | ||||
<build> | <build> | ||||
@@ -220,6 +236,9 @@ | |||||
<groupId>org.apache.maven.plugins</groupId> | <groupId>org.apache.maven.plugins</groupId> | ||||
<artifactId>maven-surefire-plugin</artifactId> | <artifactId>maven-surefire-plugin</artifactId> | ||||
<version>2.17</version> | <version>2.17</version> | ||||
<configuration> | |||||
<skip>true</skip> | |||||
</configuration> | |||||
</plugin> | </plugin> | ||||
</plugins> | </plugins> | ||||
</pluginManagement> | </pluginManagement> | ||||
@@ -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> |
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>1.3.5</version> | |||||
<version>2.0.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-common</artifactId> | <artifactId>weixin-java-common</artifactId> | ||||
@@ -11,6 +11,7 @@ public class WxConsts { | |||||
public static final String XML_MSG_TEXT = "text"; | public static final String XML_MSG_TEXT = "text"; | ||||
public static final String XML_MSG_IMAGE = "image"; | public static final String XML_MSG_IMAGE = "image"; | ||||
public static final String XML_MSG_VOICE = "voice"; | 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_VIDEO = "video"; | ||||
public static final String XML_MSG_NEWS = "news"; | public static final String XML_MSG_NEWS = "news"; | ||||
public static final String XML_MSG_MUSIC = "music"; | 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 XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | ||||
/////////////////////// | /////////////////////// | ||||
// 主动发送消息的消息类型 | |||||
// 主动发送消息(即客服消息)的消息类型 | |||||
/////////////////////// | /////////////////////// | ||||
public static final String CUSTOM_MSG_TEXT = "text"; | public static final String CUSTOM_MSG_TEXT = "text"; | ||||
public static final String CUSTOM_MSG_IMAGE = "image"; | 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_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_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 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 | // oauth2网页授权的scope | ||||
@@ -1,14 +1,14 @@ | |||||
package me.chanjar.weixin.common.bean; | 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.InputStream; | ||||
import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.nio.charset.StandardCharsets; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||||
/** | /** | ||||
* 企业号菜单 | * 企业号菜单 | ||||
* @author Daniel Qian | * @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/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
* @param json | |||||
* @return | |||||
*/ | */ | ||||
public static WxMenu fromJson(String json) { | public static WxMenu fromJson(String json) { | ||||
return WxGsonBuilder.create().fromJson(json, WxMenu.class); | 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/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | ||||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | * 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | ||||
* @param is | |||||
* @return | |||||
*/ | */ | ||||
public static WxMenu fromJson(InputStream is) { | 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 | @Override | ||||
@@ -195,7 +191,7 @@ public class WxMenu implements Serializable { | |||||
this.language = language; | this.language = language; | ||||
} | } | ||||
@Override | |||||
@Override | |||||
public String toString() { | public String toString() { | ||||
return "matchrule:{" + | return "matchrule:{" + | ||||
"tag_id='" + tagId + '\'' + | "tag_id='" + tagId + '\'' + | ||||
@@ -4,16 +4,11 @@ public interface WxSessionManager { | |||||
/** | /** | ||||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 | * 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 | ||||
* @param sessionId | |||||
* @return | |||||
*/ | */ | ||||
public WxSession getSession(String sessionId); | public WxSession getSession(String sessionId); | ||||
/** | /** | ||||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | * 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | ||||
* @param sessionId | |||||
* @param create | |||||
* @return | |||||
*/ | */ | ||||
public WxSession getSession(String sessionId, boolean create); | public WxSession getSession(String sessionId, boolean create); | ||||
@@ -12,9 +12,6 @@ public class SHA1 { | |||||
/** | /** | ||||
* 串接arr参数,生成sha1 digest | * 串接arr参数,生成sha1 digest | ||||
* | |||||
* @param arr | |||||
* @return | |||||
*/ | */ | ||||
public static String gen(String... arr) throws NoSuchAlgorithmException { | public static String gen(String... arr) throws NoSuchAlgorithmException { | ||||
Arrays.sort(arr); | Arrays.sort(arr); | ||||
@@ -27,9 +24,6 @@ public class SHA1 { | |||||
/** | /** | ||||
* 用&串接arr参数,生成sha1 digest | * 用&串接arr参数,生成sha1 digest | ||||
* | |||||
* @param arr | |||||
* @return | |||||
*/ | */ | ||||
public static String genWithAmple(String... arr) throws NoSuchAlgorithmException { | public static String genWithAmple(String... arr) throws NoSuchAlgorithmException { | ||||
Arrays.sort(arr); | Arrays.sort(arr); | ||||
@@ -35,16 +35,16 @@ public class WxCryptUtil { | |||||
private static final Base64 base64 = new Base64(); | private static final Base64 base64 = new Base64(); | ||||
private static final Charset CHARSET = Charset.forName("utf-8"); | 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 byte[] aesKey; | ||||
protected String token; | protected String token; | ||||
@@ -61,7 +61,8 @@ public class WxCryptUtil { | |||||
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | ||||
* @param appidOrCorpid 公众平台appid/corpid | * @param appidOrCorpid 公众平台appid/corpid | ||||
*/ | */ | ||||
public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { | |||||
public WxCryptUtil(String token, String encodingAesKey, | |||||
String appidOrCorpid) { | |||||
this.token = token; | this.token = token; | ||||
this.appidOrCorpid = appidOrCorpid; | this.appidOrCorpid = appidOrCorpid; | ||||
this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | ||||
@@ -105,7 +106,8 @@ public class WxCryptUtil { | |||||
ByteGroup byteCollector = new ByteGroup(); | ByteGroup byteCollector = new ByteGroup(); | ||||
byte[] randomStringBytes = randomStr.getBytes(CHARSET); | byte[] randomStringBytes = randomStr.getBytes(CHARSET); | ||||
byte[] plainTextBytes = plainText.getBytes(CHARSET); | byte[] plainTextBytes = plainText.getBytes(CHARSET); | ||||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); | |||||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | |||||
plainTextBytes.length); | |||||
byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | ||||
// randomStr + networkBytesOrder + text + appid | // randomStr + networkBytesOrder + text + appid | ||||
@@ -154,7 +156,8 @@ public class WxCryptUtil { | |||||
* @param encryptedXml 密文,对应POST请求的数据 | * @param encryptedXml 密文,对应POST请求的数据 | ||||
* @return 解密后的原文 | * @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 | // 密钥,公众账号的app corpSecret | ||||
// 提取密文 | // 提取密文 | ||||
String cipherText = extractEncryptPart(encryptedXml); | String cipherText = extractEncryptPart(encryptedXml); | ||||
@@ -186,7 +189,8 @@ public class WxCryptUtil { | |||||
// 设置解密模式为AES的CBC模式 | // 设置解密模式为AES的CBC模式 | ||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | ||||
SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); | 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); | cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | ||||
// 使用BASE64对密文进行解码 | // 使用BASE64对密文进行解码 | ||||
@@ -208,9 +212,10 @@ public class WxCryptUtil { | |||||
int xmlLength = bytesNetworkOrder2Number(networkOrder); | 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); | CHARSET); | ||||
from_appid = new String( | |||||
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
throw new RuntimeException(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数组 | * 将一个数字转换成生成4个字节的网络字节序bytes数组 | ||||
@@ -283,8 +286,6 @@ public class WxCryptUtil { | |||||
/** | /** | ||||
* 随机生成16位字符串 | * 随机生成16位字符串 | ||||
* | |||||
* @return | |||||
*/ | */ | ||||
private String genRandomStr() { | private String genRandomStr() { | ||||
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | ||||
@@ -306,14 +307,12 @@ public class WxCryptUtil { | |||||
* @param nonce 随机字符串 | * @param nonce 随机字符串 | ||||
* @return 生成的xml字符串 | * @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); | return String.format(format, encrypt, signature, timestamp, nonce); | ||||
} | } | ||||
@@ -14,8 +14,6 @@ public class FileUtils { | |||||
* @param name 文件名 | * @param name 文件名 | ||||
* @param ext 扩展名 | * @param ext 扩展名 | ||||
* @param tmpDirFile 临时文件夹目录 | * @param tmpDirFile 临时文件夹目录 | ||||
* @return | |||||
* @throws IOException | |||||
*/ | */ | ||||
public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | ||||
FileOutputStream fos = null; | FileOutputStream fos = null; | ||||
@@ -56,8 +54,6 @@ public class FileUtils { | |||||
* @param inputStream | * @param inputStream | ||||
* @param name 文件名 | * @param name 文件名 | ||||
* @param ext 扩展名 | * @param ext 扩展名 | ||||
* @return | |||||
* @throws IOException | |||||
*/ | */ | ||||
public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | ||||
return createTmpFile(inputStream, name, ext, null); | return createTmpFile(inputStream, name, ext, null); | ||||
@@ -17,35 +17,30 @@ public interface ApacheHttpClientBuilder { | |||||
/** | /** | ||||
* 代理服务器地址 | * 代理服务器地址 | ||||
* @param httpProxyHost | * @param httpProxyHost | ||||
* @return | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | ||||
/** | /** | ||||
* 代理服务器端口 | * 代理服务器端口 | ||||
* @param httpProxyPort | * @param httpProxyPort | ||||
* @return | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | ||||
/** | /** | ||||
* 代理服务器用户名 | * 代理服务器用户名 | ||||
* @param httpProxyUsername | * @param httpProxyUsername | ||||
* @return | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | ||||
/** | /** | ||||
* 代理服务器密码 | * 代理服务器密码 | ||||
* @param httpProxyPassword | * @param httpProxyPassword | ||||
* @return | |||||
*/ | */ | ||||
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | ||||
/** | /** | ||||
* ssl连接socket工厂 | * ssl连接socket工厂 | ||||
* @param sslConnectionSocketFactory | * @param sslConnectionSocketFactory | ||||
* @return | |||||
*/ | */ | ||||
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | ||||
} | } |
@@ -22,7 +22,6 @@ public interface RequestExecutor<T, E> { | |||||
* @param httpProxy http代理对象,如果没有配置代理则为空 | * @param httpProxy http代理对象,如果没有配置代理则为空 | ||||
* @param uri uri | * @param uri uri | ||||
* @param data 数据 | * @param data 数据 | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
* @throws ClientProtocolException | * @throws ClientProtocolException | ||||
* @throws IOException | * @throws IOException | ||||
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>1.3.5</version> | |||||
<version>2.0.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-cp</artifactId> | <artifactId>weixin-java-cp</artifactId> | ||||
@@ -9,8 +9,6 @@ public interface WxCpMessageMatcher { | |||||
/** | /** | ||||
* 消息是否匹配某种模式 | * 消息是否匹配某种模式 | ||||
* @param message | |||||
* @return | |||||
*/ | */ | ||||
public boolean match(WxCpXmlMessage message); | public boolean match(WxCpXmlMessage message); | ||||
@@ -124,7 +124,6 @@ public class WxCpMessageRouter { | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule rule() { | public WxCpMessageRouterRule rule() { | ||||
return new WxCpMessageRouterRule(this); | return new WxCpMessageRouterRule(this); | ||||
@@ -48,7 +48,6 @@ public class WxCpMessageRouterRule { | |||||
* 设置是否异步执行,默认是true | * 设置是否异步执行,默认是true | ||||
* | * | ||||
* @param async | * @param async | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule async(boolean async) { | public WxCpMessageRouterRule async(boolean async) { | ||||
this.async = async; | this.async = async; | ||||
@@ -59,7 +58,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果agentId匹配 | * 如果agentId匹配 | ||||
* | * | ||||
* @param agentId | * @param agentId | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule agentId(Integer agentId) { | public WxCpMessageRouterRule agentId(Integer agentId) { | ||||
this.agentId = agentId; | this.agentId = agentId; | ||||
@@ -70,7 +68,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果msgType等于某值 | * 如果msgType等于某值 | ||||
* | * | ||||
* @param msgType | * @param msgType | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule msgType(String msgType) { | public WxCpMessageRouterRule msgType(String msgType) { | ||||
this.msgType = msgType; | this.msgType = msgType; | ||||
@@ -81,7 +78,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果event等于某值 | * 如果event等于某值 | ||||
* | * | ||||
* @param event | * @param event | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule event(String event) { | public WxCpMessageRouterRule event(String event) { | ||||
this.event = event; | this.event = event; | ||||
@@ -92,7 +88,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果eventKey等于某值 | * 如果eventKey等于某值 | ||||
* | * | ||||
* @param eventKey | * @param eventKey | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule eventKey(String eventKey) { | public WxCpMessageRouterRule eventKey(String eventKey) { | ||||
this.eventKey = eventKey; | this.eventKey = eventKey; | ||||
@@ -103,7 +98,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果content等于某值 | * 如果content等于某值 | ||||
* | * | ||||
* @param content | * @param content | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule content(String content) { | public WxCpMessageRouterRule content(String content) { | ||||
this.content = content; | this.content = content; | ||||
@@ -114,7 +108,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果content匹配该正则表达式 | * 如果content匹配该正则表达式 | ||||
* | * | ||||
* @param regex | * @param regex | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule rContent(String regex) { | public WxCpMessageRouterRule rContent(String regex) { | ||||
this.rContent = regex; | this.rContent = regex; | ||||
@@ -125,7 +118,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果fromUser等于某值 | * 如果fromUser等于某值 | ||||
* | * | ||||
* @param fromUser | * @param fromUser | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule fromUser(String fromUser) { | public WxCpMessageRouterRule fromUser(String fromUser) { | ||||
this.fromUser = fromUser; | this.fromUser = fromUser; | ||||
@@ -136,7 +128,6 @@ public class WxCpMessageRouterRule { | |||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | ||||
* | * | ||||
* @param matcher | * @param matcher | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { | public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { | ||||
this.matcher = matcher; | this.matcher = matcher; | ||||
@@ -147,7 +138,6 @@ public class WxCpMessageRouterRule { | |||||
* 设置微信消息拦截器 | * 设置微信消息拦截器 | ||||
* | * | ||||
* @param interceptor | * @param interceptor | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { | public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { | ||||
return interceptor(interceptor, (WxCpMessageInterceptor[]) null); | return interceptor(interceptor, (WxCpMessageInterceptor[]) null); | ||||
@@ -158,7 +148,6 @@ public class WxCpMessageRouterRule { | |||||
* | * | ||||
* @param interceptor | * @param interceptor | ||||
* @param otherInterceptors | * @param otherInterceptors | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { | public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { | ||||
this.interceptors.add(interceptor); | this.interceptors.add(interceptor); | ||||
@@ -174,7 +163,6 @@ public class WxCpMessageRouterRule { | |||||
* 设置微信消息处理器 | * 设置微信消息处理器 | ||||
* | * | ||||
* @param handler | * @param handler | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { | public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { | ||||
return handler(handler, (WxCpMessageHandler[]) null); | return handler(handler, (WxCpMessageHandler[]) null); | ||||
@@ -185,7 +173,6 @@ public class WxCpMessageRouterRule { | |||||
* | * | ||||
* @param handler | * @param handler | ||||
* @param otherHandlers | * @param otherHandlers | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { | public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { | ||||
this.handlers.add(handler); | this.handlers.add(handler); | ||||
@@ -200,7 +187,6 @@ public class WxCpMessageRouterRule { | |||||
/** | /** | ||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | ||||
* | * | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouter end() { | public WxCpMessageRouter end() { | ||||
this.routerBuilder.getRules().add(this); | this.routerBuilder.getRules().add(this); | ||||
@@ -210,7 +196,6 @@ public class WxCpMessageRouterRule { | |||||
/** | /** | ||||
* 规则结束,但是消息还会进入其他规则 | * 规则结束,但是消息还会进入其他规则 | ||||
* | * | ||||
* @return | |||||
*/ | */ | ||||
public WxCpMessageRouter next() { | public WxCpMessageRouter next() { | ||||
this.reEnter = true; | this.reEnter = true; | ||||
@@ -32,7 +32,6 @@ public interface WxCpService { | |||||
* @param timestamp | * @param timestamp | ||||
* @param nonce | * @param nonce | ||||
* @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 | * @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 | ||||
* @return | |||||
*/ | */ | ||||
boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); | boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); | ||||
@@ -49,7 +48,6 @@ public interface WxCpService { | |||||
/** | /** | ||||
* 获取access_token, 不强制刷新access_token | * 获取access_token, 不强制刷新access_token | ||||
* @see #getAccessToken(boolean) | * @see #getAccessToken(boolean) | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String getAccessToken() throws WxErrorException; | String getAccessToken() throws WxErrorException; | ||||
@@ -63,7 +61,6 @@ public interface WxCpService { | |||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token | * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token | ||||
* </pre> | * </pre> | ||||
* @param forceRefresh 强制刷新 | * @param forceRefresh 强制刷新 | ||||
* @return | |||||
* @throws me.chanjar.weixin.common.exception.WxErrorException | * @throws me.chanjar.weixin.common.exception.WxErrorException | ||||
*/ | */ | ||||
String getAccessToken(boolean forceRefresh) throws WxErrorException; | String getAccessToken(boolean forceRefresh) throws WxErrorException; | ||||
@@ -71,7 +68,6 @@ public interface WxCpService { | |||||
/** | /** | ||||
* 获得jsapi_ticket,不强制刷新jsapi_ticket | * 获得jsapi_ticket,不强制刷新jsapi_ticket | ||||
* @see #getJsapiTicket(boolean) | * @see #getJsapiTicket(boolean) | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
public String getJsapiTicket() 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 | * 详情请见: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> | * </pre> | ||||
* @param forceRefresh 强制刷新 | * @param forceRefresh 强制刷新 | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
public String getJsapiTicket(boolean forceRefresh) 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 | * 详情请见: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> | * </pre> | ||||
* @param url url | * @param url url | ||||
* @return | |||||
*/ | */ | ||||
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | ||||
@@ -136,7 +130,7 @@ public interface WxCpService { | |||||
* | * | ||||
* @return 保存到本地的临时文件 | * @return 保存到本地的临时文件 | ||||
* @throws WxErrorException | * @throws WxErrorException | ||||
* @params media_id | |||||
* @param media_id | |||||
*/ | */ | ||||
File mediaDownload(String media_id) throws WxErrorException; | File mediaDownload(String media_id) throws WxErrorException; | ||||
@@ -216,7 +210,6 @@ public interface WxCpService { | |||||
* </pre> | * </pre> | ||||
* @see #menuGet(String) | * @see #menuGet(String) | ||||
* | * | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
WxMenu menuGet() throws WxErrorException; | WxMenu menuGet() throws WxErrorException; | ||||
@@ -231,7 +224,6 @@ public interface WxCpService { | |||||
* @see #menuGet() | * @see #menuGet() | ||||
* | * | ||||
* @param agentId 企业号应用的id | * @param agentId 企业号应用的id | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
WxMenu menuGet(String agentId) throws WxErrorException; | WxMenu menuGet(String agentId) throws WxErrorException; | ||||
@@ -255,7 +247,6 @@ public interface WxCpService { | |||||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | ||||
* </pre> | * </pre> | ||||
* | * | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
List<WxCpDepart> departGet() throws WxErrorException; | List<WxCpDepart> departGet() throws WxErrorException; | ||||
@@ -291,7 +282,6 @@ public interface WxCpService { | |||||
* @param departId 必填。部门id | * @param departId 必填。部门id | ||||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | ||||
@@ -306,7 +296,6 @@ public interface WxCpService { | |||||
* @param departId 必填。部门id | * @param departId 必填。部门id | ||||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | ||||
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | ||||
@@ -350,7 +339,6 @@ public interface WxCpService { | |||||
* 获取用户 | * 获取用户 | ||||
* | * | ||||
* @param userid | * @param userid | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
WxCpUser userGet(String userid) throws WxErrorException; | WxCpUser userGet(String userid) throws WxErrorException; | ||||
@@ -359,7 +347,6 @@ public interface WxCpService { | |||||
* 创建标签 | * 创建标签 | ||||
* | * | ||||
* @param tagName | * @param tagName | ||||
* @return | |||||
*/ | */ | ||||
String tagCreate(String tagName) throws WxErrorException; | String tagCreate(String tagName) throws WxErrorException; | ||||
@@ -381,7 +368,6 @@ public interface WxCpService { | |||||
/** | /** | ||||
* 获得标签列表 | * 获得标签列表 | ||||
* | * | ||||
* @return | |||||
*/ | */ | ||||
List<WxCpTag> tagGet() throws WxErrorException; | List<WxCpTag> tagGet() throws WxErrorException; | ||||
@@ -389,7 +375,6 @@ public interface WxCpService { | |||||
* 获取标签成员 | * 获取标签成员 | ||||
* | * | ||||
* @param tagId | * @param tagId | ||||
* @return | |||||
*/ | */ | ||||
List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException; | List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException; | ||||
@@ -478,7 +463,6 @@ public interface WxCpService { | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | ||||
* @param url | * @param url | ||||
* @param queryParam | * @param queryParam | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String get(String url, String queryParam) throws WxErrorException; | String get(String url, String queryParam) throws WxErrorException; | ||||
@@ -487,7 +471,6 @@ public interface WxCpService { | |||||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 | * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 | ||||
* @param url | * @param url | ||||
* @param postData | * @param postData | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String post(String url, String postData) throws WxErrorException; | String post(String url, String postData) throws WxErrorException; | ||||
@@ -503,7 +486,6 @@ public interface WxCpService { | |||||
* @param data | * @param data | ||||
* @param <T> | * @param <T> | ||||
* @param <E> | * @param <E> | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) 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,则新建一个并返回。 | * 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 | ||||
* @param id id可以为任意字符串,建议使用FromUserName作为id | * @param id id可以为任意字符串,建议使用FromUserName作为id | ||||
* @return | |||||
*/ | */ | ||||
WxSession getSession(String id); | WxSession getSession(String id); | ||||
@@ -544,7 +525,6 @@ public interface WxCpService { | |||||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | * 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | ||||
* @param id id可以为任意字符串,建议使用FromUserName作为id | * @param id id可以为任意字符串,建议使用FromUserName作为id | ||||
* @param create | * @param create | ||||
* @return | |||||
*/ | */ | ||||
WxSession getSession(String id, boolean create); | WxSession getSession(String id, boolean create); | ||||
@@ -556,25 +536,24 @@ public interface WxCpService { | |||||
* @param sessionManager | * @param sessionManager | ||||
*/ | */ | ||||
void setSessionManager(WxSessionManager sessionManager); | void setSessionManager(WxSessionManager sessionManager); | ||||
/** | /** | ||||
* 上传部门列表覆盖企业号上的部门信息 | * 上传部门列表覆盖企业号上的部门信息 | ||||
* @param mediaId | * @param mediaId | ||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String replaceParty(String mediaId) throws WxErrorException; | String replaceParty(String mediaId) throws WxErrorException; | ||||
/** | /** | ||||
* 上传用户列表覆盖企业号上的用户信息 | * 上传用户列表覆盖企业号上的用户信息 | ||||
* @param mediaId | * @param mediaId | ||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String replaceUser(String mediaId) throws WxErrorException; | String replaceUser(String mediaId) throws WxErrorException; | ||||
/** | /** | ||||
* 获取异步任务结果 | * 获取异步任务结果 | ||||
* @param joinId | * @param joinId | ||||
* @return | |||||
* @throws WxErrorException | * @throws WxErrorException | ||||
*/ | */ | ||||
String getTaskResult(String joinId) throws WxErrorException; | String getTaskResult(String joinId) throws WxErrorException; | ||||
@@ -510,12 +510,6 @@ public class WxCpServiceImpl implements WxCpService { | |||||
/** | /** | ||||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | * 向微信端发送请求,在这里执行的策略是当发生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 { | public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | ||||
int retryTimes = 0; | int retryTimes = 0; | ||||
@@ -28,7 +28,7 @@ public class WxCpMessage implements Serializable { | |||||
private String hqMusicUrl; | private String hqMusicUrl; | ||||
private String safe; | private String safe; | ||||
private List<WxArticle> articles = new ArrayList<WxArticle>(); | private List<WxArticle> articles = new ArrayList<WxArticle>(); | ||||
public String getToUser() { | public String getToUser() { | ||||
return toUser; | return toUser; | ||||
} | } | ||||
@@ -63,7 +63,7 @@ public class WxCpMessage implements Serializable { | |||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | return msgType; | ||||
} | } | ||||
public String getSafe() { | public String getSafe() { | ||||
return safe; | return safe; | ||||
} | } | ||||
@@ -135,18 +135,18 @@ public class WxCpMessage implements Serializable { | |||||
public void setArticles(List<WxArticle> articles) { | public void setArticles(List<WxArticle> articles) { | ||||
this.articles = articles; | this.articles = articles; | ||||
} | } | ||||
public String toJson() { | public String toJson() { | ||||
return WxCpGsonBuilder.INSTANCE.create().toJson(this); | return WxCpGsonBuilder.INSTANCE.create().toJson(this); | ||||
} | } | ||||
public static class WxArticle { | public static class WxArticle { | ||||
private String title; | private String title; | ||||
private String description; | private String description; | ||||
private String url; | private String url; | ||||
private String picUrl; | private String picUrl; | ||||
public String getTitle() { | public String getTitle() { | ||||
return title; | return title; | ||||
} | } | ||||
@@ -171,12 +171,11 @@ public class WxCpMessage implements Serializable { | |||||
public void setPicUrl(String picUrl) { | public void setPicUrl(String picUrl) { | ||||
this.picUrl = picUrl; | this.picUrl = picUrl; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* 获得文本消息builder | * 获得文本消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static TextBuilder TEXT() { | public static TextBuilder TEXT() { | ||||
return new TextBuilder(); | return new TextBuilder(); | ||||
@@ -184,7 +183,6 @@ public class WxCpMessage implements Serializable { | |||||
/** | /** | ||||
* 获得图片消息builder | * 获得图片消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static ImageBuilder IMAGE() { | public static ImageBuilder IMAGE() { | ||||
return new ImageBuilder(); | return new ImageBuilder(); | ||||
@@ -192,23 +190,20 @@ public class WxCpMessage implements Serializable { | |||||
/** | /** | ||||
* 获得语音消息builder | * 获得语音消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VoiceBuilder VOICE() { | public static VoiceBuilder VOICE() { | ||||
return new VoiceBuilder(); | return new VoiceBuilder(); | ||||
} | } | ||||
/** | /** | ||||
* 获得视频消息builder | * 获得视频消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VideoBuilder VIDEO() { | public static VideoBuilder VIDEO() { | ||||
return new VideoBuilder(); | return new VideoBuilder(); | ||||
} | } | ||||
/** | /** | ||||
* 获得图文消息builder | * 获得图文消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static NewsBuilder NEWS() { | public static NewsBuilder NEWS() { | ||||
return new NewsBuilder(); | return new NewsBuilder(); | ||||
@@ -216,10 +211,9 @@ public class WxCpMessage implements Serializable { | |||||
/** | /** | ||||
* 获得文件消息builder | * 获得文件消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static FileBuilder FILE() { | public static FileBuilder FILE() { | ||||
return new FileBuilder(); | return new FileBuilder(); | ||||
} | } | ||||
} | } |
@@ -198,7 +198,6 @@ public class WxCpXmlMessage implements Serializable { | |||||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | ||||
* </pre> | * </pre> | ||||
* | * | ||||
* @return | |||||
*/ | */ | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | return msgType; | ||||
@@ -404,7 +403,6 @@ public class WxCpXmlMessage implements Serializable { | |||||
* @param timestamp | * @param timestamp | ||||
* @param nonce | * @param nonce | ||||
* @param msgSignature | * @param msgSignature | ||||
* @return | |||||
*/ | */ | ||||
public static WxCpXmlMessage fromEncryptedXml( | public static WxCpXmlMessage fromEncryptedXml( | ||||
String encryptedXml, | String encryptedXml, | ||||
@@ -542,7 +540,6 @@ public class WxCpXmlMessage implements Serializable { | |||||
/** | /** | ||||
* 扫描类型,一般是qrcode | * 扫描类型,一般是qrcode | ||||
* @return | |||||
*/ | */ | ||||
public String getScanType() { | public String getScanType() { | ||||
@@ -555,7 +552,6 @@ public class WxCpXmlMessage implements Serializable { | |||||
/** | /** | ||||
* 扫描结果,即二维码对应的字符串信息 | * 扫描结果,即二维码对应的字符串信息 | ||||
* @return | |||||
*/ | */ | ||||
public String getScanResult() { | public String getScanResult() { | ||||
return scanResult; | return scanResult; | ||||
@@ -14,14 +14,14 @@ public abstract class WxCpXmlOutMessage { | |||||
@XStreamAlias("ToUserName") | @XStreamAlias("ToUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | @XStreamConverter(value=XStreamCDataConverter.class) | ||||
protected String toUserName; | protected String toUserName; | ||||
@XStreamAlias("FromUserName") | @XStreamAlias("FromUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | @XStreamConverter(value=XStreamCDataConverter.class) | ||||
protected String fromUserName; | protected String fromUserName; | ||||
@XStreamAlias("CreateTime") | @XStreamAlias("CreateTime") | ||||
protected Long createTime; | protected Long createTime; | ||||
@XStreamAlias("MsgType") | @XStreamAlias("MsgType") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | @XStreamConverter(value=XStreamCDataConverter.class) | ||||
protected String msgType; | protected String msgType; | ||||
@@ -57,14 +57,13 @@ public abstract class WxCpXmlOutMessage { | |||||
public void setMsgType(String msgType) { | public void setMsgType(String msgType) { | ||||
this.msgType = msgType; | this.msgType = msgType; | ||||
} | } | ||||
protected String toXml() { | protected String toXml() { | ||||
return XStreamTransformer.toXml((Class)this.getClass(), this); | return XStreamTransformer.toXml((Class)this.getClass(), this); | ||||
} | } | ||||
/** | /** | ||||
* 转换成加密的xml格式 | * 转换成加密的xml格式 | ||||
* @return | |||||
*/ | */ | ||||
public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { | public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { | ||||
String plainXml = toXml(); | String plainXml = toXml(); | ||||
@@ -74,7 +73,6 @@ public abstract class WxCpXmlOutMessage { | |||||
/** | /** | ||||
* 获得文本消息builder | * 获得文本消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static TextBuilder TEXT() { | public static TextBuilder TEXT() { | ||||
return new TextBuilder(); | return new TextBuilder(); | ||||
@@ -82,7 +80,6 @@ public abstract class WxCpXmlOutMessage { | |||||
/** | /** | ||||
* 获得图片消息builder | * 获得图片消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static ImageBuilder IMAGE() { | public static ImageBuilder IMAGE() { | ||||
return new ImageBuilder(); | return new ImageBuilder(); | ||||
@@ -90,23 +87,20 @@ public abstract class WxCpXmlOutMessage { | |||||
/** | /** | ||||
* 获得语音消息builder | * 获得语音消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VoiceBuilder VOICE() { | public static VoiceBuilder VOICE() { | ||||
return new VoiceBuilder(); | return new VoiceBuilder(); | ||||
} | } | ||||
/** | /** | ||||
* 获得视频消息builder | * 获得视频消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VideoBuilder VIDEO() { | public static VideoBuilder VIDEO() { | ||||
return new VideoBuilder(); | return new VideoBuilder(); | ||||
} | } | ||||
/** | /** | ||||
* 获得图文消息builder | * 获得图文消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static NewsBuilder NEWS() { | public static NewsBuilder NEWS() { | ||||
return new NewsBuilder(); | return new NewsBuilder(); | ||||
@@ -14,10 +14,6 @@ public class XStreamTransformer { | |||||
/** | /** | ||||
* xml -> pojo | * xml -> pojo | ||||
* | |||||
* @param clazz | |||||
* @param xml | |||||
* @return | |||||
*/ | */ | ||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") | ||||
public static <T> T fromXml(Class<T> clazz, String xml) { | public static <T> T fromXml(Class<T> clazz, String xml) { | ||||
@@ -43,9 +39,6 @@ public class XStreamTransformer { | |||||
/** | /** | ||||
* pojo -> xml | * pojo -> xml | ||||
* | * | ||||
* @param clazz | |||||
* @param object | |||||
* @return | |||||
*/ | */ | ||||
public static <T> String toXml(Class<T> clazz, T object) { | public static <T> String toXml(Class<T> clazz, T object) { | ||||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | ||||
@@ -0,0 +1 @@ | |||||
*.pmd |
@@ -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 |
@@ -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> |
@@ -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()); | |||||
} | |||||
} |
@@ -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) ; | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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(); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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(); | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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(); | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
package com.github.binarywang.demo.spring.handler; | |||||
/** | |||||
* | |||||
* @author Binary Wang | |||||
* | |||||
*/ | |||||
public abstract class ScanHandler extends AbstractHandler { | |||||
} |
@@ -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; | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -0,0 +1,2 @@ | |||||
/wx-gzh1.properties | |||||
/wx-gzh2.properties |
@@ -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> |
@@ -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 |
@@ -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> |
@@ -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> |
@@ -0,0 +1,4 @@ | |||||
wx_appid= | |||||
wx_appsecret= | |||||
wx_token= | |||||
wx_aeskey= |
@@ -0,0 +1,4 @@ | |||||
wx_appid= | |||||
wx_appsecret= | |||||
wx_token= | |||||
wx_aeskey= |
@@ -20,14 +20,6 @@ | |||||
<filter-name>encodingFilter</filter-name> | <filter-name>encodingFilter</filter-name> | ||||
<url-pattern>/*</url-pattern> | <url-pattern>/*</url-pattern> | ||||
</filter-mapping> | </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> | ||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> | <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> |
@@ -6,7 +6,7 @@ | |||||
<parent> | <parent> | ||||
<groupId>com.github.binarywang</groupId> | <groupId>com.github.binarywang</groupId> | ||||
<artifactId>weixin-java-parent</artifactId> | <artifactId>weixin-java-parent</artifactId> | ||||
<version>1.3.5</version> | |||||
<version>2.0.0-SNAPSHOT</version> | |||||
</parent> | </parent> | ||||
<artifactId>weixin-java-mp</artifactId> | <artifactId>weixin-java-mp</artifactId> | ||||
<name>WeiXin Java Tools - MP</name> | <name>WeiXin Java Tools - MP</name> | ||||
@@ -47,6 +47,12 @@ | |||||
<groupId>org.eclipse.jetty</groupId> | <groupId>org.eclipse.jetty</groupId> | ||||
<artifactId>jetty-servlet</artifactId> | <artifactId>jetty-servlet</artifactId> | ||||
<scope>test</scope> | <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> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
@@ -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; | |||||
} |
@@ -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; | |||||
} |
@@ -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; | |||||
} |
@@ -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; | |||||
} |
@@ -10,7 +10,6 @@ public interface WxMpMessageMatcher { | |||||
/** | /** | ||||
* 消息是否匹配某种模式 | * 消息是否匹配某种模式 | ||||
* @param message | * @param message | ||||
* @return | |||||
*/ | */ | ||||
public boolean match(WxMpXmlMessage message); | public boolean match(WxMpXmlMessage message); | ||||
@@ -124,7 +124,6 @@ public class WxMpMessageRouter { | |||||
/** | /** | ||||
* 开始一个新的Route规则 | * 开始一个新的Route规则 | ||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule rule() { | public WxMpMessageRouterRule rule() { | ||||
return new WxMpMessageRouterRule(this); | return new WxMpMessageRouterRule(this); | ||||
@@ -34,9 +34,9 @@ public class WxMpMessageRouterRule { | |||||
private boolean reEnter = false; | 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) { | public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) { | ||||
this.routerBuilder = routerBuilder; | this.routerBuilder = routerBuilder; | ||||
@@ -44,9 +44,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 设置是否异步执行,默认是true | * 设置是否异步执行,默认是true | ||||
* | |||||
* @param async | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule async(boolean async) { | public WxMpMessageRouterRule async(boolean async) { | ||||
this.async = async; | this.async = async; | ||||
@@ -55,9 +52,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果msgType等于某值 | * 如果msgType等于某值 | ||||
* | |||||
* @param msgType | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule msgType(String msgType) { | public WxMpMessageRouterRule msgType(String msgType) { | ||||
this.msgType = msgType; | this.msgType = msgType; | ||||
@@ -66,9 +60,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果event等于某值 | * 如果event等于某值 | ||||
* | |||||
* @param event | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule event(String event) { | public WxMpMessageRouterRule event(String event) { | ||||
this.event = event; | this.event = event; | ||||
@@ -77,9 +68,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果eventKey等于某值 | * 如果eventKey等于某值 | ||||
* | |||||
* @param eventKey | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule eventKey(String eventKey) { | public WxMpMessageRouterRule eventKey(String eventKey) { | ||||
this.eventKey = eventKey; | this.eventKey = eventKey; | ||||
@@ -88,9 +76,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果content等于某值 | * 如果content等于某值 | ||||
* | |||||
* @param content | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule content(String content) { | public WxMpMessageRouterRule content(String content) { | ||||
this.content = content; | this.content = content; | ||||
@@ -99,9 +84,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果content匹配该正则表达式 | * 如果content匹配该正则表达式 | ||||
* | |||||
* @param regex | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule rContent(String regex) { | public WxMpMessageRouterRule rContent(String regex) { | ||||
this.rContent = regex; | this.rContent = regex; | ||||
@@ -110,9 +92,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果fromUser等于某值 | * 如果fromUser等于某值 | ||||
* | |||||
* @param fromUser | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule fromUser(String fromUser) { | public WxMpMessageRouterRule fromUser(String fromUser) { | ||||
this.fromUser = fromUser; | this.fromUser = fromUser; | ||||
@@ -121,9 +100,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | ||||
* | |||||
* @param matcher | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { | public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { | ||||
this.matcher = matcher; | this.matcher = matcher; | ||||
@@ -132,9 +108,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 设置微信消息拦截器 | * 设置微信消息拦截器 | ||||
* | |||||
* @param interceptor | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { | public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { | ||||
return interceptor(interceptor, (WxMpMessageInterceptor[]) null); | return interceptor(interceptor, (WxMpMessageInterceptor[]) null); | ||||
@@ -142,10 +115,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 设置微信消息拦截器 | * 设置微信消息拦截器 | ||||
* | |||||
* @param interceptor | |||||
* @param otherInterceptors | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { | public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { | ||||
this.interceptors.add(interceptor); | this.interceptors.add(interceptor); | ||||
@@ -159,9 +128,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 设置微信消息处理器 | * 设置微信消息处理器 | ||||
* | |||||
* @param handler | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { | public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { | ||||
return handler(handler, (WxMpMessageHandler[]) null); | return handler(handler, (WxMpMessageHandler[]) null); | ||||
@@ -169,10 +135,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 设置微信消息处理器 | * 设置微信消息处理器 | ||||
* | |||||
* @param handler | |||||
* @param otherHandlers | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { | public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { | ||||
this.handlers.add(handler); | this.handlers.add(handler); | ||||
@@ -186,8 +148,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | ||||
* | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouter end() { | public WxMpMessageRouter end() { | ||||
this.routerBuilder.getRules().add(this); | this.routerBuilder.getRules().add(this); | ||||
@@ -196,8 +156,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 规则结束,但是消息还会进入其他规则 | * 规则结束,但是消息还会进入其他规则 | ||||
* | |||||
* @return | |||||
*/ | */ | ||||
public WxMpMessageRouter next() { | public WxMpMessageRouter next() { | ||||
this.reEnter = true; | this.reEnter = true; | ||||
@@ -207,8 +165,6 @@ public class WxMpMessageRouterRule { | |||||
/** | /** | ||||
* 将微信自定义的事件修正为不区分大小写, | * 将微信自定义的事件修正为不区分大小写, | ||||
* 比如框架定义的事件常量为click,但微信传递过来的却是CLICK | * 比如框架定义的事件常量为click,但微信传递过来的却是CLICK | ||||
* @param wxMessage | |||||
* @return | |||||
*/ | */ | ||||
protected boolean test(WxMpXmlMessage wxMessage) { | protected boolean test(WxMpXmlMessage wxMessage) { | ||||
return | return | ||||
@@ -243,7 +199,7 @@ public class WxMpMessageRouterRule { | |||||
try { | try { | ||||
Map<String, Object> context = new HashMap<String, Object>(); | |||||
Map<String, Object> context = new HashMap<>(); | |||||
// 如果拦截器不通过 | // 如果拦截器不通过 | ||||
for (WxMpMessageInterceptor interceptor : this.interceptors) { | for (WxMpMessageInterceptor interceptor : this.interceptors) { | ||||
if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { | if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { | ||||
@@ -255,6 +211,9 @@ public class WxMpMessageRouterRule { | |||||
WxMpXmlOutMessage res = null; | WxMpXmlOutMessage res = null; | ||||
for (WxMpMessageHandler handler : this.handlers) { | for (WxMpMessageHandler handler : this.handlers) { | ||||
// 返回最后handler的结果 | // 返回最后handler的结果 | ||||
if(handler == null){ | |||||
continue; | |||||
} | |||||
res = handler.handle(wxMessage, context, wxMpService, sessionManager); | res = handler.handle(wxMessage, context, wxMpService, sessionManager); | ||||
} | } | ||||
return res; | return res; | ||||
@@ -266,11 +225,11 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public WxMpMessageRouter getRouterBuilder() { | public WxMpMessageRouter getRouterBuilder() { | ||||
return routerBuilder; | |||||
return this.routerBuilder; | |||||
} | } | ||||
public boolean isAsync() { | public boolean isAsync() { | ||||
return async; | |||||
return this.async; | |||||
} | } | ||||
public void setAsync(boolean async) { | public void setAsync(boolean async) { | ||||
@@ -278,7 +237,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getFromUser() { | public String getFromUser() { | ||||
return fromUser; | |||||
return this.fromUser; | |||||
} | } | ||||
public void setFromUser(String fromUser) { | public void setFromUser(String fromUser) { | ||||
@@ -286,7 +245,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | |||||
return this.msgType; | |||||
} | } | ||||
public void setMsgType(String msgType) { | public void setMsgType(String msgType) { | ||||
@@ -294,7 +253,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getEvent() { | public String getEvent() { | ||||
return event; | |||||
return this.event; | |||||
} | } | ||||
public void setEvent(String event) { | public void setEvent(String event) { | ||||
@@ -302,7 +261,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getEventKey() { | public String getEventKey() { | ||||
return eventKey; | |||||
return this.eventKey; | |||||
} | } | ||||
public void setEventKey(String eventKey) { | public void setEventKey(String eventKey) { | ||||
@@ -310,7 +269,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getContent() { | public String getContent() { | ||||
return content; | |||||
return this.content; | |||||
} | } | ||||
public void setContent(String content) { | public void setContent(String content) { | ||||
@@ -318,7 +277,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public String getrContent() { | public String getrContent() { | ||||
return rContent; | |||||
return this.rContent; | |||||
} | } | ||||
public void setrContent(String rContent) { | public void setrContent(String rContent) { | ||||
@@ -326,7 +285,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public WxMpMessageMatcher getMatcher() { | public WxMpMessageMatcher getMatcher() { | ||||
return matcher; | |||||
return this.matcher; | |||||
} | } | ||||
public void setMatcher(WxMpMessageMatcher matcher) { | public void setMatcher(WxMpMessageMatcher matcher) { | ||||
@@ -334,7 +293,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public boolean isReEnter() { | public boolean isReEnter() { | ||||
return reEnter; | |||||
return this.reEnter; | |||||
} | } | ||||
public void setReEnter(boolean reEnter) { | public void setReEnter(boolean reEnter) { | ||||
@@ -342,7 +301,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public List<WxMpMessageHandler> getHandlers() { | public List<WxMpMessageHandler> getHandlers() { | ||||
return handlers; | |||||
return this.handlers; | |||||
} | } | ||||
public void setHandlers(List<WxMpMessageHandler> handlers) { | public void setHandlers(List<WxMpMessageHandler> handlers) { | ||||
@@ -350,7 +309,7 @@ public class WxMpMessageRouterRule { | |||||
} | } | ||||
public List<WxMpMessageInterceptor> getInterceptors() { | public List<WxMpMessageInterceptor> getInterceptors() { | ||||
return interceptors; | |||||
return this.interceptors; | |||||
} | } | ||||
public void setInterceptors(List<WxMpMessageInterceptor> interceptors) { | public void setInterceptors(List<WxMpMessageInterceptor> interceptors) { | ||||
@@ -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; | |||||
} |
@@ -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; | |||||
} |
@@ -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()); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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.*; | ||||
import com.google.gson.internal.Streams; | import com.google.gson.internal.Streams; | ||||
import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
import com.google.gson.stream.JsonReader; | import com.google.gson.stream.JsonReader; | ||||
import com.thoughtworks.xstream.XStream; | 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.WxAccessToken; | ||||
import me.chanjar.weixin.common.bean.WxCardApiSignature; | import me.chanjar.weixin.common.bean.WxCardApiSignature; | ||||
import me.chanjar.weixin.common.bean.WxJsapiSignature; | 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.WxError; | ||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||||
import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||
import me.chanjar.weixin.common.session.WxSessionManager; | import me.chanjar.weixin.common.session.WxSessionManager; | ||||
import me.chanjar.weixin.common.util.RandomUtils; | import me.chanjar.weixin.common.util.RandomUtils; | ||||
import me.chanjar.weixin.common.util.crypto.SHA1; | import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
import me.chanjar.weixin.common.util.crypto.WxCryptUtil; | 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.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.common.util.xml.XStreamInitializer; | ||||
import me.chanjar.weixin.mp.api.*; | |||||
import me.chanjar.weixin.mp.bean.*; | import me.chanjar.weixin.mp.bean.*; | ||||
import me.chanjar.weixin.mp.bean.result.*; | import me.chanjar.weixin.mp.bean.result.*; | ||||
import me.chanjar.weixin.mp.util.http.*; | |||||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | ||||
import org.apache.commons.io.Charsets; | |||||
import org.apache.http.Consts; | import org.apache.http.Consts; | ||||
import org.apache.http.HttpHost; | import org.apache.http.HttpHost; | ||||
import org.apache.http.client.ClientProtocolException; | import org.apache.http.client.ClientProtocolException; | ||||
@@ -44,12 +36,8 @@ import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import org.slf4j.helpers.MessageFormatter; | import org.slf4j.helpers.MessageFormatter; | ||||
import java.io.File; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | |||||
import java.io.StringReader; | import java.io.StringReader; | ||||
import java.io.UnsupportedEncodingException; | |||||
import java.net.URLEncoder; | |||||
import java.security.NoSuchAlgorithmException; | import java.security.NoSuchAlgorithmException; | ||||
import java.util.*; | import java.util.*; | ||||
import java.util.Map.Entry; | import java.util.Map.Entry; | ||||
@@ -74,6 +62,18 @@ public class WxMpServiceImpl implements WxMpService { | |||||
protected final Object globalCardApiTicketRefreshLock = new Object(); | protected final Object globalCardApiTicketRefreshLock = new Object(); | ||||
protected WxMpConfigStorage wxMpConfigStorage; | 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; | protected CloseableHttpClient httpClient; | ||||
@@ -195,172 +195,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
execute(new SimplePostRequestExecutor(), url, message.toJson()); | 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 | @Override | ||||
public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { | public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { | ||||
String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | ||||
@@ -389,158 +223,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
return WxMpMassSendResult.fromJson(responseContent); | 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 | @Override | ||||
public String shortUrl(String long_url) throws WxErrorException { | public String shortUrl(String long_url) throws WxErrorException { | ||||
String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; | String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; | ||||
@@ -685,33 +367,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
return ipArray; | 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 | @Override | ||||
public String get(String url, String queryParam) throws WxErrorException { | public String get(String url, String queryParam) throws WxErrorException { | ||||
return execute(new SimpleGetRequestExecutor(), url, queryParam); | return execute(new SimpleGetRequestExecutor(), url, queryParam); | ||||
@@ -724,12 +379,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
/** | /** | ||||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | ||||
* | |||||
* @param executor | |||||
* @param uri | |||||
* @param data | |||||
* @return | |||||
* @throws WxErrorException | |||||
*/ | */ | ||||
@Override | @Override | ||||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | 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(); | this.httpClient = apacheHttpClientBuilder.build(); | ||||
} | } | ||||
@Override | |||||
public WxMpConfigStorage getWxMpConfigStorage() { | |||||
return this.wxMpConfigStorage; | |||||
} | |||||
@Override | @Override | ||||
public void setRetrySleepMillis(int retrySleepMillis) { | public void setRetrySleepMillis(int retrySleepMillis) { | ||||
this.retrySleepMillis = retrySleepMillis; | this.retrySleepMillis = retrySleepMillis; | ||||
@@ -1347,12 +1001,6 @@ public class WxMpServiceImpl implements WxMpService { | |||||
return WxMpMassSendResult.fromJson(responseContent); | 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 | @Override | ||||
public String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException { | public String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException { | ||||
if (null == wxMpIndustry.getPrimaryIndustry() || null == wxMpIndustry.getPrimaryIndustry().getId() | if (null == wxMpIndustry.getPrimaryIndustry() || null == wxMpIndustry.getPrimaryIndustry().getId() | ||||
@@ -1369,4 +1017,35 @@ public class WxMpServiceImpl implements WxMpService { | |||||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | ||||
return WxMpIndustry.fromJson(responseContent); | 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; | |||||
} | |||||
} | } |
@@ -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()); | |||||
} | |||||
} |
@@ -13,7 +13,8 @@ import java.util.List; | |||||
* | * | ||||
*/ | */ | ||||
public class WxMpCustomMessage implements Serializable { | public class WxMpCustomMessage implements Serializable { | ||||
private static final long serialVersionUID = -9196732086954365246L; | |||||
private String toUser; | private String toUser; | ||||
private String msgType; | private String msgType; | ||||
private String content; | private String content; | ||||
@@ -23,16 +24,17 @@ public class WxMpCustomMessage implements Serializable { | |||||
private String description; | private String description; | ||||
private String musicUrl; | private String musicUrl; | ||||
private String hqMusicUrl; | private String hqMusicUrl; | ||||
private List<WxArticle> articles = new ArrayList<WxArticle>(); | |||||
private String kfAccount; | |||||
private List<WxArticle> articles = new ArrayList<>(); | |||||
public String getToUser() { | public String getToUser() { | ||||
return toUser; | |||||
return this.toUser; | |||||
} | } | ||||
public void setToUser(String toUser) { | public void setToUser(String toUser) { | ||||
this.toUser = toUser; | this.toUser = toUser; | ||||
} | } | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | |||||
return this.msgType; | |||||
} | } | ||||
/** | /** | ||||
@@ -51,49 +53,49 @@ public class WxMpCustomMessage implements Serializable { | |||||
this.msgType = msgType; | this.msgType = msgType; | ||||
} | } | ||||
public String getContent() { | public String getContent() { | ||||
return content; | |||||
return this.content; | |||||
} | } | ||||
public void setContent(String content) { | public void setContent(String content) { | ||||
this.content = content; | this.content = content; | ||||
} | } | ||||
public String getMediaId() { | public String getMediaId() { | ||||
return mediaId; | |||||
return this.mediaId; | |||||
} | } | ||||
public void setMediaId(String mediaId) { | public void setMediaId(String mediaId) { | ||||
this.mediaId = mediaId; | this.mediaId = mediaId; | ||||
} | } | ||||
public String getThumbMediaId() { | public String getThumbMediaId() { | ||||
return thumbMediaId; | |||||
return this.thumbMediaId; | |||||
} | } | ||||
public void setThumbMediaId(String thumbMediaId) { | public void setThumbMediaId(String thumbMediaId) { | ||||
this.thumbMediaId = thumbMediaId; | this.thumbMediaId = thumbMediaId; | ||||
} | } | ||||
public String getTitle() { | public String getTitle() { | ||||
return title; | |||||
return this.title; | |||||
} | } | ||||
public void setTitle(String title) { | public void setTitle(String title) { | ||||
this.title = title; | this.title = title; | ||||
} | } | ||||
public String getDescription() { | public String getDescription() { | ||||
return description; | |||||
return this.description; | |||||
} | } | ||||
public void setDescription(String description) { | public void setDescription(String description) { | ||||
this.description = description; | this.description = description; | ||||
} | } | ||||
public String getMusicUrl() { | public String getMusicUrl() { | ||||
return musicUrl; | |||||
return this.musicUrl; | |||||
} | } | ||||
public void setMusicUrl(String musicUrl) { | public void setMusicUrl(String musicUrl) { | ||||
this.musicUrl = musicUrl; | this.musicUrl = musicUrl; | ||||
} | } | ||||
public String getHqMusicUrl() { | public String getHqMusicUrl() { | ||||
return hqMusicUrl; | |||||
return this.hqMusicUrl; | |||||
} | } | ||||
public void setHqMusicUrl(String hqMusicUrl) { | public void setHqMusicUrl(String hqMusicUrl) { | ||||
this.hqMusicUrl = hqMusicUrl; | this.hqMusicUrl = hqMusicUrl; | ||||
} | } | ||||
public List<WxArticle> getArticles() { | public List<WxArticle> getArticles() { | ||||
return articles; | |||||
return this.articles; | |||||
} | } | ||||
public void setArticles(List<WxArticle> articles) { | public void setArticles(List<WxArticle> articles) { | ||||
this.articles = articles; | this.articles = articles; | ||||
@@ -111,25 +113,25 @@ public class WxMpCustomMessage implements Serializable { | |||||
private String picUrl; | private String picUrl; | ||||
public String getTitle() { | public String getTitle() { | ||||
return title; | |||||
return this.title; | |||||
} | } | ||||
public void setTitle(String title) { | public void setTitle(String title) { | ||||
this.title = title; | this.title = title; | ||||
} | } | ||||
public String getDescription() { | public String getDescription() { | ||||
return description; | |||||
return this.description; | |||||
} | } | ||||
public void setDescription(String description) { | public void setDescription(String description) { | ||||
this.description = description; | this.description = description; | ||||
} | } | ||||
public String getUrl() { | public String getUrl() { | ||||
return url; | |||||
return this.url; | |||||
} | } | ||||
public void setUrl(String url) { | public void setUrl(String url) { | ||||
this.url = url; | this.url = url; | ||||
} | } | ||||
public String getPicUrl() { | public String getPicUrl() { | ||||
return picUrl; | |||||
return this.picUrl; | |||||
} | } | ||||
public void setPicUrl(String picUrl) { | public void setPicUrl(String picUrl) { | ||||
this.picUrl = picUrl; | this.picUrl = picUrl; | ||||
@@ -139,7 +141,6 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得文本消息builder | * 获得文本消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static TextBuilder TEXT() { | public static TextBuilder TEXT() { | ||||
return new TextBuilder(); | return new TextBuilder(); | ||||
@@ -147,7 +148,6 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得图片消息builder | * 获得图片消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static ImageBuilder IMAGE() { | public static ImageBuilder IMAGE() { | ||||
return new ImageBuilder(); | return new ImageBuilder(); | ||||
@@ -155,7 +155,6 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得语音消息builder | * 获得语音消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VoiceBuilder VOICE() { | public static VoiceBuilder VOICE() { | ||||
return new VoiceBuilder(); | return new VoiceBuilder(); | ||||
@@ -163,7 +162,6 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得视频消息builder | * 获得视频消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VideoBuilder VIDEO() { | public static VideoBuilder VIDEO() { | ||||
return new VideoBuilder(); | return new VideoBuilder(); | ||||
@@ -171,7 +169,6 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得音乐消息builder | * 获得音乐消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static MusicBuilder MUSIC() { | public static MusicBuilder MUSIC() { | ||||
return new MusicBuilder(); | return new MusicBuilder(); | ||||
@@ -179,10 +176,17 @@ public class WxMpCustomMessage implements Serializable { | |||||
/** | /** | ||||
* 获得图文消息builder | * 获得图文消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static NewsBuilder NEWS() { | public static NewsBuilder NEWS() { | ||||
return new NewsBuilder(); | return new NewsBuilder(); | ||||
} | } | ||||
public String getKfAccount() { | |||||
return kfAccount; | |||||
} | |||||
public void setKfAccount(String kfAccount) { | |||||
this.kfAccount = kfAccount; | |||||
} | |||||
} | } |
@@ -12,8 +12,9 @@ import java.util.List; | |||||
* @author chanjarster | * @author chanjarster | ||||
*/ | */ | ||||
public class WxMpMassOpenIdsMessage implements Serializable { | 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 msgType; | ||||
private String content; | private String content; | ||||
private String mediaId; | private String mediaId; | ||||
@@ -23,7 +24,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||||
} | } | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | |||||
return this.msgType; | |||||
} | } | ||||
/** | /** | ||||
@@ -43,7 +44,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||||
} | } | ||||
public String getContent() { | public String getContent() { | ||||
return content; | |||||
return this.content; | |||||
} | } | ||||
public void setContent(String content) { | public void setContent(String content) { | ||||
@@ -51,7 +52,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||||
} | } | ||||
public String getMediaId() { | public String getMediaId() { | ||||
return mediaId; | |||||
return this.mediaId; | |||||
} | } | ||||
public void setMediaId(String mediaId) { | public void setMediaId(String mediaId) { | ||||
@@ -64,10 +65,9 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||||
/** | /** | ||||
* OpenId列表,最多支持10,000个 | * OpenId列表,最多支持10,000个 | ||||
* @return | |||||
*/ | */ | ||||
public List<String> getToUsers() { | public List<String> getToUsers() { | ||||
return toUsers; | |||||
return this.toUsers; | |||||
} | } | ||||
/** | /** | ||||
@@ -1,18 +1,24 @@ | |||||
package me.chanjar.weixin.mp.bean; | 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.XStreamAlias; | ||||
import com.thoughtworks.xstream.annotations.XStreamConverter; | import com.thoughtworks.xstream.annotations.XStreamConverter; | ||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | ||||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | import me.chanjar.weixin.mp.api.WxMpConfigStorage; | ||||
import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; | import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; | ||||
import me.chanjar.weixin.mp.util.xml.XStreamTransformer; | 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> | * <pre> | ||||
@@ -28,46 +34,49 @@ import java.util.List; | |||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
public class WxMpXmlMessage implements Serializable { | public class WxMpXmlMessage implements Serializable { | ||||
private static final long serialVersionUID = -3586245291677274914L; | |||||
/////////////////////// | /////////////////////// | ||||
// 以下都是微信推送过来的消息的xml的element所对应的属性 | // 以下都是微信推送过来的消息的xml的element所对应的属性 | ||||
/////////////////////// | /////////////////////// | ||||
@XStreamAlias("ToUserName") | @XStreamAlias("ToUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String toUserName; | private String toUserName; | ||||
@XStreamAlias("FromUserName") | @XStreamAlias("FromUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String fromUserName; | private String fromUserName; | ||||
@XStreamAlias("CreateTime") | @XStreamAlias("CreateTime") | ||||
@JsonSerialize(using = WxLongTimeJsonSerializer.class) | |||||
private Long createTime; | private Long createTime; | ||||
@XStreamAlias("MsgType") | @XStreamAlias("MsgType") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String msgType; | private String msgType; | ||||
@XStreamAlias("Content") | @XStreamAlias("Content") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String content; | private String content; | ||||
@XStreamAlias("MsgId") | @XStreamAlias("MsgId") | ||||
private Long msgId; | private Long msgId; | ||||
@XStreamAlias("PicUrl") | @XStreamAlias("PicUrl") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String picUrl; | private String picUrl; | ||||
@XStreamAlias("MediaId") | @XStreamAlias("MediaId") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String mediaId; | private String mediaId; | ||||
@XStreamAlias("Format") | @XStreamAlias("Format") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String format; | private String format; | ||||
@XStreamAlias("ThumbMediaId") | @XStreamAlias("ThumbMediaId") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String thumbMediaId; | private String thumbMediaId; | ||||
@XStreamAlias("Location_X") | @XStreamAlias("Location_X") | ||||
@@ -80,31 +89,31 @@ public class WxMpXmlMessage implements Serializable { | |||||
private Double scale; | private Double scale; | ||||
@XStreamAlias("Label") | @XStreamAlias("Label") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String label; | private String label; | ||||
@XStreamAlias("Title") | @XStreamAlias("Title") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String title; | private String title; | ||||
@XStreamAlias("Description") | @XStreamAlias("Description") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String description; | private String description; | ||||
@XStreamAlias("Url") | @XStreamAlias("Url") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String url; | private String url; | ||||
@XStreamAlias("Event") | @XStreamAlias("Event") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String event; | private String event; | ||||
@XStreamAlias("EventKey") | @XStreamAlias("EventKey") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String eventKey; | private String eventKey; | ||||
@XStreamAlias("Ticket") | @XStreamAlias("Ticket") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String ticket; | private String ticket; | ||||
@XStreamAlias("Latitude") | @XStreamAlias("Latitude") | ||||
@@ -117,7 +126,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
private Double precision; | private Double precision; | ||||
@XStreamAlias("Recognition") | @XStreamAlias("Recognition") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String recognition; | private String recognition; | ||||
/////////////////////////////////////// | /////////////////////////////////////// | ||||
@@ -127,7 +136,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
* 群发的结果 | * 群发的结果 | ||||
*/ | */ | ||||
@XStreamAlias("Status") | @XStreamAlias("Status") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String status; | private String status; | ||||
/** | /** | ||||
* group_id下粉丝数;或者openid_list中的粉丝数 | * group_id下粉丝数;或者openid_list中的粉丝数 | ||||
@@ -150,26 +159,45 @@ public class WxMpXmlMessage implements Serializable { | |||||
@XStreamAlias("ErrorCount") | @XStreamAlias("ErrorCount") | ||||
private Integer errorCount; | private Integer errorCount; | ||||
/////////////////////////////////////// | |||||
// 客服会话管理相关事件推送 | |||||
/////////////////////////////////////// | |||||
/** | |||||
* 创建或关闭客服会话时的客服帐号 | |||||
*/ | |||||
@XStreamAlias("KfAccount") | |||||
private String kfAccount; | |||||
/** | |||||
* 转接客服会话时的转入客服帐号 | |||||
*/ | |||||
@XStreamAlias("ToKfAccount") | |||||
private String toKfAccount; | |||||
/** | |||||
* 转接客服会话时的转出客服帐号 | |||||
*/ | |||||
@XStreamAlias("FromKfAccount") | |||||
private String fromKfAccount; | |||||
/////////////////////////////////////// | /////////////////////////////////////// | ||||
// 卡券相关事件推送 | // 卡券相关事件推送 | ||||
/////////////////////////////////////// | /////////////////////////////////////// | ||||
@XStreamAlias("CardId") | @XStreamAlias("CardId") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String cardId; | private String cardId; | ||||
@XStreamAlias("FriendUserName") | @XStreamAlias("FriendUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String friendUserName; | private String friendUserName; | ||||
@XStreamAlias("IsGiveByFriend") | @XStreamAlias("IsGiveByFriend") | ||||
private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否 | private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否 | ||||
@XStreamAlias("UserCardCode") | @XStreamAlias("UserCardCode") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String userCardCode; | private String userCardCode; | ||||
@XStreamAlias("OldUserCardCode") | @XStreamAlias("OldUserCardCode") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String oldUserCardCode; | private String oldUserCardCode; | ||||
@XStreamAlias("OuterId") | @XStreamAlias("OuterId") | ||||
@@ -185,7 +213,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
private SendLocationInfo sendLocationInfo = new SendLocationInfo(); | private SendLocationInfo sendLocationInfo = new SendLocationInfo(); | ||||
public String getToUserName() { | public String getToUserName() { | ||||
return toUserName; | |||||
return this.toUserName; | |||||
} | } | ||||
public void setToUserName(String toUserName) { | public void setToUserName(String toUserName) { | ||||
@@ -193,7 +221,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Long getCreateTime() { | public Long getCreateTime() { | ||||
return createTime; | |||||
return this.createTime; | |||||
} | } | ||||
public void setCreateTime(Long 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} | * {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | ||||
* </pre> | * </pre> | ||||
* | * | ||||
* @return | |||||
*/ | */ | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | |||||
return this.msgType; | |||||
} | } | ||||
/** | /** | ||||
@@ -236,7 +263,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getContent() { | public String getContent() { | ||||
return content; | |||||
return this.content; | |||||
} | } | ||||
public void setContent(String content) { | public void setContent(String content) { | ||||
@@ -244,7 +271,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Long getMsgId() { | public Long getMsgId() { | ||||
return msgId; | |||||
return this.msgId; | |||||
} | } | ||||
public void setMsgId(Long msgId) { | public void setMsgId(Long msgId) { | ||||
@@ -252,7 +279,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getPicUrl() { | public String getPicUrl() { | ||||
return picUrl; | |||||
return this.picUrl; | |||||
} | } | ||||
public void setPicUrl(String picUrl) { | public void setPicUrl(String picUrl) { | ||||
@@ -260,7 +287,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getMediaId() { | public String getMediaId() { | ||||
return mediaId; | |||||
return this.mediaId; | |||||
} | } | ||||
public void setMediaId(String mediaId) { | public void setMediaId(String mediaId) { | ||||
@@ -268,7 +295,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getFormat() { | public String getFormat() { | ||||
return format; | |||||
return this.format; | |||||
} | } | ||||
public void setFormat(String format) { | public void setFormat(String format) { | ||||
@@ -276,7 +303,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getThumbMediaId() { | public String getThumbMediaId() { | ||||
return thumbMediaId; | |||||
return this.thumbMediaId; | |||||
} | } | ||||
public void setThumbMediaId(String thumbMediaId) { | public void setThumbMediaId(String thumbMediaId) { | ||||
@@ -284,7 +311,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getLocationX() { | public Double getLocationX() { | ||||
return locationX; | |||||
return this.locationX; | |||||
} | } | ||||
public void setLocationX(Double locationX) { | public void setLocationX(Double locationX) { | ||||
@@ -292,7 +319,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getLocationY() { | public Double getLocationY() { | ||||
return locationY; | |||||
return this.locationY; | |||||
} | } | ||||
public void setLocationY(Double locationY) { | public void setLocationY(Double locationY) { | ||||
@@ -300,7 +327,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getScale() { | public Double getScale() { | ||||
return scale; | |||||
return this.scale; | |||||
} | } | ||||
public void setScale(Double scale) { | public void setScale(Double scale) { | ||||
@@ -308,7 +335,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getLabel() { | public String getLabel() { | ||||
return label; | |||||
return this.label; | |||||
} | } | ||||
public void setLabel(String label) { | public void setLabel(String label) { | ||||
@@ -316,7 +343,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getTitle() { | public String getTitle() { | ||||
return title; | |||||
return this.title; | |||||
} | } | ||||
public void setTitle(String title) { | public void setTitle(String title) { | ||||
@@ -324,7 +351,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getDescription() { | public String getDescription() { | ||||
return description; | |||||
return this.description; | |||||
} | } | ||||
public void setDescription(String description) { | public void setDescription(String description) { | ||||
@@ -332,7 +359,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getUrl() { | public String getUrl() { | ||||
return url; | |||||
return this.url; | |||||
} | } | ||||
public void setUrl(String url) { | public void setUrl(String url) { | ||||
@@ -340,7 +367,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getEvent() { | public String getEvent() { | ||||
return event; | |||||
return this.event; | |||||
} | } | ||||
public void setEvent(String event) { | public void setEvent(String event) { | ||||
@@ -348,7 +375,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getEventKey() { | public String getEventKey() { | ||||
return eventKey; | |||||
return this.eventKey; | |||||
} | } | ||||
public void setEventKey(String eventKey) { | public void setEventKey(String eventKey) { | ||||
@@ -356,7 +383,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getTicket() { | public String getTicket() { | ||||
return ticket; | |||||
return this.ticket; | |||||
} | } | ||||
public void setTicket(String ticket) { | public void setTicket(String ticket) { | ||||
@@ -364,7 +391,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getLatitude() { | public Double getLatitude() { | ||||
return latitude; | |||||
return this.latitude; | |||||
} | } | ||||
public void setLatitude(Double latitude) { | public void setLatitude(Double latitude) { | ||||
@@ -372,7 +399,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getLongitude() { | public Double getLongitude() { | ||||
return longitude; | |||||
return this.longitude; | |||||
} | } | ||||
public void setLongitude(Double longitude) { | public void setLongitude(Double longitude) { | ||||
@@ -380,7 +407,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Double getPrecision() { | public Double getPrecision() { | ||||
return precision; | |||||
return this.precision; | |||||
} | } | ||||
public void setPrecision(Double precision) { | public void setPrecision(Double precision) { | ||||
@@ -388,7 +415,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getRecognition() { | public String getRecognition() { | ||||
return recognition; | |||||
return this.recognition; | |||||
} | } | ||||
public void setRecognition(String recognition) { | public void setRecognition(String recognition) { | ||||
@@ -396,7 +423,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getFromUserName() { | public String getFromUserName() { | ||||
return fromUserName; | |||||
return this.fromUserName; | |||||
} | } | ||||
public void setFromUserName(String fromUserName) { | public void setFromUserName(String fromUserName) { | ||||
@@ -419,30 +446,29 @@ public class WxMpXmlMessage implements Serializable { | |||||
* @param timestamp | * @param timestamp | ||||
* @param nonce | * @param nonce | ||||
* @param msgSignature | * @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); | WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage); | ||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | |||||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, | |||||
encryptedXml); | |||||
return fromXml(plainText); | 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 { | 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) { | } catch (IOException e) { | ||||
throw new RuntimeException(e); | throw new RuntimeException(e); | ||||
} | } | ||||
} | } | ||||
public String getStatus() { | public String getStatus() { | ||||
return status; | |||||
return this.status; | |||||
} | } | ||||
public void setStatus(String status) { | public void setStatus(String status) { | ||||
@@ -450,7 +476,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getTotalCount() { | public Integer getTotalCount() { | ||||
return totalCount; | |||||
return this.totalCount; | |||||
} | } | ||||
public void setTotalCount(Integer totalCount) { | public void setTotalCount(Integer totalCount) { | ||||
@@ -458,7 +484,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getFilterCount() { | public Integer getFilterCount() { | ||||
return filterCount; | |||||
return this.filterCount; | |||||
} | } | ||||
public void setFilterCount(Integer filterCount) { | public void setFilterCount(Integer filterCount) { | ||||
@@ -466,7 +492,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getSentCount() { | public Integer getSentCount() { | ||||
return sentCount; | |||||
return this.sentCount; | |||||
} | } | ||||
public void setSentCount(Integer sentCount) { | public void setSentCount(Integer sentCount) { | ||||
@@ -474,7 +500,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getErrorCount() { | public Integer getErrorCount() { | ||||
return errorCount; | |||||
return this.errorCount; | |||||
} | } | ||||
public void setErrorCount(Integer errorCount) { | public void setErrorCount(Integer errorCount) { | ||||
@@ -482,7 +508,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getCardId() { | public String getCardId() { | ||||
return cardId; | |||||
return this.cardId; | |||||
} | } | ||||
public void setCardId(String cardId) { | public void setCardId(String cardId) { | ||||
@@ -490,7 +516,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getFriendUserName() { | public String getFriendUserName() { | ||||
return friendUserName; | |||||
return this.friendUserName; | |||||
} | } | ||||
public void setFriendUserName(String friendUserName) { | public void setFriendUserName(String friendUserName) { | ||||
@@ -498,7 +524,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getIsGiveByFriend() { | public Integer getIsGiveByFriend() { | ||||
return isGiveByFriend; | |||||
return this.isGiveByFriend; | |||||
} | } | ||||
public void setIsGiveByFriend(Integer isGiveByFriend) { | public void setIsGiveByFriend(Integer isGiveByFriend) { | ||||
@@ -506,7 +532,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getUserCardCode() { | public String getUserCardCode() { | ||||
return userCardCode; | |||||
return this.userCardCode; | |||||
} | } | ||||
public void setUserCardCode(String userCardCode) { | public void setUserCardCode(String userCardCode) { | ||||
@@ -514,7 +540,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getOldUserCardCode() { | public String getOldUserCardCode() { | ||||
return oldUserCardCode; | |||||
return this.oldUserCardCode; | |||||
} | } | ||||
public void setOldUserCardCode(String oldUserCardCode) { | public void setOldUserCardCode(String oldUserCardCode) { | ||||
@@ -522,7 +548,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public Integer getOuterId() { | public Integer getOuterId() { | ||||
return outerId; | |||||
return this.outerId; | |||||
} | } | ||||
public void setOuterId(Integer outerId) { | public void setOuterId(Integer outerId) { | ||||
@@ -530,7 +556,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { | public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { | ||||
return scanCodeInfo; | |||||
return this.scanCodeInfo; | |||||
} | } | ||||
public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { | public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { | ||||
@@ -538,7 +564,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { | public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { | ||||
return sendPicsInfo; | |||||
return this.sendPicsInfo; | |||||
} | } | ||||
public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { | public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { | ||||
@@ -546,31 +572,59 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { | public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { | ||||
return sendLocationInfo; | |||||
return this.sendLocationInfo; | |||||
} | } | ||||
public void setSendLocationInfo(WxMpXmlMessage.SendLocationInfo sendLocationInfo) { | |||||
public void setSendLocationInfo( | |||||
WxMpXmlMessage.SendLocationInfo sendLocationInfo) { | |||||
this.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") | @XStreamAlias("ScanCodeInfo") | ||||
public static class ScanCodeInfo { | public static class ScanCodeInfo { | ||||
@Override | |||||
public String toString() { | |||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
} | |||||
@XStreamAlias("ScanType") | @XStreamAlias("ScanType") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String scanType; | private String scanType; | ||||
@XStreamAlias("ScanResult") | @XStreamAlias("ScanResult") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String scanResult; | private String scanResult; | ||||
/** | /** | ||||
* 扫描类型,一般是qrcode | * 扫描类型,一般是qrcode | ||||
* @return | |||||
*/ | */ | ||||
public String getScanType() { | public String getScanType() { | ||||
return scanType; | |||||
return this.scanType; | |||||
} | } | ||||
public void setScanType(String scanType) { | public void setScanType(String scanType) { | ||||
@@ -579,10 +633,9 @@ public class WxMpXmlMessage implements Serializable { | |||||
/** | /** | ||||
* 扫描结果,即二维码对应的字符串信息 | * 扫描结果,即二维码对应的字符串信息 | ||||
* @return | |||||
*/ | */ | ||||
public String getScanResult() { | public String getScanResult() { | ||||
return scanResult; | |||||
return this.scanResult; | |||||
} | } | ||||
public void setScanResult(String scanResult) { | public void setScanResult(String scanResult) { | ||||
@@ -593,15 +646,19 @@ public class WxMpXmlMessage implements Serializable { | |||||
@XStreamAlias("SendPicsInfo") | @XStreamAlias("SendPicsInfo") | ||||
public static class SendPicsInfo { | public static class SendPicsInfo { | ||||
@Override | |||||
public String toString() { | |||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
} | |||||
@XStreamAlias("Count") | @XStreamAlias("Count") | ||||
private Long count; | private Long count; | ||||
@XStreamAlias("PicList") | @XStreamAlias("PicList") | ||||
protected final List<Item> picList = new ArrayList<Item>(); | |||||
protected final List<Item> picList = new ArrayList<>(); | |||||
public Long getCount() { | public Long getCount() { | ||||
return count; | |||||
return this.count; | |||||
} | } | ||||
public void setCount(Long count) { | public void setCount(Long count) { | ||||
@@ -609,18 +666,23 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public List<Item> getPicList() { | public List<Item> getPicList() { | ||||
return picList; | |||||
return this.picList; | |||||
} | } | ||||
@XStreamAlias("item") | @XStreamAlias("item") | ||||
public static class Item { | public static class Item { | ||||
@Override | |||||
public String toString() { | |||||
return ToStringBuilder.reflectionToString(this, | |||||
ToStringStyle.JSON_STYLE); | |||||
} | |||||
@XStreamAlias("PicMd5Sum") | @XStreamAlias("PicMd5Sum") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String picMd5Sum; | private String picMd5Sum; | ||||
public String getPicMd5Sum() { | public String getPicMd5Sum() { | ||||
return picMd5Sum; | |||||
return this.picMd5Sum; | |||||
} | } | ||||
public void setPicMd5Sum(String picMd5Sum) { | public void setPicMd5Sum(String picMd5Sum) { | ||||
@@ -633,27 +695,32 @@ public class WxMpXmlMessage implements Serializable { | |||||
public static class SendLocationInfo { | public static class SendLocationInfo { | ||||
@XStreamAlias("Location_X") | @XStreamAlias("Location_X") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String locationX; | private String locationX; | ||||
@XStreamAlias("Location_Y") | @XStreamAlias("Location_Y") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String locationY; | private String locationY; | ||||
@XStreamAlias("Scale") | @XStreamAlias("Scale") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String scale; | private String scale; | ||||
@XStreamAlias("Label") | @XStreamAlias("Label") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String label; | private String label; | ||||
@XStreamAlias("Poiname") | @XStreamAlias("Poiname") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | |||||
@XStreamConverter(value = XStreamCDataConverter.class) | |||||
private String poiname; | private String poiname; | ||||
@Override | |||||
public String toString() { | |||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||||
} | |||||
public String getLocationX() { | public String getLocationX() { | ||||
return locationX; | |||||
return this.locationX; | |||||
} | } | ||||
public void setLocationX(String locationX) { | public void setLocationX(String locationX) { | ||||
@@ -661,7 +728,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getLocationY() { | public String getLocationY() { | ||||
return locationY; | |||||
return this.locationY; | |||||
} | } | ||||
public void setLocationY(String locationY) { | public void setLocationY(String locationY) { | ||||
@@ -669,7 +736,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getScale() { | public String getScale() { | ||||
return scale; | |||||
return this.scale; | |||||
} | } | ||||
public void setScale(String scale) { | public void setScale(String scale) { | ||||
@@ -677,7 +744,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getLabel() { | public String getLabel() { | ||||
return label; | |||||
return this.label; | |||||
} | } | ||||
public void setLabel(String label) { | public void setLabel(String label) { | ||||
@@ -685,7 +752,7 @@ public class WxMpXmlMessage implements Serializable { | |||||
} | } | ||||
public String getPoiname() { | public String getPoiname() { | ||||
return poiname; | |||||
return this.poiname; | |||||
} | } | ||||
public void setPoiname(String poiname) { | public void setPoiname(String poiname) { | ||||
@@ -695,44 +762,6 @@ public class WxMpXmlMessage implements Serializable { | |||||
@Override | @Override | ||||
public String toString() { | 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); | |||||
} | } | ||||
} | } |
@@ -13,6 +13,8 @@ import java.io.Serializable; | |||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
public abstract class WxMpXmlOutMessage implements Serializable { | public abstract class WxMpXmlOutMessage implements Serializable { | ||||
private static final long serialVersionUID = -381382011286216263L; | |||||
@XStreamAlias("ToUserName") | @XStreamAlias("ToUserName") | ||||
@XStreamConverter(value=XStreamCDataConverter.class) | @XStreamConverter(value=XStreamCDataConverter.class) | ||||
protected String toUserName; | protected String toUserName; | ||||
@@ -29,7 +31,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
protected String msgType; | protected String msgType; | ||||
public String getToUserName() { | public String getToUserName() { | ||||
return toUserName; | |||||
return this.toUserName; | |||||
} | } | ||||
public void setToUserName(String toUserName) { | public void setToUserName(String toUserName) { | ||||
@@ -37,7 +39,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
} | } | ||||
public String getFromUserName() { | public String getFromUserName() { | ||||
return fromUserName; | |||||
return this.fromUserName; | |||||
} | } | ||||
public void setFromUserName(String fromUserName) { | public void setFromUserName(String fromUserName) { | ||||
@@ -45,7 +47,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
} | } | ||||
public Long getCreateTime() { | public Long getCreateTime() { | ||||
return createTime; | |||||
return this.createTime; | |||||
} | } | ||||
public void setCreateTime(Long createTime) { | public void setCreateTime(Long createTime) { | ||||
@@ -53,7 +55,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
} | } | ||||
public String getMsgType() { | public String getMsgType() { | ||||
return msgType; | |||||
return this.msgType; | |||||
} | } | ||||
public void setMsgType(String msgType) { | public void setMsgType(String msgType) { | ||||
@@ -61,12 +63,11 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
} | } | ||||
public String toXml() { | public String toXml() { | ||||
return XStreamTransformer.toXml((Class) this.getClass(), this); | |||||
return XStreamTransformer.toXml((Class<WxMpXmlOutMessage>) this.getClass(), this); | |||||
} | } | ||||
/** | /** | ||||
* 转换成加密的xml格式 | * 转换成加密的xml格式 | ||||
* @return | |||||
*/ | */ | ||||
public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { | public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { | ||||
String plainXml = toXml(); | String plainXml = toXml(); | ||||
@@ -76,7 +77,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得文本消息builder | * 获得文本消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static TextBuilder TEXT() { | public static TextBuilder TEXT() { | ||||
return new TextBuilder(); | return new TextBuilder(); | ||||
@@ -84,7 +84,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得图片消息builder | * 获得图片消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static ImageBuilder IMAGE() { | public static ImageBuilder IMAGE() { | ||||
return new ImageBuilder(); | return new ImageBuilder(); | ||||
@@ -92,7 +91,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得语音消息builder | * 获得语音消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VoiceBuilder VOICE() { | public static VoiceBuilder VOICE() { | ||||
return new VoiceBuilder(); | return new VoiceBuilder(); | ||||
@@ -100,7 +98,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得视频消息builder | * 获得视频消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static VideoBuilder VIDEO() { | public static VideoBuilder VIDEO() { | ||||
return new VideoBuilder(); | return new VideoBuilder(); | ||||
@@ -108,7 +105,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得音乐消息builder | * 获得音乐消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static MusicBuilder MUSIC() { | public static MusicBuilder MUSIC() { | ||||
return new MusicBuilder(); | return new MusicBuilder(); | ||||
@@ -116,15 +112,13 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||||
/** | /** | ||||
* 获得图文消息builder | * 获得图文消息builder | ||||
* @return | |||||
*/ | */ | ||||
public static NewsBuilder NEWS() { | public static NewsBuilder NEWS() { | ||||
return new NewsBuilder(); | return new NewsBuilder(); | ||||
} | } | ||||
/** | |||||
/** | |||||
* 获得客服消息builder | * 获得客服消息builder | ||||
* | |||||
* @return | |||||
*/ | */ | ||||
public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { | public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { | ||||
return new TransferCustomerServiceBuilder(); | return new TransferCustomerServiceBuilder(); | ||||
@@ -7,6 +7,8 @@ import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||||
@XStreamAlias("xml") | @XStreamAlias("xml") | ||||
public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage { | public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage { | ||||
private static final long serialVersionUID = 1850903037285841322L; | |||||
@XStreamAlias("TransInfo") | @XStreamAlias("TransInfo") | ||||
protected TransInfo transInfo; | protected TransInfo transInfo; | ||||
@@ -15,7 +17,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage | |||||
} | } | ||||
public TransInfo getTransInfo() { | public TransInfo getTransInfo() { | ||||
return transInfo; | |||||
return this.transInfo; | |||||
} | } | ||||
public void setTransInfo(TransInfo transInfo) { | public void setTransInfo(TransInfo transInfo) { | ||||
@@ -30,7 +32,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage | |||||
private String kfAccount; | private String kfAccount; | ||||
public String getKfAccount() { | public String getKfAccount() { | ||||
return kfAccount; | |||||
return this.kfAccount; | |||||
} | } | ||||
public void setKfAccount(String kfAccount) { | public void setKfAccount(String kfAccount) { | ||||
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -14,18 +14,18 @@ import me.chanjar.weixin.mp.bean.WxMpXmlOutTransferCustomerServiceMessage; | |||||
public final class TransferCustomerServiceBuilder extends BaseBuilder<TransferCustomerServiceBuilder, WxMpXmlOutTransferCustomerServiceMessage> { | public final class TransferCustomerServiceBuilder extends BaseBuilder<TransferCustomerServiceBuilder, WxMpXmlOutTransferCustomerServiceMessage> { | ||||
private String kfAccount; | private String kfAccount; | ||||
public TransferCustomerServiceBuilder kfAccount(String kfAccount) { | |||||
this.kfAccount = kfAccount; | |||||
public TransferCustomerServiceBuilder kfAccount(String kf) { | |||||
this.kfAccount = kf; | |||||
return this; | return this; | ||||
} | } | ||||
@Override | |||||
public WxMpXmlOutTransferCustomerServiceMessage build() { | public WxMpXmlOutTransferCustomerServiceMessage build() { | ||||
WxMpXmlOutTransferCustomerServiceMessage m = new WxMpXmlOutTransferCustomerServiceMessage(); | WxMpXmlOutTransferCustomerServiceMessage m = new WxMpXmlOutTransferCustomerServiceMessage(); | ||||
setCommon(m); | setCommon(m); | ||||
if(StringUtils.isNotBlank(kfAccount)){ | |||||
if(StringUtils.isNotBlank(this.kfAccount)){ | |||||
WxMpXmlOutTransferCustomerServiceMessage.TransInfo transInfo = new WxMpXmlOutTransferCustomerServiceMessage.TransInfo(); | WxMpXmlOutTransferCustomerServiceMessage.TransInfo transInfo = new WxMpXmlOutTransferCustomerServiceMessage.TransInfo(); | ||||
transInfo.setKfAccount(kfAccount); | |||||
transInfo.setKfAccount(this.kfAccount); | |||||
m.setTransInfo(transInfo); | m.setTransInfo(transInfo); | ||||
} | } | ||||
return m; | return m; | ||||
@@ -45,4 +45,9 @@ public class WxMpQrCodeTicket implements Serializable { | |||||
public static WxMpQrCodeTicket fromJson(String json) { | public static WxMpQrCodeTicket fromJson(String json) { | ||||
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); | return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); | ||||
} | } | ||||
@Override | |||||
public String toString() { | |||||
return WxMpGsonBuilder.INSTANCE.create().toJson(this); | |||||
} | |||||
} | } |
@@ -44,4 +44,9 @@ public class WxMpUserList { | |||||
public static WxMpUserList fromJson(String json) { | public static WxMpUserList fromJson(String json) { | ||||
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); | return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); | ||||
} | } | ||||
@Override | |||||
public String toString() { | |||||
return WxMpGsonBuilder.INSTANCE.create().toJson(this); | |||||
} | |||||
} | } |
@@ -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)); | |||||
} | |||||
} |