@@ -1,11 +1,11 @@ | |||
<?xml version="1.0"?> | |||
<project | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | |||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" | |||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>1.3.5</version> | |||
<version>2.0.0-SNAPSHOT</version> | |||
<packaging>pom</packaging> | |||
<name>WeiXin Java Tools - Parent</name> | |||
<description>微信公众号、企业号上级POM</description> | |||
@@ -39,7 +39,6 @@ | |||
<module>weixin-java-common</module> | |||
<module>weixin-java-cp</module> | |||
<module>weixin-java-mp</module> | |||
<module>spring-demo</module> | |||
</modules> | |||
<properties> | |||
@@ -50,6 +49,13 @@ | |||
<slf4j.version>1.7.10</slf4j.version> | |||
<logback.version>1.1.2</logback.version> | |||
<jodd-http.version>3.6.7</jodd-http.version> | |||
<jackson.version>2.8.0</jackson.version> | |||
<gson.version>2.7</gson.version> | |||
<commons-lang3.version>3.4</commons-lang3.version> | |||
<commons-io.version>2.5</commons-io.version> | |||
<commons-codec.version>1.10</commons-codec.version> | |||
<jetty.version>9.3.0.M0</jetty.version> | |||
<jetty-new.version>9.3.10.v20160621</jetty-new.version> | |||
</properties> | |||
<dependencies> | |||
@@ -82,20 +88,30 @@ | |||
<dependency> | |||
<groupId>com.google.code.gson</groupId> | |||
<artifactId>gson</artifactId> | |||
<version>2.2.2</version> | |||
<version>${gson.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-codec</groupId> | |||
<artifactId>commons-codec</artifactId> | |||
<version>1.9</version> | |||
<version>${commons-codec.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-io</groupId> | |||
<artifactId>commons-io</artifactId> | |||
<version>2.4</version> | |||
<version>${commons-io.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.commons</groupId> | |||
<artifactId>commons-lang3</artifactId> | |||
<version>${commons-lang3.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.fasterxml.jackson.core</groupId> | |||
<artifactId>jackson-databind</artifactId> | |||
<version>${jackson.version}</version> | |||
</dependency> | |||
</dependencies> | |||
<dependencyManagement> | |||
<dependencies> | |||
<dependency> | |||
@@ -125,13 +141,13 @@ | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-server</artifactId> | |||
<version>9.3.0.M0</version> | |||
<version>${jetty.version}</version> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-servlet</artifactId> | |||
<version>9.3.0.M0</version> | |||
<version>${jetty.version}</version> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
@@ -149,16 +165,16 @@ | |||
</distributionManagement> | |||
<profiles> | |||
<profile> | |||
<id>doclint-java8-disable</id> | |||
<activation> | |||
<jdk>[1.8,)</jdk> | |||
</activation> | |||
<properties> | |||
<javadoc.opts>-Xdoclint:none</javadoc.opts> | |||
</properties> | |||
</profile> | |||
<profile> | |||
<id>doclint-java8-disable</id> | |||
<activation> | |||
<jdk>[1.8,)</jdk> | |||
</activation> | |||
<properties> | |||
<javadoc.opts>-Xdoclint:none</javadoc.opts> | |||
</properties> | |||
</profile> | |||
<profile> | |||
<id>release</id> | |||
<build> | |||
@@ -220,6 +236,9 @@ | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-surefire-plugin</artifactId> | |||
<version>2.17</version> | |||
<configuration> | |||
<skip>true</skip> | |||
</configuration> | |||
</plugin> | |||
</plugins> | |||
</pluginManagement> | |||
@@ -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> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>1.3.5</version> | |||
<version>2.0.0-SNAPSHOT</version> | |||
</parent> | |||
<artifactId>weixin-java-common</artifactId> | |||
@@ -11,6 +11,7 @@ public class WxConsts { | |||
public static final String XML_MSG_TEXT = "text"; | |||
public static final String XML_MSG_IMAGE = "image"; | |||
public static final String XML_MSG_VOICE = "voice"; | |||
public static final String XML_MSG_SHORTVIDEO = "shortvideo"; | |||
public static final String XML_MSG_VIDEO = "video"; | |||
public static final String XML_MSG_NEWS = "news"; | |||
public static final String XML_MSG_MUSIC = "music"; | |||
@@ -20,7 +21,7 @@ public class WxConsts { | |||
public static final String XML_TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service"; | |||
/////////////////////// | |||
// 主动发送消息的消息类型 | |||
// 主动发送消息(即客服消息)的消息类型 | |||
/////////////////////// | |||
public static final String CUSTOM_MSG_TEXT = "text"; | |||
public static final String CUSTOM_MSG_IMAGE = "image"; | |||
@@ -103,6 +104,10 @@ public class WxConsts { | |||
public static final String EVT_USER_ENTER_SESSION_FROM_CARD = "user_enter_session_from_card"; | |||
public static final String EVT_CARD_SKU_REMIND = "card_sku_remind"; // 库存报警 | |||
public static final String EVT_KF_CREATE_SESSION = "kf_create_session"; // 客服接入会话 | |||
public static final String EVT_KF_CLOSE_SESSION = "kf_close_session"; // 客服关闭会话 | |||
public static final String EVT_KF_SWITCH_SESSION = "kf_switch_session"; // 客服转接会话 | |||
/////////////////////// | |||
// 上传多媒体文件的类型 | |||
/////////////////////// | |||
@@ -133,13 +138,17 @@ public class WxConsts { | |||
/** 扫码推事件且弹出“消息接收中”提示框 */ | |||
public static final String BUTTON_SCANCODE_WAITMSG = "scancode_waitmsg"; | |||
/** 弹出系统拍照发图 */ | |||
public static final String PIC_SYSPHOTO = "pic_sysphoto"; | |||
public static final String BUTTON_PIC_SYSPHOTO = "pic_sysphoto"; | |||
/** 弹出拍照或者相册发图 */ | |||
public static final String PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
public static final String BUTTON_PIC_PHOTO_OR_ALBUM = "pic_photo_or_album"; | |||
/** 弹出微信相册发图器 */ | |||
public static final String PIC_WEIXIN = "pic_weixin"; | |||
public static final String BUTTON_PIC_WEIXIN = "pic_weixin"; | |||
/** 弹出地理位置选择器 */ | |||
public static final String LOCATION_SELECT = "location_select"; | |||
public static final String BUTTON_LOCATION_SELECT = "location_select"; | |||
/** 下发消息(除文本消息) */ | |||
public static final String BUTTON_MEDIA_ID = "media_id"; | |||
/** 跳转图文消息URL */ | |||
public static final String BUTTON_VIEW_LIMITED = "view_limited"; | |||
/////////////////////// | |||
// oauth2网页授权的scope | |||
@@ -1,14 +1,14 @@ | |||
package me.chanjar.weixin.common.bean; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
import org.apache.commons.codec.Charsets; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.Serializable; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
/** | |||
* 企业号菜单 | |||
* @author Daniel Qian | |||
@@ -45,8 +45,6 @@ public class WxMenu implements Serializable { | |||
/** | |||
* 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | |||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | |||
* @param json | |||
* @return | |||
*/ | |||
public static WxMenu fromJson(String json) { | |||
return WxGsonBuilder.create().fromJson(json, WxMenu.class); | |||
@@ -55,11 +53,9 @@ public class WxMenu implements Serializable { | |||
/** | |||
* 要用 http://mp.weixin.qq.com/wiki/16/ff9b7b85220e1396ffa16794a9d95adc.html 格式来反序列化 | |||
* 相比 http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html 的格式,外层多套了一个menu | |||
* @param is | |||
* @return | |||
*/ | |||
public static WxMenu fromJson(InputStream is) { | |||
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, Charsets.UTF_8), WxMenu.class); | |||
return WxGsonBuilder.create().fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), WxMenu.class); | |||
} | |||
@Override | |||
@@ -195,7 +191,7 @@ public class WxMenu implements Serializable { | |||
this.language = language; | |||
} | |||
@Override | |||
@Override | |||
public String toString() { | |||
return "matchrule:{" + | |||
"tag_id='" + tagId + '\'' + | |||
@@ -4,16 +4,11 @@ public interface WxSessionManager { | |||
/** | |||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 | |||
* @param sessionId | |||
* @return | |||
*/ | |||
public WxSession getSession(String sessionId); | |||
/** | |||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | |||
* @param sessionId | |||
* @param create | |||
* @return | |||
*/ | |||
public WxSession getSession(String sessionId, boolean create); | |||
@@ -12,9 +12,6 @@ public class SHA1 { | |||
/** | |||
* 串接arr参数,生成sha1 digest | |||
* | |||
* @param arr | |||
* @return | |||
*/ | |||
public static String gen(String... arr) throws NoSuchAlgorithmException { | |||
Arrays.sort(arr); | |||
@@ -27,9 +24,6 @@ public class SHA1 { | |||
/** | |||
* 用&串接arr参数,生成sha1 digest | |||
* | |||
* @param arr | |||
* @return | |||
*/ | |||
public static String genWithAmple(String... arr) throws NoSuchAlgorithmException { | |||
Arrays.sort(arr); | |||
@@ -35,16 +35,16 @@ public class WxCryptUtil { | |||
private static final Base64 base64 = new Base64(); | |||
private static final Charset CHARSET = Charset.forName("utf-8"); | |||
private static final ThreadLocal<DocumentBuilder> builderLocal = | |||
new ThreadLocal<DocumentBuilder>() { | |||
@Override protected DocumentBuilder initialValue() { | |||
try { | |||
return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||
} catch (ParserConfigurationException exc) { | |||
throw new IllegalArgumentException(exc); | |||
} | |||
} | |||
}; | |||
private static final ThreadLocal<DocumentBuilder> builderLocal = new ThreadLocal<DocumentBuilder>() { | |||
@Override | |||
protected DocumentBuilder initialValue() { | |||
try { | |||
return DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||
} catch (ParserConfigurationException exc) { | |||
throw new IllegalArgumentException(exc); | |||
} | |||
} | |||
}; | |||
protected byte[] aesKey; | |||
protected String token; | |||
@@ -61,7 +61,8 @@ public class WxCryptUtil { | |||
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | |||
* @param appidOrCorpid 公众平台appid/corpid | |||
*/ | |||
public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { | |||
public WxCryptUtil(String token, String encodingAesKey, | |||
String appidOrCorpid) { | |||
this.token = token; | |||
this.appidOrCorpid = appidOrCorpid; | |||
this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | |||
@@ -105,7 +106,8 @@ public class WxCryptUtil { | |||
ByteGroup byteCollector = new ByteGroup(); | |||
byte[] randomStringBytes = randomStr.getBytes(CHARSET); | |||
byte[] plainTextBytes = plainText.getBytes(CHARSET); | |||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); | |||
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | |||
plainTextBytes.length); | |||
byte[] appIdBytes = appidOrCorpid.getBytes(CHARSET); | |||
// randomStr + networkBytesOrder + text + appid | |||
@@ -154,7 +156,8 @@ public class WxCryptUtil { | |||
* @param encryptedXml 密文,对应POST请求的数据 | |||
* @return 解密后的原文 | |||
*/ | |||
public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) { | |||
public String decrypt(String msgSignature, String timeStamp, String nonce, | |||
String encryptedXml) { | |||
// 密钥,公众账号的app corpSecret | |||
// 提取密文 | |||
String cipherText = extractEncryptPart(encryptedXml); | |||
@@ -186,7 +189,8 @@ public class WxCryptUtil { | |||
// 设置解密模式为AES的CBC模式 | |||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | |||
SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); | |||
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); | |||
IvParameterSpec iv = new IvParameterSpec( | |||
Arrays.copyOfRange(aesKey, 0, 16)); | |||
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | |||
// 使用BASE64对密文进行解码 | |||
@@ -208,9 +212,10 @@ public class WxCryptUtil { | |||
int xmlLength = bytesNetworkOrder2Number(networkOrder); | |||
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); | |||
from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), | |||
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | |||
CHARSET); | |||
from_appid = new String( | |||
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||
} catch (Exception e) { | |||
throw new RuntimeException(e); | |||
} | |||
@@ -224,34 +229,32 @@ public class WxCryptUtil { | |||
} | |||
/** | |||
* 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) | |||
* @param packageParams 原始参数 | |||
* @param signKey 加密Key(即 商户Key) | |||
* @param charset 编码 | |||
* @return 签名字符串 | |||
*/ | |||
public static String createSign(Map<String, String> packageParams, String signKey) { | |||
SortedMap<String, String> sortedMap = new TreeMap<String, String>(); | |||
sortedMap.putAll(packageParams); | |||
List<String> keys = new ArrayList<String>(packageParams.keySet()); | |||
Collections.sort(keys); | |||
StringBuffer toSign = new StringBuffer(); | |||
for (String key : keys) { | |||
String value = packageParams.get(key); | |||
if (null != value && !"".equals(value) && !"sign".equals(key) | |||
&& !"key".equals(key)) { | |||
toSign.append(key + "=" + value + "&"); | |||
} | |||
} | |||
toSign.append("key=" + signKey); | |||
String sign = DigestUtils.md5Hex(toSign.toString()) | |||
.toUpperCase(); | |||
return sign; | |||
/** | |||
* 微信公众号支付签名算法(详见:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=4_3) | |||
* @param packageParams 原始参数 | |||
* @param signKey 加密Key(即 商户Key) | |||
* @return 签名字符串 | |||
*/ | |||
public static String createSign(Map<String, String> packageParams, | |||
String signKey) { | |||
SortedMap<String, String> sortedMap = new TreeMap<String, String>(); | |||
sortedMap.putAll(packageParams); | |||
List<String> keys = new ArrayList<String>(packageParams.keySet()); | |||
Collections.sort(keys); | |||
StringBuffer toSign = new StringBuffer(); | |||
for (String key : keys) { | |||
String value = packageParams.get(key); | |||
if (null != value && !"".equals(value) && !"sign".equals(key) | |||
&& !"key".equals(key)) { | |||
toSign.append(key + "=" + value + "&"); | |||
} | |||
} | |||
toSign.append("key=" + signKey); | |||
String sign = DigestUtils.md5Hex(toSign.toString()).toUpperCase(); | |||
return sign; | |||
} | |||
/** | |||
* 将一个数字转换成生成4个字节的网络字节序bytes数组 | |||
@@ -283,8 +286,6 @@ public class WxCryptUtil { | |||
/** | |||
* 随机生成16位字符串 | |||
* | |||
* @return | |||
*/ | |||
private String genRandomStr() { | |||
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |||
@@ -306,14 +307,12 @@ public class WxCryptUtil { | |||
* @param nonce 随机字符串 | |||
* @return 生成的xml字符串 | |||
*/ | |||
private String generateXml(String encrypt, String signature, String timestamp, String nonce) { | |||
String format = | |||
"<xml>\n" | |||
+ "<Encrypt><![CDATA[%1$s]]></Encrypt>\n" | |||
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n" | |||
+ "<TimeStamp>%3$s</TimeStamp>\n" | |||
+ "<Nonce><![CDATA[%4$s]]></Nonce>\n" | |||
+ "</xml>"; | |||
private String generateXml(String encrypt, String signature, String timestamp, | |||
String nonce) { | |||
String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n" | |||
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n" | |||
+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" | |||
+ "</xml>"; | |||
return String.format(format, encrypt, signature, timestamp, nonce); | |||
} | |||
@@ -14,8 +14,6 @@ public class FileUtils { | |||
* @param name 文件名 | |||
* @param ext 扩展名 | |||
* @param tmpDirFile 临时文件夹目录 | |||
* @return | |||
* @throws IOException | |||
*/ | |||
public static File createTmpFile(InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException { | |||
FileOutputStream fos = null; | |||
@@ -56,8 +54,6 @@ public class FileUtils { | |||
* @param inputStream | |||
* @param name 文件名 | |||
* @param ext 扩展名 | |||
* @return | |||
* @throws IOException | |||
*/ | |||
public static File createTmpFile(InputStream inputStream, String name, String ext) throws IOException { | |||
return createTmpFile(inputStream, name, ext, null); | |||
@@ -17,35 +17,30 @@ public interface ApacheHttpClientBuilder { | |||
/** | |||
* 代理服务器地址 | |||
* @param httpProxyHost | |||
* @return | |||
*/ | |||
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); | |||
/** | |||
* 代理服务器端口 | |||
* @param httpProxyPort | |||
* @return | |||
*/ | |||
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); | |||
/** | |||
* 代理服务器用户名 | |||
* @param httpProxyUsername | |||
* @return | |||
*/ | |||
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); | |||
/** | |||
* 代理服务器密码 | |||
* @param httpProxyPassword | |||
* @return | |||
*/ | |||
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); | |||
/** | |||
* ssl连接socket工厂 | |||
* @param sslConnectionSocketFactory | |||
* @return | |||
*/ | |||
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); | |||
} |
@@ -22,7 +22,6 @@ public interface RequestExecutor<T, E> { | |||
* @param httpProxy http代理对象,如果没有配置代理则为空 | |||
* @param uri uri | |||
* @param data 数据 | |||
* @return | |||
* @throws WxErrorException | |||
* @throws ClientProtocolException | |||
* @throws IOException | |||
@@ -6,7 +6,7 @@ | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>1.3.5</version> | |||
<version>2.0.0-SNAPSHOT</version> | |||
</parent> | |||
<artifactId>weixin-java-cp</artifactId> | |||
@@ -9,8 +9,6 @@ public interface WxCpMessageMatcher { | |||
/** | |||
* 消息是否匹配某种模式 | |||
* @param message | |||
* @return | |||
*/ | |||
public boolean match(WxCpXmlMessage message); | |||
@@ -124,7 +124,6 @@ public class WxCpMessageRouter { | |||
/** | |||
* 开始一个新的Route规则 | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule rule() { | |||
return new WxCpMessageRouterRule(this); | |||
@@ -48,7 +48,6 @@ public class WxCpMessageRouterRule { | |||
* 设置是否异步执行,默认是true | |||
* | |||
* @param async | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule async(boolean async) { | |||
this.async = async; | |||
@@ -59,7 +58,6 @@ public class WxCpMessageRouterRule { | |||
* 如果agentId匹配 | |||
* | |||
* @param agentId | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule agentId(Integer agentId) { | |||
this.agentId = agentId; | |||
@@ -70,7 +68,6 @@ public class WxCpMessageRouterRule { | |||
* 如果msgType等于某值 | |||
* | |||
* @param msgType | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule msgType(String msgType) { | |||
this.msgType = msgType; | |||
@@ -81,7 +78,6 @@ public class WxCpMessageRouterRule { | |||
* 如果event等于某值 | |||
* | |||
* @param event | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule event(String event) { | |||
this.event = event; | |||
@@ -92,7 +88,6 @@ public class WxCpMessageRouterRule { | |||
* 如果eventKey等于某值 | |||
* | |||
* @param eventKey | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule eventKey(String eventKey) { | |||
this.eventKey = eventKey; | |||
@@ -103,7 +98,6 @@ public class WxCpMessageRouterRule { | |||
* 如果content等于某值 | |||
* | |||
* @param content | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule content(String content) { | |||
this.content = content; | |||
@@ -114,7 +108,6 @@ public class WxCpMessageRouterRule { | |||
* 如果content匹配该正则表达式 | |||
* | |||
* @param regex | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule rContent(String regex) { | |||
this.rContent = regex; | |||
@@ -125,7 +118,6 @@ public class WxCpMessageRouterRule { | |||
* 如果fromUser等于某值 | |||
* | |||
* @param fromUser | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule fromUser(String fromUser) { | |||
this.fromUser = fromUser; | |||
@@ -136,7 +128,6 @@ public class WxCpMessageRouterRule { | |||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||
* | |||
* @param matcher | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule matcher(WxCpMessageMatcher matcher) { | |||
this.matcher = matcher; | |||
@@ -147,7 +138,6 @@ public class WxCpMessageRouterRule { | |||
* 设置微信消息拦截器 | |||
* | |||
* @param interceptor | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor) { | |||
return interceptor(interceptor, (WxCpMessageInterceptor[]) null); | |||
@@ -158,7 +148,6 @@ public class WxCpMessageRouterRule { | |||
* | |||
* @param interceptor | |||
* @param otherInterceptors | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule interceptor(WxCpMessageInterceptor interceptor, WxCpMessageInterceptor... otherInterceptors) { | |||
this.interceptors.add(interceptor); | |||
@@ -174,7 +163,6 @@ public class WxCpMessageRouterRule { | |||
* 设置微信消息处理器 | |||
* | |||
* @param handler | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler) { | |||
return handler(handler, (WxCpMessageHandler[]) null); | |||
@@ -185,7 +173,6 @@ public class WxCpMessageRouterRule { | |||
* | |||
* @param handler | |||
* @param otherHandlers | |||
* @return | |||
*/ | |||
public WxCpMessageRouterRule handler(WxCpMessageHandler handler, WxCpMessageHandler... otherHandlers) { | |||
this.handlers.add(handler); | |||
@@ -200,7 +187,6 @@ public class WxCpMessageRouterRule { | |||
/** | |||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||
* | |||
* @return | |||
*/ | |||
public WxCpMessageRouter end() { | |||
this.routerBuilder.getRules().add(this); | |||
@@ -210,7 +196,6 @@ public class WxCpMessageRouterRule { | |||
/** | |||
* 规则结束,但是消息还会进入其他规则 | |||
* | |||
* @return | |||
*/ | |||
public WxCpMessageRouter next() { | |||
this.reEnter = true; | |||
@@ -32,7 +32,6 @@ public interface WxCpService { | |||
* @param timestamp | |||
* @param nonce | |||
* @param data 微信传输过来的数据,有可能是echoStr,有可能是xml消息 | |||
* @return | |||
*/ | |||
boolean checkSignature(String msgSignature, String timestamp, String nonce, String data); | |||
@@ -49,7 +48,6 @@ public interface WxCpService { | |||
/** | |||
* 获取access_token, 不强制刷新access_token | |||
* @see #getAccessToken(boolean) | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
String getAccessToken() throws WxErrorException; | |||
@@ -63,7 +61,6 @@ public interface WxCpService { | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token | |||
* </pre> | |||
* @param forceRefresh 强制刷新 | |||
* @return | |||
* @throws me.chanjar.weixin.common.exception.WxErrorException | |||
*/ | |||
String getAccessToken(boolean forceRefresh) throws WxErrorException; | |||
@@ -71,7 +68,6 @@ public interface WxCpService { | |||
/** | |||
* 获得jsapi_ticket,不强制刷新jsapi_ticket | |||
* @see #getJsapiTicket(boolean) | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public String getJsapiTicket() throws WxErrorException; | |||
@@ -84,7 +80,6 @@ public interface WxCpService { | |||
* 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 | |||
* </pre> | |||
* @param forceRefresh 强制刷新 | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException; | |||
@@ -96,7 +91,6 @@ public interface WxCpService { | |||
* 详情请见:http://qydev.weixin.qq.com/wiki/index.php?title=微信JS接口#.E9.99.84.E5.BD.951-JS-SDK.E4.BD.BF.E7.94.A8.E6.9D.83.E9.99.90.E7.AD.BE.E5.90.8D.E7.AE.97.E6.B3.95 | |||
* </pre> | |||
* @param url url | |||
* @return | |||
*/ | |||
public WxJsapiSignature createJsapiSignature(String url) throws WxErrorException; | |||
@@ -136,7 +130,7 @@ public interface WxCpService { | |||
* | |||
* @return 保存到本地的临时文件 | |||
* @throws WxErrorException | |||
* @params media_id | |||
* @param media_id | |||
*/ | |||
File mediaDownload(String media_id) throws WxErrorException; | |||
@@ -216,7 +210,6 @@ public interface WxCpService { | |||
* </pre> | |||
* @see #menuGet(String) | |||
* | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
WxMenu menuGet() throws WxErrorException; | |||
@@ -231,7 +224,6 @@ public interface WxCpService { | |||
* @see #menuGet() | |||
* | |||
* @param agentId 企业号应用的id | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
WxMenu menuGet(String agentId) throws WxErrorException; | |||
@@ -255,7 +247,6 @@ public interface WxCpService { | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=部门管理接口 | |||
* </pre> | |||
* | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
List<WxCpDepart> departGet() throws WxErrorException; | |||
@@ -291,7 +282,6 @@ public interface WxCpService { | |||
* @param departId 必填。部门id | |||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | |||
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
List<WxCpUser> userList(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||
@@ -306,7 +296,6 @@ public interface WxCpService { | |||
* @param departId 必填。部门id | |||
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 | |||
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
List<WxCpUser> departGetUsers(Integer departId, Boolean fetchChild, Integer status) throws WxErrorException; | |||
@@ -350,7 +339,6 @@ public interface WxCpService { | |||
* 获取用户 | |||
* | |||
* @param userid | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
WxCpUser userGet(String userid) throws WxErrorException; | |||
@@ -359,7 +347,6 @@ public interface WxCpService { | |||
* 创建标签 | |||
* | |||
* @param tagName | |||
* @return | |||
*/ | |||
String tagCreate(String tagName) throws WxErrorException; | |||
@@ -381,7 +368,6 @@ public interface WxCpService { | |||
/** | |||
* 获得标签列表 | |||
* | |||
* @return | |||
*/ | |||
List<WxCpTag> tagGet() throws WxErrorException; | |||
@@ -389,7 +375,6 @@ public interface WxCpService { | |||
* 获取标签成员 | |||
* | |||
* @param tagId | |||
* @return | |||
*/ | |||
List<WxCpUser> tagGetUsers(String tagId) throws WxErrorException; | |||
@@ -478,7 +463,6 @@ public interface WxCpService { | |||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求 | |||
* @param url | |||
* @param queryParam | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
String get(String url, String queryParam) throws WxErrorException; | |||
@@ -487,7 +471,6 @@ public interface WxCpService { | |||
* 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求 | |||
* @param url | |||
* @param postData | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
String post(String url, String postData) throws WxErrorException; | |||
@@ -503,7 +486,6 @@ public interface WxCpService { | |||
* @param data | |||
* @param <T> | |||
* @param <E> | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException; | |||
@@ -536,7 +518,6 @@ public interface WxCpService { | |||
/** | |||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,则新建一个并返回。 | |||
* @param id id可以为任意字符串,建议使用FromUserName作为id | |||
* @return | |||
*/ | |||
WxSession getSession(String id); | |||
@@ -544,7 +525,6 @@ public interface WxCpService { | |||
* 获取某个sessionId对应的session,如果sessionId没有对应的session,若create为true则新建一个,否则返回null。 | |||
* @param id id可以为任意字符串,建议使用FromUserName作为id | |||
* @param create | |||
* @return | |||
*/ | |||
WxSession getSession(String id, boolean create); | |||
@@ -556,25 +536,24 @@ public interface WxCpService { | |||
* @param sessionManager | |||
*/ | |||
void setSessionManager(WxSessionManager sessionManager); | |||
/** | |||
* 上传部门列表覆盖企业号上的部门信息 | |||
* @param mediaId | |||
* @throws WxErrorException | |||
*/ | |||
String replaceParty(String mediaId) throws WxErrorException; | |||
/** | |||
* 上传用户列表覆盖企业号上的用户信息 | |||
* @param mediaId | |||
* @throws WxErrorException | |||
*/ | |||
String replaceUser(String mediaId) throws WxErrorException; | |||
/** | |||
* 获取异步任务结果 | |||
* @param joinId | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
String getTaskResult(String joinId) throws WxErrorException; | |||
@@ -510,12 +510,6 @@ public class WxCpServiceImpl implements WxCpService { | |||
/** | |||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | |||
* | |||
* @param executor | |||
* @param uri | |||
* @param data | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
int retryTimes = 0; | |||
@@ -28,7 +28,7 @@ public class WxCpMessage implements Serializable { | |||
private String hqMusicUrl; | |||
private String safe; | |||
private List<WxArticle> articles = new ArrayList<WxArticle>(); | |||
public String getToUser() { | |||
return toUser; | |||
} | |||
@@ -63,7 +63,7 @@ public class WxCpMessage implements Serializable { | |||
public String getMsgType() { | |||
return msgType; | |||
} | |||
public String getSafe() { | |||
return safe; | |||
} | |||
@@ -135,18 +135,18 @@ public class WxCpMessage implements Serializable { | |||
public void setArticles(List<WxArticle> articles) { | |||
this.articles = articles; | |||
} | |||
public String toJson() { | |||
return WxCpGsonBuilder.INSTANCE.create().toJson(this); | |||
} | |||
public static class WxArticle { | |||
private String title; | |||
private String description; | |||
private String url; | |||
private String picUrl; | |||
public String getTitle() { | |||
return title; | |||
} | |||
@@ -171,12 +171,11 @@ public class WxCpMessage implements Serializable { | |||
public void setPicUrl(String picUrl) { | |||
this.picUrl = picUrl; | |||
} | |||
} | |||
/** | |||
* 获得文本消息builder | |||
* @return | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
@@ -184,7 +183,6 @@ public class WxCpMessage implements Serializable { | |||
/** | |||
* 获得图片消息builder | |||
* @return | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
@@ -192,23 +190,20 @@ public class WxCpMessage implements Serializable { | |||
/** | |||
* 获得语音消息builder | |||
* @return | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
} | |||
/** | |||
* 获得视频消息builder | |||
* @return | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
} | |||
/** | |||
* 获得图文消息builder | |||
* @return | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
@@ -216,10 +211,9 @@ public class WxCpMessage implements Serializable { | |||
/** | |||
* 获得文件消息builder | |||
* @return | |||
*/ | |||
public static FileBuilder FILE() { | |||
return new FileBuilder(); | |||
} | |||
} |
@@ -198,7 +198,6 @@ public class WxCpXmlMessage implements Serializable { | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | |||
* </pre> | |||
* | |||
* @return | |||
*/ | |||
public String getMsgType() { | |||
return msgType; | |||
@@ -404,7 +403,6 @@ public class WxCpXmlMessage implements Serializable { | |||
* @param timestamp | |||
* @param nonce | |||
* @param msgSignature | |||
* @return | |||
*/ | |||
public static WxCpXmlMessage fromEncryptedXml( | |||
String encryptedXml, | |||
@@ -542,7 +540,6 @@ public class WxCpXmlMessage implements Serializable { | |||
/** | |||
* 扫描类型,一般是qrcode | |||
* @return | |||
*/ | |||
public String getScanType() { | |||
@@ -555,7 +552,6 @@ public class WxCpXmlMessage implements Serializable { | |||
/** | |||
* 扫描结果,即二维码对应的字符串信息 | |||
* @return | |||
*/ | |||
public String getScanResult() { | |||
return scanResult; | |||
@@ -14,14 +14,14 @@ public abstract class WxCpXmlOutMessage { | |||
@XStreamAlias("ToUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
protected String toUserName; | |||
@XStreamAlias("FromUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
protected String fromUserName; | |||
@XStreamAlias("CreateTime") | |||
protected Long createTime; | |||
@XStreamAlias("MsgType") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
protected String msgType; | |||
@@ -57,14 +57,13 @@ public abstract class WxCpXmlOutMessage { | |||
public void setMsgType(String msgType) { | |||
this.msgType = msgType; | |||
} | |||
protected String toXml() { | |||
return XStreamTransformer.toXml((Class)this.getClass(), this); | |||
} | |||
/** | |||
* 转换成加密的xml格式 | |||
* @return | |||
*/ | |||
public String toEncryptedXml(WxCpConfigStorage wxCpConfigStorage) { | |||
String plainXml = toXml(); | |||
@@ -74,7 +73,6 @@ public abstract class WxCpXmlOutMessage { | |||
/** | |||
* 获得文本消息builder | |||
* @return | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
@@ -82,7 +80,6 @@ public abstract class WxCpXmlOutMessage { | |||
/** | |||
* 获得图片消息builder | |||
* @return | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
@@ -90,23 +87,20 @@ public abstract class WxCpXmlOutMessage { | |||
/** | |||
* 获得语音消息builder | |||
* @return | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
} | |||
/** | |||
* 获得视频消息builder | |||
* @return | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
} | |||
/** | |||
* 获得图文消息builder | |||
* @return | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
@@ -14,10 +14,6 @@ public class XStreamTransformer { | |||
/** | |||
* xml -> pojo | |||
* | |||
* @param clazz | |||
* @param xml | |||
* @return | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public static <T> T fromXml(Class<T> clazz, String xml) { | |||
@@ -43,9 +39,6 @@ public class XStreamTransformer { | |||
/** | |||
* pojo -> xml | |||
* | |||
* @param clazz | |||
* @param object | |||
* @return | |||
*/ | |||
public static <T> String toXml(Class<T> clazz, T object) { | |||
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object); | |||
@@ -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> | |||
<url-pattern>/*</url-pattern> | |||
</filter-mapping> | |||
<filter> | |||
<filter-name>springSecurityFilterChain</filter-name> | |||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> | |||
</filter> | |||
<filter-mapping> | |||
<filter-name>springSecurityFilterChain</filter-name> | |||
<url-pattern>/v1/admin/*</url-pattern> | |||
</filter-mapping> | |||
<listener> | |||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> |
@@ -6,7 +6,7 @@ | |||
<parent> | |||
<groupId>com.github.binarywang</groupId> | |||
<artifactId>weixin-java-parent</artifactId> | |||
<version>1.3.5</version> | |||
<version>2.0.0-SNAPSHOT</version> | |||
</parent> | |||
<artifactId>weixin-java-mp</artifactId> | |||
<name>WeiXin Java Tools - MP</name> | |||
@@ -47,6 +47,12 @@ | |||
<groupId>org.eclipse.jetty</groupId> | |||
<artifactId>jetty-servlet</artifactId> | |||
<scope>test</scope> | |||
</dependency><!-- https://mvnrepository.com/artifact/joda-time/joda-time --> | |||
<dependency> | |||
<groupId>joda-time</groupId> | |||
<artifactId>joda-time</artifactId> | |||
<version>2.9.4</version> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
@@ -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 | |||
* @return | |||
*/ | |||
public boolean match(WxMpXmlMessage message); | |||
@@ -124,7 +124,6 @@ public class WxMpMessageRouter { | |||
/** | |||
* 开始一个新的Route规则 | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule rule() { | |||
return new WxMpMessageRouterRule(this); | |||
@@ -34,9 +34,9 @@ public class WxMpMessageRouterRule { | |||
private boolean reEnter = false; | |||
private List<WxMpMessageHandler> handlers = new ArrayList<WxMpMessageHandler>(); | |||
private List<WxMpMessageHandler> handlers = new ArrayList<>(); | |||
private List<WxMpMessageInterceptor> interceptors = new ArrayList<WxMpMessageInterceptor>(); | |||
private List<WxMpMessageInterceptor> interceptors = new ArrayList<>(); | |||
public WxMpMessageRouterRule(WxMpMessageRouter routerBuilder) { | |||
this.routerBuilder = routerBuilder; | |||
@@ -44,9 +44,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 设置是否异步执行,默认是true | |||
* | |||
* @param async | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule async(boolean async) { | |||
this.async = async; | |||
@@ -55,9 +52,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果msgType等于某值 | |||
* | |||
* @param msgType | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule msgType(String msgType) { | |||
this.msgType = msgType; | |||
@@ -66,9 +60,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果event等于某值 | |||
* | |||
* @param event | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule event(String event) { | |||
this.event = event; | |||
@@ -77,9 +68,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果eventKey等于某值 | |||
* | |||
* @param eventKey | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule eventKey(String eventKey) { | |||
this.eventKey = eventKey; | |||
@@ -88,9 +76,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果content等于某值 | |||
* | |||
* @param content | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule content(String content) { | |||
this.content = content; | |||
@@ -99,9 +84,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果content匹配该正则表达式 | |||
* | |||
* @param regex | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule rContent(String regex) { | |||
this.rContent = regex; | |||
@@ -110,9 +92,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果fromUser等于某值 | |||
* | |||
* @param fromUser | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule fromUser(String fromUser) { | |||
this.fromUser = fromUser; | |||
@@ -121,9 +100,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候 | |||
* | |||
* @param matcher | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule matcher(WxMpMessageMatcher matcher) { | |||
this.matcher = matcher; | |||
@@ -132,9 +108,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 设置微信消息拦截器 | |||
* | |||
* @param interceptor | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor) { | |||
return interceptor(interceptor, (WxMpMessageInterceptor[]) null); | |||
@@ -142,10 +115,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 设置微信消息拦截器 | |||
* | |||
* @param interceptor | |||
* @param otherInterceptors | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule interceptor(WxMpMessageInterceptor interceptor, WxMpMessageInterceptor... otherInterceptors) { | |||
this.interceptors.add(interceptor); | |||
@@ -159,9 +128,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 设置微信消息处理器 | |||
* | |||
* @param handler | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler) { | |||
return handler(handler, (WxMpMessageHandler[]) null); | |||
@@ -169,10 +135,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 设置微信消息处理器 | |||
* | |||
* @param handler | |||
* @param otherHandlers | |||
* @return | |||
*/ | |||
public WxMpMessageRouterRule handler(WxMpMessageHandler handler, WxMpMessageHandler... otherHandlers) { | |||
this.handlers.add(handler); | |||
@@ -186,8 +148,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则 | |||
* | |||
* @return | |||
*/ | |||
public WxMpMessageRouter end() { | |||
this.routerBuilder.getRules().add(this); | |||
@@ -196,8 +156,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 规则结束,但是消息还会进入其他规则 | |||
* | |||
* @return | |||
*/ | |||
public WxMpMessageRouter next() { | |||
this.reEnter = true; | |||
@@ -207,8 +165,6 @@ public class WxMpMessageRouterRule { | |||
/** | |||
* 将微信自定义的事件修正为不区分大小写, | |||
* 比如框架定义的事件常量为click,但微信传递过来的却是CLICK | |||
* @param wxMessage | |||
* @return | |||
*/ | |||
protected boolean test(WxMpXmlMessage wxMessage) { | |||
return | |||
@@ -243,7 +199,7 @@ public class WxMpMessageRouterRule { | |||
try { | |||
Map<String, Object> context = new HashMap<String, Object>(); | |||
Map<String, Object> context = new HashMap<>(); | |||
// 如果拦截器不通过 | |||
for (WxMpMessageInterceptor interceptor : this.interceptors) { | |||
if (!interceptor.intercept(wxMessage, context, wxMpService, sessionManager)) { | |||
@@ -255,6 +211,9 @@ public class WxMpMessageRouterRule { | |||
WxMpXmlOutMessage res = null; | |||
for (WxMpMessageHandler handler : this.handlers) { | |||
// 返回最后handler的结果 | |||
if(handler == null){ | |||
continue; | |||
} | |||
res = handler.handle(wxMessage, context, wxMpService, sessionManager); | |||
} | |||
return res; | |||
@@ -266,11 +225,11 @@ public class WxMpMessageRouterRule { | |||
} | |||
public WxMpMessageRouter getRouterBuilder() { | |||
return routerBuilder; | |||
return this.routerBuilder; | |||
} | |||
public boolean isAsync() { | |||
return async; | |||
return this.async; | |||
} | |||
public void setAsync(boolean async) { | |||
@@ -278,7 +237,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getFromUser() { | |||
return fromUser; | |||
return this.fromUser; | |||
} | |||
public void setFromUser(String fromUser) { | |||
@@ -286,7 +245,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getMsgType() { | |||
return msgType; | |||
return this.msgType; | |||
} | |||
public void setMsgType(String msgType) { | |||
@@ -294,7 +253,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getEvent() { | |||
return event; | |||
return this.event; | |||
} | |||
public void setEvent(String event) { | |||
@@ -302,7 +261,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getEventKey() { | |||
return eventKey; | |||
return this.eventKey; | |||
} | |||
public void setEventKey(String eventKey) { | |||
@@ -310,7 +269,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getContent() { | |||
return content; | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
@@ -318,7 +277,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public String getrContent() { | |||
return rContent; | |||
return this.rContent; | |||
} | |||
public void setrContent(String rContent) { | |||
@@ -326,7 +285,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public WxMpMessageMatcher getMatcher() { | |||
return matcher; | |||
return this.matcher; | |||
} | |||
public void setMatcher(WxMpMessageMatcher matcher) { | |||
@@ -334,7 +293,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public boolean isReEnter() { | |||
return reEnter; | |||
return this.reEnter; | |||
} | |||
public void setReEnter(boolean reEnter) { | |||
@@ -342,7 +301,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public List<WxMpMessageHandler> getHandlers() { | |||
return handlers; | |||
return this.handlers; | |||
} | |||
public void setHandlers(List<WxMpMessageHandler> handlers) { | |||
@@ -350,7 +309,7 @@ public class WxMpMessageRouterRule { | |||
} | |||
public List<WxMpMessageInterceptor> getInterceptors() { | |||
return interceptors; | |||
return this.interceptors; | |||
} | |||
public void setInterceptors(List<WxMpMessageInterceptor> interceptors) { | |||
@@ -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.internal.Streams; | |||
import com.google.gson.reflect.TypeToken; | |||
import com.google.gson.stream.JsonReader; | |||
import com.thoughtworks.xstream.XStream; | |||
import me.chanjar.weixin.common.api.WxConsts; | |||
import me.chanjar.weixin.common.bean.WxAccessToken; | |||
import me.chanjar.weixin.common.bean.WxCardApiSignature; | |||
import me.chanjar.weixin.common.bean.WxJsapiSignature; | |||
import me.chanjar.weixin.common.bean.WxMenu; | |||
import me.chanjar.weixin.common.bean.result.WxError; | |||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||
import me.chanjar.weixin.common.exception.WxErrorException; | |||
import me.chanjar.weixin.common.session.StandardSessionManager; | |||
import me.chanjar.weixin.common.session.WxSessionManager; | |||
import me.chanjar.weixin.common.util.RandomUtils; | |||
import me.chanjar.weixin.common.util.crypto.SHA1; | |||
import me.chanjar.weixin.common.util.crypto.WxCryptUtil; | |||
import me.chanjar.weixin.common.util.fs.FileUtils; | |||
import me.chanjar.weixin.common.util.http.*; | |||
import me.chanjar.weixin.common.util.json.GsonHelper; | |||
import me.chanjar.weixin.common.util.json.WxGsonBuilder; | |||
import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
import me.chanjar.weixin.mp.api.*; | |||
import me.chanjar.weixin.mp.bean.*; | |||
import me.chanjar.weixin.mp.bean.result.*; | |||
import me.chanjar.weixin.mp.util.http.*; | |||
import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; | |||
import org.apache.commons.io.Charsets; | |||
import org.apache.http.Consts; | |||
import org.apache.http.HttpHost; | |||
import org.apache.http.client.ClientProtocolException; | |||
@@ -44,12 +36,8 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.slf4j.helpers.MessageFormatter; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.StringReader; | |||
import java.io.UnsupportedEncodingException; | |||
import java.net.URLEncoder; | |||
import java.security.NoSuchAlgorithmException; | |||
import java.util.*; | |||
import java.util.Map.Entry; | |||
@@ -74,6 +62,18 @@ public class WxMpServiceImpl implements WxMpService { | |||
protected final Object globalCardApiTicketRefreshLock = new Object(); | |||
protected WxMpConfigStorage wxMpConfigStorage; | |||
protected WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); | |||
protected WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); | |||
protected WxMpMenuService menuService = new WxMpMenuServiceImpl(this); | |||
protected WxMpUserService userService = new WxMpUserServiceImpl(this); | |||
protected WxMpGroupService groupService = new WxMpGroupServiceImpl(this); | |||
protected WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this); | |||
protected CloseableHttpClient httpClient; | |||
@@ -195,172 +195,6 @@ public class WxMpServiceImpl implements WxMpService { | |||
execute(new SimplePostRequestExecutor(), url, message.toJson()); | |||
} | |||
@Override | |||
public void menuCreate(WxMenu menu) throws WxErrorException { | |||
if (menu.getMatchRule() != null) { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional"; | |||
execute(new SimplePostRequestExecutor(), url, menu.toJson()); | |||
} else { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/create"; | |||
execute(new SimplePostRequestExecutor(), url, menu.toJson()); | |||
} | |||
} | |||
@Override | |||
public void menuDelete() throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/delete"; | |||
execute(new SimpleGetRequestExecutor(), url, null); | |||
} | |||
@Override | |||
public void menuDelete(String menuid) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional"; | |||
execute(new SimpleGetRequestExecutor(), url, "menuid=" + menuid); | |||
} | |||
@Override | |||
public WxMenu menuGet() throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/get"; | |||
try { | |||
String resultContent = execute(new SimpleGetRequestExecutor(), url, null); | |||
return WxMenu.fromJson(resultContent); | |||
} catch (WxErrorException e) { | |||
// 46003 不存在的菜单数据 | |||
if (e.getError().getErrorCode() == 46003) { | |||
return null; | |||
} | |||
throw e; | |||
} | |||
} | |||
@Override | |||
public WxMenu menuTryMatch(String userid) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/menu/trymatch"; | |||
try { | |||
String resultContent = execute(new SimpleGetRequestExecutor(), url, "user_id=" + userid); | |||
return WxMenu.fromJson(resultContent); | |||
} catch (WxErrorException e) { | |||
// 46003 不存在的菜单数据 46002 不存在的菜单版本 | |||
if (e.getError().getErrorCode() == 46003 || e.getError().getErrorCode() == 46002) { | |||
return null; | |||
} | |||
throw e; | |||
} | |||
} | |||
@Override | |||
public WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { | |||
return mediaUpload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); | |||
} | |||
@Override | |||
public WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; | |||
return execute(new MediaUploadRequestExecutor(), url, file); | |||
} | |||
@Override | |||
public File mediaDownload(String media_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/media/get"; | |||
return execute(new MediaDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, "media_id=" + media_id); | |||
} | |||
@Override | |||
public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/add_material?type=" + mediaType; | |||
return execute(new MaterialUploadRequestExecutor(), url, material); | |||
} | |||
@Override | |||
public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException { | |||
if (news == null || news.isEmpty()) { | |||
throw new IllegalArgumentException("news is empty!"); | |||
} | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/add_news"; | |||
String responseContent = post(url, news.toJson()); | |||
return WxMpMaterialUploadResult.fromJson(responseContent); | |||
} | |||
@Override | |||
public InputStream materialImageOrVoiceDownload(String media_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; | |||
return execute(new MaterialVoiceAndImageDownloadRequestExecutor(this.wxMpConfigStorage.getTmpDirFile()), url, media_id); | |||
} | |||
@Override | |||
public WxMpMaterialVideoInfoResult materialVideoInfo(String media_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; | |||
return execute(new MaterialVideoInfoRequestExecutor(), url, media_id); | |||
} | |||
@Override | |||
public WxMpMaterialNews materialNewsInfo(String media_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/get_material"; | |||
return execute(new MaterialNewsInfoRequestExecutor(), url, media_id); | |||
} | |||
@Override | |||
public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/update_news"; | |||
String responseText = post(url, wxMpMaterialArticleUpdate.toJson()); | |||
WxError wxError = WxError.fromJson(responseText); | |||
if (wxError.getErrorCode() == 0) { | |||
return true; | |||
} else { | |||
throw new WxErrorException(wxError); | |||
} | |||
} | |||
@Override | |||
public boolean materialDelete(String media_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/del_material"; | |||
return execute(new MaterialDeleteRequestExecutor(), url, media_id); | |||
} | |||
@Override | |||
public WxMpMaterialCountResult materialCount() throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount"; | |||
String responseText = get(url, null); | |||
WxError wxError = WxError.fromJson(responseText); | |||
if (wxError.getErrorCode() == 0) { | |||
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialCountResult.class); | |||
} else { | |||
throw new WxErrorException(wxError); | |||
} | |||
} | |||
@Override | |||
public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; | |||
Map<String, Object> params = new HashMap<>(); | |||
params.put("type", WxConsts.MATERIAL_NEWS); | |||
params.put("offset", offset); | |||
params.put("count", count); | |||
String responseText = post(url, WxGsonBuilder.create().toJson(params)); | |||
WxError wxError = WxError.fromJson(responseText); | |||
if (wxError.getErrorCode() == 0) { | |||
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialNewsBatchGetResult.class); | |||
} else { | |||
throw new WxErrorException(wxError); | |||
} | |||
} | |||
@Override | |||
public WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material"; | |||
Map<String, Object> params = new HashMap<>(); | |||
params.put("type", type); | |||
params.put("offset", offset); | |||
params.put("count", count); | |||
String responseText = post(url, WxGsonBuilder.create().toJson(params)); | |||
WxError wxError = WxError.fromJson(responseText); | |||
if (wxError.getErrorCode() == 0) { | |||
return WxMpGsonBuilder.create().fromJson(responseText, WxMpMaterialFileBatchGetResult.class); | |||
} else { | |||
throw new WxErrorException(wxError); | |||
} | |||
} | |||
@Override | |||
public WxMpMassUploadResult massNewsUpload(WxMpMassNews news) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | |||
@@ -389,158 +223,6 @@ public class WxMpServiceImpl implements WxMpService { | |||
return WxMpMassSendResult.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpGroup groupCreate(String name) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/groups/create"; | |||
JsonObject json = new JsonObject(); | |||
JsonObject groupJson = new JsonObject(); | |||
json.add("group", groupJson); | |||
groupJson.addProperty("name", name); | |||
String responseContent = execute( | |||
new SimplePostRequestExecutor(), | |||
url, | |||
json.toString()); | |||
return WxMpGroup.fromJson(responseContent); | |||
} | |||
@Override | |||
public List<WxMpGroup> groupGet() throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/groups/get"; | |||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | |||
/* | |||
* 操蛋的微信API,创建时返回的是 { group : { id : ..., name : ...} } | |||
* 查询时返回的是 { groups : [ { id : ..., name : ..., count : ... }, ... ] } | |||
*/ | |||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("groups"), | |||
new TypeToken<List<WxMpGroup>>() { | |||
}.getType()); | |||
} | |||
@Override | |||
public long userGetGroup(String openid) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/groups/getid"; | |||
JsonObject o = new JsonObject(); | |||
o.addProperty("openid", openid); | |||
String responseContent = execute(new SimplePostRequestExecutor(), url, o.toString()); | |||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); | |||
return GsonHelper.getAsLong(tmpJsonElement.getAsJsonObject().get("groupid")); | |||
} | |||
@Override | |||
public void groupUpdate(WxMpGroup group) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/groups/update"; | |||
execute(new SimplePostRequestExecutor(), url, group.toJson()); | |||
} | |||
@Override | |||
public void userUpdateGroup(String openid, long to_groupid) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/groups/members/update"; | |||
JsonObject json = new JsonObject(); | |||
json.addProperty("openid", openid); | |||
json.addProperty("to_groupid", to_groupid); | |||
execute(new SimplePostRequestExecutor(), url, json.toString()); | |||
} | |||
@Override | |||
public void userUpdateRemark(String openid, String remark) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark"; | |||
JsonObject json = new JsonObject(); | |||
json.addProperty("openid", openid); | |||
json.addProperty("remark", remark); | |||
execute(new SimplePostRequestExecutor(), url, json.toString()); | |||
} | |||
@Override | |||
public WxMpUser userInfo(String openid, String lang) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/user/info"; | |||
lang = lang == null ? "zh_CN" : lang; | |||
String responseContent = execute(new SimpleGetRequestExecutor(), url, "openid=" + openid + "&lang=" + lang); | |||
return WxMpUser.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpUserList userList(String next_openid) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/user/get"; | |||
String responseContent = execute(new SimpleGetRequestExecutor(), url, next_openid == null ? null : "next_openid=" + next_openid); | |||
return WxMpUserList.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpQrCodeTicket qrCodeCreateTmpTicket(int scene_id, Integer expire_seconds) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; | |||
JsonObject json = new JsonObject(); | |||
json.addProperty("action_name", "QR_SCENE"); | |||
if (expire_seconds != null) { | |||
json.addProperty("expire_seconds", expire_seconds); | |||
} | |||
JsonObject actionInfo = new JsonObject(); | |||
JsonObject scene = new JsonObject(); | |||
scene.addProperty("scene_id", scene_id); | |||
actionInfo.add("scene", scene); | |||
json.add("action_info", actionInfo); | |||
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); | |||
return WxMpQrCodeTicket.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpQrCodeTicket qrCodeCreateLastTicket(int scene_id) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; | |||
JsonObject json = new JsonObject(); | |||
json.addProperty("action_name", "QR_LIMIT_SCENE"); | |||
JsonObject actionInfo = new JsonObject(); | |||
JsonObject scene = new JsonObject(); | |||
scene.addProperty("scene_id", scene_id); | |||
actionInfo.add("scene", scene); | |||
json.add("action_info", actionInfo); | |||
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); | |||
return WxMpQrCodeTicket.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpQrCodeTicket qrCodeCreateLastTicket(String scene_str) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create"; | |||
JsonObject json = new JsonObject(); | |||
json.addProperty("action_name", "QR_LIMIT_STR_SCENE"); | |||
JsonObject actionInfo = new JsonObject(); | |||
JsonObject scene = new JsonObject(); | |||
scene.addProperty("scene_str", scene_str); | |||
actionInfo.add("scene", scene); | |||
json.add("action_info", actionInfo); | |||
String responseContent = execute(new SimplePostRequestExecutor(), url, json.toString()); | |||
return WxMpQrCodeTicket.fromJson(responseContent); | |||
} | |||
@Override | |||
public File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException { | |||
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode"; | |||
return execute(new QrCodeRequestExecutor(), url, ticket); | |||
} | |||
@Override | |||
public String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException { | |||
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s"; | |||
try { | |||
String resultUrl = String.format(url, | |||
URLEncoder.encode(ticket, Charsets.UTF_8.name())); | |||
if(needShortUrl){ | |||
return this.shortUrl(resultUrl); | |||
} | |||
return resultUrl; | |||
} catch (UnsupportedEncodingException e) { | |||
WxError error = WxError.newBuilder().setErrorCode(-1) | |||
.setErrorMsg(e.getMessage()).build(); | |||
throw new WxErrorException(error); | |||
} | |||
} | |||
@Override | |||
public String qrCodePictureUrl(String ticket) throws WxErrorException { | |||
return qrCodePictureUrl(ticket, false); | |||
} | |||
@Override | |||
public String shortUrl(String long_url) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/shorturl"; | |||
@@ -685,33 +367,6 @@ public class WxMpServiceImpl implements WxMpService { | |||
return ipArray; | |||
} | |||
@Override | |||
public List<WxMpUserSummary> getUserSummary(Date beginDate, Date endDate) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/datacube/getusersummary"; | |||
JsonObject param = new JsonObject(); | |||
param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); | |||
param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); | |||
String responseContent = post(url, param.toString()); | |||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), | |||
new TypeToken<List<WxMpUserSummary>>() { | |||
}.getType()); | |||
} | |||
@Override | |||
public List<WxMpUserCumulate> getUserCumulate(Date beginDate, Date endDate) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/datacube/getusercumulate"; | |||
JsonObject param = new JsonObject(); | |||
param.addProperty("begin_date", SIMPLE_DATE_FORMAT.format(beginDate)); | |||
param.addProperty("end_date", SIMPLE_DATE_FORMAT.format(endDate)); | |||
String responseContent = post(url, param.toString()); | |||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent))); | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement.getAsJsonObject().get("list"), | |||
new TypeToken<List<WxMpUserCumulate>>() { | |||
}.getType()); | |||
} | |||
@Override | |||
public String get(String url, String queryParam) throws WxErrorException { | |||
return execute(new SimpleGetRequestExecutor(), url, queryParam); | |||
@@ -724,12 +379,6 @@ public class WxMpServiceImpl implements WxMpService { | |||
/** | |||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | |||
* | |||
* @param executor | |||
* @param uri | |||
* @param data | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
@Override | |||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException { | |||
@@ -822,6 +471,11 @@ public class WxMpServiceImpl implements WxMpService { | |||
this.httpClient = apacheHttpClientBuilder.build(); | |||
} | |||
@Override | |||
public WxMpConfigStorage getWxMpConfigStorage() { | |||
return this.wxMpConfigStorage; | |||
} | |||
@Override | |||
public void setRetrySleepMillis(int retrySleepMillis) { | |||
this.retrySleepMillis = retrySleepMillis; | |||
@@ -1347,12 +1001,6 @@ public class WxMpServiceImpl implements WxMpService { | |||
return WxMpMassSendResult.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException { | |||
String url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg"; | |||
return execute(new MediaImgUploadRequestExecutor(), url, file); | |||
} | |||
@Override | |||
public String setIndustry(WxMpIndustry wxMpIndustry) throws WxErrorException { | |||
if (null == wxMpIndustry.getPrimaryIndustry() || null == wxMpIndustry.getPrimaryIndustry().getId() | |||
@@ -1369,4 +1017,35 @@ public class WxMpServiceImpl implements WxMpService { | |||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null); | |||
return WxMpIndustry.fromJson(responseContent); | |||
} | |||
@Override | |||
public WxMpKefuService getKefuService() { | |||
return this.kefuService; | |||
} | |||
@Override | |||
public WxMpMaterialService getMaterialService() { | |||
return this.materialService; | |||
} | |||
@Override | |||
public WxMpMenuService getMenuService() { | |||
return this.menuService; | |||
} | |||
@Override | |||
public WxMpUserService getUserService() { | |||
return this.userService; | |||
} | |||
@Override | |||
public WxMpGroupService getGroupService() { | |||
return this.groupService; | |||
} | |||
@Override | |||
public WxMpQrcodeService getQrcodeService() { | |||
return this.qrCodeService; | |||
} | |||
} |
@@ -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 { | |||
private static final long serialVersionUID = -9196732086954365246L; | |||
private String toUser; | |||
private String msgType; | |||
private String content; | |||
@@ -23,16 +24,17 @@ public class WxMpCustomMessage implements Serializable { | |||
private String description; | |||
private String musicUrl; | |||
private String hqMusicUrl; | |||
private List<WxArticle> articles = new ArrayList<WxArticle>(); | |||
private String kfAccount; | |||
private List<WxArticle> articles = new ArrayList<>(); | |||
public String getToUser() { | |||
return toUser; | |||
return this.toUser; | |||
} | |||
public void setToUser(String toUser) { | |||
this.toUser = toUser; | |||
} | |||
public String getMsgType() { | |||
return msgType; | |||
return this.msgType; | |||
} | |||
/** | |||
@@ -51,49 +53,49 @@ public class WxMpCustomMessage implements Serializable { | |||
this.msgType = msgType; | |||
} | |||
public String getContent() { | |||
return content; | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
this.content = content; | |||
} | |||
public String getMediaId() { | |||
return mediaId; | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
this.mediaId = mediaId; | |||
} | |||
public String getThumbMediaId() { | |||
return thumbMediaId; | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
this.thumbMediaId = thumbMediaId; | |||
} | |||
public String getTitle() { | |||
return title; | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return description; | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String getMusicUrl() { | |||
return musicUrl; | |||
return this.musicUrl; | |||
} | |||
public void setMusicUrl(String musicUrl) { | |||
this.musicUrl = musicUrl; | |||
} | |||
public String getHqMusicUrl() { | |||
return hqMusicUrl; | |||
return this.hqMusicUrl; | |||
} | |||
public void setHqMusicUrl(String hqMusicUrl) { | |||
this.hqMusicUrl = hqMusicUrl; | |||
} | |||
public List<WxArticle> getArticles() { | |||
return articles; | |||
return this.articles; | |||
} | |||
public void setArticles(List<WxArticle> articles) { | |||
this.articles = articles; | |||
@@ -111,25 +113,25 @@ public class WxMpCustomMessage implements Serializable { | |||
private String picUrl; | |||
public String getTitle() { | |||
return title; | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
this.title = title; | |||
} | |||
public String getDescription() { | |||
return description; | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
this.description = description; | |||
} | |||
public String getUrl() { | |||
return url; | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
this.url = url; | |||
} | |||
public String getPicUrl() { | |||
return picUrl; | |||
return this.picUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
this.picUrl = picUrl; | |||
@@ -139,7 +141,6 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得文本消息builder | |||
* @return | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
@@ -147,7 +148,6 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得图片消息builder | |||
* @return | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
@@ -155,7 +155,6 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得语音消息builder | |||
* @return | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
@@ -163,7 +162,6 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得视频消息builder | |||
* @return | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
@@ -171,7 +169,6 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得音乐消息builder | |||
* @return | |||
*/ | |||
public static MusicBuilder MUSIC() { | |||
return new MusicBuilder(); | |||
@@ -179,10 +176,17 @@ public class WxMpCustomMessage implements Serializable { | |||
/** | |||
* 获得图文消息builder | |||
* @return | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
} | |||
public String getKfAccount() { | |||
return kfAccount; | |||
} | |||
public void setKfAccount(String kfAccount) { | |||
this.kfAccount = kfAccount; | |||
} | |||
} |
@@ -12,8 +12,9 @@ import java.util.List; | |||
* @author chanjarster | |||
*/ | |||
public class WxMpMassOpenIdsMessage implements Serializable { | |||
private static final long serialVersionUID = -8022910911104788999L; | |||
private List<String> toUsers = new ArrayList<String>(); | |||
private List<String> toUsers = new ArrayList<>(); | |||
private String msgType; | |||
private String content; | |||
private String mediaId; | |||
@@ -23,7 +24,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||
} | |||
public String getMsgType() { | |||
return msgType; | |||
return this.msgType; | |||
} | |||
/** | |||
@@ -43,7 +44,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||
} | |||
public String getContent() { | |||
return content; | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
@@ -51,7 +52,7 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||
} | |||
public String getMediaId() { | |||
return mediaId; | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
@@ -64,10 +65,9 @@ public class WxMpMassOpenIdsMessage implements Serializable { | |||
/** | |||
* OpenId列表,最多支持10,000个 | |||
* @return | |||
*/ | |||
public List<String> getToUsers() { | |||
return toUsers; | |||
return this.toUsers; | |||
} | |||
/** | |||
@@ -1,18 +1,24 @@ | |||
package me.chanjar.weixin.mp.bean; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; | |||
import me.chanjar.weixin.mp.util.json.WxLongTimeJsonSerializer; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.lang3.builder.ToStringBuilder; | |||
import org.apache.commons.lang3.builder.ToStringStyle; | |||
import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||
import me.chanjar.weixin.mp.util.crypto.WxMpCryptUtil; | |||
import me.chanjar.weixin.mp.util.xml.XStreamTransformer; | |||
import org.apache.commons.io.IOUtils; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.Serializable; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* <pre> | |||
@@ -28,46 +34,49 @@ import java.util.List; | |||
@XStreamAlias("xml") | |||
public class WxMpXmlMessage implements Serializable { | |||
private static final long serialVersionUID = -3586245291677274914L; | |||
/////////////////////// | |||
// 以下都是微信推送过来的消息的xml的element所对应的属性 | |||
/////////////////////// | |||
@XStreamAlias("ToUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String toUserName; | |||
@XStreamAlias("FromUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String fromUserName; | |||
@XStreamAlias("CreateTime") | |||
@JsonSerialize(using = WxLongTimeJsonSerializer.class) | |||
private Long createTime; | |||
@XStreamAlias("MsgType") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String msgType; | |||
@XStreamAlias("Content") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String content; | |||
@XStreamAlias("MsgId") | |||
private Long msgId; | |||
@XStreamAlias("PicUrl") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String picUrl; | |||
@XStreamAlias("MediaId") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String mediaId; | |||
@XStreamAlias("Format") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String format; | |||
@XStreamAlias("ThumbMediaId") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String thumbMediaId; | |||
@XStreamAlias("Location_X") | |||
@@ -80,31 +89,31 @@ public class WxMpXmlMessage implements Serializable { | |||
private Double scale; | |||
@XStreamAlias("Label") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String label; | |||
@XStreamAlias("Title") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String title; | |||
@XStreamAlias("Description") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String description; | |||
@XStreamAlias("Url") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String url; | |||
@XStreamAlias("Event") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String event; | |||
@XStreamAlias("EventKey") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String eventKey; | |||
@XStreamAlias("Ticket") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String ticket; | |||
@XStreamAlias("Latitude") | |||
@@ -117,7 +126,7 @@ public class WxMpXmlMessage implements Serializable { | |||
private Double precision; | |||
@XStreamAlias("Recognition") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String recognition; | |||
/////////////////////////////////////// | |||
@@ -127,7 +136,7 @@ public class WxMpXmlMessage implements Serializable { | |||
* 群发的结果 | |||
*/ | |||
@XStreamAlias("Status") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String status; | |||
/** | |||
* group_id下粉丝数;或者openid_list中的粉丝数 | |||
@@ -150,26 +159,45 @@ public class WxMpXmlMessage implements Serializable { | |||
@XStreamAlias("ErrorCount") | |||
private Integer errorCount; | |||
/////////////////////////////////////// | |||
// 客服会话管理相关事件推送 | |||
/////////////////////////////////////// | |||
/** | |||
* 创建或关闭客服会话时的客服帐号 | |||
*/ | |||
@XStreamAlias("KfAccount") | |||
private String kfAccount; | |||
/** | |||
* 转接客服会话时的转入客服帐号 | |||
*/ | |||
@XStreamAlias("ToKfAccount") | |||
private String toKfAccount; | |||
/** | |||
* 转接客服会话时的转出客服帐号 | |||
*/ | |||
@XStreamAlias("FromKfAccount") | |||
private String fromKfAccount; | |||
/////////////////////////////////////// | |||
// 卡券相关事件推送 | |||
/////////////////////////////////////// | |||
@XStreamAlias("CardId") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String cardId; | |||
@XStreamAlias("FriendUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String friendUserName; | |||
@XStreamAlias("IsGiveByFriend") | |||
private Integer isGiveByFriend; // 是否为转赠,1代表是,0代表否 | |||
@XStreamAlias("UserCardCode") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String userCardCode; | |||
@XStreamAlias("OldUserCardCode") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String oldUserCardCode; | |||
@XStreamAlias("OuterId") | |||
@@ -185,7 +213,7 @@ public class WxMpXmlMessage implements Serializable { | |||
private SendLocationInfo sendLocationInfo = new SendLocationInfo(); | |||
public String getToUserName() { | |||
return toUserName; | |||
return this.toUserName; | |||
} | |||
public void setToUserName(String toUserName) { | |||
@@ -193,7 +221,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Long getCreateTime() { | |||
return createTime; | |||
return this.createTime; | |||
} | |||
public void setCreateTime(Long createTime) { | |||
@@ -212,10 +240,9 @@ public class WxMpXmlMessage implements Serializable { | |||
* {@link me.chanjar.weixin.common.api.WxConsts#XML_MSG_EVENT} | |||
* </pre> | |||
* | |||
* @return | |||
*/ | |||
public String getMsgType() { | |||
return msgType; | |||
return this.msgType; | |||
} | |||
/** | |||
@@ -236,7 +263,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getContent() { | |||
return content; | |||
return this.content; | |||
} | |||
public void setContent(String content) { | |||
@@ -244,7 +271,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Long getMsgId() { | |||
return msgId; | |||
return this.msgId; | |||
} | |||
public void setMsgId(Long msgId) { | |||
@@ -252,7 +279,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getPicUrl() { | |||
return picUrl; | |||
return this.picUrl; | |||
} | |||
public void setPicUrl(String picUrl) { | |||
@@ -260,7 +287,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getMediaId() { | |||
return mediaId; | |||
return this.mediaId; | |||
} | |||
public void setMediaId(String mediaId) { | |||
@@ -268,7 +295,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getFormat() { | |||
return format; | |||
return this.format; | |||
} | |||
public void setFormat(String format) { | |||
@@ -276,7 +303,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getThumbMediaId() { | |||
return thumbMediaId; | |||
return this.thumbMediaId; | |||
} | |||
public void setThumbMediaId(String thumbMediaId) { | |||
@@ -284,7 +311,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getLocationX() { | |||
return locationX; | |||
return this.locationX; | |||
} | |||
public void setLocationX(Double locationX) { | |||
@@ -292,7 +319,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getLocationY() { | |||
return locationY; | |||
return this.locationY; | |||
} | |||
public void setLocationY(Double locationY) { | |||
@@ -300,7 +327,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getScale() { | |||
return scale; | |||
return this.scale; | |||
} | |||
public void setScale(Double scale) { | |||
@@ -308,7 +335,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getLabel() { | |||
return label; | |||
return this.label; | |||
} | |||
public void setLabel(String label) { | |||
@@ -316,7 +343,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getTitle() { | |||
return title; | |||
return this.title; | |||
} | |||
public void setTitle(String title) { | |||
@@ -324,7 +351,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getDescription() { | |||
return description; | |||
return this.description; | |||
} | |||
public void setDescription(String description) { | |||
@@ -332,7 +359,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getUrl() { | |||
return url; | |||
return this.url; | |||
} | |||
public void setUrl(String url) { | |||
@@ -340,7 +367,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getEvent() { | |||
return event; | |||
return this.event; | |||
} | |||
public void setEvent(String event) { | |||
@@ -348,7 +375,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getEventKey() { | |||
return eventKey; | |||
return this.eventKey; | |||
} | |||
public void setEventKey(String eventKey) { | |||
@@ -356,7 +383,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getTicket() { | |||
return ticket; | |||
return this.ticket; | |||
} | |||
public void setTicket(String ticket) { | |||
@@ -364,7 +391,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getLatitude() { | |||
return latitude; | |||
return this.latitude; | |||
} | |||
public void setLatitude(Double latitude) { | |||
@@ -372,7 +399,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getLongitude() { | |||
return longitude; | |||
return this.longitude; | |||
} | |||
public void setLongitude(Double longitude) { | |||
@@ -380,7 +407,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Double getPrecision() { | |||
return precision; | |||
return this.precision; | |||
} | |||
public void setPrecision(Double precision) { | |||
@@ -388,7 +415,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getRecognition() { | |||
return recognition; | |||
return this.recognition; | |||
} | |||
public void setRecognition(String recognition) { | |||
@@ -396,7 +423,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getFromUserName() { | |||
return fromUserName; | |||
return this.fromUserName; | |||
} | |||
public void setFromUserName(String fromUserName) { | |||
@@ -419,30 +446,29 @@ public class WxMpXmlMessage implements Serializable { | |||
* @param timestamp | |||
* @param nonce | |||
* @param msgSignature | |||
* @return | |||
*/ | |||
public static WxMpXmlMessage fromEncryptedXml( | |||
String encryptedXml, | |||
WxMpConfigStorage wxMpConfigStorage, | |||
String timestamp, String nonce, String msgSignature) { | |||
public static WxMpXmlMessage fromEncryptedXml(String encryptedXml, | |||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, | |||
String msgSignature) { | |||
WxMpCryptUtil cryptUtil = new WxMpCryptUtil(wxMpConfigStorage); | |||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | |||
String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, | |||
encryptedXml); | |||
return fromXml(plainText); | |||
} | |||
public static WxMpXmlMessage fromEncryptedXml( | |||
InputStream is, | |||
WxMpConfigStorage wxMpConfigStorage, | |||
String timestamp, String nonce, String msgSignature) { | |||
public static WxMpXmlMessage fromEncryptedXml(InputStream is, | |||
WxMpConfigStorage wxMpConfigStorage, String timestamp, String nonce, | |||
String msgSignature) { | |||
try { | |||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, timestamp, nonce, msgSignature); | |||
return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxMpConfigStorage, | |||
timestamp, nonce, msgSignature); | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
public String getStatus() { | |||
return status; | |||
return this.status; | |||
} | |||
public void setStatus(String status) { | |||
@@ -450,7 +476,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getTotalCount() { | |||
return totalCount; | |||
return this.totalCount; | |||
} | |||
public void setTotalCount(Integer totalCount) { | |||
@@ -458,7 +484,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getFilterCount() { | |||
return filterCount; | |||
return this.filterCount; | |||
} | |||
public void setFilterCount(Integer filterCount) { | |||
@@ -466,7 +492,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getSentCount() { | |||
return sentCount; | |||
return this.sentCount; | |||
} | |||
public void setSentCount(Integer sentCount) { | |||
@@ -474,7 +500,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getErrorCount() { | |||
return errorCount; | |||
return this.errorCount; | |||
} | |||
public void setErrorCount(Integer errorCount) { | |||
@@ -482,7 +508,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getCardId() { | |||
return cardId; | |||
return this.cardId; | |||
} | |||
public void setCardId(String cardId) { | |||
@@ -490,7 +516,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getFriendUserName() { | |||
return friendUserName; | |||
return this.friendUserName; | |||
} | |||
public void setFriendUserName(String friendUserName) { | |||
@@ -498,7 +524,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getIsGiveByFriend() { | |||
return isGiveByFriend; | |||
return this.isGiveByFriend; | |||
} | |||
public void setIsGiveByFriend(Integer isGiveByFriend) { | |||
@@ -506,7 +532,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getUserCardCode() { | |||
return userCardCode; | |||
return this.userCardCode; | |||
} | |||
public void setUserCardCode(String userCardCode) { | |||
@@ -514,7 +540,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getOldUserCardCode() { | |||
return oldUserCardCode; | |||
return this.oldUserCardCode; | |||
} | |||
public void setOldUserCardCode(String oldUserCardCode) { | |||
@@ -522,7 +548,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public Integer getOuterId() { | |||
return outerId; | |||
return this.outerId; | |||
} | |||
public void setOuterId(Integer outerId) { | |||
@@ -530,7 +556,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public WxMpXmlMessage.ScanCodeInfo getScanCodeInfo() { | |||
return scanCodeInfo; | |||
return this.scanCodeInfo; | |||
} | |||
public void setScanCodeInfo(WxMpXmlMessage.ScanCodeInfo scanCodeInfo) { | |||
@@ -538,7 +564,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public WxMpXmlMessage.SendPicsInfo getSendPicsInfo() { | |||
return sendPicsInfo; | |||
return this.sendPicsInfo; | |||
} | |||
public void setSendPicsInfo(WxMpXmlMessage.SendPicsInfo sendPicsInfo) { | |||
@@ -546,31 +572,59 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public WxMpXmlMessage.SendLocationInfo getSendLocationInfo() { | |||
return sendLocationInfo; | |||
return this.sendLocationInfo; | |||
} | |||
public void setSendLocationInfo(WxMpXmlMessage.SendLocationInfo sendLocationInfo) { | |||
public void setSendLocationInfo( | |||
WxMpXmlMessage.SendLocationInfo sendLocationInfo) { | |||
this.sendLocationInfo = sendLocationInfo; | |||
} | |||
public String getKfAccount() { | |||
return this.kfAccount; | |||
} | |||
public void setKfAccount(String kfAccount) { | |||
this.kfAccount = kfAccount; | |||
} | |||
public String getToKfAccount() { | |||
return this.toKfAccount; | |||
} | |||
public void setToKfAccount(String toKfAccount) { | |||
this.toKfAccount = toKfAccount; | |||
} | |||
public String getFromKfAccount() { | |||
return this.fromKfAccount; | |||
} | |||
public void setFromKfAccount(String fromKfAccount) { | |||
this.fromKfAccount = fromKfAccount; | |||
} | |||
@XStreamAlias("ScanCodeInfo") | |||
public static class ScanCodeInfo { | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||
} | |||
@XStreamAlias("ScanType") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String scanType; | |||
@XStreamAlias("ScanResult") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String scanResult; | |||
/** | |||
* 扫描类型,一般是qrcode | |||
* @return | |||
*/ | |||
public String getScanType() { | |||
return scanType; | |||
return this.scanType; | |||
} | |||
public void setScanType(String scanType) { | |||
@@ -579,10 +633,9 @@ public class WxMpXmlMessage implements Serializable { | |||
/** | |||
* 扫描结果,即二维码对应的字符串信息 | |||
* @return | |||
*/ | |||
public String getScanResult() { | |||
return scanResult; | |||
return this.scanResult; | |||
} | |||
public void setScanResult(String scanResult) { | |||
@@ -593,15 +646,19 @@ public class WxMpXmlMessage implements Serializable { | |||
@XStreamAlias("SendPicsInfo") | |||
public static class SendPicsInfo { | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||
} | |||
@XStreamAlias("Count") | |||
private Long count; | |||
@XStreamAlias("PicList") | |||
protected final List<Item> picList = new ArrayList<Item>(); | |||
protected final List<Item> picList = new ArrayList<>(); | |||
public Long getCount() { | |||
return count; | |||
return this.count; | |||
} | |||
public void setCount(Long count) { | |||
@@ -609,18 +666,23 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public List<Item> getPicList() { | |||
return picList; | |||
return this.picList; | |||
} | |||
@XStreamAlias("item") | |||
public static class Item { | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, | |||
ToStringStyle.JSON_STYLE); | |||
} | |||
@XStreamAlias("PicMd5Sum") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String picMd5Sum; | |||
public String getPicMd5Sum() { | |||
return picMd5Sum; | |||
return this.picMd5Sum; | |||
} | |||
public void setPicMd5Sum(String picMd5Sum) { | |||
@@ -633,27 +695,32 @@ public class WxMpXmlMessage implements Serializable { | |||
public static class SendLocationInfo { | |||
@XStreamAlias("Location_X") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String locationX; | |||
@XStreamAlias("Location_Y") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String locationY; | |||
@XStreamAlias("Scale") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String scale; | |||
@XStreamAlias("Label") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String label; | |||
@XStreamAlias("Poiname") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
@XStreamConverter(value = XStreamCDataConverter.class) | |||
private String poiname; | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||
} | |||
public String getLocationX() { | |||
return locationX; | |||
return this.locationX; | |||
} | |||
public void setLocationX(String locationX) { | |||
@@ -661,7 +728,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getLocationY() { | |||
return locationY; | |||
return this.locationY; | |||
} | |||
public void setLocationY(String locationY) { | |||
@@ -669,7 +736,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getScale() { | |||
return scale; | |||
return this.scale; | |||
} | |||
public void setScale(String scale) { | |||
@@ -677,7 +744,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getLabel() { | |||
return label; | |||
return this.label; | |||
} | |||
public void setLabel(String label) { | |||
@@ -685,7 +752,7 @@ public class WxMpXmlMessage implements Serializable { | |||
} | |||
public String getPoiname() { | |||
return poiname; | |||
return this.poiname; | |||
} | |||
public void setPoiname(String poiname) { | |||
@@ -695,44 +762,6 @@ public class WxMpXmlMessage implements Serializable { | |||
@Override | |||
public String toString() { | |||
return "WxMpXmlMessage{" + | |||
"toUserName='" + toUserName + '\'' + | |||
", fromUserName='" + fromUserName + '\'' + | |||
", createTime=" + createTime + | |||
", msgType='" + msgType + '\'' + | |||
", content='" + content + '\'' + | |||
", msgId=" + msgId + | |||
", picUrl='" + picUrl + '\'' + | |||
", mediaId='" + mediaId + '\'' + | |||
", format='" + format + '\'' + | |||
", thumbMediaId='" + thumbMediaId + '\'' + | |||
", locationX=" + locationX + | |||
", locationY=" + locationY + | |||
", scale=" + scale + | |||
", label='" + label + '\'' + | |||
", title='" + title + '\'' + | |||
", description='" + description + '\'' + | |||
", url='" + url + '\'' + | |||
", event='" + event + '\'' + | |||
", eventKey='" + eventKey + '\'' + | |||
", ticket='" + ticket + '\'' + | |||
", latitude=" + latitude + | |||
", longitude=" + longitude + | |||
", precision=" + precision + | |||
", recognition='" + recognition + '\'' + | |||
", status='" + status + '\'' + | |||
", totalCount=" + totalCount + | |||
", filterCount=" + filterCount + | |||
", sentCount=" + sentCount + | |||
", errorCount=" + errorCount + | |||
", cardId='" + cardId + '\'' + | |||
", isGiveByFriend=" + isGiveByFriend + | |||
", userCardCode='" + userCardCode + '\'' + | |||
", oldUserCardCode='" + oldUserCardCode + '\'' + | |||
", outerId=" + outerId + | |||
", scanCodeInfo=" + scanCodeInfo + | |||
", sendPicsInfo=" + sendPicsInfo + | |||
", sendLocationInfo=" + sendLocationInfo + | |||
'}'; | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); | |||
} | |||
} |
@@ -13,6 +13,8 @@ import java.io.Serializable; | |||
@XStreamAlias("xml") | |||
public abstract class WxMpXmlOutMessage implements Serializable { | |||
private static final long serialVersionUID = -381382011286216263L; | |||
@XStreamAlias("ToUserName") | |||
@XStreamConverter(value=XStreamCDataConverter.class) | |||
protected String toUserName; | |||
@@ -29,7 +31,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
protected String msgType; | |||
public String getToUserName() { | |||
return toUserName; | |||
return this.toUserName; | |||
} | |||
public void setToUserName(String toUserName) { | |||
@@ -37,7 +39,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
} | |||
public String getFromUserName() { | |||
return fromUserName; | |||
return this.fromUserName; | |||
} | |||
public void setFromUserName(String fromUserName) { | |||
@@ -45,7 +47,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
} | |||
public Long getCreateTime() { | |||
return createTime; | |||
return this.createTime; | |||
} | |||
public void setCreateTime(Long createTime) { | |||
@@ -53,7 +55,7 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
} | |||
public String getMsgType() { | |||
return msgType; | |||
return this.msgType; | |||
} | |||
public void setMsgType(String msgType) { | |||
@@ -61,12 +63,11 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
} | |||
public String toXml() { | |||
return XStreamTransformer.toXml((Class) this.getClass(), this); | |||
return XStreamTransformer.toXml((Class<WxMpXmlOutMessage>) this.getClass(), this); | |||
} | |||
/** | |||
* 转换成加密的xml格式 | |||
* @return | |||
*/ | |||
public String toEncryptedXml(WxMpConfigStorage wxMpConfigStorage) { | |||
String plainXml = toXml(); | |||
@@ -76,7 +77,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得文本消息builder | |||
* @return | |||
*/ | |||
public static TextBuilder TEXT() { | |||
return new TextBuilder(); | |||
@@ -84,7 +84,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得图片消息builder | |||
* @return | |||
*/ | |||
public static ImageBuilder IMAGE() { | |||
return new ImageBuilder(); | |||
@@ -92,7 +91,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得语音消息builder | |||
* @return | |||
*/ | |||
public static VoiceBuilder VOICE() { | |||
return new VoiceBuilder(); | |||
@@ -100,7 +98,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得视频消息builder | |||
* @return | |||
*/ | |||
public static VideoBuilder VIDEO() { | |||
return new VideoBuilder(); | |||
@@ -108,7 +105,6 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得音乐消息builder | |||
* @return | |||
*/ | |||
public static MusicBuilder MUSIC() { | |||
return new MusicBuilder(); | |||
@@ -116,15 +112,13 @@ public abstract class WxMpXmlOutMessage implements Serializable { | |||
/** | |||
* 获得图文消息builder | |||
* @return | |||
*/ | |||
public static NewsBuilder NEWS() { | |||
return new NewsBuilder(); | |||
} | |||
/** | |||
/** | |||
* 获得客服消息builder | |||
* | |||
* @return | |||
*/ | |||
public static TransferCustomerServiceBuilder TRANSFER_CUSTOMER_SERVICE() { | |||
return new TransferCustomerServiceBuilder(); | |||
@@ -7,6 +7,8 @@ import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
@XStreamAlias("xml") | |||
public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage { | |||
private static final long serialVersionUID = 1850903037285841322L; | |||
@XStreamAlias("TransInfo") | |||
protected TransInfo transInfo; | |||
@@ -15,7 +17,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage | |||
} | |||
public TransInfo getTransInfo() { | |||
return transInfo; | |||
return this.transInfo; | |||
} | |||
public void setTransInfo(TransInfo transInfo) { | |||
@@ -30,7 +32,7 @@ public class WxMpXmlOutTransferCustomerServiceMessage extends WxMpXmlOutMessage | |||
private String kfAccount; | |||
public String getKfAccount() { | |||
return kfAccount; | |||
return this.kfAccount; | |||
} | |||
public void setKfAccount(String kfAccount) { | |||
@@ -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> { | |||
private String kfAccount; | |||
public TransferCustomerServiceBuilder kfAccount(String kfAccount) { | |||
this.kfAccount = kfAccount; | |||
public TransferCustomerServiceBuilder kfAccount(String kf) { | |||
this.kfAccount = kf; | |||
return this; | |||
} | |||
@Override | |||
public WxMpXmlOutTransferCustomerServiceMessage build() { | |||
WxMpXmlOutTransferCustomerServiceMessage m = new WxMpXmlOutTransferCustomerServiceMessage(); | |||
setCommon(m); | |||
if(StringUtils.isNotBlank(kfAccount)){ | |||
if(StringUtils.isNotBlank(this.kfAccount)){ | |||
WxMpXmlOutTransferCustomerServiceMessage.TransInfo transInfo = new WxMpXmlOutTransferCustomerServiceMessage.TransInfo(); | |||
transInfo.setKfAccount(kfAccount); | |||
transInfo.setKfAccount(this.kfAccount); | |||
m.setTransInfo(transInfo); | |||
} | |||
return m; | |||
@@ -45,4 +45,9 @@ public class WxMpQrCodeTicket implements Serializable { | |||
public static WxMpQrCodeTicket fromJson(String json) { | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpQrCodeTicket.class); | |||
} | |||
@Override | |||
public String toString() { | |||
return WxMpGsonBuilder.INSTANCE.create().toJson(this); | |||
} | |||
} |
@@ -44,4 +44,9 @@ public class WxMpUserList { | |||
public static WxMpUserList fromJson(String json) { | |||
return WxMpGsonBuilder.INSTANCE.create().fromJson(json, WxMpUserList.class); | |||
} | |||
@Override | |||
public String toString() { | |||
return WxMpGsonBuilder.INSTANCE.create().toJson(this); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |